diff --git a/android/apex_contributions.go b/android/apex_contributions.go index a30964080..236abf663 100644 --- a/android/apex_contributions.go +++ b/android/apex_contributions.go @@ -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 diff --git a/android/prebuilt.go b/android/prebuilt.go index 6a417a8c7..d2b8fa13f 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -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 diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go index 953258edd..4a696283b 100644 --- a/android/prebuilt_test.go +++ b/android/prebuilt_test.go @@ -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", } diff --git a/apex/apex_test.go b/apex/apex_test.go index a943e4e02..72bafe6f0 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -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) + } +} diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go index 2600169a5..b431661ae 100644 --- a/apex/bootclasspath_fragment_test.go +++ b/apex/bootclasspath_fragment_test.go @@ -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, "")) }) } diff --git a/apex/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go index 34ccdd713..d9ab8fa60 100644 --- a/apex/dexpreopt_bootjars_test.go +++ b/apex/dexpreopt_bootjars_test.go @@ -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 { diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 188875ac9..9db3b7a9d 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -87,6 +87,12 @@ type PrebuiltCommonProperties struct { // device (/apex/). 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) diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go index 90fd2caa9..01629c9d2 100644 --- a/apex/systemserver_classpath_fragment_test.go +++ b/apex/systemserver_classpath_fragment_test.go @@ -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", diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go index a89e28e1a..273a5cfc0 100644 --- a/sdk/bootclasspath_fragment_sdk_test.go +++ b/sdk/bootclasspath_fragment_sdk_test.go @@ -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...,