diff --git a/apex/boot_image_test.go b/apex/boot_image_test.go index 574166a53..aa0d9c4b9 100644 --- a/apex/boot_image_test.go +++ b/apex/boot_image_test.go @@ -305,6 +305,7 @@ func TestBootImageInPrebuiltArtApex(t *testing.T) { `) 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 e7aa5514a..1db13f916 100644 --- a/apex/deapexer.go +++ b/apex/deapexer.go @@ -49,21 +49,27 @@ type DeapexerProperties struct { 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 ":" + // 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) DepsMutator(ctx android.BottomUpMutatorContext) { } 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 8c7e64c6a..9d84281cb 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -91,11 +91,40 @@ func (p *prebuiltCommon) checkForceDisable(ctx android.ModuleContext) bool { 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 @@ type ApexFileProperties struct { // 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 @@ func (p *Prebuilt) Name() string { // 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) ApexInfoMutator(mctx android.TopDownMutatorContext) { 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) {