diff --git a/Android.bp b/Android.bp index e9597f4a3..10e6a2e6a 100644 --- a/Android.bp +++ b/Android.bp @@ -55,6 +55,7 @@ bootstrap_go_package { "android/namespace.go", "android/neverallow.go", "android/onceper.go", + "android/override_module.go", "android/package_ctx.go", "android/paths.go", "android/prebuilt.go", diff --git a/android/config.go b/android/config.go index 24be10a96..33986f754 100644 --- a/android/config.go +++ b/android/config.go @@ -895,16 +895,30 @@ func (c *deviceConfig) PlatPrivateSepolicyDirs() []string { } func (c *deviceConfig) OverrideManifestPackageNameFor(name string) (manifestName string, overridden bool) { + if newManifestName, overridden := c.manifestPackageNameOverrides().Load(name); overridden { + return newManifestName.(string), true + } return findOverrideValue(c.config.productVariables.ManifestPackageNameOverrides, name, "invalid override rule %q in PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES should be :") } func (c *deviceConfig) OverrideCertificateFor(name string) (certificatePath string, overridden bool) { - return findOverrideValue(c.config.productVariables.CertificateOverrides, name, + if newCert, overridden := c.certificateOverrides().Load(name); overridden { + return newCert.(string), true + } + newCert, overridden := findOverrideValue(c.config.productVariables.CertificateOverrides, name, "invalid override rule %q in PRODUCT_CERTIFICATE_OVERRIDES should be :") + if overridden { + // PRODUCT_CERTIFICATE_OVERRIDES only supports cert modules. + newCert = ":" + newCert + } + return newCert, overridden } func (c *deviceConfig) OverridePackageNameFor(name string) string { + if newName, overridden := c.moduleNameOverrides().Load(name); overridden { + return newName.(string) + } newName, overridden := findOverrideValue( c.config.productVariables.PackageNameOverrides, name, diff --git a/android/override_module.go b/android/override_module.go new file mode 100644 index 000000000..9fe5f2182 --- /dev/null +++ b/android/override_module.go @@ -0,0 +1,97 @@ +package android + +import ( + "github.com/google/blueprint/proptools" + "sync" +) + +func init() { + RegisterModuleType("override_module", OverrideModuleFactory) +} + +type OverrideModule struct { + ModuleBase + properties OverrideModuleProperties +} + +type OverrideModuleProperties struct { + // base module to override + Base *string + + // file path or module name (in the form ":module") of a certificate to override with + Certificate *string + + // manifest package name to override with + Manifest_package_name *string +} + +// TODO(jungjw): Work with the mainline team to see if we can deprecate all PRODUCT_*_OVERRIDES vars +// and hand over overriding values directly to base module code. +func processOverrides(ctx LoadHookContext, p *OverrideModuleProperties) { + base := proptools.String(p.Base) + if base == "" { + ctx.PropertyErrorf("base", "base module name must be provided") + } + + config := ctx.DeviceConfig() + if other, loaded := config.moduleNameOverrides().LoadOrStore(base, ctx.ModuleName()); loaded { + ctx.ModuleErrorf("multiple overriding modules for %q, the other: %q", base, other.(string)) + } + + if p.Certificate != nil { + config.certificateOverrides().Store(base, *p.Certificate) + } + + if p.Manifest_package_name != nil { + config.manifestPackageNameOverrides().Store(base, *p.Manifest_package_name) + } +} + +func (i *OverrideModule) DepsMutator(ctx BottomUpMutatorContext) { + base := *i.properties.Base + // Right now, we add a dependency only to check the base module exists, and so are not using a tag here. + // TODO(jungjw): Add a tag and check the base module type once we finalize supported base module types. + ctx.AddDependency(ctx.Module(), nil, base) +} + +func (i *OverrideModule) GenerateAndroidBuildActions(ctx ModuleContext) { + // All the overrides happen in the base module. + // TODO(jungjw): Check the base module type. +} + +// override_module overrides an existing module with the specified properties. +// +// Currently, only android_app is officially supported. +func OverrideModuleFactory() Module { + m := &OverrideModule{} + AddLoadHook(m, func(ctx LoadHookContext) { + processOverrides(ctx, &m.properties) + }) + m.AddProperties(&m.properties) + InitAndroidModule(m) + return m +} + +var moduleNameOverridesKey = NewOnceKey("moduleNameOverrides") + +func (c *deviceConfig) moduleNameOverrides() *sync.Map { + return c.Once(moduleNameOverridesKey, func() interface{} { + return &sync.Map{} + }).(*sync.Map) +} + +var certificateOverridesKey = NewOnceKey("certificateOverrides") + +func (c *deviceConfig) certificateOverrides() *sync.Map { + return c.Once(certificateOverridesKey, func() interface{} { + return &sync.Map{} + }).(*sync.Map) +} + +var manifestPackageNameOverridesKey = NewOnceKey("manifestPackageNameOverrides") + +func (c *deviceConfig) manifestPackageNameOverrides() *sync.Map { + return c.Once(manifestPackageNameOverridesKey, func() interface{} { + return &sync.Map{} + }).(*sync.Map) +} diff --git a/apex/apex.go b/apex/apex.go index 9ab518752..5d0c52a9c 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -534,7 +534,7 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { func (a *apexBundle) getCertString(ctx android.BaseContext) string { certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(ctx.ModuleName()) if overridden { - return ":" + certificate + return certificate } return String(a.properties.Certificate) } diff --git a/java/app.go b/java/app.go index c08aefd1f..08b2d9159 100644 --- a/java/app.go +++ b/java/app.go @@ -392,7 +392,7 @@ func (a *AndroidApp) collectAppDeps(ctx android.ModuleContext) ([]jniLib, []Cert func (a *AndroidApp) getCertString(ctx android.BaseContext) string { certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(ctx.ModuleName()) if overridden { - return ":" + certificate + return certificate } return String(a.appProperties.Certificate) } diff --git a/java/app_test.go b/java/app_test.go index 317c75288..313844fa2 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -747,3 +747,57 @@ func TestPackageNameOverride(t *testing.T) { }) } } + +func TestOverrideModule(t *testing.T) { + ctx := testJava(t, ` + android_app { + name: "foo", + srcs: ["a.java"], + } + + override_module { + name: "bar", + base: "foo", + certificate: ":new_certificate", + manifest_package_name: "org.dandroid.bp", + } + + android_app_certificate { + name: "new_certificate", + certificate: "cert/new_cert", + } + `) + + // The base module still contains all the final outputs after overrides. + foo := ctx.ModuleForTests("foo", "android_common") + + // Check the final apk name + outputs := foo.AllOutputs() + e := buildDir + "/target/product/test_device/system/app/bar/bar.apk" + found := false + for _, o := range outputs { + if o == e { + found = true + break + } + } + if !found { + t.Errorf("Can't find %q in output files.\nAll outputs:%v", e, outputs) + } + + // Check the certificate paths + signapk := foo.Output("foo.apk") + signFlags := signapk.Args["certificates"] + e = "cert/new_cert.x509.pem cert/new_cert.pk8" + if e != signFlags { + t.Errorf("Incorrect signing flags, expected: %q, got: %q", e, signFlags) + } + + // Check the manifest package name + res := foo.Output("package-res.apk") + aapt2Flags := res.Args["flags"] + e = "--rename-manifest-package org.dandroid.bp" + if !strings.Contains(aapt2Flags, e) { + t.Errorf("package renaming flag, %q is missing in aapt2 link flags, %q", e, aapt2Flags) + } +} diff --git a/java/java_test.go b/java/java_test.go index 8d3efcb81..bbcc9ede2 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -81,11 +81,13 @@ func testContext(config android.Config, bp string, ctx.RegisterModuleType("droiddoc_host", android.ModuleFactoryAdaptor(DroiddocHostFactory)) ctx.RegisterModuleType("droiddoc_template", android.ModuleFactoryAdaptor(ExportedDroiddocDirFactory)) ctx.RegisterModuleType("java_sdk_library", android.ModuleFactoryAdaptor(SdkLibraryFactory)) + ctx.RegisterModuleType("override_module", android.ModuleFactoryAdaptor(android.OverrideModuleFactory)) ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(PrebuiltApisFactory)) ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators) ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) { + ctx.TopDown("load_hooks", android.LoadHookMutator).Parallel() ctx.TopDown("prebuilt_apis", PrebuiltApisMutator).Parallel() ctx.TopDown("java_sdk_library", SdkLibraryMutator).Parallel() })