Add override_apex module type

override_apex module type is used to override existing apex module with
certain properties overridden. Currently, only the 'apps' property is
overridable.

Bug: 144338929
Test: m
Change-Id: Ic050b062093cda29ce78126cc92dd6097647f7db
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 8ebf802..dd5da97 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -179,6 +179,7 @@
 				fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.ToMakePath().String())
 				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix())
 				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
+				fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(a.properties.Overrides, " "))
 				if len(moduleNames) > 0 {
 					fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(moduleNames, " "))
 				}
diff --git a/apex/apex.go b/apex/apex.go
index c021e1d..b831333 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -64,6 +64,7 @@
 	android.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
 	android.RegisterModuleType("apex_defaults", defaultsFactory)
 	android.RegisterModuleType("prebuilt_apex", PrebuiltFactory)
+	android.RegisterModuleType("override_apex", overrideApexFactory)
 
 	android.PreDepsMutators(RegisterPreDepsMutators)
 	android.PostDepsMutators(RegisterPostDepsMutators)
@@ -127,7 +128,15 @@
 		if mctx.Device() && a.installable() {
 			addApexFileContextsInfos(mctx, a)
 		}
+	} else if o, ok := mctx.Module().(*OverrideApex); ok {
+		apexBundleName := o.GetOverriddenModuleName()
+		if apexBundleName == "" {
+			mctx.ModuleErrorf("base property is not set")
+			return
+		}
+		mctx.CreateVariations(apexBundleName)
 	}
+
 }
 
 var (
@@ -181,6 +190,8 @@
 				}
 			}
 		}
+	} else if _, ok := mctx.Module().(*OverrideApex); ok {
+		mctx.CreateVariations(imageApexType, flattenedApexType)
 	}
 }
 
@@ -320,9 +331,6 @@
 	// A txt file containing list of files that are whitelisted to be included in this APEX.
 	Whitelisted_files *string
 
-	// List of APKs to package inside APEX
-	Apps []string
-
 	// package format of this apex variant; could be non-flattened, flattened, or zip.
 	// imageApex, zipApex or flattened
 	ApexType apexPackaging `blueprint:"mutated"`
@@ -332,6 +340,13 @@
 	// is implied. This value affects all modules included in this APEX. In other words, they are
 	// also built with the SDKs specified here.
 	Uses_sdks []string
+
+	// Names of modules to be overridden. Listed modules can only be other binaries
+	// (in Make or Soong).
+	// This does not completely prevent installation of the overridden binaries, but if both
+	// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
+	// from PRODUCT_PACKAGES.
+	Overrides []string
 }
 
 type apexTargetBundleProperties struct {
@@ -358,6 +373,11 @@
 	}
 }
 
+type overridableProperties struct {
+	// List of APKs to package inside APEX
+	Apps []string
+}
+
 type apexFileClass int
 
 const (
@@ -441,11 +461,13 @@
 type apexBundle struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	android.OverridableModuleBase
 	android.SdkBase
 
-	properties       apexBundleProperties
-	targetProperties apexTargetBundleProperties
-	vndkProperties   apexVndkProperties
+	properties            apexBundleProperties
+	targetProperties      apexTargetBundleProperties
+	vndkProperties        apexVndkProperties
+	overridableProperties overridableProperties
 
 	bundleModuleFile android.WritablePath
 	outputFile       android.WritablePath
@@ -633,9 +655,6 @@
 	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
 		javaLibTag, a.properties.Java_libs...)
 
-	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
-		androidAppTag, a.properties.Apps...)
-
 	if String(a.properties.Key) == "" {
 		ctx.ModuleErrorf("key is missing")
 		return
@@ -658,6 +677,11 @@
 	}
 }
 
+func (a *apexBundle) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) {
+	ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
+		androidAppTag, a.overridableProperties.Apps...)
+}
+
 func (a *apexBundle) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
 	// direct deps of an APEX bundle are all part of the APEX bundle
 	return true
@@ -1156,12 +1180,14 @@
 	module := &apexBundle{}
 	module.AddProperties(&module.properties)
 	module.AddProperties(&module.targetProperties)
+	module.AddProperties(&module.overridableProperties)
 	module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
 		return class == android.Device && ctx.Config().DevicePrefer32BitExecutables()
 	})
 	android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
 	android.InitSdkAwareModule(module)
+	android.InitOverridableModule(module, &module.properties.Overrides)
 	return module
 }
 
@@ -1206,3 +1232,26 @@
 	android.InitDefaultsModule(module)
 	return module
 }
+
+//
+// OverrideApex
+//
+type OverrideApex struct {
+	android.ModuleBase
+	android.OverrideModuleBase
+}
+
+func (o *OverrideApex) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// All the overrides happen in the base module.
+}
+
+// override_apex is used to create an apex module based on another apex module
+// by overriding some of its properties.
+func overrideApexFactory() android.Module {
+	m := &OverrideApex{}
+	m.AddProperties(&overridableProperties{})
+
+	android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon)
+	android.InitOverrideModule(m)
+	return m
+}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 1aac852..f4b8e35 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -107,6 +107,7 @@
 	ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(ApexKeyFactory))
 	ctx.RegisterModuleType("apex_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
 	ctx.RegisterModuleType("prebuilt_apex", android.ModuleFactoryAdaptor(PrebuiltFactory))
+	ctx.RegisterModuleType("override_apex", android.ModuleFactoryAdaptor(overrideApexFactory))
 
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
 	ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory))
@@ -132,6 +133,7 @@
 	ctx.RegisterModuleType("java_system_modules", android.ModuleFactoryAdaptor(java.SystemModulesFactory))
 	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(java.AndroidAppFactory))
 	ctx.RegisterModuleType("android_app_import", android.ModuleFactoryAdaptor(java.AndroidAppImportFactory))
+	ctx.RegisterModuleType("override_android_app", android.ModuleFactoryAdaptor(java.OverrideAndroidAppModuleFactory))
 
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
 	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
@@ -146,6 +148,7 @@
 		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
 	})
 	ctx.PreDepsMutators(RegisterPreDepsMutators)
+	ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
 	ctx.PostDepsMutators(RegisterPostDepsMutators)
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
@@ -2815,6 +2818,49 @@
 	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_static")
 }
 
+func TestOverrideApex(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			apps: ["app"],
+		}
+
+		override_apex {
+			name: "override_myapex",
+			base: "myapex",
+			apps: ["override_app"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		android_app {
+			name: "app",
+			srcs: ["foo/bar/MyClass.java"],
+			package_name: "foo",
+			sdk_version: "none",
+			system_modules: "none",
+		}
+
+		override_android_app {
+			name: "override_app",
+			base: "app",
+			package_name: "bar",
+		}
+	`)
+
+	module := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image")
+	apexRule := module.Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+
+	ensureNotContains(t, copyCmds, "image.apex/app/app/app.apk")
+	ensureContains(t, copyCmds, "image.apex/app/app/override_app.apk")
+}
+
 func TestMain(m *testing.M) {
 	run := func() int {
 		setUp()