From 525443aa22641c57c1fac269ddba8bf869266c5f Mon Sep 17 00:00:00 2001 From: Jaewoong Jung Date: Thu, 28 Feb 2019 15:35:54 -0800 Subject: [PATCH] Add override_android_app module type. This is a new implementation of overriding module types that makes use of local variants. With this, product owners can use PRODUCT_PACKAGES to decide which override module to include in their products. Bug: 122957760 Bug: 123640028 Test: app_test.go Change-Id: Ie65e97f615d006b6e9475193b6017ea9d97e8e97 --- Android.bp | 1 + android/mutator.go | 1 + android/override_module.go | 213 +++++++++++++++++++++++++++++++++++++ java/app.go | 49 +++++++-- java/app_test.go | 72 +++++++++++++ java/java.go | 1 + java/java_test.go | 2 + 7 files changed, 331 insertions(+), 8 deletions(-) create mode 100644 android/override_module.go diff --git a/Android.bp b/Android.bp index 84ac82fb5..7465341be 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/path_properties.go", "android/paths.go", diff --git a/android/mutator.go b/android/mutator.go index 6c9f17a34..71237a1cd 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -79,6 +79,7 @@ var preArch = []RegisterMutatorFunc{ RegisterNamespaceMutator, RegisterPrebuiltsPreArchMutators, RegisterDefaultsPreArchMutators, + RegisterOverridePreArchMutators, } func registerArchMutator(ctx RegisterMutatorsContext) { diff --git a/android/override_module.go b/android/override_module.go new file mode 100644 index 000000000..02db359fa --- /dev/null +++ b/android/override_module.go @@ -0,0 +1,213 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +// This file contains all the foundation components for override modules and their base module +// types. Override modules are a kind of opposite of default modules in that they override certain +// properties of an existing base module whereas default modules provide base module data to be +// overridden. However, unlike default and defaultable module pairs, both override and overridable +// modules generate and output build actions, and it is up to product make vars to decide which one +// to actually build and install in the end. In other words, default modules and defaultable modules +// can be compared to abstract classes and concrete classes in C++ and Java. By the same analogy, +// both override and overridable modules act like concrete classes. +// +// There is one more crucial difference from the logic perspective. Unlike default pairs, most Soong +// actions happen in the base (overridable) module by creating a local variant for each override +// module based on it. + +import ( + "sync" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +// Interface for override module types, e.g. override_android_app, override_apex +type OverrideModule interface { + Module + + getOverridingProperties() []interface{} + setOverridingProperties(properties []interface{}) + + getOverrideModuleProperties() *OverrideModuleProperties +} + +// Base module struct for override module types +type OverrideModuleBase struct { + moduleProperties OverrideModuleProperties + + overridingProperties []interface{} +} + +type OverrideModuleProperties struct { + // Name of the base module to be overridden + Base *string + + // TODO(jungjw): Add an optional override_name bool flag. +} + +func (o *OverrideModuleBase) getOverridingProperties() []interface{} { + return o.overridingProperties +} + +func (o *OverrideModuleBase) setOverridingProperties(properties []interface{}) { + o.overridingProperties = properties +} + +func (o *OverrideModuleBase) getOverrideModuleProperties() *OverrideModuleProperties { + return &o.moduleProperties +} + +func InitOverrideModule(m OverrideModule) { + m.setOverridingProperties(m.GetProperties()) + + m.AddProperties(m.getOverrideModuleProperties()) +} + +// Interface for overridable module types, e.g. android_app, apex +type OverridableModule interface { + setOverridableProperties(prop []interface{}) + + addOverride(o OverrideModule) + getOverrides() []OverrideModule + + override(ctx BaseModuleContext, o OverrideModule) + + setOverridesProperty(overridesProperties *[]string) +} + +// Base module struct for overridable module types +type OverridableModuleBase struct { + ModuleBase + + // List of OverrideModules that override this base module + overrides []OverrideModule + // Used to parallelize registerOverrideMutator executions. Note that only addOverride locks this + // mutex. It is because addOverride and getOverride are used in different mutators, and so are + // guaranteed to be not mixed. (And, getOverride only reads from overrides, and so don't require + // mutex locking.) + overridesLock sync.Mutex + + overridableProperties []interface{} + + // If an overridable module has a property to list other modules that itself overrides, it should + // set this to a pointer to the property through the InitOverridableModule function, so that + // override information is propagated and aggregated correctly. + overridesProperty *[]string +} + +func InitOverridableModule(m OverridableModule, overridesProperty *[]string) { + m.setOverridableProperties(m.(Module).GetProperties()) + m.setOverridesProperty(overridesProperty) +} + +func (b *OverridableModuleBase) setOverridableProperties(prop []interface{}) { + b.overridableProperties = prop +} + +func (b *OverridableModuleBase) addOverride(o OverrideModule) { + b.overridesLock.Lock() + b.overrides = append(b.overrides, o) + b.overridesLock.Unlock() +} + +// Should NOT be used in the same mutator as addOverride. +func (b *OverridableModuleBase) getOverrides() []OverrideModule { + return b.overrides +} + +func (b *OverridableModuleBase) setOverridesProperty(overridesProperty *[]string) { + b.overridesProperty = overridesProperty +} + +// Overrides a base module with the given OverrideModule. +func (b *OverridableModuleBase) override(ctx BaseModuleContext, o OverrideModule) { + for _, p := range b.overridableProperties { + for _, op := range o.getOverridingProperties() { + if proptools.TypeEqual(p, op) { + err := proptools.PrependProperties(p, op, nil) + if err != nil { + if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { + ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) + } else { + panic(err) + } + } + } + } + } + // Adds the base module to the overrides property, if exists, of the overriding module. See the + // comment on OverridableModuleBase.overridesProperty for details. + if b.overridesProperty != nil { + *b.overridesProperty = append(*b.overridesProperty, b.Name()) + } + // The base module name property has to be updated separately for Name() to work as intended. + b.module.base().nameProperties.Name = proptools.StringPtr(o.Name()) +} + +// Mutators for override/overridable modules. All the fun happens in these functions. It is critical +// to keep them in this order and not put any order mutators between them. +func RegisterOverridePreArchMutators(ctx RegisterMutatorsContext) { + ctx.BottomUp("override_deps", overrideModuleDepsMutator).Parallel() + ctx.TopDown("register_override", registerOverrideMutator).Parallel() + ctx.BottomUp("perform_override", performOverrideMutator).Parallel() +} + +type overrideBaseDependencyTag struct { + blueprint.BaseDependencyTag +} + +var overrideBaseDepTag overrideBaseDependencyTag + +// Adds dependency on the base module to the overriding module so that they can be visited in the +// next phase. +func overrideModuleDepsMutator(ctx BottomUpMutatorContext) { + if module, ok := ctx.Module().(OverrideModule); ok { + ctx.AddDependency(ctx.Module(), overrideBaseDepTag, *module.getOverrideModuleProperties().Base) + } +} + +// Visits the base module added as a dependency above, checks the module type, and registers the +// overriding module. +func registerOverrideMutator(ctx TopDownMutatorContext) { + ctx.VisitDirectDepsWithTag(overrideBaseDepTag, func(base Module) { + if o, ok := base.(OverridableModule); ok { + o.addOverride(ctx.Module().(OverrideModule)) + } else { + ctx.PropertyErrorf("base", "unsupported base module type") + } + }) +} + +// Now, goes through all overridable modules, finds all modules overriding them, creates a local +// variant for each of them, and performs the actual overriding operation by calling override(). +func performOverrideMutator(ctx BottomUpMutatorContext) { + if b, ok := ctx.Module().(OverridableModule); ok { + overrides := b.getOverrides() + if len(overrides) == 0 { + return + } + variants := make([]string, len(overrides)+1) + // The first variant is for the original, non-overridden, base module. + variants[0] = "" + for i, o := range overrides { + variants[i+1] = o.(Module).Name() + } + mods := ctx.CreateLocalVariations(variants...) + for i, o := range overrides { + mods[i+1].(OverridableModule).override(ctx, o) + } + } +} diff --git a/java/app.go b/java/app.go index 8f5d010c2..b31f2323b 100644 --- a/java/app.go +++ b/java/app.go @@ -33,16 +33,13 @@ func init() { android.RegisterModuleType("android_test", AndroidTestFactory) android.RegisterModuleType("android_test_helper_app", AndroidTestHelperAppFactory) android.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory) + android.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory) } // AndroidManifest.xml merging // package splits type appProperties struct { - // The name of a certificate in the default certificate directory, blank to use the default product certificate, - // or an android_app_certificate module name in the form ":module". - Certificate *string - // Names of extra android_app_certificate modules to sign the apk with in the form ":module". Additional_certificates []string @@ -79,14 +76,24 @@ type appProperties struct { Use_embedded_dex *bool } +// android_app properties that can be overridden by override_android_app +type overridableAppProperties struct { + // The name of a certificate in the default certificate directory, blank to use the default product certificate, + // or an android_app_certificate module name in the form ":module". + Certificate *string +} + type AndroidApp struct { Library aapt + android.OverridableModuleBase certificate Certificate appProperties appProperties + overridableAppProperties overridableAppProperties + installJniLibs []jniLib bundleFile android.Path @@ -320,7 +327,7 @@ func (a *AndroidApp) certificateBuildActions(certificateDeps []Certificate, ctx func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { // Check if the install APK name needs to be overridden. - a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(ctx.ModuleName()) + a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Name()) // Process all building blocks, from AAPT to certificates. a.aaptBuildActions(ctx) @@ -339,6 +346,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { certificates := a.certificateBuildActions(certificateDeps, ctx) // Build a final signed app package. + // TODO(jungjw): Consider changing this to installApkName. packageFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".apk") CreateAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates) a.outputFile = packageFile @@ -413,7 +421,7 @@ func (a *AndroidApp) getCertString(ctx android.BaseContext) string { if overridden { return ":" + certificate } - return String(a.appProperties.Certificate) + return String(a.overridableAppProperties.Certificate) } // android_app compiles sources and Android resources into an Android application package `.apk` file. @@ -432,7 +440,8 @@ func AndroidAppFactory() android.Module { &module.Module.dexpreoptProperties, &module.Module.protoProperties, &module.aaptProperties, - &module.appProperties) + &module.appProperties, + &module.overridableAppProperties) module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool { return class == android.Device && ctx.Config().DevicePrefer32BitApps() @@ -440,6 +449,7 @@ func AndroidAppFactory() android.Module { android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) + android.InitOverridableModule(module, &module.appProperties.Overrides) return module } @@ -503,6 +513,7 @@ func AndroidTestFactory() android.Module { &module.aaptProperties, &module.appProperties, &module.appTestProperties, + &module.overridableAppProperties, &module.testProperties) android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) @@ -541,7 +552,8 @@ func AndroidTestHelperAppFactory() android.Module { &module.Module.protoProperties, &module.aaptProperties, &module.appProperties, - &module.appTestHelperAppProperties) + &module.appTestHelperAppProperties, + &module.overridableAppProperties) android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) @@ -575,3 +587,24 @@ func (c *AndroidAppCertificate) GenerateAndroidBuildActions(ctx android.ModuleCo android.PathForModuleSrc(ctx, cert+".pk8"), } } + +type OverrideAndroidApp struct { + android.ModuleBase + android.OverrideModuleBase +} + +func (i *OverrideAndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // All the overrides happen in the base module. + // TODO(jungjw): Check the base module type. +} + +// override_android_app is used to create an android_app module based on another android_app by overriding +// some of its properties. +func OverrideAndroidAppModuleFactory() android.Module { + m := &OverrideAndroidApp{} + m.AddProperties(&overridableAppProperties{}) + + android.InitAndroidModule(m) + android.InitOverrideModule(m) + return m +} diff --git a/java/app_test.go b/java/app_test.go index 1bad12377..cf57c809a 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -827,3 +827,75 @@ func TestInstrumentationTargetOverridden(t *testing.T) { t.Errorf("target package renaming flag, %q is missing in aapt2 link flags, %q", e, aapt2Flags) } } + +func TestOverrideAndroidApp(t *testing.T) { + ctx := testJava(t, ` + android_app { + name: "foo", + srcs: ["a.java"], + overrides: ["baz"], + } + + override_android_app { + name: "bar", + base: "foo", + certificate: ":new_certificate", + } + + android_app_certificate { + name: "new_certificate", + certificate: "cert/new_cert", + } + `) + + expectedVariants := []struct { + variantName string + apkName string + apkPath string + signFlag string + overrides []string + }{ + { + variantName: "android_common", + apkPath: "/target/product/test_device/system/app/foo/foo.apk", + signFlag: "build/target/product/security/testkey.x509.pem build/target/product/security/testkey.pk8", + overrides: []string{"baz"}, + }, + { + variantName: "bar_android_common", + apkPath: "/target/product/test_device/system/app/bar/bar.apk", + signFlag: "cert/new_cert.x509.pem cert/new_cert.pk8", + overrides: []string{"baz", "foo"}, + }, + } + for _, expected := range expectedVariants { + variant := ctx.ModuleForTests("foo", expected.variantName) + + // Check the final apk name + outputs := variant.AllOutputs() + expectedApkPath := buildDir + expected.apkPath + found := false + for _, o := range outputs { + if o == expectedApkPath { + found = true + break + } + } + if !found { + t.Errorf("Can't find %q in output files.\nAll outputs:%v", expectedApkPath, outputs) + } + + // Check the certificate paths + signapk := variant.Output("foo.apk") + signFlag := signapk.Args["certificates"] + if expected.signFlag != signFlag { + t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected.signFlag, signFlag) + } + + mod := variant.Module().(*AndroidApp) + if !reflect.DeepEqual(expected.overrides, mod.appProperties.Overrides) { + t.Errorf("Incorrect overrides property value, expected: %q, got: %q", + expected.overrides, mod.appProperties.Overrides) + } + } +} diff --git a/java/java.go b/java/java.go index e0da00636..3eae93294 100644 --- a/java/java.go +++ b/java/java.go @@ -2068,6 +2068,7 @@ func DefaultsFactory(props ...interface{}) android.Module { &androidLibraryProperties{}, &appProperties{}, &appTestProperties{}, + &overridableAppProperties{}, &ImportProperties{}, &AARImportProperties{}, &sdkLibraryProperties{}, diff --git a/java/java_test.go b/java/java_test.go index 35dd696be..ec6d27a89 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -86,10 +86,12 @@ 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_android_app", android.ModuleFactoryAdaptor(OverrideAndroidAppModuleFactory)) ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(PrebuiltApisFactory)) ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators) ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) + ctx.PreArchMutators(android.RegisterOverridePreArchMutators) ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) { ctx.TopDown("prebuilt_apis", PrebuiltApisMutator).Parallel() ctx.TopDown("java_sdk_library", SdkLibraryMutator).Parallel()