Separate apex selection from apex.Prebuilt

This dedups the apex selection (which was previously being done by both
the apex.Prebuilt module type and the Deapexer module type) by
separating it out into its own module.

The apex.Prebuilt module retrieves the selected apex from its
selected_apex property which is simply initialized with
":<selector-module-name>".

The Deapexer module retrieves the selected apex it should use from its
src property which is initialized in the same way. That makes it easy
for the Deapexer module to be reused by the apex_set in a similar way.

Bug: 181267622
Test: m droid
Change-Id: I90cfb55698d35a97dcf28b95afcb1f58584bc90c
This commit is contained in:
Paul Duffin 2021-03-01 14:14:52 +00:00
parent 56dc66e2ea
commit 11216db1d3
3 changed files with 110 additions and 25 deletions

View File

@ -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`,
})

View File

@ -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 ":<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) 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")

View File

@ -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) {