Handle installation rules for co-existing prebuilts
Every module belonging to a single mainline module family will be hidden from make, except the one which has been flagged using apex_contributions Details - Introduce a new `source_apex_name` property to prebuilt_apex and override_apex. This property will be used to identify the source equivalent of a prebuilt soong apex module. - Create an N-ary tree from source to prebuilt(s). The tree wil be rooted at the source module. - In a subsequent mutator, visit every node in the tree(s). Query apex_contributions and store the handle of the node which is "active" (if any) - In the same mutator, do another pass over the tree. Invoke `HideFromMake` on every node which is not "active". The two-pass approach is needed PrebuiltSelectionInfoProvider does not know about the inter source-prebuilt dependency, this dependency can only be known by doing a graph walk of the N-ary tree. Some tangential implementation details - Each prebuilt apex has an internal deapxer module that is responsible for generating the deapex ninja rules. The name of this internal module uses the BaseModuleName (without the prebuilt_ prefix). Since we can have multiple prebuilt soong modules in trunk stable, change this to follow the name of the prebuilt module in order to avoid name collisions. Update existing unit tests accordingly Bug: 316179314 Test: go test ./apex -run TestInstallationRulesForMultipleApexPrebuilts Test: m nothing --no-skip-soong-tests Test: presubmits Change-Id: I58aa99d5e6a9859954614e6db9a8e9e2e581642d
This commit is contained in:
parent
ec3887ad2f
commit
3576e769a4
9 changed files with 286 additions and 74 deletions
|
@ -102,7 +102,6 @@ func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BaseModuleCo
|
|||
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(),
|
||||
|
@ -126,7 +125,8 @@ func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BaseModuleCo
|
|||
// 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
|
||||
// Map of selected module names to a metadata object
|
||||
// The metadata contains information about the api_domain of the selected module
|
||||
type PrebuiltSelectionInfoMap map[string]PrebuiltSelectionInfo
|
||||
|
||||
// Add a new entry to the map with some validations
|
||||
|
@ -134,18 +134,10 @@ func (pm *PrebuiltSelectionInfoMap) Add(ctx BaseModuleContext, p *PrebuiltSelect
|
|||
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
|
||||
(*pm)[p.selectedModuleName] = *p
|
||||
}
|
||||
|
||||
type PrebuiltSelectionInfo struct {
|
||||
// e.g. libc
|
||||
baseModuleName string
|
||||
// e.g. (libc|prebuilt_libc)
|
||||
selectedModuleName string
|
||||
// Name of the apex_contributions module
|
||||
|
@ -156,12 +148,9 @@ type PrebuiltSelectionInfo struct {
|
|||
|
||||
// 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
|
||||
}
|
||||
func (p *PrebuiltSelectionInfoMap) IsSelected(name string) bool {
|
||||
_, exists := (*p)[name]
|
||||
return exists
|
||||
}
|
||||
|
||||
// Return the list of soong modules selected for this api domain
|
||||
|
|
|
@ -391,12 +391,19 @@ func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) {
|
|||
ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).Parallel()
|
||||
}
|
||||
|
||||
// Returns the name of the source module corresponding to a prebuilt module
|
||||
// For source modules, it returns its own name
|
||||
type baseModuleName interface {
|
||||
BaseModuleName() string
|
||||
}
|
||||
|
||||
// PrebuiltRenameMutator ensures that there always is a module with an
|
||||
// undecorated name.
|
||||
func PrebuiltRenameMutator(ctx BottomUpMutatorContext) {
|
||||
m := ctx.Module()
|
||||
if p := GetEmbeddedPrebuilt(m); p != nil {
|
||||
name := m.base().BaseModuleName()
|
||||
bmn, _ := m.(baseModuleName)
|
||||
name := bmn.BaseModuleName()
|
||||
if !ctx.OtherModuleExists(name) {
|
||||
ctx.Rename(name)
|
||||
p.properties.PrebuiltRenamedToSource = true
|
||||
|
@ -413,7 +420,8 @@ func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) {
|
|||
// If this module is a prebuilt, is enabled and has not been renamed to source then add a
|
||||
// dependency onto the source if it is present.
|
||||
if p := GetEmbeddedPrebuilt(m); p != nil && m.Enabled() && !p.properties.PrebuiltRenamedToSource {
|
||||
name := m.base().BaseModuleName()
|
||||
bmn, _ := m.(baseModuleName)
|
||||
name := bmn.BaseModuleName()
|
||||
if ctx.OtherModuleReverseDependencyVariantExists(name) {
|
||||
ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
|
||||
p.properties.SourceExists = true
|
||||
|
@ -466,6 +474,13 @@ func PrebuiltSelectModuleMutator(ctx BottomUpMutatorContext) {
|
|||
})
|
||||
|
||||
} else if s, ok := ctx.Module().(Module); ok {
|
||||
// Use `all_apex_contributions` for source vs prebuilt selection.
|
||||
psi := PrebuiltSelectionInfoMap{}
|
||||
ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(am Module) {
|
||||
// The value of psi gets overwritten with the provider from the last visited prebuilt.
|
||||
// But all prebuilts have the same value of the provider, so this should be idempontent.
|
||||
psi, _ = OtherModuleProvider(ctx, am, PrebuiltSelectionInfoProvider)
|
||||
})
|
||||
ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(prebuiltModule Module) {
|
||||
p := GetEmbeddedPrebuilt(prebuiltModule)
|
||||
if p.usePrebuilt(ctx, s, prebuiltModule) {
|
||||
|
@ -475,7 +490,18 @@ func PrebuiltSelectModuleMutator(ctx BottomUpMutatorContext) {
|
|||
s.ReplacedByPrebuilt()
|
||||
}
|
||||
})
|
||||
|
||||
// If any module in this mainline module family has been flagged using apex_contributions, disable every other module in that family
|
||||
// Add source
|
||||
allModules := []Module{s}
|
||||
// Add each prebuilt
|
||||
ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(prebuiltModule Module) {
|
||||
allModules = append(allModules, prebuiltModule)
|
||||
})
|
||||
hideUnflaggedModules(ctx, psi, allModules)
|
||||
|
||||
}
|
||||
|
||||
// If this is `all_apex_contributions`, set a provider containing
|
||||
// metadata about source vs prebuilts selection
|
||||
if am, ok := m.(*allApexContributions); ok {
|
||||
|
@ -483,13 +509,41 @@ func PrebuiltSelectModuleMutator(ctx BottomUpMutatorContext) {
|
|||
}
|
||||
}
|
||||
|
||||
// If any module in this mainline module family has been flagged using apex_contributions, disable every other module in that family
|
||||
func hideUnflaggedModules(ctx BottomUpMutatorContext, psi PrebuiltSelectionInfoMap, allModulesInFamily []Module) {
|
||||
var selectedModuleInFamily Module
|
||||
// query all_apex_contributions to see if any module in this family has been selected
|
||||
for _, moduleInFamily := range allModulesInFamily {
|
||||
// validate that are no duplicates
|
||||
if psi.IsSelected(moduleInFamily.Name()) {
|
||||
if selectedModuleInFamily == nil {
|
||||
// Store this so we can validate that there are no duplicates
|
||||
selectedModuleInFamily = moduleInFamily
|
||||
} else {
|
||||
// There are duplicate modules from the same mainline module family
|
||||
ctx.ModuleErrorf("Found duplicate variations of the same module in apex_contributions: %s and %s. Please remove one of these.\n", selectedModuleInFamily.Name(), moduleInFamily.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If a module has been selected, hide all other modules
|
||||
if selectedModuleInFamily != nil {
|
||||
for _, moduleInFamily := range allModulesInFamily {
|
||||
if moduleInFamily.Name() != selectedModuleInFamily.Name() {
|
||||
moduleInFamily.HideFromMake()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PrebuiltPostDepsMutator replaces dependencies on the source module with dependencies on the
|
||||
// prebuilt when both modules exist and the prebuilt should be used. When the prebuilt should not
|
||||
// be used, disable installing it.
|
||||
func PrebuiltPostDepsMutator(ctx BottomUpMutatorContext) {
|
||||
m := ctx.Module()
|
||||
if p := GetEmbeddedPrebuilt(m); p != nil {
|
||||
name := m.base().BaseModuleName()
|
||||
bmn, _ := m.(baseModuleName)
|
||||
name := bmn.BaseModuleName()
|
||||
if p.properties.UsePrebuilt {
|
||||
if p.properties.SourceExists {
|
||||
ctx.ReplaceDependenciesIf(name, func(from blueprint.Module, tag blueprint.DependencyTag, to blueprint.Module) bool {
|
||||
|
@ -533,13 +587,13 @@ func isSelected(psi PrebuiltSelectionInfoMap, m Module) bool {
|
|||
|
||||
// Stub library created by java_sdk_library_import
|
||||
if p := GetEmbeddedPrebuilt(m); p != nil {
|
||||
return psi.IsSelected(sln, PrebuiltNameFromSource(sln))
|
||||
return psi.IsSelected(PrebuiltNameFromSource(sln))
|
||||
}
|
||||
|
||||
// Stub library created by java_sdk_library
|
||||
return psi.IsSelected(sln, sln)
|
||||
return psi.IsSelected(sln)
|
||||
}
|
||||
return psi.IsSelected(m.base().BaseModuleName(), m.Name())
|
||||
return psi.IsSelected(m.Name())
|
||||
}
|
||||
|
||||
// usePrebuilt returns true if a prebuilt should be used instead of the source module. The prebuilt
|
||||
|
|
|
@ -741,7 +741,7 @@ func TestPrebuiltErrorCannotListBothSourceAndPrebuiltInContributions(t *testing.
|
|||
}
|
||||
}),
|
||||
)
|
||||
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`, `
|
||||
testPrebuiltErrorWithFixture(t, `Found duplicate variations of the same module in apex_contributions: foo and prebuilt_foo. Please remove one of these`, `
|
||||
source {
|
||||
name: "foo",
|
||||
}
|
||||
|
|
|
@ -5374,7 +5374,7 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) {
|
|||
dexJarBuildPath := p.DexJarBuildPath(moduleErrorfTestCtx{}).PathOrNil()
|
||||
stem := android.RemoveOptionalPrebuiltPrefix(name)
|
||||
android.AssertStringEquals(t, "DexJarBuildPath should be apex-related path.",
|
||||
".intermediates/myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar",
|
||||
".intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar",
|
||||
android.NormalizePathForTesting(dexJarBuildPath))
|
||||
}
|
||||
|
||||
|
@ -5428,8 +5428,8 @@ func TestPrebuiltExportDexImplementationJars(t *testing.T) {
|
|||
// Make sure that dexpreopt can access dex implementation files from the prebuilt.
|
||||
ctx := testDexpreoptWithApexes(t, bp, "", transform)
|
||||
|
||||
deapexerName := deapexerModuleName("myapex")
|
||||
android.AssertStringEquals(t, "APEX module name from deapexer name", "myapex", apexModuleName(deapexerName))
|
||||
deapexerName := deapexerModuleName("prebuilt_myapex")
|
||||
android.AssertStringEquals(t, "APEX module name from deapexer name", "prebuilt_myapex", apexModuleName(deapexerName))
|
||||
|
||||
// Make sure that the deapexer has the correct input APEX.
|
||||
deapexer := ctx.ModuleForTests(deapexerName, "android_common")
|
||||
|
@ -5652,8 +5652,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
|
|||
`
|
||||
|
||||
ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
|
||||
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
|
||||
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
|
||||
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
|
||||
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
|
||||
|
||||
// Verify the correct module jars contribute to the hiddenapi index file.
|
||||
checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
|
||||
|
@ -5730,8 +5730,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
|
|||
`
|
||||
|
||||
ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
|
||||
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
|
||||
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
|
||||
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
|
||||
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
|
||||
|
||||
// Verify the correct module jars contribute to the hiddenapi index file.
|
||||
checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
|
||||
|
@ -5744,7 +5744,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
|
|||
myApex := ctx.ModuleForTests("myapex", "android_common_myapex").Module()
|
||||
|
||||
overrideNames := []string{
|
||||
"",
|
||||
"myapex",
|
||||
"myjavalib.myapex",
|
||||
"libfoo.myapex",
|
||||
"libbar.myapex",
|
||||
|
@ -5919,8 +5919,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
|
|||
`
|
||||
|
||||
ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
|
||||
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
|
||||
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
|
||||
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
|
||||
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
|
||||
|
||||
// Verify the correct module jars contribute to the hiddenapi index file.
|
||||
checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
|
||||
|
@ -6116,8 +6116,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) {
|
|||
`
|
||||
|
||||
ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
|
||||
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
|
||||
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
|
||||
checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
|
||||
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
|
||||
|
||||
// Verify the correct module jars contribute to the hiddenapi index file.
|
||||
checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
|
||||
|
@ -8320,9 +8320,9 @@ func TestAppSetBundlePrebuilt(t *testing.T) {
|
|||
ctx := testApex(t, bp, prepareForTestWithSantitizeHwaddress)
|
||||
|
||||
// Check that the extractor produces the correct output file from the correct input file.
|
||||
extractorOutput := "out/soong/.intermediates/myapex.apex.extractor/android_common/extracted/myapex.hwasan.apks"
|
||||
extractorOutput := "out/soong/.intermediates/prebuilt_myapex.apex.extractor/android_common/extracted/myapex.hwasan.apks"
|
||||
|
||||
m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
|
||||
m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
|
||||
extractedApex := m.Output(extractorOutput)
|
||||
|
||||
android.AssertArrayString(t, "extractor input", []string{"myapex.hwasan.apks"}, extractedApex.Inputs.Strings())
|
||||
|
@ -8347,10 +8347,10 @@ func TestApexSetApksModuleAssignment(t *testing.T) {
|
|||
}
|
||||
`)
|
||||
|
||||
m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
|
||||
m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
|
||||
|
||||
// Check that the extractor produces the correct apks file from the input module
|
||||
extractorOutput := "out/soong/.intermediates/myapex.apex.extractor/android_common/extracted/myapex.apks"
|
||||
extractorOutput := "out/soong/.intermediates/prebuilt_myapex.apex.extractor/android_common/extracted/myapex.apks"
|
||||
extractedApex := m.Output(extractorOutput)
|
||||
|
||||
android.AssertArrayString(t, "extractor input", []string{"myapex.apks"}, extractedApex.Inputs.Strings())
|
||||
|
@ -8420,7 +8420,7 @@ func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
|
|||
PrepareForTestWithApexBuildComponents,
|
||||
).
|
||||
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
|
||||
"Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.art and com.mycompany.android.art"))
|
||||
"Multiple installable prebuilt APEXes provide ambiguous deapexers: prebuilt_com.android.art and prebuilt_com.mycompany.android.art"))
|
||||
|
||||
bpBase := `
|
||||
apex_set {
|
||||
|
@ -8548,7 +8548,7 @@ func TestDuplicateButEquivalentDeapexersFromPrebuiltApexes(t *testing.T) {
|
|||
module := result.Module("libfoo", "android_common_com.android.myapex")
|
||||
usesLibraryDep := module.(java.UsesLibraryDependency)
|
||||
android.AssertPathRelativeToTopEquals(t, "dex jar path",
|
||||
"out/soong/.intermediates/com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
|
||||
"out/soong/.intermediates/prebuilt_com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
|
||||
usesLibraryDep.DexJarBuildPath(errCtx).Path())
|
||||
})
|
||||
|
||||
|
@ -8571,7 +8571,7 @@ func TestDuplicateButEquivalentDeapexersFromPrebuiltApexes(t *testing.T) {
|
|||
module := result.Module("libfoo", "android_common_com.android.myapex")
|
||||
usesLibraryDep := module.(java.UsesLibraryDependency)
|
||||
android.AssertPathRelativeToTopEquals(t, "dex jar path",
|
||||
"out/soong/.intermediates/com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
|
||||
"out/soong/.intermediates/prebuilt_com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
|
||||
usesLibraryDep.DexJarBuildPath(errCtx).Path())
|
||||
})
|
||||
|
||||
|
@ -9144,7 +9144,7 @@ func TestApexSet(t *testing.T) {
|
|||
}),
|
||||
)
|
||||
|
||||
m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
|
||||
m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
|
||||
|
||||
// Check extract_apks tool parameters.
|
||||
extractedApex := m.Output("extracted/myapex.apks")
|
||||
|
@ -9185,7 +9185,7 @@ func TestApexSet_NativeBridge(t *testing.T) {
|
|||
}),
|
||||
)
|
||||
|
||||
m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
|
||||
m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
|
||||
|
||||
// Check extract_apks tool parameters. No native bridge arch expected
|
||||
extractedApex := m.Output("extracted/myapex.apks")
|
||||
|
@ -11570,12 +11570,12 @@ func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) {
|
|||
{
|
||||
desc: "Prebuilt apex prebuilt_com.android.foo is selected, profile should come from .prof deapexed from the prebuilt",
|
||||
selectedApexContributions: "foo.prebuilt.contributions",
|
||||
expectedBootJar: "out/soong/.intermediates/com.android.foo.deapexer/android_common/deapexer/javalib/framework-foo.jar",
|
||||
expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo.deapexer/android_common/deapexer/javalib/framework-foo.jar",
|
||||
},
|
||||
{
|
||||
desc: "Prebuilt apex prebuilt_com.android.foo.v2 is selected, profile should come from .prof deapexed from the prebuilt",
|
||||
selectedApexContributions: "foo.prebuilt.v2.contributions",
|
||||
expectedBootJar: "out/soong/.intermediates/com.android.foo.v2.deapexer/android_common/deapexer/javalib/framework-foo.jar",
|
||||
expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo.v2.deapexer/android_common/deapexer/javalib/framework-foo.jar",
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -11602,3 +11602,165 @@ func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) {
|
|||
checkBootJarsForMonolithicHiddenapi(t, ctx, tc.expectedBootJar)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that product packaging installs the selected mainline module (either source or a specific prebuilt)
|
||||
// RELEASE_APEX_CONTIRBUTIONS_* build flags will be used to select the correct prebuilt for a specific release config
|
||||
func TestInstallationRulesForMultipleApexPrebuilts(t *testing.T) {
|
||||
// check that the LOCAL_MODULE in the generated mk file matches the name used in PRODUCT_PACKAGES
|
||||
// Since the name used in PRODUCT_PACKAGES does not contain prebuilt_ prefix, LOCAL_MODULE should not contain any prefix either
|
||||
checkLocalModuleName := func(t *testing.T, ctx *android.TestContext, soongApexModuleName string, expectedLocalModuleName string) {
|
||||
// Variations are created based on apex_name
|
||||
entries := android.AndroidMkEntriesForTest(t, ctx, ctx.ModuleForTests(soongApexModuleName, "android_common_com.android.foo").Module())
|
||||
android.AssertStringEquals(t, "LOCAL_MODULE of the prebuilt apex must match the name listed in PRODUCT_PACKAGES", expectedLocalModuleName, entries[0].EntryMap["LOCAL_MODULE"][0])
|
||||
}
|
||||
// for a mainline module family, check that only the flagged soong module is visible to make
|
||||
checkHideFromMake := func(t *testing.T, ctx *android.TestContext, visibleModuleName string, hiddenModuleNames []string) {
|
||||
variation := func(moduleName string) string {
|
||||
ret := "android_common_com.android.foo"
|
||||
if moduleName == "com.google.android.foo" {
|
||||
ret = "android_common_com.google.android.foo_com.android.foo"
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
visibleModule := ctx.ModuleForTests(visibleModuleName, variation(visibleModuleName)).Module()
|
||||
android.AssertBoolEquals(t, "Apex "+visibleModuleName+" selected using apex_contributions should be visible to make", false, visibleModule.IsHideFromMake())
|
||||
|
||||
for _, hiddenModuleName := range hiddenModuleNames {
|
||||
hiddenModule := ctx.ModuleForTests(hiddenModuleName, variation(hiddenModuleName)).Module()
|
||||
android.AssertBoolEquals(t, "Apex "+hiddenModuleName+" not selected using apex_contributions should be hidden from make", true, hiddenModule.IsHideFromMake())
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bp := `
|
||||
apex_key {
|
||||
name: "com.android.foo.key",
|
||||
public_key: "com.android.foo.avbpubkey",
|
||||
private_key: "com.android.foo.pem",
|
||||
}
|
||||
|
||||
// AOSP source apex
|
||||
apex {
|
||||
name: "com.android.foo",
|
||||
key: "com.android.foo.key",
|
||||
updatable: false,
|
||||
}
|
||||
|
||||
// Google source apex
|
||||
override_apex {
|
||||
name: "com.google.android.foo",
|
||||
base: "com.android.foo",
|
||||
key: "com.android.foo.key",
|
||||
}
|
||||
|
||||
// Prebuilt Google APEX.
|
||||
|
||||
prebuilt_apex {
|
||||
name: "com.google.android.foo",
|
||||
apex_name: "com.android.foo",
|
||||
src: "com.android.foo-arm.apex",
|
||||
prefer: true, // prefer is set to true on both the prebuilts to induce an error if flagging is not present
|
||||
}
|
||||
|
||||
// Another Prebuilt Google APEX
|
||||
prebuilt_apex {
|
||||
name: "com.google.android.foo.v2",
|
||||
apex_name: "com.android.foo",
|
||||
source_apex_name: "com.google.android.foo", // source_apex_name becomes LOCAL_MODULE in the generated mk file
|
||||
src: "com.android.foo-arm.apex",
|
||||
prefer: true, // prefer is set to true on both the prebuilts to induce an error if flagging is not present
|
||||
}
|
||||
|
||||
// APEX contribution modules
|
||||
|
||||
apex_contributions {
|
||||
name: "foo.source.contributions",
|
||||
api_domain: "com.android.foo",
|
||||
contents: ["com.google.android.foo"],
|
||||
}
|
||||
|
||||
apex_contributions {
|
||||
name: "foo.prebuilt.contributions",
|
||||
api_domain: "com.android.foo",
|
||||
contents: ["prebuilt_com.google.android.foo"],
|
||||
}
|
||||
|
||||
apex_contributions {
|
||||
name: "foo.prebuilt.v2.contributions",
|
||||
api_domain: "com.android.foo",
|
||||
contents: ["prebuilt_com.google.android.foo.v2"],
|
||||
}
|
||||
|
||||
// This is an incompatible module because it selects multiple versions of the same mainline module
|
||||
apex_contributions {
|
||||
name: "foo.prebuilt.duplicate.contributions",
|
||||
api_domain: "com.android.foo",
|
||||
contents: [
|
||||
"prebuilt_com.google.android.foo",
|
||||
"prebuilt_com.google.android.foo.v2",
|
||||
],
|
||||
}
|
||||
`
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
selectedApexContributions string
|
||||
expectedVisibleModuleName string
|
||||
expectedHiddenModuleNames []string
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
desc: "Source apex is selected, prebuilts should be hidden from make",
|
||||
selectedApexContributions: "foo.source.contributions",
|
||||
expectedVisibleModuleName: "com.google.android.foo",
|
||||
expectedHiddenModuleNames: []string{"prebuilt_com.google.android.foo", "prebuilt_com.google.android.foo.v2"},
|
||||
},
|
||||
{
|
||||
desc: "Prebuilt apex prebuilt_com.android.foo is selected, source and the other prebuilt should be hidden from make",
|
||||
selectedApexContributions: "foo.prebuilt.contributions",
|
||||
expectedVisibleModuleName: "prebuilt_com.google.android.foo",
|
||||
expectedHiddenModuleNames: []string{"com.google.android.foo", "prebuilt_com.google.android.foo.v2"},
|
||||
},
|
||||
{
|
||||
desc: "Prebuilt apex prebuilt_com.android.fooi.v2 is selected, source and the other prebuilt should be hidden from make",
|
||||
selectedApexContributions: "foo.prebuilt.v2.contributions",
|
||||
expectedVisibleModuleName: "prebuilt_com.google.android.foo.v2",
|
||||
expectedHiddenModuleNames: []string{"com.google.android.foo", "prebuilt_com.google.android.foo"},
|
||||
},
|
||||
{
|
||||
desc: "Multiple versions of a prebuilt apex is selected in the same release config",
|
||||
selectedApexContributions: "foo.prebuilt.duplicate.contributions",
|
||||
expectedError: "Found duplicate variations of the same module in apex_contributions: prebuilt_com.google.android.foo and prebuilt_com.google.android.foo.v2",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
preparer := android.GroupFixturePreparers(
|
||||
android.FixtureMergeMockFs(map[string][]byte{
|
||||
"system/sepolicy/apex/com.android.foo-file_contexts": nil,
|
||||
}),
|
||||
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
|
||||
variables.BuildFlags = map[string]string{
|
||||
"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": tc.selectedApexContributions,
|
||||
}
|
||||
}),
|
||||
)
|
||||
if tc.expectedError != "" {
|
||||
preparer = preparer.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(tc.expectedError))
|
||||
testApex(t, bp, preparer)
|
||||
return
|
||||
}
|
||||
ctx := testApex(t, bp, preparer)
|
||||
|
||||
// Check that the LOCAL_MODULE of the two prebuilts is com.android.foo
|
||||
// This ensures that product packaging can pick them for installation if it has been flagged by apex_contributions
|
||||
checkLocalModuleName(t, ctx, "prebuilt_com.google.android.foo", "com.google.android.foo")
|
||||
checkLocalModuleName(t, ctx, "prebuilt_com.google.android.foo.v2", "com.google.android.foo")
|
||||
|
||||
// Check that
|
||||
// 1. The contents of the selected apex_contributions are visible to make
|
||||
// 2. The rest of the apexes in the mainline module family (source or other prebuilt) is hidden from make
|
||||
checkHideFromMake(t, ctx, tc.expectedVisibleModuleName, tc.expectedHiddenModuleNames)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -374,7 +374,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) {
|
|||
java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"),
|
||||
).RunTest(t)
|
||||
|
||||
ensureExactDeapexedContents(t, result.TestContext, "com.android.art", "android_common", []string{
|
||||
ensureExactDeapexedContents(t, result.TestContext, "prebuilt_com.android.art", "android_common", []string{
|
||||
"etc/boot-image.prof",
|
||||
"javalib/bar.jar",
|
||||
"javalib/foo.jar",
|
||||
|
@ -529,16 +529,16 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) {
|
|||
result := preparers.RunTestWithBp(t, fmt.Sprintf(bp, "enabled: false,"))
|
||||
|
||||
java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
|
||||
`com.android.art.apex.selector`,
|
||||
`com.android.art.deapexer`,
|
||||
`dex2oatd`,
|
||||
`prebuilt_art-bootclasspath-fragment`,
|
||||
`prebuilt_com.android.art.apex.selector`,
|
||||
`prebuilt_com.android.art.deapexer`,
|
||||
})
|
||||
|
||||
java.CheckModuleDependencies(t, result.TestContext, "art-bootclasspath-fragment", "android_common_com.android.art", []string{
|
||||
`com.android.art.deapexer`,
|
||||
`dex2oatd`,
|
||||
`prebuilt_bar`,
|
||||
`prebuilt_com.android.art.deapexer`,
|
||||
`prebuilt_foo`,
|
||||
})
|
||||
|
||||
|
@ -548,7 +548,7 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) {
|
|||
|
||||
t.Run("enabled alternative APEX", func(t *testing.T) {
|
||||
preparers.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
|
||||
"Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.art and com.mycompany.android.art")).
|
||||
"Multiple installable prebuilt APEXes provide ambiguous deapexers: prebuilt_com.android.art and prebuilt_com.mycompany.android.art")).
|
||||
RunTestWithBp(t, fmt.Sprintf(bp, ""))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ func TestDexpreoptBootJarsWithPrebuiltArtApex(t *testing.T) {
|
|||
"out/soong/dexpreopt_arm64/dex_bootjars_input/foo.jar",
|
||||
"out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar",
|
||||
"out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar",
|
||||
"out/soong/.intermediates/com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
|
||||
"out/soong/.intermediates/prebuilt_com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
|
||||
"out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof",
|
||||
}
|
||||
|
||||
|
@ -382,12 +382,12 @@ func TestDexpreoptProfileWithMultiplePrebuiltArtApexes(t *testing.T) {
|
|||
{
|
||||
desc: "Prebuilt apex prebuilt_com.android.art is selected, profile should come from .prof deapexed from the prebuilt",
|
||||
selectedArtApexContributions: "art.prebuilt.contributions",
|
||||
expectedProfile: "out/soong/.intermediates/com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
|
||||
expectedProfile: "out/soong/.intermediates/prebuilt_com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
|
||||
},
|
||||
{
|
||||
desc: "Prebuilt apex prebuilt_com.android.art.v2 is selected, profile should come from .prof deapexed from the prebuilt",
|
||||
selectedArtApexContributions: "art.prebuilt.v2.contributions",
|
||||
expectedProfile: "out/soong/.intermediates/com.android.art.v2.deapexer/android_common/deapexer/etc/boot-image.prof",
|
||||
expectedProfile: "out/soong/.intermediates/prebuilt_com.android.art.v2.deapexer/android_common/deapexer/etc/boot-image.prof",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
|
|
|
@ -87,6 +87,12 @@ type PrebuiltCommonProperties struct {
|
|||
// device (/apex/<apex_name>). If unspecified, follows the name property.
|
||||
Apex_name *string
|
||||
|
||||
// Name of the source APEX that gets shadowed by this prebuilt
|
||||
// e.g. com.mycompany.android.myapex
|
||||
// If unspecified, follows the naming convention that the source apex of
|
||||
// the prebuilt is Name() without "prebuilt_" prefix
|
||||
Source_apex_name *string
|
||||
|
||||
ForceDisable bool `blueprint:"mutated"`
|
||||
|
||||
// whether the extracted apex file is installable.
|
||||
|
@ -126,7 +132,11 @@ func (p *prebuiltCommon) initPrebuiltCommon(module android.Module, properties *P
|
|||
}
|
||||
|
||||
func (p *prebuiltCommon) ApexVariationName() string {
|
||||
return proptools.StringDefault(p.prebuiltCommonProperties.Apex_name, p.ModuleBase.BaseModuleName())
|
||||
return proptools.StringDefault(p.prebuiltCommonProperties.Apex_name, p.BaseModuleName())
|
||||
}
|
||||
|
||||
func (p *prebuiltCommon) BaseModuleName() string {
|
||||
return proptools.StringDefault(p.prebuiltCommonProperties.Source_apex_name, p.ModuleBase.BaseModuleName())
|
||||
}
|
||||
|
||||
func (p *prebuiltCommon) Prebuilt() *android.Prebuilt {
|
||||
|
@ -226,6 +236,7 @@ func (p *prebuiltCommon) AndroidMkEntries() []android.AndroidMkEntries {
|
|||
OutputFile: android.OptionalPathForPath(p.outputApex),
|
||||
Include: "$(BUILD_PREBUILT)",
|
||||
Host_required: p.hostRequired,
|
||||
OverrideName: p.BaseModuleName(),
|
||||
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
|
||||
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
|
||||
entries.SetString("LOCAL_MODULE_PATH", p.installDir.String())
|
||||
|
@ -436,7 +447,7 @@ func (p *prebuiltCommon) apexInfoMutator(mctx android.TopDownMutatorContext) {
|
|||
apexInfo := android.ApexInfo{
|
||||
ApexVariationName: apexVariationName,
|
||||
InApexVariants: []string{apexVariationName},
|
||||
InApexModules: []string{p.ModuleBase.BaseModuleName()}, // BaseModuleName() to avoid the prebuilt_ prefix.
|
||||
InApexModules: []string{p.BaseModuleName()}, // BaseModuleName() to avoid the prebuilt_ prefix.
|
||||
ApexContents: []*android.ApexContents{apexContents},
|
||||
ForPrebuiltApex: true,
|
||||
}
|
||||
|
@ -739,13 +750,11 @@ var _ prebuiltApexModuleCreator = (*Prebuilt)(nil)
|
|||
// V V V
|
||||
// selector <--- deapexer <--- exported java lib
|
||||
func (p *Prebuilt) createPrebuiltApexModules(ctx android.TopDownMutatorContext) {
|
||||
baseModuleName := p.BaseModuleName()
|
||||
|
||||
apexSelectorModuleName := apexSelectorModuleName(baseModuleName)
|
||||
apexSelectorModuleName := apexSelectorModuleName(p.Name())
|
||||
createApexSelectorModule(ctx, apexSelectorModuleName, &p.properties.ApexFileProperties)
|
||||
|
||||
apexFileSource := ":" + apexSelectorModuleName
|
||||
p.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(baseModuleName), apexFileSource)
|
||||
p.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(p.Name()), apexFileSource)
|
||||
|
||||
// Add a source reference to retrieve the selected apex from the selector module.
|
||||
p.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource)
|
||||
|
@ -759,7 +768,7 @@ func (p *prebuiltCommon) DepsMutator(ctx android.BottomUpMutatorContext) {
|
|||
if p.hasExportedDeps() {
|
||||
// Create a dependency from the prebuilt apex (prebuilt_apex/apex_set) to the internal deapexer module
|
||||
// The deapexer will return a provider that will be bubbled up to the rdeps of apexes (e.g. dex_bootjars)
|
||||
ctx.AddDependency(ctx.Module(), android.DeapexerTag, deapexerModuleName(p.BaseModuleName()))
|
||||
ctx.AddDependency(ctx.Module(), android.DeapexerTag, deapexerModuleName(p.Name()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -997,13 +1006,11 @@ var _ prebuiltApexModuleCreator = (*ApexSet)(nil)
|
|||
// from those provided this creates an extractor module which extracts the appropriate .apex file
|
||||
// from the zip file containing them.
|
||||
func (a *ApexSet) createPrebuiltApexModules(ctx android.TopDownMutatorContext) {
|
||||
baseModuleName := a.BaseModuleName()
|
||||
|
||||
apexExtractorModuleName := apexExtractorModuleName(baseModuleName)
|
||||
apexExtractorModuleName := apexExtractorModuleName(a.Name())
|
||||
createApexExtractorModule(ctx, apexExtractorModuleName, &a.properties.ApexExtractorProperties)
|
||||
|
||||
apexFileSource := ":" + apexExtractorModuleName
|
||||
a.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(baseModuleName), apexFileSource)
|
||||
a.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(a.Name()), apexFileSource)
|
||||
|
||||
// After passing the arch specific src properties to the creating the apex selector module
|
||||
a.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource)
|
||||
|
|
|
@ -273,18 +273,18 @@ func TestPrebuiltSystemserverclasspathFragmentContents(t *testing.T) {
|
|||
|
||||
java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{
|
||||
`dex2oatd`,
|
||||
`myapex.apex.selector`,
|
||||
`myapex.deapexer`,
|
||||
`prebuilt_myapex.apex.selector`,
|
||||
`prebuilt_myapex.deapexer`,
|
||||
`prebuilt_mysystemserverclasspathfragment`,
|
||||
})
|
||||
|
||||
java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_myapex", []string{
|
||||
`myapex.deapexer`,
|
||||
`prebuilt_bar`,
|
||||
`prebuilt_foo`,
|
||||
`prebuilt_myapex.deapexer`,
|
||||
})
|
||||
|
||||
ensureExactDeapexedContents(t, ctx, "myapex", "android_common", []string{
|
||||
ensureExactDeapexedContents(t, ctx, "prebuilt_myapex", "android_common", []string{
|
||||
"javalib/foo.jar",
|
||||
"javalib/bar.jar",
|
||||
"javalib/bar.jar.prof",
|
||||
|
@ -430,12 +430,12 @@ func TestPrebuiltStandaloneSystemserverclasspathFragmentContents(t *testing.T) {
|
|||
ctx := result.TestContext
|
||||
|
||||
java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_myapex", []string{
|
||||
`myapex.deapexer`,
|
||||
`prebuilt_bar`,
|
||||
`prebuilt_foo`,
|
||||
`prebuilt_myapex.deapexer`,
|
||||
})
|
||||
|
||||
ensureExactDeapexedContents(t, ctx, "myapex", "android_common", []string{
|
||||
ensureExactDeapexedContents(t, ctx, "prebuilt_myapex", "android_common", []string{
|
||||
"javalib/foo.jar",
|
||||
"javalib/bar.jar",
|
||||
"javalib/bar.jar.prof",
|
||||
|
|
|
@ -206,8 +206,8 @@ java_import {
|
|||
checkBootJarsPackageCheckRule(t, result,
|
||||
append(
|
||||
[]string{
|
||||
"out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/core1.jar",
|
||||
"out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/core2.jar",
|
||||
"out/soong/.intermediates/prebuilts/apex/prebuilt_com.android.art.deapexer/android_common/deapexer/javalib/core1.jar",
|
||||
"out/soong/.intermediates/prebuilts/apex/prebuilt_com.android.art.deapexer/android_common/deapexer/javalib/core2.jar",
|
||||
"out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar",
|
||||
},
|
||||
java.ApexBootJarDexJarPaths...,
|
||||
|
|
Loading…
Reference in a new issue