diff --git a/Android.bp b/Android.bp index 63de01589..b1db8e937 100644 --- a/Android.bp +++ b/Android.bp @@ -130,3 +130,8 @@ buildinfo_prop { // Currently, only microdroid can refer to buildinfo.prop visibility: ["//packages/modules/Virtualization/microdroid"], } + +// container for apex_contributions selected using build flags +all_apex_contributions { + name: "all_apex_contributions", +} diff --git a/android/apex_contributions.go b/android/apex_contributions.go index a28ac31bf..6eaca8b23 100644 --- a/android/apex_contributions.go +++ b/android/apex_contributions.go @@ -15,6 +15,7 @@ package android import ( + "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -24,6 +25,7 @@ func init() { func RegisterApexContributionsBuildComponents(ctx RegistrationContext) { ctx.RegisterModuleType("apex_contributions", apexContributionsFactory) + ctx.RegisterSingletonModuleType("all_apex_contributions", allApexContributionsFactory) } type apexContributions struct { @@ -65,3 +67,109 @@ func apexContributionsFactory() Module { // prebuilts selection. 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) { +} diff --git a/android/config.go b/android/config.go index 4c31bb052..696632a64 100644 --- a/android/config.go +++ b/android/config.go @@ -2129,3 +2129,41 @@ func (c *config) GetBuildFlag(name string) (string, bool) { val, ok := c.productVariables.BuildFlags[name] 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 +} diff --git a/android/prebuilt.go b/android/prebuilt.go index e7b79796e..5acef1de4 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -435,6 +435,10 @@ func checkInvariantsForSourceAndPrebuilt(ctx BaseModuleContext, s, p Module) { // 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. +// +// 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) { m := ctx.Module() 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 diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go index fc47cfd97..915e6fab0 100644 --- a/android/prebuilt_test.go +++ b/android/prebuilt_test.go @@ -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() fs := MockFS{ "prebuilt_file": nil, @@ -508,9 +508,15 @@ func testPrebuiltError(t *testing.T, expectedError, bp string) { PrepareForTestWithOverrides, fs.AddToFixture(), FixtureRegisterWithContext(registerTestPrebuiltModules), + OptionalFixturePreparer(fixture), ). ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(expectedError)). RunTestWithBp(t, bp) + +} + +func testPrebuiltError(t *testing.T, expectedError, bp string) { + testPrebuiltErrorWithFixture(t, expectedError, bp, nil) } func TestPrebuiltShouldNotChangePartition(t *testing.T) { @@ -559,6 +565,7 @@ func registerTestPrebuiltModules(ctx RegistrationContext) { ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory) ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory) ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory) + RegisterApexContributionsBuildComponents(ctx) } type prebuiltModule struct { @@ -653,3 +660,33 @@ func newOverrideSourceModule() Module { InitOverrideModule(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) +}