diff --git a/android/override_module.go b/android/override_module.go index 22fb7de44..09959e43d 100644 --- a/android/override_module.go +++ b/android/override_module.go @@ -175,6 +175,7 @@ func RegisterOverridePostDepsMutators(ctx RegisterMutatorsContext) { ctx.TopDown("register_override", registerOverrideMutator).Parallel() ctx.BottomUp("perform_override", performOverrideMutator).Parallel() ctx.BottomUp("overridable_deps", overridableModuleDepsMutator).Parallel() + ctx.BottomUp("replace_deps_on_override", replaceDepsOnOverridingModuleMutator).Parallel() } type overrideBaseDependencyTag struct { @@ -218,6 +219,9 @@ func performOverrideMutator(ctx BottomUpMutatorContext) { variants[i+1] = o.(Module).Name() } mods := ctx.CreateLocalVariations(variants...) + // Make the original variation the default one to depend on if no other override module variant + // is specified. + ctx.AliasVariation(variants[0]) for i, o := range overrides { mods[i+1].(OverridableModule).override(ctx, o) } @@ -226,10 +230,18 @@ func performOverrideMutator(ctx BottomUpMutatorContext) { // variant name rule for overridden modules, and thus allows ReplaceDependencies to match the // two. ctx.CreateLocalVariations(o.Name()) + // To allow dependencies to be added without having to know the above variation. + ctx.AliasVariation(o.Name()) } } func overridableModuleDepsMutator(ctx BottomUpMutatorContext) { + if b, ok := ctx.Module().(OverridableModule); ok { + b.OverridablePropertiesDepsMutator(ctx) + } +} + +func replaceDepsOnOverridingModuleMutator(ctx BottomUpMutatorContext) { if b, ok := ctx.Module().(OverridableModule); ok { if o := b.getOverriddenBy(); o != "" { // Redirect dependencies on the overriding module to this overridden module. Overriding @@ -237,6 +249,5 @@ func overridableModuleDepsMutator(ctx BottomUpMutatorContext) { // modules. Therefore, dependencies on overriding modules need to be forwarded there as well. ctx.ReplaceDependencies(o) } - b.OverridablePropertiesDepsMutator(ctx) } } diff --git a/java/app.go b/java/app.go index 30cd6cb68..e1128c9e3 100644 --- a/java/app.go +++ b/java/app.go @@ -38,6 +38,7 @@ func init() { android.RegisterModuleType("android_test_helper_app", AndroidTestHelperAppFactory) android.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory) android.RegisterModuleType("override_android_app", OverrideAndroidAppModuleFactory) + android.RegisterModuleType("override_android_test", OverrideAndroidTestModuleFactory) android.RegisterModuleType("android_app_import", AndroidAppImportFactory) android.RegisterModuleType("android_test_import", AndroidTestImportFactory) @@ -596,6 +597,9 @@ func AndroidAppFactory() android.Module { type appTestProperties struct { Instrumentation_for *string + + // if specified, the instrumentation target package name in the manifest is overwritten by it. + Instrumentation_target_package *string } type AndroidTest struct { @@ -614,8 +618,11 @@ func (a *AndroidTest) InstallInTestcases() bool { } func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { - // Check if the instrumentation target package is overridden before generating build actions. - if a.appTestProperties.Instrumentation_for != nil { + if a.appTestProperties.Instrumentation_target_package != nil { + a.additionalAaptFlags = append(a.additionalAaptFlags, + "--rename-instrumentation-target-package "+*a.appTestProperties.Instrumentation_target_package) + } else if a.appTestProperties.Instrumentation_for != nil { + // Check if the instrumentation target package is overridden. manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(*a.appTestProperties.Instrumentation_for) if overridden { a.additionalAaptFlags = append(a.additionalAaptFlags, "--rename-instrumentation-target-package "+manifestPackageName) @@ -630,6 +637,10 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (a *AndroidTest) DepsMutator(ctx android.BottomUpMutatorContext) { a.AndroidApp.DepsMutator(ctx) +} + +func (a *AndroidTest) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) { + a.AndroidApp.OverridablePropertiesDepsMutator(ctx) if a.appTestProperties.Instrumentation_for != nil { // The android_app dependency listed in instrumentation_for needs to be added to the classpath for javac, // but not added to the aapt2 link includes like a normal android_app or android_library dependency, so @@ -665,6 +676,7 @@ func AndroidTestFactory() android.Module { android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) + android.InitOverridableModule(module, &module.appProperties.Overrides) return module } @@ -763,6 +775,28 @@ func OverrideAndroidAppModuleFactory() android.Module { return m } +type OverrideAndroidTest struct { + android.ModuleBase + android.OverrideModuleBase +} + +func (i *OverrideAndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // All the overrides happen in the base module. + // TODO(jungjw): Check the base module type. +} + +// override_android_test is used to create an android_app module based on another android_test by overriding +// some of its properties. +func OverrideAndroidTestModuleFactory() android.Module { + m := &OverrideAndroidTest{} + m.AddProperties(&overridableAppProperties{}) + m.AddProperties(&appTestProperties{}) + + android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon) + android.InitOverrideModule(m) + return m +} + type AndroidAppImport struct { android.ModuleBase android.DefaultableModuleBase diff --git a/java/app_test.go b/java/app_test.go index 7635f3d3b..2a4c4ec50 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -1118,6 +1118,101 @@ func TestOverrideAndroidAppDependency(t *testing.T) { } } +func TestOverrideAndroidTest(t *testing.T) { + ctx, _ := testJava(t, ` + android_app { + name: "foo", + srcs: ["a.java"], + package_name: "com.android.foo", + sdk_version: "current", + } + + override_android_app { + name: "bar", + base: "foo", + package_name: "com.android.bar", + } + + android_test { + name: "foo_test", + srcs: ["b.java"], + instrumentation_for: "foo", + } + + override_android_test { + name: "bar_test", + base: "foo_test", + package_name: "com.android.bar.test", + instrumentation_for: "bar", + instrumentation_target_package: "com.android.bar", + } + `) + + expectedVariants := []struct { + moduleName string + variantName string + apkPath string + overrides []string + targetVariant string + packageFlag string + targetPackageFlag string + }{ + { + variantName: "android_common", + apkPath: "/target/product/test_device/testcases/foo_test/foo_test.apk", + overrides: nil, + targetVariant: "android_common", + packageFlag: "", + targetPackageFlag: "", + }, + { + variantName: "android_common_bar_test", + apkPath: "/target/product/test_device/testcases/bar_test/bar_test.apk", + overrides: []string{"foo_test"}, + targetVariant: "android_common_bar", + packageFlag: "com.android.bar.test", + targetPackageFlag: "com.android.bar", + }, + } + for _, expected := range expectedVariants { + variant := ctx.ModuleForTests("foo_test", 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 if the overrides field values are correctly aggregated. + mod := variant.Module().(*AndroidTest) + if !reflect.DeepEqual(expected.overrides, mod.appProperties.Overrides) { + t.Errorf("Incorrect overrides property value, expected: %q, got: %q", + expected.overrides, mod.appProperties.Overrides) + } + + // Check if javac classpath has the correct jar file path. This checks instrumentation_for overrides. + javac := variant.Rule("javac") + turbine := filepath.Join(buildDir, ".intermediates", "foo", expected.targetVariant, "turbine-combined", "foo.jar") + if !strings.Contains(javac.Args["classpath"], turbine) { + t.Errorf("classpath %q does not contain %q", javac.Args["classpath"], turbine) + } + + // Check aapt2 flags. + res := variant.Output("package-res.apk") + aapt2Flags := res.Args["flags"] + checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) + checkAapt2LinkFlag(t, aapt2Flags, "rename-instrumentation-target-package", expected.targetPackageFlag) + } +} + func TestAndroidAppImport(t *testing.T) { ctx, _ := testJava(t, ` android_app_import { @@ -1853,3 +1948,17 @@ func TestUncompressDex(t *testing.T) { }) } } + +func checkAapt2LinkFlag(t *testing.T, aapt2Flags, flagName, expectedValue string) { + if expectedValue != "" { + expectedFlag := "--" + flagName + " " + expectedValue + if !strings.Contains(aapt2Flags, expectedFlag) { + t.Errorf("%q is missing in aapt2 link flags, %q", expectedFlag, aapt2Flags) + } + } else { + unexpectedFlag := "--" + flagName + if strings.Contains(aapt2Flags, unexpectedFlag) { + t.Errorf("unexpected flag, %q is found in aapt2 link flags, %q", unexpectedFlag, aapt2Flags) + } + } +} diff --git a/java/java_test.go b/java/java_test.go index e7b68dd6b..0f7e6dee8 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -92,6 +92,7 @@ func testContext(bp string, fs map[string][]byte) *android.TestContext { ctx.RegisterModuleType("java_sdk_library", android.ModuleFactoryAdaptor(SdkLibraryFactory)) ctx.RegisterModuleType("java_sdk_library_import", android.ModuleFactoryAdaptor(sdkLibraryImportFactory)) ctx.RegisterModuleType("override_android_app", android.ModuleFactoryAdaptor(OverrideAndroidAppModuleFactory)) + ctx.RegisterModuleType("override_android_test", android.ModuleFactoryAdaptor(OverrideAndroidTestModuleFactory)) ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(PrebuiltApisFactory)) ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators) ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)