Merge "Separate apex selection from apex.Prebuilt"
diff --git a/apex/boot_image_test.go b/apex/boot_image_test.go
index 574166a..aa0d9c4 100644
--- a/apex/boot_image_test.go
+++ b/apex/boot_image_test.go
@@ -305,6 +305,7 @@
 	`)
 
 	java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common", []string{
+		`com.android.art.apex.selector`,
 		`prebuilt_bar`,
 		`prebuilt_foo`,
 	})
diff --git a/apex/deapexer.go b/apex/deapexer.go
index e7aa551..1db13f9 100644
--- a/apex/deapexer.go
+++ b/apex/deapexer.go
@@ -49,21 +49,27 @@
 	Exported_java_libs []string
 }
 
+type SelectedApexProperties struct {
+	// The path to the apex selected for use by this module.
+	//
+	// Is tagged as `android:"path"` because it will usually contain a string of the form ":<module>"
+	// and is tagged as "`blueprint:"mutate"` because it is only initialized in a LoadHook not an
+	// Android.bp file.
+	Selected_apex *string `android:"path" blueprint:"mutated"`
+}
+
 type Deapexer struct {
 	android.ModuleBase
 
-	properties         DeapexerProperties
-	apexFileProperties ApexFileProperties
+	properties             DeapexerProperties
+	selectedApexProperties SelectedApexProperties
 
 	inputApex android.Path
 }
 
 func privateDeapexerFactory() android.Module {
 	module := &Deapexer{}
-	module.AddProperties(
-		&module.properties,
-		&module.apexFileProperties,
-	)
+	module.AddProperties(&module.properties, &module.selectedApexProperties)
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	return module
 }
@@ -78,7 +84,7 @@
 }
 
 func (p *Deapexer) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	p.inputApex = android.SingleSourcePathFromSupplier(ctx, p.apexFileProperties.prebuiltApexSelector, "src")
+	p.inputApex = android.OptionalPathForModuleSrc(ctx, p.selectedApexProperties.Selected_apex).Path()
 
 	// Create and remember the directory into which the .apex file's contents will be unpacked.
 	deapexerOutput := android.PathForModuleOut(ctx, "deapexer")
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 8c7e64c..9d84281 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -91,11 +91,40 @@
 	return false
 }
 
+// prebuiltApexSelectorModule is a private module type that is only created by the prebuilt_apex
+// module. It selects the apex to use and makes it available for use by prebuilt_apex and the
+// deapexer.
+type prebuiltApexSelectorModule struct {
+	android.ModuleBase
+
+	apexFileProperties ApexFileProperties
+
+	inputApex android.Path
+}
+
+func privateApexSelectorModuleFactory() android.Module {
+	module := &prebuiltApexSelectorModule{}
+	module.AddProperties(
+		&module.apexFileProperties,
+	)
+	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	return module
+}
+
+func (p *prebuiltApexSelectorModule) Srcs() android.Paths {
+	return android.Paths{p.inputApex}
+}
+
+func (p *prebuiltApexSelectorModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	p.inputApex = android.SingleSourcePathFromSupplier(ctx, p.apexFileProperties.prebuiltApexSelector, "src")
+}
+
 type Prebuilt struct {
 	android.ModuleBase
 	prebuiltCommon
 
-	properties PrebuiltProperties
+	properties             PrebuiltProperties
+	selectedApexProperties SelectedApexProperties
 
 	inputApex       android.Path
 	installDir      android.InstallPath
@@ -113,19 +142,19 @@
 	// This cannot be marked as `android:"arch_variant"` because the `prebuilt_apex` is only mutated
 	// for android_common. That is so that it will have the same arch variant as, and so be compatible
 	// with, the source `apex` module type that it replaces.
-	Src  *string
+	Src  *string `android:"path"`
 	Arch struct {
 		Arm struct {
-			Src *string
+			Src *string `android:"path"`
 		}
 		Arm64 struct {
-			Src *string
+			Src *string `android:"path"`
 		}
 		X86 struct {
-			Src *string
+			Src *string `android:"path"`
 		}
 		X86_64 struct {
-			Src *string
+			Src *string `android:"path"`
 		}
 	}
 }
@@ -224,28 +253,77 @@
 // 3. The `deapexer` module adds a dependency from the modules that require the exported files onto
 //    itself so that they can retrieve the file paths to those files.
 //
+// It also creates a child module `selector` that is responsible for selecting the appropriate
+// input apex for both the prebuilt_apex and the deapexer. That is needed for a couple of reasons:
+// 1. To dedup the selection logic so it only runs in one module.
+// 2. To allow the deapexer to be wired up to a different source for the input apex, e.g. an
+//    `apex_set`.
+//
+//                     prebuilt_apex
+//                    /      |      \
+//                 /         |         \
+//              V            |            V
+//       selector  <---  deapexer  <---  exported java lib
+//
 func PrebuiltFactory() android.Module {
 	module := &Prebuilt{}
-	module.AddProperties(&module.properties)
-	android.InitPrebuiltModuleWithSrcSupplier(module, module.properties.prebuiltApexSelector, "src")
+	module.AddProperties(&module.properties, &module.selectedApexProperties)
+	android.InitSingleSourcePrebuiltModule(module, &module.selectedApexProperties, "Selected_apex")
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 
 	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
-		props := struct {
-			Name *string
-		}{
-			Name: proptools.StringPtr(module.BaseModuleName() + ".deapexer"),
+		baseModuleName := module.BaseModuleName()
+
+		apexSelectorModuleName := apexSelectorModuleName(baseModuleName)
+		createApexSelectorModule(ctx, apexSelectorModuleName, &module.properties.ApexFileProperties)
+
+		apexFileSource := ":" + apexSelectorModuleName
+		if len(module.properties.Exported_java_libs) != 0 {
+			createDeapexerModule(ctx, deapexerModuleName(baseModuleName), apexFileSource, &module.properties.DeapexerProperties)
 		}
-		ctx.CreateModule(privateDeapexerFactory,
-			&props,
-			&module.properties.ApexFileProperties,
-			&module.properties.DeapexerProperties,
-		)
+
+		// Add a source reference to retrieve the selected apex from the selector module.
+		module.selectedApexProperties.Selected_apex = proptools.StringPtr(apexFileSource)
 	})
 
 	return module
 }
 
+func createApexSelectorModule(ctx android.LoadHookContext, name string, apexFileProperties *ApexFileProperties) {
+	props := struct {
+		Name *string
+	}{
+		Name: proptools.StringPtr(name),
+	}
+
+	ctx.CreateModule(privateApexSelectorModuleFactory,
+		&props,
+		apexFileProperties,
+	)
+}
+
+func createDeapexerModule(ctx android.LoadHookContext, deapexerName string, apexFileSource string, deapexerProperties *DeapexerProperties) {
+	props := struct {
+		Name          *string
+		Selected_apex *string
+	}{
+		Name:          proptools.StringPtr(deapexerName),
+		Selected_apex: proptools.StringPtr(apexFileSource),
+	}
+	ctx.CreateModule(privateDeapexerFactory,
+		&props,
+		deapexerProperties,
+	)
+}
+
+func deapexerModuleName(baseModuleName string) string {
+	return baseModuleName + ".deapexer"
+}
+
+func apexSelectorModuleName(baseModuleName string) string {
+	return baseModuleName + ".apex.selector"
+}
+
 func prebuiltApexExportedModuleName(ctx android.BottomUpMutatorContext, name string) string {
 	// The prebuilt_apex should be depending on prebuilt modules but as this runs after
 	// prebuilt_rename the prebuilt module may or may not be using the prebuilt_ prefixed named. So,
@@ -378,7 +456,7 @@
 
 func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	// TODO(jungjw): Check the key validity.
-	p.inputApex = p.Prebuilt().SingleSourcePath(ctx)
+	p.inputApex = android.OptionalPathForModuleSrc(ctx, p.selectedApexProperties.Selected_apex).Path()
 	p.installDir = android.PathForModuleInstall(ctx, "apex")
 	p.installFilename = p.InstallFilename()
 	if !strings.HasSuffix(p.installFilename, imageApexSuffix) {