diff options
Diffstat (limited to 'java')
| -rw-r--r-- | java/androidmk.go | 3 | ||||
| -rw-r--r-- | java/app_import.go | 27 | ||||
| -rw-r--r-- | java/app_import_test.go | 63 | ||||
| -rw-r--r-- | java/builder.go | 11 | ||||
| -rw-r--r-- | java/dexpreopt_bootjars.go | 5 | ||||
| -rw-r--r-- | java/hiddenapi.go | 22 | ||||
| -rw-r--r-- | java/hiddenapi_singleton.go | 62 | ||||
| -rw-r--r-- | java/hiddenapi_singleton_test.go | 54 | ||||
| -rw-r--r-- | java/java.go | 35 |
9 files changed, 232 insertions, 50 deletions
diff --git a/java/androidmk.go b/java/androidmk.go index 21f3012a4..6e7c437ab 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -646,6 +646,9 @@ func (a *AndroidAppImport) AndroidMkEntries() []android.AndroidMkEntries { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", a.dexpreopter.builtInstalled) } entries.AddStrings("LOCAL_INSTALLED_MODULE_STEM", a.installPath.Rel()) + if Bool(a.properties.Export_package_resources) { + entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.outputFile) + } }, }, }} diff --git a/java/app_import.go b/java/app_import.go index 6f21bfbbf..59eb10a9b 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -92,6 +92,10 @@ type AndroidAppImportProperties struct { // Optional name for the installed app. If unspecified, it is derived from the module name. Filename *string + + // If set, create package-export.apk, which other packages can + // use to get PRODUCT-agnostic resource data like IDs and type definitions. + Export_package_resources *bool } func (a *AndroidAppImport) IsInstallable() bool { @@ -142,13 +146,17 @@ func MergePropertiesFromVariant(ctx android.EarlyModuleContext, } } +func (a *AndroidAppImport) isPrebuiltFrameworkRes() bool { + return a.Name() == "prebuilt_framework-res" +} + func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) { cert := android.SrcIsModule(String(a.properties.Certificate)) if cert != "" { ctx.AddDependency(ctx.Module(), certificateTag, cert) } - a.usesLibrary.deps(ctx, true) + a.usesLibrary.deps(ctx, !a.isPrebuiltFrameworkRes()) } func (a *AndroidAppImport) uncompressEmbeddedJniLibs( @@ -247,7 +255,12 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath) var installDir android.InstallPath - if Bool(a.properties.Privileged) { + + if a.isPrebuiltFrameworkRes() { + // framework-res.apk is installed as system/framework/framework-res.apk + installDir = android.PathForModuleInstall(ctx, "framework") + a.preprocessed = true + } else if Bool(a.properties.Privileged) { installDir = android.PathForModuleInstall(ctx, "priv-app", a.BaseModuleName()) } else if ctx.InstallInTestcases() { installDir = android.PathForModuleInstall(ctx, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch()) @@ -275,7 +288,15 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext // TODO: Handle EXTERNAL // Sign or align the package if package has not been preprocessed - if a.preprocessed { + + if a.isPrebuiltFrameworkRes() { + a.outputFile = srcApk + certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx) + if len(certificates) != 1 { + ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates) + } + a.certificate = certificates[0] + } else if a.preprocessed { a.outputFile = srcApk a.certificate = PresignedCertificate } else if !Bool(a.properties.Presigned) { diff --git a/java/app_import_test.go b/java/app_import_test.go index 344d23b55..d7f69eb36 100644 --- a/java/app_import_test.go +++ b/java/app_import_test.go @@ -393,6 +393,69 @@ func TestAndroidAppImport_overridesDisabledAndroidApp(t *testing.T) { } } +func TestAndroidAppImport_frameworkRes(t *testing.T) { + ctx, config := testJava(t, ` + android_app_import { + name: "framework-res", + certificate: "platform", + apk: "package-res.apk", + prefer: true, + export_package_resources: true, + // Disable dexpreopt and verify_uses_libraries check as the app + // contains no Java code to be dexpreopted. + enforce_uses_libs: false, + dex_preopt: { + enabled: false, + }, + } + `) + + mod := ctx.ModuleForTests("prebuilt_framework-res", "android_common").Module() + a := mod.(*AndroidAppImport) + + if !a.preprocessed { + t.Errorf("prebuilt framework-res is not preprocessed") + } + + expectedInstallPath := buildDir + "/target/product/test_device/system/framework/framework-res.apk" + + if a.dexpreopter.installPath.String() != expectedInstallPath { + t.Errorf("prebuilt framework-res installed to incorrect location, actual: %s, expected: %s", a.dexpreopter.installPath, expectedInstallPath) + + } + + entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0] + + expectedPath := "." + // From apk property above, in the root of the source tree. + expectedPrebuiltModuleFile := "package-res.apk" + // Verify that the apk is preprocessed: The export package is the same + // as the prebuilt. + expectedSoongResourceExportPackage := expectedPrebuiltModuleFile + + actualPath := entries.EntryMap["LOCAL_PATH"] + actualPrebuiltModuleFile := entries.EntryMap["LOCAL_PREBUILT_MODULE_FILE"] + actualSoongResourceExportPackage := entries.EntryMap["LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE"] + + if len(actualPath) != 1 { + t.Errorf("LOCAL_PATH incorrect len %d", len(actualPath)) + } else if actualPath[0] != expectedPath { + t.Errorf("LOCAL_PATH mismatch, actual: %s, expected: %s", actualPath[0], expectedPath) + } + + if len(actualPrebuiltModuleFile) != 1 { + t.Errorf("LOCAL_PREBUILT_MODULE_FILE incorrect len %d", len(actualPrebuiltModuleFile)) + } else if actualPrebuiltModuleFile[0] != expectedPrebuiltModuleFile { + t.Errorf("LOCAL_PREBUILT_MODULE_FILE mismatch, actual: %s, expected: %s", actualPrebuiltModuleFile[0], expectedPrebuiltModuleFile) + } + + if len(actualSoongResourceExportPackage) != 1 { + t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE incorrect len %d", len(actualSoongResourceExportPackage)) + } else if actualSoongResourceExportPackage[0] != expectedSoongResourceExportPackage { + t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE mismatch, actual: %s, expected: %s", actualSoongResourceExportPackage[0], expectedSoongResourceExportPackage) + } +} + func TestAndroidTestImport(t *testing.T) { ctx, config := testJava(t, ` android_test_import { diff --git a/java/builder.go b/java/builder.go index 995160d0e..22a891ae1 100644 --- a/java/builder.go +++ b/java/builder.go @@ -193,12 +193,19 @@ var ( jarjar = pctx.AndroidStaticRule("jarjar", blueprint.RuleParams{ - Command: "${config.JavaCmd} ${config.JavaVmFlags}" + + Command: "" + + // Jarjar doesn't exit with an error when the rules file contains a syntax error, + // leading to stale or missing files later in the build. Remove the output file + // before running jarjar. + "rm -f ${out} && " + + "${config.JavaCmd} ${config.JavaVmFlags}" + // b/146418363 Enable Android specific jarjar transformer to drop compat annotations // for newly repackaged classes. Dropping @UnsupportedAppUsage on repackaged classes // avoids adding new hiddenapis after jarjar'ing. " -DremoveAndroidCompatAnnotations=true" + - " -jar ${config.JarjarCmd} process $rulesFile $in $out", + " -jar ${config.JarjarCmd} process $rulesFile $in $out && " + + // Turn a missing output file into a ninja error + `[ -e ${out} ] || (echo "Missing output file"; exit 1)`, CommandDeps: []string{"${config.JavaCmd}", "${config.JarjarCmd}", "$rulesFile"}, }, "rulesFile") diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 2a7eb42dc..86b189558 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -435,6 +435,11 @@ func (d *dexpreoptBootJars) GenerateSingletonBuildActions(ctx android.SingletonC // Inspect this module to see if it contains a bootclasspath dex jar. // Note that the same jar may occur in multiple modules. // This logic is tested in the apex package to avoid import cycle apex <-> java. +// +// This is similar to logic in isModuleInConfiguredList() so any changes needed here are likely to +// be needed there too. +// +// TODO(b/177892522): Avoid having to perform this type of check or if necessary dedup it. func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, module android.Module) (int, android.Path) { name := ctx.ModuleName(module) diff --git a/java/hiddenapi.go b/java/hiddenapi.go index eafbf5df0..ada11c341 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -108,9 +108,18 @@ func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, name string, primary bo // not on the list then that will cause failures in the CtsHiddenApiBlacklist... // tests. if inList(bootJarName, ctx.Config().BootJars()) { - // Create ninja rules to generate various CSV files needed by hiddenapi and store the paths - // in the hiddenAPI structure. - h.hiddenAPIGenerateCSV(ctx, implementationJar) + // More than one library with the same classes may need to be encoded but only one should be + // used as a source of information for hidden API processing otherwise it will result in + // duplicate entries in the files. + if primary { + // Create ninja rules to generate various CSV files needed by hiddenapi and store the paths + // in the hiddenAPI structure. + h.hiddenAPIGenerateCSV(ctx, implementationJar) + + // Save the unencoded dex jar so it can be used when generating the + // hiddenAPISingletonPathsStruct.stubFlags file. + h.bootDexJarPath = dexJar + } // If this module is actually on the boot jars list and not providing // hiddenapi information for a module on the boot jars list then encode @@ -118,13 +127,6 @@ func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, name string, primary bo if name == bootJarName { hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", name+".jar").OutputPath - // More than one library with the same classes can be encoded but only one can - // be added to the global set of flags, otherwise it will result in duplicate - // classes which is an error. Therefore, only add the dex jar of one of them - // to the global set of flags. - if primary { - h.bootDexJarPath = dexJar - } hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex) dexJar = hiddenAPIJar } diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index ccb874506..46994c396 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -22,9 +22,13 @@ import ( ) func init() { - android.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) - android.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory) - android.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory) + RegisterHiddenApiSingletonComponents(android.InitRegistrationContext) +} + +func RegisterHiddenApiSingletonComponents(ctx android.RegistrationContext) { + ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) + ctx.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory) + ctx.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory) } type hiddenAPISingletonPathsStruct struct { @@ -213,6 +217,10 @@ func stubFlagsRule(ctx android.SingletonContext) { var bootDexJars android.Paths + // Get the configured non-updatable and updatable boot jars. + nonUpdatableBootJars := ctx.Config().NonUpdatableBootJars() + updatableBootJars := ctx.Config().UpdatableBootJars() + ctx.VisitAllModules(func(module android.Module) { // Collect dex jar paths for the modules listed above. if j, ok := module.(Dependency); ok { @@ -227,11 +235,8 @@ func stubFlagsRule(ctx android.SingletonContext) { // Collect dex jar paths for modules that had hiddenapi encode called on them. if h, ok := module.(hiddenAPIIntf); ok { if jar := h.bootDexJar(); jar != nil { - // For a java lib included in an APEX, only take the one built for - // the platform variant, and skip the variants for APEXes. - // Otherwise, the hiddenapi tool will complain about duplicated classes - apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo) - if !apexInfo.IsForPlatform() { + if !isModuleInConfiguredList(ctx, module, nonUpdatableBootJars) && + !isModuleInConfiguredList(ctx, module, updatableBootJars) { return } @@ -280,6 +285,47 @@ func stubFlagsRule(ctx android.SingletonContext) { rule.Build("hiddenAPIStubFlagsFile", "hiddenapi stub flags") } +// Checks to see whether the supplied module variant is in the list of boot jars. +// +// This is similar to logic in getBootImageJar() so any changes needed here are likely to be needed +// there too. +// +// TODO(b/179354495): Avoid having to perform this type of check or if necessary dedup it. +func isModuleInConfiguredList(ctx android.SingletonContext, module android.Module, configuredBootJars android.ConfiguredJarList) bool { + name := ctx.ModuleName(module) + + // Strip a prebuilt_ prefix so that this can match a prebuilt module that has not been renamed. + name = android.RemoveOptionalPrebuiltPrefix(name) + + // Ignore any module that is not listed in the boot image configuration. + index := configuredBootJars.IndexOfJar(name) + if index == -1 { + return false + } + + // It is an error if the module is not an ApexModule. + if _, ok := module.(android.ApexModule); !ok { + ctx.Errorf("module %q configured in boot jars does not support being added to an apex", module) + return false + } + + apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo) + + // Now match the apex part of the boot image configuration. + requiredApex := configuredBootJars.Apex(index) + if requiredApex == "platform" { + if len(apexInfo.InApexes) != 0 { + // A platform variant is required but this is for an apex so ignore it. + return false + } + } else if !apexInfo.InApexByBaseName(requiredApex) { + // An apex variant for a specific apex is required but this is the wrong apex. + return false + } + + return true +} + func prebuiltFlagsRule(ctx android.SingletonContext) android.Path { outputPath := hiddenAPISingletonPaths(ctx).flags inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-flags.csv") diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go index 27f363e0c..fcaa94adc 100644 --- a/java/hiddenapi_singleton_test.go +++ b/java/hiddenapi_singleton_test.go @@ -15,11 +15,12 @@ package java import ( - "android/soong/android" "fmt" "strings" "testing" + "android/soong/android" + "github.com/google/blueprint/proptools" ) @@ -32,7 +33,7 @@ func testConfigWithBootJars(bp string, bootJars []string, prebuiltHiddenApiDir * func testContextWithHiddenAPI(config android.Config) *android.TestContext { ctx := testContext(config) - ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) + RegisterHiddenApiSingletonComponents(ctx) return ctx } @@ -64,7 +65,7 @@ func TestHiddenAPISingleton(t *testing.T) { name: "foo", srcs: ["a.java"], compile_dex: true, - } + } `, []string{"platform:foo"}, nil) hiddenAPI := ctx.SingletonForTests("hiddenapi") @@ -75,6 +76,45 @@ func TestHiddenAPISingleton(t *testing.T) { } } +func checkRuleInputs(t *testing.T, expected string, hiddenAPIRule android.TestingBuildParams) { + actual := strings.TrimSpace(strings.Join(android.NormalizePathsForTesting(hiddenAPIRule.Implicits), "\n")) + expected = strings.TrimSpace(expected) + if actual != expected { + t.Errorf("Expected hiddenapi rule inputs:\n%s\nactual inputs:\n%s", expected, actual) + } +} + +func TestHiddenAPIIndexSingleton(t *testing.T) { + ctx, _ := testHiddenAPIBootJars(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + } + + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + prefer: false, + } + + java_sdk_library { + name: "bar", + srcs: ["a.java"], + compile_dex: true, + } + `, []string{"platform:foo", "platform:bar"}, nil) + + hiddenAPIIndex := ctx.SingletonForTests("hiddenapi_index") + indexRule := hiddenAPIIndex.Rule("singleton-merged-hiddenapi-index") + checkRuleInputs(t, ` +.intermediates/bar/android_common/hiddenapi/index.csv +.intermediates/foo/android_common/hiddenapi/index.csv +`, + indexRule) +} + func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { ctx, _ := testHiddenAPIBootJars(t, ` java_import { @@ -98,14 +138,14 @@ func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { name: "foo", srcs: ["a.java"], compile_dex: true, - } + } java_import { name: "foo", jars: ["a.jar"], compile_dex: true, prefer: false, - } + } `, []string{"platform:foo"}, nil) hiddenAPI := ctx.SingletonForTests("hiddenapi") @@ -127,14 +167,14 @@ func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { name: "foo", srcs: ["a.java"], compile_dex: true, - } + } java_import { name: "foo", jars: ["a.jar"], compile_dex: true, prefer: true, - } + } `, []string{"platform:foo"}, nil) hiddenAPI := ctx.SingletonForTests("hiddenapi") diff --git a/java/java.go b/java/java.go index 91944f6e3..bed232b4e 100644 --- a/java/java.go +++ b/java/java.go @@ -40,18 +40,21 @@ func init() { // Register sdk member types. android.RegisterSdkMemberType(javaHeaderLibsSdkMemberType) + // Export implementation classes jar as part of the sdk. + exportImplementationClassesJar := func(_ android.SdkMemberContext, j *Library) android.Path { + implementationJars := j.ImplementationAndResourcesJars() + if len(implementationJars) != 1 { + panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name())) + } + return implementationJars[0] + } + // Register java implementation libraries for use only in module_exports (not sdk). android.RegisterSdkMemberType(&librarySdkMemberType{ android.SdkMemberTypeBase{ PropertyName: "java_libs", }, - func(_ android.SdkMemberContext, j *Library) android.Path { - implementationJars := j.ImplementationAndResourcesJars() - if len(implementationJars) != 1 { - panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name())) - } - return implementationJars[0] - }, + exportImplementationClassesJar, sdkSnapshotFilePathForJar, copyEverythingToSnapshot, }) @@ -72,19 +75,11 @@ func init() { PropertyName: "java_boot_libs", SupportsSdk: true, }, - func(ctx android.SdkMemberContext, j *Library) android.Path { - // Java boot libs are only provided in the SDK to provide access to their dex implementation - // jar for use by dexpreopting and boot jars package check. They do not need to provide an - // actual implementation jar but the java_import will need a file that exists so just copy an - // empty file. Any attempt to use that file as a jar will cause a build error. - return ctx.SnapshotBuilder().EmptyFile() - }, - func(osPrefix, name string) string { - // Create a special name for the implementation jar to try and provide some useful information - // to a developer that attempts to compile against this. - // TODO(b/175714559): Provide a proper error message in Soong not ninja. - return filepath.Join(osPrefix, "java_boot_libs", "snapshot", "jars", "are", "invalid", name+jarFileSuffix) - }, + // Temporarily export implementation classes jar for java_boot_libs as it is required for the + // hiddenapi processing. + // TODO(b/179354495): Revert once hiddenapi processing has been modularized. + exportImplementationClassesJar, + sdkSnapshotFilePathForJar, onlyCopyJarToSnapshot, }) |