Merge changes from topic "apex_contributions_build_flags" into main

* changes:
  Special-case java_sdk_library in source vs prebuilt selection
  Use `all_apex_contributions` for source/prebuilts selection
  Create a singleton all_apex_contributions module type
This commit is contained in:
Spandan Das 2023-11-09 01:31:57 +00:00 committed by Gerrit Code Review
commit c31b24977e
7 changed files with 484 additions and 4 deletions

View file

@ -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",
}

View file

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

View file

@ -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
}

View file

@ -3231,6 +3231,8 @@ func IsMetaDependencyTag(tag blueprint.DependencyTag) bool {
return true
} else if tag == licensesTag {
return true
} else if tag == acDepTag {
return true
}
return false
}

View file

@ -387,7 +387,7 @@ func RegisterPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) {
func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) {
ctx.BottomUp("prebuilt_source", PrebuiltSourceDepsMutator).Parallel()
ctx.TopDown("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
ctx.BottomUp("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).Parallel()
}
@ -406,6 +406,8 @@ func PrebuiltRenameMutator(ctx BottomUpMutatorContext) {
// PrebuiltSourceDepsMutator adds dependencies to the prebuilt module from the
// corresponding source module, if one exists for the same variant.
// Add a dependency from the prebuilt to `all_apex_contributions`
// The metadata will be used for source vs prebuilts selection
func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) {
m := ctx.Module()
// If this module is a prebuilt, is enabled and has not been renamed to source then add a
@ -416,6 +418,14 @@ func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) {
ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
p.properties.SourceExists = true
}
// Add a dependency from the prebuilt to the `all_apex_contributions`
// metadata module
// TODO: When all branches contain this singleton module, make this strict
// TODO: Add this dependency only for mainline prebuilts and not every prebuilt module
if ctx.OtherModuleExists("all_apex_contributions") {
ctx.AddDependency(m, acDepTag, "all_apex_contributions")
}
}
}
@ -435,7 +445,11 @@ 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.
func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
//
// 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 BottomUpMutatorContext) {
m := ctx.Module()
if p := GetEmbeddedPrebuilt(m); p != nil {
if p.srcsSupplier == nil && p.srcsPropertyName == "" {
@ -444,6 +458,17 @@ func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
if !p.properties.SourceExists {
p.properties.UsePrebuilt = p.usePrebuilt(ctx, nil, m)
}
// Propagate the provider received from `all_apex_contributions`
// to the source module
ctx.VisitDirectDepsWithTag(acDepTag, func(am Module) {
if ctx.Config().Bp2buildMode() {
// This provider key is not applicable in bp2build
return
}
psi := ctx.OtherModuleProvider(am, PrebuiltSelectionInfoProvider).(PrebuiltSelectionInfoMap)
ctx.SetProvider(PrebuiltSelectionInfoProvider, psi)
})
} else if s, ok := ctx.Module().(Module); ok {
ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(prebuiltModule Module) {
p := GetEmbeddedPrebuilt(prebuiltModule)
@ -455,6 +480,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
@ -480,9 +510,66 @@ func PrebuiltPostDepsMutator(ctx BottomUpMutatorContext) {
}
}
// A wrapper around PrebuiltSelectionInfoMap.IsSelected with special handling for java_sdk_library
// java_sdk_library is a macro that creates
// 1. top-level impl library
// 2. stub libraries (suffixed with .stubs...)
//
// java_sdk_library_import is a macro that creates
// 1. top-level "impl" library
// 2. stub libraries (suffixed with .stubs...)
//
// the impl of java_sdk_library_import is a "hook" for hiddenapi and dexpreopt processing. It does not have an impl jar, but acts as a shim
// to provide the jar deapxed from the prebuilt apex
//
// isSelected uses `all_apex_contributions` to supersede source vs prebuilts selection of the stub libraries. It does not supersede the
// selection of the top-level "impl" library so that this hook can work
//
// TODO (b/308174306) - Fix this when we need to support multiple prebuilts in main
func isSelected(psi PrebuiltSelectionInfoMap, m Module) bool {
if sdkLibrary, ok := m.(interface{ SdkLibraryName() *string }); ok && sdkLibrary.SdkLibraryName() != nil {
sln := proptools.String(sdkLibrary.SdkLibraryName())
// This is the top-level library
// Do not supersede the existing prebuilts vs source selection mechanisms
if sln == m.base().BaseModuleName() {
return false
}
// Stub library created by java_sdk_library_import
if p := GetEmbeddedPrebuilt(m); p != nil {
return psi.IsSelected(sln, PrebuiltNameFromSource(sln))
}
// Stub library created by java_sdk_library
return psi.IsSelected(sln, sln)
}
return psi.IsSelected(m.base().BaseModuleName(), m.Name())
}
// usePrebuilt returns true if a prebuilt should be used instead of the source module. The prebuilt
// will be used if it is marked "prefer" or if the source module is disabled.
func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module, prebuilt Module) bool {
func (p *Prebuilt) usePrebuilt(ctx BaseMutatorContext, source Module, prebuilt Module) bool {
// Use `all_apex_contributions` for source vs prebuilt selection.
psi := PrebuiltSelectionInfoMap{}
ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(am Module) {
if ctx.OtherModuleHasProvider(am, PrebuiltSelectionInfoProvider) {
psi = ctx.OtherModuleProvider(am, PrebuiltSelectionInfoProvider).(PrebuiltSelectionInfoMap)
}
})
// If the source module is explicitly listed in the metadata module, use that
if source != nil && isSelected(psi, source) {
return false
}
// If the prebuilt module is explicitly listed in the metadata module, use that
if isSelected(psi, prebuilt) {
return true
}
// If the baseModuleName could not be found in the metadata module,
// fall back to the existing source vs prebuilt selection.
// TODO: Drop the fallback mechanisms
if !ctx.Config().Bp2buildMode() {
if p.srcsSupplier != nil && len(p.srcsSupplier(ctx, prebuilt)) == 0 {
return false

View file

@ -334,6 +334,78 @@ func TestPrebuilts(t *testing.T) {
// be used.
prebuilt: []OsType{Android, buildOS},
},
{
name: "apex_contributions supersedes any source preferred via use_source_config_var",
modules: `
source {
name: "bar",
}
prebuilt {
name: "bar",
use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
srcs: ["prebuilt_file"],
}
apex_contributions {
name: "my_mainline_module_contribution",
api_domain: "apexfoo",
// this metadata module contains prebuilt
contents: ["prebuilt_bar"],
}
all_apex_contributions {
name: "all_apex_contributions",
}
`,
preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
variables.VendorVars = map[string]map[string]string{
"acme": {
"use_source": "true",
},
}
variables.BuildFlags = map[string]string{
"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contribution",
}
}),
// use_source_config_var indicates that source should be used
// but this is superseded by `my_mainline_module_contribution`
prebuilt: []OsType{Android, buildOS},
},
{
name: "apex_contributions supersedes any prebuilt preferred via use_source_config_var",
modules: `
source {
name: "bar",
}
prebuilt {
name: "bar",
use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
srcs: ["prebuilt_file"],
}
apex_contributions {
name: "my_mainline_module_contribution",
api_domain: "apexfoo",
// this metadata module contains source
contents: ["bar"],
}
all_apex_contributions {
name: "all_apex_contributions",
}
`,
preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
variables.VendorVars = map[string]map[string]string{
"acme": {
"use_source": "false",
},
}
variables.BuildFlags = map[string]string{
"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contribution",
}
}),
// use_source_config_var indicates that prebuilt should be used
// but this is superseded by `my_mainline_module_contribution`
prebuilt: nil,
},
{
name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=true",
modules: `
@ -497,7 +569,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 +580,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 +637,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 +732,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)
}

View file

@ -1068,6 +1068,137 @@ func TestJavaSdkLibraryImport_Preferred(t *testing.T) {
})
}
// If a module is listed in `mainline_module_contributions, it should be used
// It will supersede any other source vs prebuilt selection mechanism like `prefer` attribute
func TestSdkLibraryImport_MetadataModuleSupersedesPreferred(t *testing.T) {
bp := `
apex_contributions {
name: "my_mainline_module_contributions",
api_domain: "my_mainline_module",
contents: [
// legacy mechanism prefers the prebuilt
// mainline_module_contributions supersedes this since source is listed explicitly
"sdklib.prebuilt_preferred_using_legacy_flags",
// legacy mechanism prefers the source
// mainline_module_contributions supersedes this since prebuilt is listed explicitly
"prebuilt_sdklib.source_preferred_using_legacy_flags",
],
}
all_apex_contributions {
name: "all_apex_contributions",
}
java_sdk_library {
name: "sdklib.prebuilt_preferred_using_legacy_flags",
srcs: ["a.java"],
sdk_version: "none",
system_modules: "none",
public: {
enabled: true,
},
system: {
enabled: true,
}
}
java_sdk_library_import {
name: "sdklib.prebuilt_preferred_using_legacy_flags",
prefer: true, // prebuilt is preferred using legacy mechanism
public: {
jars: ["a.jar"],
stub_srcs: ["a.java"],
current_api: "current.txt",
removed_api: "removed.txt",
annotations: "annotations.zip",
},
system: {
jars: ["a.jar"],
stub_srcs: ["a.java"],
current_api: "current.txt",
removed_api: "removed.txt",
annotations: "annotations.zip",
},
}
java_sdk_library {
name: "sdklib.source_preferred_using_legacy_flags",
srcs: ["a.java"],
sdk_version: "none",
system_modules: "none",
public: {
enabled: true,
},
system: {
enabled: true,
}
}
java_sdk_library_import {
name: "sdklib.source_preferred_using_legacy_flags",
prefer: false, // source is preferred using legacy mechanism
public: {
jars: ["a.jar"],
stub_srcs: ["a.java"],
current_api: "current.txt",
removed_api: "removed.txt",
annotations: "annotations.zip",
},
system: {
jars: ["a.jar"],
stub_srcs: ["a.java"],
current_api: "current.txt",
removed_api: "removed.txt",
annotations: "annotations.zip",
},
}
// rdeps
java_library {
name: "public",
srcs: ["a.java"],
libs: [
// this should get source since source is listed in my_mainline_module_contributions
"sdklib.prebuilt_preferred_using_legacy_flags.stubs",
"sdklib.prebuilt_preferred_using_legacy_flags.stubs.system",
// this should get prebuilt since source is listed in my_mainline_module_contributions
"sdklib.source_preferred_using_legacy_flags.stubs",
"sdklib.source_preferred_using_legacy_flags.stubs.system",
],
}
`
result := android.GroupFixturePreparers(
prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles,
FixtureWithLastReleaseApis("sdklib.source_preferred_using_legacy_flags", "sdklib.prebuilt_preferred_using_legacy_flags"),
android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
android.RegisterApexContributionsBuildComponents(ctx)
}),
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.BuildFlags = map[string]string{
"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contributions",
}
}),
).RunTestWithBp(t, bp)
// Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions
public := result.ModuleForTests("public", "android_common")
rule := public.Output("javac/public.jar")
inputs := rule.Implicits.Strings()
expectedInputs := []string{
// source
"out/soong/.intermediates/sdklib.prebuilt_preferred_using_legacy_flags.stubs/android_common/turbine-combined/sdklib.prebuilt_preferred_using_legacy_flags.stubs.jar",
"out/soong/.intermediates/sdklib.prebuilt_preferred_using_legacy_flags.stubs.system/android_common/turbine-combined/sdklib.prebuilt_preferred_using_legacy_flags.stubs.system.jar",
// prebuilt
"out/soong/.intermediates/prebuilt_sdklib.source_preferred_using_legacy_flags.stubs/android_common/combined/sdklib.source_preferred_using_legacy_flags.stubs.jar",
"out/soong/.intermediates/prebuilt_sdklib.source_preferred_using_legacy_flags.stubs.system/android_common/combined/sdklib.source_preferred_using_legacy_flags.stubs.system.jar",
}
for _, expected := range expectedInputs {
if !android.InList(expected, inputs) {
t.Errorf("expected %q to contain %q", inputs, expected)
}
}
}
func TestJavaSdkLibraryEnforce(t *testing.T) {
partitionToBpOption := func(partition string) string {
switch partition {