diff --git a/apex/apex_test.go b/apex/apex_test.go index f2c0ab6ea..b14600e80 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -5922,7 +5922,6 @@ func TestApexWithApps(t *testing.T) { srcs: ["foo/bar/MyClass.java"], sdk_version: "current", system_modules: "none", - use_embedded_native_libs: true, jni_libs: ["libjni"], stl: "none", apex_available: [ "myapex" ], diff --git a/java/androidmk.go b/java/androidmk.go index 43160741b..4f740b231 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -17,6 +17,7 @@ package java import ( "fmt" "io" + "strings" "android/soong/android" @@ -412,6 +413,23 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { if app.embeddedJniLibs { jniSymbols := app.JNISymbolsInstalls(app.installPathForJNISymbols.String()) entries.SetString("LOCAL_SOONG_JNI_LIBS_SYMBOLS", jniSymbols.String()) + } else { + for _, jniLib := range app.jniLibs { + entries.AddStrings("LOCAL_SOONG_JNI_LIBS_"+jniLib.target.Arch.ArchType.String(), jniLib.name) + var partitionTag string + + // Mimic the creation of partition_tag in build/make, + // which defaults to an empty string when the partition is system. + // Otherwise, capitalize with a leading _ + if jniLib.partition == "system" { + partitionTag = "" + } else { + split := strings.Split(jniLib.partition, "/") + partitionTag = "_" + strings.ToUpper(split[len(split)-1]) + } + entries.AddStrings("LOCAL_SOONG_JNI_LIBS_PARTITION_"+jniLib.target.Arch.ArchType.String(), + jniLib.name+":"+partitionTag) + } } if len(app.jniCoverageOutputs) > 0 { diff --git a/java/androidmk_test.go b/java/androidmk_test.go index 875e06f11..2978a40aa 100644 --- a/java/androidmk_test.go +++ b/java/androidmk_test.go @@ -19,6 +19,9 @@ import ( "testing" "android/soong/android" + "android/soong/cc" + + "github.com/google/blueprint/proptools" ) func TestRequired(t *testing.T) { @@ -252,3 +255,149 @@ func TestGetOverriddenPackages(t *testing.T) { android.AssertDeepEquals(t, "overrides property", expected.overrides, actual) } } + +func TestJniPartition(t *testing.T) { + bp := ` + cc_library { + name: "libjni_system", + system_shared_libs: [], + sdk_version: "current", + stl: "none", + } + + cc_library { + name: "libjni_system_ext", + system_shared_libs: [], + sdk_version: "current", + stl: "none", + system_ext_specific: true, + } + + cc_library { + name: "libjni_odm", + system_shared_libs: [], + sdk_version: "current", + stl: "none", + device_specific: true, + } + + cc_library { + name: "libjni_product", + system_shared_libs: [], + sdk_version: "current", + stl: "none", + product_specific: true, + } + + cc_library { + name: "libjni_vendor", + system_shared_libs: [], + sdk_version: "current", + stl: "none", + soc_specific: true, + } + + android_app { + name: "test_app_system_jni_system", + privileged: true, + platform_apis: true, + certificate: "platform", + jni_libs: ["libjni_system"], + } + + android_app { + name: "test_app_system_jni_system_ext", + privileged: true, + platform_apis: true, + certificate: "platform", + jni_libs: ["libjni_system_ext"], + } + + android_app { + name: "test_app_system_ext_jni_system", + privileged: true, + platform_apis: true, + certificate: "platform", + jni_libs: ["libjni_system"], + system_ext_specific: true + } + + android_app { + name: "test_app_system_ext_jni_system_ext", + sdk_version: "core_platform", + jni_libs: ["libjni_system_ext"], + system_ext_specific: true + } + + android_app { + name: "test_app_product_jni_product", + sdk_version: "core_platform", + jni_libs: ["libjni_product"], + product_specific: true + } + + android_app { + name: "test_app_vendor_jni_odm", + sdk_version: "core_platform", + jni_libs: ["libjni_odm"], + soc_specific: true + } + + android_app { + name: "test_app_odm_jni_vendor", + sdk_version: "core_platform", + jni_libs: ["libjni_vendor"], + device_specific: true + } + android_app { + name: "test_app_system_jni_multiple", + privileged: true, + platform_apis: true, + certificate: "platform", + jni_libs: ["libjni_system", "libjni_system_ext"], + } + android_app { + name: "test_app_vendor_jni_multiple", + sdk_version: "core_platform", + jni_libs: ["libjni_odm", "libjni_vendor"], + soc_specific: true + } + ` + arch := "arm64" + ctx := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + cc.PrepareForTestWithCcDefaultModules, + android.PrepareForTestWithAndroidMk, + android.FixtureModifyConfig(func(config android.Config) { + config.TestProductVariables.DeviceArch = proptools.StringPtr(arch) + }), + ). + RunTestWithBp(t, bp) + testCases := []struct { + name string + partitionNames []string + partitionTags []string + }{ + {"test_app_system_jni_system", []string{"libjni_system"}, []string{""}}, + {"test_app_system_jni_system_ext", []string{"libjni_system_ext"}, []string{"_SYSTEM_EXT"}}, + {"test_app_system_ext_jni_system", []string{"libjni_system"}, []string{""}}, + {"test_app_system_ext_jni_system_ext", []string{"libjni_system_ext"}, []string{"_SYSTEM_EXT"}}, + {"test_app_product_jni_product", []string{"libjni_product"}, []string{"_PRODUCT"}}, + {"test_app_vendor_jni_odm", []string{"libjni_odm"}, []string{"_ODM"}}, + {"test_app_odm_jni_vendor", []string{"libjni_vendor"}, []string{"_VENDOR"}}, + {"test_app_system_jni_multiple", []string{"libjni_system", "libjni_system_ext"}, []string{"", "_SYSTEM_EXT"}}, + {"test_app_vendor_jni_multiple", []string{"libjni_odm", "libjni_vendor"}, []string{"_ODM", "_VENDOR"}}, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + mod := ctx.ModuleForTests(test.name, "android_common").Module() + entry := android.AndroidMkEntriesForTest(t, ctx.TestContext, mod)[0] + for i := range test.partitionNames { + actual := entry.EntryMap["LOCAL_SOONG_JNI_LIBS_PARTITION_"+arch][i] + expected := test.partitionNames[i] + ":" + test.partitionTags[i] + android.AssertStringEquals(t, "Expected and actual differ", expected, actual) + } + }) + } +} diff --git a/java/app.go b/java/app.go index 377851e39..f05b8a7cd 100644 --- a/java/app.go +++ b/java/app.go @@ -274,37 +274,16 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { variation := append(jniTarget.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"}) - // Test whether to use the SDK variant or the non-SDK variant of JNI dependencies. - // Many factors are considered here. - // 1. Basically, the selection follows whether the app has sdk_version set or not. - jniUsesSdkVariant := usesSDK - // 2. However, jni_uses_platform_apis and jni_uses_sdk_apis can override it - if Bool(a.appProperties.Jni_uses_sdk_apis) { - jniUsesSdkVariant = true - } - if Bool(a.appProperties.Jni_uses_platform_apis) { - jniUsesSdkVariant = false - } - // 3. Then the use of SDK variant is again prohibited for the following cases: - // 3.1. the app is shipped on unbundled partitions like vendor. Since the entire - // partition (not only the app) is considered unbudled, there's no need to use the - // SDK variant. - // 3.2. the app doesn't support embedding the JNI libs - if a.RequiresStableAPIs(ctx) || !a.shouldEmbedJnis(ctx) { - jniUsesSdkVariant = false - } - if jniUsesSdkVariant { + // If the app builds against an Android SDK use the SDK variant of JNI dependencies + // unless jni_uses_platform_apis is set. + // Don't require the SDK variant for apps that are shipped on vendor, etc., as they already + // have stable APIs through the VNDK. + if (usesSDK && !a.RequiresStableAPIs(ctx) && + !Bool(a.appProperties.Jni_uses_platform_apis)) || + Bool(a.appProperties.Jni_uses_sdk_apis) { variation = append(variation, blueprint.Variation{Mutator: "sdk", Variation: "sdk"}) } - - // Use the installable dep tag when the JNIs are not embedded - var tag dependencyTag - if a.shouldEmbedJnis(ctx) { - tag = jniLibTag - } else { - tag = jniInstallTag - } - ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...) + ctx.AddFarVariationDependencies(variation, jniLibTag, a.appProperties.Jni_libs...) } for _, aconfig_declaration := range a.aaptProperties.Flags_packages { ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration) @@ -355,7 +334,6 @@ func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleCon func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.checkAppSdkVersions(ctx) - a.checkEmbedJnis(ctx) a.generateAndroidBuildActions(ctx) a.generateJavaUsedByApex(ctx) } @@ -400,17 +378,6 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { a.checkSdkVersions(ctx) } -// Ensures that use_embedded_native_libs are set for apk-in-apex -func (a *AndroidApp) checkEmbedJnis(ctx android.BaseModuleContext) { - apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) - apkInApex := !apexInfo.IsForPlatform() - hasJnis := len(a.appProperties.Jni_libs) > 0 - - if apkInApex && hasJnis && !Bool(a.appProperties.Use_embedded_native_libs) { - ctx.ModuleErrorf("APK in APEX should have use_embedded_native_libs: true") - } -} - // If an updatable APK sets min_sdk_version, min_sdk_vesion of JNI libs should match with it. // This check is enforced for "updatable" APKs (including APK-in-APEX). func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion android.ApiLevel) { @@ -466,9 +433,9 @@ func (a *AndroidApp) shouldUncompressDex(ctx android.ModuleContext) bool { } func (a *AndroidApp) shouldEmbedJnis(ctx android.BaseModuleContext) bool { + apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) return ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) || - Bool(a.appProperties.Updatable) || - a.appProperties.AlwaysPackageNativeLibs + !apexInfo.IsForPlatform() || a.appProperties.AlwaysPackageNativeLibs } func generateAaptRenamePackageFlags(packageName string, renameResourcesPackage bool) []string { @@ -862,9 +829,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { dexJarFile, packageResources := a.dexBuildActions(ctx) - // No need to check the SDK version of the JNI deps unless we embed them - checkNativeSdkVersion := a.shouldEmbedJnis(ctx) && !Bool(a.appProperties.Jni_uses_platform_apis) - jniLibs, prebuiltJniPackages, certificates := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), checkNativeSdkVersion) + jniLibs, prebuiltJniPackages, certificates := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis)) jniJarFile := a.jniBuildActions(jniLibs, prebuiltJniPackages, ctx) if ctx.Failed() { @@ -946,22 +911,6 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { installed := ctx.InstallFile(a.installDir, extra.Base(), extra) extraInstalledPaths = append(extraInstalledPaths, installed) } - // If we don't embed jni libs, make sure that those are installed along with the - // app, and also place symlinks to the installed paths under the lib/ - // directory of the app installation directory. ex: - // /system/app/MyApp/lib/arm64/libfoo.so -> /system/lib64/libfoo.so - if !a.embeddedJniLibs { - for _, jniLib := range jniLibs { - archStr := jniLib.target.Arch.ArchType.String() - symlinkDir := a.installDir.Join(ctx, "lib", archStr) - for _, installedLib := range jniLib.installPaths { - // install the symlink itself - symlinkName := installedLib.Base() - symlinkTarget := android.InstallPathToOnDevicePath(ctx, installedLib) - ctx.InstallAbsoluteSymlink(symlinkDir, symlinkName, symlinkTarget) - } - } - } ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...) } @@ -1049,7 +998,6 @@ func collectJniDeps(ctx android.ModuleContext, coverageFile: dep.CoverageOutputFile(), unstrippedFile: dep.UnstrippedOutputFile(), partition: dep.Partition(), - installPaths: dep.FilesToInstall(), }) } else if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{otherName}) diff --git a/java/java.go b/java/java.go index 05ef5d04f..0df96a3a5 100644 --- a/java/java.go +++ b/java/java.go @@ -366,14 +366,14 @@ type dependencyTag struct { toolchain bool static bool - - installable bool } -var _ android.InstallNeededDependencyTag = (*dependencyTag)(nil) - -func (d dependencyTag) InstallDepNeeded() bool { - return d.installable +// installDependencyTag is a dependency tag that is annotated to cause the installed files of the +// dependency to be installed when the parent module is installed. +type installDependencyTag struct { + blueprint.BaseDependencyTag + android.InstallAlwaysNeededDependencyTag + name string } func (d dependencyTag) LicenseAnnotations() []android.LicenseAnnotation { @@ -405,7 +405,7 @@ func makeUsesLibraryDependencyTag(sdkVersion int, optional bool) usesLibraryDepe } func IsJniDepTag(depTag blueprint.DependencyTag) bool { - return depTag == jniLibTag || depTag == jniInstallTag + return depTag == jniLibTag } var ( @@ -434,8 +434,8 @@ var ( javaApiContributionTag = dependencyTag{name: "java-api-contribution"} depApiSrcsTag = dependencyTag{name: "dep-api-srcs"} aconfigDeclarationTag = dependencyTag{name: "aconfig-declaration"} - jniInstallTag = dependencyTag{name: "jni install", runtimeLinked: true, installable: true} - binaryInstallTag = dependencyTag{name: "binary install", runtimeLinked: true, installable: true} + jniInstallTag = installDependencyTag{name: "jni install"} + binaryInstallTag = installDependencyTag{name: "binary install"} usesLibReqTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false) usesLibOptTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, true) usesLibCompat28OptTag = makeUsesLibraryDependencyTag(28, true) @@ -491,7 +491,6 @@ type jniLib struct { coverageFile android.OptionalPath unstrippedFile android.Path partition string - installPaths android.InstallPaths } func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext android.SdkContext, d dexer) {