From 2ca8427124bce30076e3f7fa3ce4435a9ca0ee9b Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Sat, 10 Feb 2024 00:15:21 +0000 Subject: [PATCH] [Ravenwood] Install transitive JNI libraries too Ignore-AOSP-First: Will cherry-pick later. Bug: 318393625 Bug: 323931246 Test: run-ravenwood-tests.sh Test: (with local change) atest RavenwoodBivalentTest_device RavenwoodMockitoTest_device (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:55c035761c8b7b758d710ed5eeb9192525677057) Merged-In: Ie0f6bbf1aa6252d415c53cfc19178f0986cc57f1 Change-Id: Ie0f6bbf1aa6252d415c53cfc19178f0986cc57f1 --- java/app.go | 46 ++++++++++++++-------- java/ravenwood.go | 86 +++++++++++++++++++++++++++++++++--------- java/ravenwood_test.go | 46 ++++++++++++++++++---- 3 files changed, 138 insertions(+), 40 deletions(-) diff --git a/java/app.go b/java/app.go index 0c56d81fc..9be3f6d50 100755 --- a/java/app.go +++ b/java/app.go @@ -920,15 +920,39 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, shouldCollectRecursiveNativeDeps bool, checkNativeSdkVersion bool) ([]jniLib, android.Paths, []Certificate) { - var jniLibs []jniLib - var prebuiltJniPackages android.Paths - var certificates []Certificate - seenModulePaths := make(map[string]bool) - if checkNativeSdkVersion { checkNativeSdkVersion = app.SdkVersion(ctx).Specified() && app.SdkVersion(ctx).Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx) } + jniLib, prebuiltJniPackages := collectJniDeps(ctx, shouldCollectRecursiveNativeDeps, + checkNativeSdkVersion, func(dep cc.LinkableInterface) bool { + return !dep.IsNdk(ctx.Config()) && !dep.IsStubs() + }) + + var certificates []Certificate + + ctx.VisitDirectDeps(func(module android.Module) { + otherName := ctx.OtherModuleName(module) + tag := ctx.OtherModuleDependencyTag(module) + + if tag == certificateTag { + if dep, ok := module.(*AndroidAppCertificate); ok { + certificates = append(certificates, dep.Certificate) + } else { + ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", otherName) + } + } + }) + return jniLib, prebuiltJniPackages, certificates +} + +func collectJniDeps(ctx android.ModuleContext, + shouldCollectRecursiveNativeDeps bool, + checkNativeSdkVersion bool, + filter func(cc.LinkableInterface) bool) ([]jniLib, android.Paths) { + var jniLibs []jniLib + var prebuiltJniPackages android.Paths + seenModulePaths := make(map[string]bool) ctx.WalkDeps(func(module android.Module, parent android.Module) bool { otherName := ctx.OtherModuleName(module) @@ -936,7 +960,7 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, if IsJniDepTag(tag) || cc.IsSharedDepTag(tag) { if dep, ok := module.(cc.LinkableInterface); ok { - if dep.IsNdk(ctx.Config()) || dep.IsStubs() { + if filter != nil && !filter(dep) { return false } @@ -977,18 +1001,10 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, prebuiltJniPackages = append(prebuiltJniPackages, info.JniPackages...) } - if tag == certificateTag { - if dep, ok := module.(*AndroidAppCertificate); ok { - certificates = append(certificates, dep.Certificate) - } else { - ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", otherName) - } - } - return false }) - return jniLibs, prebuiltJniPackages, certificates + return jniLibs, prebuiltJniPackages } func (a *AndroidApp) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) { diff --git a/java/ravenwood.go b/java/ravenwood.go index dcb5c8bdb..908619d5f 100644 --- a/java/ravenwood.go +++ b/java/ravenwood.go @@ -17,6 +17,7 @@ import ( "android/soong/android" "android/soong/tradefed" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -29,12 +30,20 @@ func RegisterRavenwoodBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("android_ravenwood_libgroup", ravenwoodLibgroupFactory) } -var ravenwoodTag = dependencyTag{name: "ravenwood"} -var ravenwoodJniTag = dependencyTag{name: "ravenwood-jni"} +var ravenwoodLibContentTag = dependencyTag{name: "ravenwoodlibcontent"} +var ravenwoodUtilsTag = dependencyTag{name: "ravenwoodutils"} +var ravenwoodRuntimeTag = dependencyTag{name: "ravenwoodruntime"} const ravenwoodUtilsName = "ravenwood-utils" const ravenwoodRuntimeName = "ravenwood-runtime" +type ravenwoodLibgroupJniDepProviderInfo struct { + // All the jni_libs module names with transient dependencies. + names map[string]bool +} + +var ravenwoodLibgroupJniDepProvider = blueprint.NewProvider[ravenwoodLibgroupJniDepProviderInfo]() + func getLibPath(archType android.ArchType) string { if archType.Multilib == "lib64" { return "lib64" @@ -91,10 +100,10 @@ func (r *ravenwoodTest) DepsMutator(ctx android.BottomUpMutatorContext) { r.Library.DepsMutator(ctx) // Generically depend on the runtime so that it's installed together with us - ctx.AddVariationDependencies(nil, ravenwoodTag, ravenwoodRuntimeName) + ctx.AddVariationDependencies(nil, ravenwoodRuntimeTag, ravenwoodRuntimeName) // Directly depend on any utils so that we link against them - utils := ctx.AddVariationDependencies(nil, ravenwoodTag, ravenwoodUtilsName)[0] + utils := ctx.AddVariationDependencies(nil, ravenwoodUtilsTag, ravenwoodUtilsName)[0] if utils != nil { for _, lib := range utils.(*ravenwoodLibgroup).ravenwoodLibgroupProperties.Libs { ctx.AddVariationDependencies(nil, libTag, lib) @@ -103,7 +112,7 @@ func (r *ravenwoodTest) DepsMutator(ctx android.BottomUpMutatorContext) { // Add jni libs for _, lib := range r.ravenwoodTestProperties.Jni_libs { - ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), ravenwoodJniTag, lib) + ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib) } } @@ -122,24 +131,47 @@ func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { r.Library.GenerateAndroidBuildActions(ctx) - // Start by depending on all files installed by dependancies + // Start by depending on all files installed by dependencies var installDeps android.InstallPaths - for _, dep := range ctx.GetDirectDepsWithTag(ravenwoodTag) { - for _, installFile := range dep.FilesToInstall() { + + // All JNI libraries included in the runtime + var runtimeJniModuleNames map[string]bool + + if utils := ctx.GetDirectDepsWithTag(ravenwoodUtilsTag)[0]; utils != nil { + for _, installFile := range utils.FilesToInstall() { installDeps = append(installDeps, installFile) } + jniDeps, ok := android.OtherModuleProvider(ctx, utils, ravenwoodLibgroupJniDepProvider) + if ok { + runtimeJniModuleNames = jniDeps.names + } } + if runtime := ctx.GetDirectDepsWithTag(ravenwoodRuntimeTag)[0]; runtime != nil { + for _, installFile := range runtime.FilesToInstall() { + installDeps = append(installDeps, installFile) + } + jniDeps, ok := android.OtherModuleProvider(ctx, runtime, ravenwoodLibgroupJniDepProvider) + if ok { + runtimeJniModuleNames = jniDeps.names + } + } + + // Also remember what JNI libs are in the runtime. + // Also depend on our config installPath := android.PathForModuleInstall(ctx, r.BaseModuleName()) installConfig := ctx.InstallFile(installPath, ctx.ModuleName()+".config", r.testConfig) installDeps = append(installDeps, installConfig) - // Depend on the JNI libraries. + // Depend on the JNI libraries, but don't install the ones that the runtime already + // contains. soInstallPath := installPath.Join(ctx, getLibPath(r.forceArchType)) - for _, dep := range ctx.GetDirectDepsWithTag(ravenwoodJniTag) { - file := android.OutputFileForModule(ctx, dep, "") - installJni := ctx.InstallFile(soInstallPath, file.Base(), file) + for _, jniLib := range collectTransitiveJniDeps(ctx) { + if _, ok := runtimeJniModuleNames[jniLib.name]; ok { + continue // Runtime already includes it. + } + installJni := ctx.InstallFile(soInstallPath, jniLib.path.Base(), jniLib.path) installDeps = append(installDeps, installJni) } @@ -199,10 +231,10 @@ func (r *ravenwoodLibgroup) TestSuites() []string { func (r *ravenwoodLibgroup) DepsMutator(ctx android.BottomUpMutatorContext) { // Always depends on our underlying libs for _, lib := range r.ravenwoodLibgroupProperties.Libs { - ctx.AddVariationDependencies(nil, ravenwoodTag, lib) + ctx.AddVariationDependencies(nil, ravenwoodLibContentTag, lib) } for _, lib := range r.ravenwoodLibgroupProperties.Jni_libs { - ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), ravenwoodJniTag, lib) + ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib) } } @@ -210,19 +242,37 @@ func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContex r.forceOSType = ctx.Config().BuildOS r.forceArchType = ctx.Config().BuildArch + // Collect the JNI dependencies, including the transitive deps. + jniDepNames := make(map[string]bool) + jniLibs := collectTransitiveJniDeps(ctx) + + for _, jni := range jniLibs { + jniDepNames[jni.name] = true + } + android.SetProvider(ctx, ravenwoodLibgroupJniDepProvider, ravenwoodLibgroupJniDepProviderInfo{ + names: jniDepNames, + }) + // Install our runtime into expected location for packaging installPath := android.PathForModuleInstall(ctx, r.BaseModuleName()) for _, lib := range r.ravenwoodLibgroupProperties.Libs { - libModule := ctx.GetDirectDepWithTag(lib, ravenwoodTag) + libModule := ctx.GetDirectDepWithTag(lib, ravenwoodLibContentTag) libJar := android.OutputFileForModule(ctx, libModule, "") ctx.InstallFile(installPath, lib+".jar", libJar) } soInstallPath := android.PathForModuleInstall(ctx, r.BaseModuleName()).Join(ctx, getLibPath(r.forceArchType)) - for _, dep := range ctx.GetDirectDepsWithTag(ravenwoodJniTag) { - file := android.OutputFileForModule(ctx, dep, "") - ctx.InstallFile(soInstallPath, file.Base(), file) + + for _, jniLib := range jniLibs { + ctx.InstallFile(soInstallPath, jniLib.path.Base(), jniLib.path) } // Normal build should perform install steps ctx.Phony(r.BaseModuleName(), android.PathForPhony(ctx, r.BaseModuleName()+"-install")) } + +// collectTransitiveJniDeps returns all JNI dependencies, including transitive +// ones, including NDK / stub libs. (Because Ravenwood has no "preinstalled" libraries) +func collectTransitiveJniDeps(ctx android.ModuleContext) []jniLib { + libs, _ := collectJniDeps(ctx, true, false, nil) + return libs +} diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go index a71391cad..59612645c 100644 --- a/java/ravenwood_test.go +++ b/java/ravenwood_test.go @@ -27,7 +27,7 @@ var prepareRavenwoodRuntime = android.GroupFixturePreparers( }), android.FixtureAddTextFile("ravenwood/Android.bp", ` cc_library_shared { - name: "ravenwood-runtime-jni", + name: "ravenwood-runtime-jni1", host_supported: true, srcs: ["jni.cpp"], } @@ -36,6 +36,14 @@ var prepareRavenwoodRuntime = android.GroupFixturePreparers( host_supported: true, srcs: ["jni.cpp"], stem: "libred", + shared_libs: [ + "ravenwood-runtime-jni3", + ], + } + cc_library_shared { + name: "ravenwood-runtime-jni3", + host_supported: true, + srcs: ["jni.cpp"], } java_library_static { name: "framework-minus-apex.ravenwood", @@ -55,7 +63,10 @@ var prepareRavenwoodRuntime = android.GroupFixturePreparers( "framework-minus-apex.ravenwood", "framework-services.ravenwood", ], - jni_libs: ["ravenwood-runtime-jni", "ravenwood-runtime-jni2"], + jni_libs: [ + "ravenwood-runtime-jni1", + "ravenwood-runtime-jni2", + ], } android_ravenwood_libgroup { name: "ravenwood-utils", @@ -88,8 +99,9 @@ func TestRavenwoodRuntime(t *testing.T) { runtime := ctx.ModuleForTests("ravenwood-runtime", "android_common") runtime.Output(installPathPrefix + "/ravenwood-runtime/framework-minus-apex.ravenwood.jar") runtime.Output(installPathPrefix + "/ravenwood-runtime/framework-services.ravenwood.jar") - runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni.so") + runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni1.so") runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/libred.so") + runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni3.so") utils := ctx.ModuleForTests("ravenwood-utils", "android_common") utils.Output(installPathPrefix + "/ravenwood-utils/framework-rules.ravenwood.jar") } @@ -104,7 +116,7 @@ func TestRavenwoodTest(t *testing.T) { prepareRavenwoodRuntime, ).RunTestWithBp(t, ` cc_library_shared { - name: "jni-lib", + name: "jni-lib1", host_supported: true, srcs: ["jni.cpp"], } @@ -113,11 +125,24 @@ func TestRavenwoodTest(t *testing.T) { host_supported: true, srcs: ["jni.cpp"], stem: "libblue", + shared_libs: [ + "jni-lib3", + ], + } + cc_library_shared { + name: "jni-lib3", + host_supported: true, + srcs: ["jni.cpp"], + stem: "libpink", } android_ravenwood_test { name: "ravenwood-test", srcs: ["Test.java"], - jni_libs: ["jni-lib", "jni-lib2"], + jni_libs: [ + "jni-lib1", + "jni-lib2", + "ravenwood-runtime-jni2", + ], sdk_version: "test_current", } `) @@ -141,14 +166,21 @@ func TestRavenwoodTest(t *testing.T) { // Verify that we've emitted test artifacts in expected location outputJar := module.Output(installPathPrefix + "/ravenwood-test/ravenwood-test.jar") module.Output(installPathPrefix + "/ravenwood-test/ravenwood-test.config") - module.Output(installPathPrefix + "/ravenwood-test/lib64/jni-lib.so") + module.Output(installPathPrefix + "/ravenwood-test/lib64/jni-lib1.so") module.Output(installPathPrefix + "/ravenwood-test/lib64/libblue.so") + module.Output(installPathPrefix + "/ravenwood-test/lib64/libpink.so") + + // ravenwood-runtime*.so are included in the runtime, so it shouldn't be emitted. + for _, o := range module.AllOutputs() { + android.AssertStringDoesNotContain(t, "runtime libs shouldn't be included", o, "/ravenwood-test/lib64/ravenwood-runtime") + } // Verify that we're going to install underlying libs orderOnly := outputJar.OrderOnly.Strings() android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/framework-minus-apex.ravenwood.jar") android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/framework-services.ravenwood.jar") - android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/lib64/ravenwood-runtime-jni.so") + android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/lib64/ravenwood-runtime-jni1.so") android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/lib64/libred.so") + android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/lib64/ravenwood-runtime-jni3.so") android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-utils/framework-rules.ravenwood.jar") }