Create a singleton all_apex_contributions module type

This will be a container for the the apex_contributions
selected using build flags. This module will be used to query the state of
selected apex contributions instead of a global that can be mutated by
anyone.

It will set a provider containing metadata for source vs prebuilts
selection. To reduce the overhead of a new mutator, this will be done in
the existing `prebuilt_select` mutator.

It will validate that there are no dups (`foo` and `prebuilt_foo` cannot
be both selected)

Bug: 308174923

Test: go test ./android

Change-Id: Ie42999a71f35d70e0e977f5ab07ce451608d9f35
This commit is contained in:
Spandan Das 2023-10-26 20:48:02 +00:00
parent 04445d5443
commit e3fcb41ff7
5 changed files with 198 additions and 1 deletions

View file

@ -130,3 +130,8 @@ buildinfo_prop {
// Currently, only microdroid can refer to buildinfo.prop // Currently, only microdroid can refer to buildinfo.prop
visibility: ["//packages/modules/Virtualization/microdroid"], visibility: ["//packages/modules/Virtualization/microdroid"],
} }
// container for apex_contributions selected using build flags
all_apex_contributions {
name: "all_apex_contributions",
}

View file

@ -15,6 +15,7 @@
package android package android
import ( import (
"github.com/google/blueprint"
"github.com/google/blueprint/proptools" "github.com/google/blueprint/proptools"
) )
@ -24,6 +25,7 @@ func init() {
func RegisterApexContributionsBuildComponents(ctx RegistrationContext) { func RegisterApexContributionsBuildComponents(ctx RegistrationContext) {
ctx.RegisterModuleType("apex_contributions", apexContributionsFactory) ctx.RegisterModuleType("apex_contributions", apexContributionsFactory)
ctx.RegisterSingletonModuleType("all_apex_contributions", allApexContributionsFactory)
} }
type apexContributions struct { type apexContributions struct {
@ -65,3 +67,109 @@ func apexContributionsFactory() Module {
// prebuilts selection. // prebuilts selection.
func (m *apexContributions) GenerateAndroidBuildActions(ctx ModuleContext) { func (m *apexContributions) GenerateAndroidBuildActions(ctx ModuleContext) {
} }
// A container for apex_contributions.
// Based on product_config, it will create a dependency on the selected
// apex_contributions per mainline module
type allApexContributions struct {
SingletonModuleBase
}
func allApexContributionsFactory() SingletonModule {
module := &allApexContributions{}
InitAndroidModule(module)
return module
}
type apexContributionsDepTag struct {
blueprint.BaseDependencyTag
}
var (
acDepTag = apexContributionsDepTag{}
)
// Creates a dep to each selected apex_contributions
func (a *allApexContributions) DepsMutator(ctx BottomUpMutatorContext) {
ctx.AddDependency(ctx.Module(), acDepTag, ctx.Config().AllApexContributions()...)
}
// Set PrebuiltSelectionInfoProvider in post deps phase
func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BaseModuleContext) {
addContentsToProvider := func(p *PrebuiltSelectionInfoMap, m *apexContributions) {
for _, content := range m.Contents() {
if !ctx.OtherModuleExists(content) {
ctx.ModuleErrorf("%s listed in apex_contributions %s does not exist\n", content, m.Name())
}
pi := &PrebuiltSelectionInfo{
baseModuleName: RemoveOptionalPrebuiltPrefix(content),
selectedModuleName: content,
metadataModuleName: m.Name(),
apiDomain: m.ApiDomain(),
}
p.Add(ctx, pi)
}
}
if ctx.Config().Bp2buildMode() { // Skip bp2build
return
}
p := PrebuiltSelectionInfoMap{}
ctx.VisitDirectDepsWithTag(acDepTag, func(child Module) {
if m, ok := child.(*apexContributions); ok {
addContentsToProvider(&p, m)
} else {
ctx.ModuleErrorf("%s is not an apex_contributions module\n", child.Name())
}
})
ctx.SetProvider(PrebuiltSelectionInfoProvider, p)
}
// A provider containing metadata about whether source or prebuilt should be used
// This provider will be used in prebuilt_select mutator to redirect deps
var PrebuiltSelectionInfoProvider = blueprint.NewMutatorProvider(PrebuiltSelectionInfoMap{}, "prebuilt_select")
// Map of baseModuleName to the selected source or prebuilt
type PrebuiltSelectionInfoMap map[string]PrebuiltSelectionInfo
// Add a new entry to the map with some validations
func (pm *PrebuiltSelectionInfoMap) Add(ctx BaseModuleContext, p *PrebuiltSelectionInfo) {
if p == nil {
return
}
// Do not allow dups. If the base module (without the prebuilt_) has been added before, raise an exception.
if old, exists := (*pm)[p.baseModuleName]; exists {
ctx.ModuleErrorf("Cannot use Soong module: %s from apex_contributions: %s because it has been added previously as: %s from apex_contributions: %s\n",
p.selectedModuleName, p.metadataModuleName, old.selectedModuleName, old.metadataModuleName,
)
}
(*pm)[p.baseModuleName] = *p
}
type PrebuiltSelectionInfo struct {
// e.g. libc
baseModuleName string
// e.g. (libc|prebuilt_libc)
selectedModuleName string
// Name of the apex_contributions module
metadataModuleName string
// e.g. com.android.runtime
apiDomain string
}
// Returns true if `name` is explicitly requested using one of the selected
// apex_contributions metadata modules.
func (p *PrebuiltSelectionInfoMap) IsSelected(baseModuleName, name string) bool {
if i, exists := (*p)[baseModuleName]; exists {
return i.selectedModuleName == name
} else {
return false
}
}
// This module type does not have any build actions.
func (a *allApexContributions) GenerateAndroidBuildActions(ctx ModuleContext) {
}
func (a *allApexContributions) GenerateSingletonBuildActions(ctx SingletonContext) {
}

View file

@ -2129,3 +2129,41 @@ func (c *config) GetBuildFlag(name string) (string, bool) {
val, ok := c.productVariables.BuildFlags[name] val, ok := c.productVariables.BuildFlags[name]
return val, ok return val, ok
} }
var (
mainlineApexContributionBuildFlags = []string{
"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES",
"RELEASE_APEX_CONTRIBUTIONS_APPSEARCH",
"RELEASE_APEX_CONTRIBUTIONS_ART",
"RELEASE_APEX_CONTRIBUTIONS_BLUETOOTH",
"RELEASE_APEX_CONTRIBUTIONS_CONFIGINFRASTRUCTURE",
"RELEASE_APEX_CONTRIBUTIONS_CONNECTIVITY",
"RELEASE_APEX_CONTRIBUTIONS_CONSCRYPT",
"RELEASE_APEX_CONTRIBUTIONS_CRASHRECOVERY",
"RELEASE_APEX_CONTRIBUTIONS_DEVICELOCK",
"RELEASE_APEX_CONTRIBUTIONS_HEALTHFITNESS",
"RELEASE_APEX_CONTRIBUTIONS_IPSEC",
"RELEASE_APEX_CONTRIBUTIONS_MEDIA",
"RELEASE_APEX_CONTRIBUTIONS_MEDIAPROVIDER",
"RELEASE_APEX_CONTRIBUTIONS_ONDEVICEPERSONALIZATION",
"RELEASE_APEX_CONTRIBUTIONS_PERMISSION",
"RELEASE_APEX_CONTRIBUTIONS_REMOTEKEYPROVISIONING",
"RELEASE_APEX_CONTRIBUTIONS_SCHEDULING",
"RELEASE_APEX_CONTRIBUTIONS_SDKEXTENSIONS",
"RELEASE_APEX_CONTRIBUTIONS_STATSD",
"RELEASE_APEX_CONTRIBUTIONS_UWB",
"RELEASE_APEX_CONTRIBUTIONS_WIFI",
}
)
// Returns the list of _selected_ apex_contributions
// Each mainline module will have one entry in the list
func (c *config) AllApexContributions() []string {
ret := []string{}
for _, f := range mainlineApexContributionBuildFlags {
if val, exists := c.GetBuildFlag(f); exists && val != "" {
ret = append(ret, val)
}
}
return ret
}

View file

@ -435,6 +435,10 @@ func checkInvariantsForSourceAndPrebuilt(ctx BaseModuleContext, s, p Module) {
// PrebuiltSelectModuleMutator marks prebuilts that are used, either overriding source modules or // PrebuiltSelectModuleMutator marks prebuilts that are used, either overriding source modules or
// because the source module doesn't exist. It also disables installing overridden source modules. // because the source module doesn't exist. It also disables installing overridden source modules.
//
// If the visited module is the metadata module `all_apex_contributions`, it sets a
// provider containing metadata about whether source or prebuilt of mainline modules should be used.
// This logic was added here to prevent the overhead of creating a new mutator.
func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) { func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
m := ctx.Module() m := ctx.Module()
if p := GetEmbeddedPrebuilt(m); p != nil { if p := GetEmbeddedPrebuilt(m); p != nil {
@ -455,6 +459,11 @@ func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
} }
}) })
} }
// If this is `all_apex_contributions`, set a provider containing
// metadata about source vs prebuilts selection
if am, ok := m.(*allApexContributions); ok {
am.SetPrebuiltSelectionInfoProvider(ctx)
}
} }
// PrebuiltPostDepsMutator replaces dependencies on the source module with dependencies on the // PrebuiltPostDepsMutator replaces dependencies on the source module with dependencies on the

View file

@ -497,7 +497,7 @@ func TestPrebuilts(t *testing.T) {
} }
} }
func testPrebuiltError(t *testing.T, expectedError, bp string) { func testPrebuiltErrorWithFixture(t *testing.T, expectedError, bp string, fixture FixturePreparer) {
t.Helper() t.Helper()
fs := MockFS{ fs := MockFS{
"prebuilt_file": nil, "prebuilt_file": nil,
@ -508,9 +508,15 @@ func testPrebuiltError(t *testing.T, expectedError, bp string) {
PrepareForTestWithOverrides, PrepareForTestWithOverrides,
fs.AddToFixture(), fs.AddToFixture(),
FixtureRegisterWithContext(registerTestPrebuiltModules), FixtureRegisterWithContext(registerTestPrebuiltModules),
OptionalFixturePreparer(fixture),
). ).
ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(expectedError)). ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(expectedError)).
RunTestWithBp(t, bp) RunTestWithBp(t, bp)
}
func testPrebuiltError(t *testing.T, expectedError, bp string) {
testPrebuiltErrorWithFixture(t, expectedError, bp, nil)
} }
func TestPrebuiltShouldNotChangePartition(t *testing.T) { func TestPrebuiltShouldNotChangePartition(t *testing.T) {
@ -559,6 +565,7 @@ func registerTestPrebuiltModules(ctx RegistrationContext) {
ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory) ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory) ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory) ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
RegisterApexContributionsBuildComponents(ctx)
} }
type prebuiltModule struct { type prebuiltModule struct {
@ -653,3 +660,33 @@ func newOverrideSourceModule() Module {
InitOverrideModule(m) InitOverrideModule(m)
return m return m
} }
func TestPrebuiltErrorCannotListBothSourceAndPrebuiltInContributions(t *testing.T) {
selectMainlineModuleContritbutions := GroupFixturePreparers(
FixtureModifyProductVariables(func(variables FixtureProductVariables) {
variables.BuildFlags = map[string]string{
"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_apex_contributions",
}
}),
)
testPrebuiltErrorWithFixture(t, `Cannot use Soong module: prebuilt_foo from apex_contributions: my_apex_contributions because it has been added previously as: foo from apex_contributions: my_apex_contributions`, `
source {
name: "foo",
}
prebuilt {
name: "foo",
srcs: ["prebuilt_file"],
}
apex_contributions {
name: "my_apex_contributions",
api_domain: "my_mainline_module",
contents: [
"foo",
"prebuilt_foo",
],
}
all_apex_contributions {
name: "all_apex_contributions",
}
`, selectMainlineModuleContritbutions)
}