diff --git a/apex/apex.go b/apex/apex.go index 76fa60b6d..c7911624a 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -52,6 +52,7 @@ type dependencyTag struct { var ( sharedLibTag = dependencyTag{name: "sharedLib", payload: true} + jniLibTag = dependencyTag{name: "jniLib", payload: true} executableTag = dependencyTag{name: "executable", payload: true} javaLibTag = dependencyTag{name: "javaLib", payload: true} prebuiltTag = dependencyTag{name: "prebuilt", payload: true} @@ -1159,6 +1160,9 @@ type ApexNativeDependencies struct { // List of native libraries Native_shared_libs []string + // List of JNI libraries + Jni_libs []string + // List of native executables Binaries []string @@ -1406,6 +1410,8 @@ type apexFile struct { jacocoReportClassesFile android.Path // only for javalibs and apps certificate java.Certificate // only for apps + + isJniLib bool } func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, moduleName string, installDir string, class apexFileClass, module android.Module) apexFile { @@ -1536,6 +1542,12 @@ func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, {Mutator: "version", Variation: ""}, // "" is the non-stub variant }...), sharedLibTag, nativeModules.Native_shared_libs...) + ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{ + {Mutator: "image", Variation: imageVariation}, + {Mutator: "link", Variation: "shared"}, + {Mutator: "version", Variation: ""}, // "" is the non-stub variant + }...), jniLibTag, nativeModules.Jni_libs...) + ctx.AddFarVariationDependencies(append(target.Variations(), blueprint.Variation{Mutator: "image", Variation: imageVariation}), executableTag, nativeModules.Binaries...) @@ -1576,12 +1588,13 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { } } for i, target := range targets { - // When multilib.* is omitted for native_shared_libs/tests, it implies + // When multilib.* is omitted for native_shared_libs/jni_libs/tests, it implies // multilib.both addDependenciesForNativeModules(ctx, ApexNativeDependencies{ Native_shared_libs: a.properties.Native_shared_libs, Tests: a.properties.Tests, + Jni_libs: a.properties.Jni_libs, Binaries: nil, }, target, a.getImageVariation(config)) @@ -1600,6 +1613,7 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { ApexNativeDependencies{ Native_shared_libs: nil, Tests: nil, + Jni_libs: nil, Binaries: a.properties.Binaries, }, target, a.getImageVariation(config)) @@ -1641,7 +1655,7 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { for _, sanitizer := range ctx.Config().SanitizeDevice() { if sanitizer == "hwaddress" { addDependenciesForNativeModules(ctx, - ApexNativeDependencies{[]string{"libclang_rt.hwasan-aarch64-android"}, nil, nil}, + ApexNativeDependencies{[]string{"libclang_rt.hwasan-aarch64-android"}, nil, nil, nil}, target, a.getImageVariation(config)) break } @@ -2063,16 +2077,23 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { depName := ctx.OtherModuleName(child) if _, isDirectDep := parent.(*apexBundle); isDirectDep { switch depTag { - case sharedLibTag: + case sharedLibTag, jniLibTag: + isJniLib := depTag == jniLibTag if c, ok := child.(*cc.Module); ok { // bootstrap bionic libs are treated as provided by system if c.HasStubsVariants() && !cc.InstallToBootstrap(c.BaseModuleName(), ctx.Config()) { provideNativeLibs = append(provideNativeLibs, c.OutputFile().Path().Base()) } - filesInfo = append(filesInfo, apexFileForNativeLibrary(ctx, c, handleSpecialLibs)) + fi := apexFileForNativeLibrary(ctx, c, handleSpecialLibs) + fi.isJniLib = isJniLib + filesInfo = append(filesInfo, fi) return true // track transitive dependencies } else { - ctx.PropertyErrorf("native_shared_libs", "%q is not a cc_library or cc_library_shared module", depName) + propertyName := "native_shared_libs" + if isJniLib { + propertyName = "jni_libs" + } + ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName) } case executableTag: if cc, ok := child.(*cc.Module); ok { diff --git a/apex/apex_test.go b/apex/apex_test.go index d1d8d6491..8c5ca8b6d 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -226,6 +226,14 @@ func tearDown() { os.RemoveAll(buildDir) } +// ensure that 'result' equals 'expected' +func ensureEquals(t *testing.T, result string, expected string) { + t.Helper() + if result != expected { + t.Errorf("%q != %q", expected, result) + } +} + // ensure that 'result' contains 'expected' func ensureContains(t *testing.T, result string, expected string) { t.Helper() @@ -3621,6 +3629,70 @@ func TestSymlinksFromApexToSystem(t *testing.T) { ensureRealfileExists(t, files, "lib64/myotherlib.so") // this is a real file } +func TestApexWithJniLibs(t *testing.T) { + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + jni_libs: ["mylib"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + shared_libs: ["mylib2"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + } + + cc_library { + name: "mylib2", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + } + `) + + rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") + // Notice mylib2.so (transitive dep) is not added as a jni_lib + ensureEquals(t, rule.Args["opt"], "-a jniLibs mylib.so") + ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + "lib64/mylib.so", + "lib64/mylib2.so", + }) +} + +func TestApexWithJniLibs_Errors(t *testing.T) { + testApexError(t, `jni_libs: "xxx" is not a cc_library`, ` + apex { + name: "myapex", + key: "myapex.key", + jni_libs: ["xxx"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + prebuilt_etc { + name: "xxx", + src: "xxx", + } + `, withFiles(map[string][]byte{ + "xxx": nil, + })) +} + func TestMain(m *testing.M) { run := func() int { setUp() diff --git a/apex/builder.go b/apex/builder.go index 9eaf6565b..8c81fb471 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -180,6 +180,17 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, optCommands = append(optCommands, "-v name "+*a.properties.Apex_name) } + // collect jniLibs. Notice that a.filesInfo is already sorted + var jniLibs []string + for _, fi := range a.filesInfo { + if fi.isJniLib { + jniLibs = append(jniLibs, fi.builtFile.Base()) + } + } + if len(jniLibs) > 0 { + optCommands = append(optCommands, "-a jniLibs "+strings.Join(jniLibs, " ")) + } + ctx.Build(pctx, android.BuildParams{ Rule: apexManifestRule, Input: manifestSrc,