diff options
author | 2024-11-18 19:22:39 +0000 | |
---|---|---|
committer | 2024-12-03 03:37:21 +0000 | |
commit | ef56908c70ae9777388987857995fd6e6404fdf6 (patch) | |
tree | 4a201ca8a0ecf3a1c4c4d5c127a8ca1e343780fb | |
parent | 4e305cec97bd9bb6a9e4472a167efc4ac11a0836 (diff) |
Use soong built autogenerated RROs
At ToT, soong emits metadata to make (LOCAL_SOONG_PRODUCT_RRO_DIRS and
LOCAL_SOONG_DEVICE_RRO_DIRS), and make uses this metadata to build and
install apks that are intalled in /vendor or /product. This CL ports
this logic to soong.
This CL autogenerates these modules in a load hook for android_app and
override_android_app, and adds them to the `LOCAL_REQUIRED_MODULES` of
the base app. The autogenerated modules will inherit the enabled
property of the apps. This required me to add `Target.Android.Enabled`
to commonProperties in ModuleBase.
Since autogeneration happens in soong now,
`LOCAL_SOONG_(DEVICE|PRODUCT)_RRO_DIRS` no longer needs to be exported.
Followup work
- Installing the overlay variants for soong built filesystems.
Test: lunch aosp_cf_x86_64_phone-trunk_staging-userdebug
Test: no diff in system, vendor, product file_list.txt
Test: m out/target/product/vsoc_x86_64/vendor/overlay/SystemUI__aosp_cf_x86_64_phone__auto_generated_rro_vendor.apk
the apk is not bit-identical, but this is likely due to different
aapt link flags between make and soong (e.g. `--enable-compact-entries`
is added as default in soong but not in make
Test: aapt2 diff
SystemUI__aosp_cf_x86_64_phone__auto_generated_rro_vendor.apk.before
SystemUI__aosp_cf_x86_64_phone__auto_generated_rro_vendor.apk.after
reports no diffs
Change-Id: I9b212a4ed443250a63dbe27cb955c6f133cff9af
-rw-r--r-- | android/module.go | 1 | ||||
-rw-r--r-- | java/aar.go | 12 | ||||
-rw-r--r-- | java/androidmk.go | 31 | ||||
-rw-r--r-- | java/app.go | 91 | ||||
-rw-r--r-- | java/app_test.go | 71 | ||||
-rw-r--r-- | java/rro_test.go | 97 |
6 files changed, 171 insertions, 132 deletions
diff --git a/android/module.go b/android/module.go index 67dab4f9f..6d2c39b7d 100644 --- a/android/module.go +++ b/android/module.go @@ -338,6 +338,7 @@ type commonProperties struct { } Android struct { Compile_multilib *string + Enabled *bool } } diff --git a/java/aar.go b/java/aar.go index e0e642e36..1e5c95a7f 100644 --- a/java/aar.go +++ b/java/aar.go @@ -588,14 +588,16 @@ func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptio } } - for _, dir := range overlayDirs { - compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files, - compileFlags, a.filterProduct(), opts.aconfigTextFiles).Paths()...) - } - var compiledRro, compiledRroOverlay android.Paths if opts.rroDirs != nil { compiledRro, compiledRroOverlay = a.compileResInDir(ctx, *opts.rroDirs, compileFlags, opts.aconfigTextFiles) + } else { + // RRO enforcement is done based on module name. Compile the overlayDirs only if rroDirs is nil. + // This ensures that the autogenerated RROs do not compile the overlay dirs twice. + for _, dir := range overlayDirs { + compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files, + compileFlags, a.filterProduct(), opts.aconfigTextFiles).Paths()...) + } } var splitPackages android.WritablePaths diff --git a/java/androidmk.go b/java/androidmk.go index 2ad30b132..35024c1d6 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -307,15 +307,11 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { Disabled: true, }} } - var required []string - if proptools.Bool(app.appProperties.Generate_product_characteristics_rro) { - required = []string{app.productCharacteristicsRROPackageName()} - } return []android.AndroidMkEntries{android.AndroidMkEntries{ Class: "APPS", OutputFile: android.OptionalPathForPath(app.outputFile), Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk", - Required: required, + Required: app.requiredModuleNames, ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { // App module names can be overridden. @@ -350,31 +346,6 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { entries.SetBoolIfTrue("LOCAL_NO_STANDARD_LIBRARIES", true) } - filterRRO := func(filter overlayType) android.Paths { - var paths android.Paths - seen := make(map[android.Path]bool) - for _, d := range app.rroDirsDepSet.ToList() { - if d.overlayType == filter { - if seen[d.path] { - continue - } - seen[d.path] = true - paths = append(paths, d.path) - } - } - // Reverse the order, Soong stores rroDirs in aapt2 order (low to high priority), but Make - // expects it in LOCAL_RESOURCE_DIRS order (high to low priority). - return android.ReversePaths(paths) - } - deviceRRODirs := filterRRO(device) - if len(deviceRRODirs) > 0 { - entries.AddStrings("LOCAL_SOONG_DEVICE_RRO_DIRS", deviceRRODirs.Strings()...) - } - productRRODirs := filterRRO(product) - if len(productRRODirs) > 0 { - entries.AddStrings("LOCAL_SOONG_PRODUCT_RRO_DIRS", productRRODirs.Strings()...) - } - entries.SetBoolIfTrue("LOCAL_EXPORT_PACKAGE_RESOURCES", Bool(app.appProperties.Export_package_resources)) entries.SetPath("LOCAL_FULL_MANIFEST_FILE", app.manifestPath) diff --git a/java/app.go b/java/app.go index 34a548e5a..34884d75c 100644 --- a/java/app.go +++ b/java/app.go @@ -223,6 +223,8 @@ type AndroidApp struct { javaApiUsedByOutputFile android.ModuleOutPath privAppAllowlist android.OptionalPath + + requiredModuleNames []string } func (a *AndroidApp) IsInstallable() bool { @@ -421,6 +423,24 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { TestHelperApp: false, EmbeddedJNILibs: embeddedJniLibs, }) + + a.requiredModuleNames = a.getRequiredModuleNames(ctx) +} + +func (a *AndroidApp) getRequiredModuleNames(ctx android.ModuleContext) []string { + var required []string + if proptools.Bool(a.appProperties.Generate_product_characteristics_rro) { + required = []string{a.productCharacteristicsRROPackageName()} + } + // Install the vendor overlay variant if this app is installed. + if len(filterRRO(a.rroDirsDepSet, device)) > 0 { + required = append(required, AutogeneratedRroModuleName(ctx, ctx.Module().Name(), "vendor")) + } + // Install the product overlay variant if this app is installed. + if len(filterRRO(a.rroDirsDepSet, product)) > 0 { + required = append(required, AutogeneratedRroModuleName(ctx, ctx.Module().Name(), "product")) + } + return required } func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { @@ -1377,6 +1397,11 @@ func AndroidAppFactory() android.Module { } } ctx.CreateModule(RuntimeResourceOverlayFactory, &rroProperties) + + }) + + module.SetDefaultableHook(func(ctx android.DefaultableHookContext) { + createInternalRuntimeOverlays(ctx, module.ModuleBase) }) return module @@ -1386,6 +1411,68 @@ func AutogeneratedRroModuleName(ctx android.EarlyModuleContext, moduleName, part return fmt.Sprintf("%s__%s__auto_generated_rro_%s", moduleName, ctx.Config().DeviceProduct(), partition) } +type createModuleContext interface { + android.EarlyModuleContext + CreateModule(android.ModuleFactory, ...interface{}) android.Module +} + +func createInternalRuntimeOverlays(ctx createModuleContext, a android.ModuleBase) { + if !ctx.Config().HasDeviceProduct() { + return + } + // vendor + vendorOverlayProps := struct { + Name *string + Base *string + Vendor *bool + Product_specific *bool + System_ext_specific *bool + Manifest *string + Sdk_version *string + Compile_multilib *string + Enabled proptools.Configurable[bool] + }{ + Name: proptools.StringPtr(AutogeneratedRroModuleName(ctx, a.Name(), "vendor")), + Base: proptools.StringPtr(a.Name()), + Vendor: proptools.BoolPtr(true), + Product_specific: proptools.BoolPtr(false), + System_ext_specific: proptools.BoolPtr(false), + Manifest: proptools.StringPtr(":" + a.Name() + "{.manifest.xml}"), + Sdk_version: proptools.StringPtr("current"), + Compile_multilib: proptools.StringPtr("first"), + Enabled: a.EnabledProperty().Clone(), + } + ctx.CreateModule(AutogenRuntimeResourceOverlayFactory, &vendorOverlayProps) + + // product + productOverlayProps := struct { + Name *string + Base *string + Vendor *bool + Proprietary *bool + Soc_specific *bool + Product_specific *bool + System_ext_specific *bool + Manifest *string + Sdk_version *string + Compile_multilib *string + Enabled proptools.Configurable[bool] + }{ + Name: proptools.StringPtr(AutogeneratedRroModuleName(ctx, a.Name(), "product")), + Base: proptools.StringPtr(a.Name()), + Vendor: proptools.BoolPtr(false), + Proprietary: proptools.BoolPtr(false), + Soc_specific: proptools.BoolPtr(false), + Product_specific: proptools.BoolPtr(true), + System_ext_specific: proptools.BoolPtr(false), + Manifest: proptools.StringPtr(":" + a.Name() + "{.manifest.xml}"), + Sdk_version: proptools.StringPtr("current"), + Compile_multilib: proptools.StringPtr("first"), + Enabled: a.EnabledProperty().Clone(), + } + ctx.CreateModule(AutogenRuntimeResourceOverlayFactory, &productOverlayProps) +} + // A dictionary of values to be overridden in the manifest. type Manifest_values struct { // Overrides the value of package_name in the manifest @@ -1696,6 +1783,10 @@ func OverrideAndroidAppModuleFactory() android.Module { android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon) android.InitOverrideModule(m) + android.AddLoadHook(m, func(ctx android.LoadHookContext) { + createInternalRuntimeOverlays(ctx, m.ModuleBase) + }) + return m } diff --git a/java/app_test.go b/java/app_test.go index 3d83ea1dc..61b718d00 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -4727,3 +4727,74 @@ func TestResourcesWithFlagDirectories(t *testing.T) { "out/soong/.intermediates/foo/android_common/aapt2/res/values_strings.(test.package.flag1).arsc.flat", ) } + +func TestAutogeneratedStaticRro(t *testing.T) { + t.Parallel() + bp := ` +android_app { + name: "foo", + srcs: ["foo.java"], + platform_apis: true, +} +override_android_app { + name: "override_foo", + base: "foo", +} +` + testCases := []struct { + desc string + preparer android.FixturePreparer + overlayApkExpected bool + }{ + { + desc: "No DEVICE_PACKAGE_OVERLAYS, no overlay .apk file", + overlayApkExpected: false, + }, + { + desc: "DEVICE_PACKAGE_OVERLAYS exists, but the directory is empty", + overlayApkExpected: false, + preparer: android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.DeviceResourceOverlays = []string{"device/company/test_product"} + }), + }, + { + desc: "DEVICE_PACKAGE_OVERLAYS exists, directory is non-empty, but does not contain a matching resource dir", + overlayApkExpected: false, + preparer: android.GroupFixturePreparers( + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.DeviceResourceOverlays = []string{"device/company/test_product"} + }), + android.MockFS{ + "res/foo.xml": nil, + "device/company/test_product/different_res/foo.xml": nil, // different dir + }.AddToFixture(), + ), + }, + { + desc: "DEVICE_PACKAGE_OVERLAYS and the directory contain a matching resource dir", + overlayApkExpected: true, + preparer: android.GroupFixturePreparers( + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.DeviceResourceOverlays = []string{"device/company/test_product"} + }), + android.MockFS{ + "res/foo.xml": nil, + "device/company/test_product/res/foo.xml": nil, + }.AddToFixture(), + ), + }, + } + for _, tc := range testCases { + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.EnforceRROTargets = []string{"*"} + }), + android.OptionalFixturePreparer(tc.preparer), + ).RunTestWithBp(t, bp) + vendorOverlayApk := result.ModuleForTests("foo__test_product__auto_generated_rro_vendor", "android_arm64_armv8-a").MaybeOutput("foo__test_product__auto_generated_rro_vendor.apk") + android.AssertBoolEquals(t, tc.desc, tc.overlayApkExpected, vendorOverlayApk.Rule != nil) + overrideVendorOverlayApk := result.ModuleForTests("override_foo__test_product__auto_generated_rro_vendor", "android_arm64_armv8-a").MaybeOutput("override_foo__test_product__auto_generated_rro_vendor.apk") + android.AssertBoolEquals(t, tc.desc, tc.overlayApkExpected, overrideVendorOverlayApk.Rule != nil) + } +} diff --git a/java/rro_test.go b/java/rro_test.go index 4d791305e..4d58bb498 100644 --- a/java/rro_test.go +++ b/java/rro_test.go @@ -255,103 +255,6 @@ func TestOverrideRuntimeResourceOverlay(t *testing.T) { } } -func TestEnforceRRO_propagatesToDependencies(t *testing.T) { - testCases := []struct { - name string - enforceRROTargets []string - rroDirs map[string][]string - }{ - { - name: "no RRO", - enforceRROTargets: nil, - rroDirs: map[string][]string{ - "foo": nil, - "bar": nil, - }, - }, - { - name: "enforce RRO on all", - enforceRROTargets: []string{"*"}, - rroDirs: map[string][]string{ - "foo": {"product/vendor/blah/overlay/lib2/res"}, - "bar": {"product/vendor/blah/overlay/lib2/res"}, - }, - }, - { - name: "enforce RRO on foo", - enforceRROTargets: []string{"foo"}, - rroDirs: map[string][]string{ - "foo": {"product/vendor/blah/overlay/lib2/res"}, - "bar": nil, - }, - }, - } - - productResourceOverlays := []string{ - "product/vendor/blah/overlay", - } - - fs := android.MockFS{ - "lib2/res/values/strings.xml": nil, - "product/vendor/blah/overlay/lib2/res/values/strings.xml": nil, - } - - bp := ` - android_app { - name: "foo", - sdk_version: "current", - resource_dirs: [], - static_libs: ["lib"], - } - - android_app { - name: "bar", - sdk_version: "current", - resource_dirs: [], - static_libs: ["lib"], - } - - android_library { - name: "lib", - sdk_version: "current", - resource_dirs: [], - static_libs: ["lib2"], - } - - android_library { - name: "lib2", - sdk_version: "current", - resource_dirs: ["lib2/res"], - } - ` - - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - result := android.GroupFixturePreparers( - PrepareForTestWithJavaDefaultModules, - fs.AddToFixture(), - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.ProductResourceOverlays = productResourceOverlays - if testCase.enforceRROTargets != nil { - variables.EnforceRROTargets = testCase.enforceRROTargets - } - }), - ).RunTestWithBp(t, bp) - - modules := []string{"foo", "bar"} - for _, moduleName := range modules { - module := result.ModuleForTests(moduleName, "android_common") - mkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, module.Module())[0] - actualRRODirs := mkEntries.EntryMap["LOCAL_SOONG_PRODUCT_RRO_DIRS"] - if !reflect.DeepEqual(actualRRODirs, testCase.rroDirs[moduleName]) { - t.Errorf("exected %s LOCAL_SOONG_PRODUCT_RRO_DIRS entry: %v\ngot:%q", - moduleName, testCase.rroDirs[moduleName], actualRRODirs) - } - } - }) - } -} - func TestRuntimeResourceOverlayPartition(t *testing.T) { bp := ` runtime_resource_overlay { |