From d8d8b85c5666b3ded986f1b5c64df31dea5076ee Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 20 Dec 2024 16:32:37 -0800 Subject: Move prebuilt mutators earlier Move the prebuilt mutators from postdeps to predeps mutators. This ensures that the decisions on whether the source or prebuilt will be used can be made earlier, which simplifies the apex and dexpreopt code, allowing it to directly depend on the correct module. This requires some mutators that previously ran before the prebuilt mutator and now run after the prebuilt mutator be aware of prebuilts. In particular, the cc.linkageTransitionMutator and rust.libraryTransitionMutator now have to manually disable prebuilts when they don't produce a static or shared variant that the source module produces, and some mutators have to ignore PrebuiltDepTag dependencies when propagating transitions. The apexTransitionMutator also needs to temporarily use an interface on the dependency tag to correctly resolve some dependencies that exist before the apex variation is created onto the correct variation. This will shortly be replaced with depending on the apex itself instead, and then walking the dependencies of the apex to find the necessary module. Bug: 372543712 Test: go test ./... Change-Id: If125ea981be87673bae3bd0a7e3b2c16c337e8f7 --- java/platform_bootclasspath.go | 62 +++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 34 deletions(-) (limited to 'java/platform_bootclasspath.go') diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index 86062d489..3b05b16e3 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -31,12 +31,6 @@ func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContex // The tags used for the dependencies between the platform bootclasspath and any configured boot // jars. -var ( - platformBootclasspathArtBootJarDepTag = bootclasspathDependencyTag{name: "art-boot-jar"} - platformBootclasspathBootJarDepTag = bootclasspathDependencyTag{name: "platform-boot-jar"} - platformBootclasspathApexBootJarDepTag = bootclasspathDependencyTag{name: "apex-boot-jar"} -) - type platformBootclasspathImplLibDepTagType struct { blueprint.BaseDependencyTag } @@ -100,26 +94,12 @@ func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorCon b.hiddenAPIDepsMutator(ctx) - if !dexpreopt.IsDex2oatNeeded(ctx) { - return + if dexpreopt.IsDex2oatNeeded(ctx) { + // Add a dependency onto the dex2oat tool which is needed for creating the boot image. The + // path is retrieved from the dependency by GetGlobalSoongConfig(ctx). + dexpreopt.RegisterToolDeps(ctx) } - // Add a dependency onto the dex2oat tool which is needed for creating the boot image. The - // path is retrieved from the dependency by GetGlobalSoongConfig(ctx). - dexpreopt.RegisterToolDeps(ctx) -} - -func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) { - if ctx.Config().DisableHiddenApiChecks() { - return - } - - // Add dependencies onto the stub lib modules. - apiLevelToStubLibModules := hiddenAPIComputeMonolithicStubLibModules(ctx.Config()) - hiddenAPIAddStubLibDependencies(ctx, apiLevelToStubLibModules) -} - -func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) { // Add dependencies on all the ART jars. global := dexpreopt.GetGlobalConfig(ctx) addDependenciesOntoSelectedBootImageApexes(ctx, "com.android.art") @@ -127,13 +107,13 @@ func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.Botto var bootImageModuleNames []string // TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly - addDependenciesOntoBootImageModules(ctx, global.ArtApexJars, platformBootclasspathArtBootJarDepTag) + addDependenciesOntoBootImageModules(ctx, global.ArtApexJars, artBootJar) bootImageModuleNames = append(bootImageModuleNames, global.ArtApexJars.CopyOfJars()...) // Add dependencies on all the non-updatable jars, which are on the platform or in non-updatable // APEXes. platformJars := b.platformJars(ctx) - addDependenciesOntoBootImageModules(ctx, platformJars, platformBootclasspathBootJarDepTag) + addDependenciesOntoBootImageModules(ctx, platformJars, platformBootJar) bootImageModuleNames = append(bootImageModuleNames, platformJars.CopyOfJars()...) // Add dependencies on all the updatable jars, except the ART jars. @@ -144,7 +124,7 @@ func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.Botto } addDependenciesOntoSelectedBootImageApexes(ctx, android.FirstUniqueStrings(apexes)...) // TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly - addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag) + addDependenciesOntoBootImageModules(ctx, apexJars, apexBootJar) bootImageModuleNames = append(bootImageModuleNames, apexJars.CopyOfJars()...) // Add dependencies on all the fragments. @@ -158,20 +138,30 @@ func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.Botto } } -func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList, tag bootclasspathDependencyTag) { +func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) { + if ctx.Config().DisableHiddenApiChecks() { + return + } + + // Add dependencies onto the stub lib modules. + apiLevelToStubLibModules := hiddenAPIComputeMonolithicStubLibModules(ctx.Config()) + hiddenAPIAddStubLibDependencies(ctx, apiLevelToStubLibModules) +} + +func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList, tagType bootclasspathDependencyTagType) { for i := 0; i < modules.Len(); i++ { apex := modules.Apex(i) name := modules.Jar(i) - addDependencyOntoApexModulePair(ctx, apex, name, tag) + addDependencyOntoApexModulePair(ctx, apex, name, tagType) } } func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Gather all the dependencies from the art, platform, and apex boot jars. - artModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathArtBootJarDepTag) - platformModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathBootJarDepTag) - apexModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathApexBootJarDepTag) + artModules := gatherApexModulePairDepsWithTag(ctx, artBootJar) + platformModules := gatherApexModulePairDepsWithTag(ctx, platformBootJar) + apexModules := gatherApexModulePairDepsWithTag(ctx, apexBootJar) // Concatenate them all, in order as they would appear on the bootclasspath. var allModules []android.Module @@ -199,7 +189,7 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo TransformResourcesToJar(ctx, srcjar, jarArgs, transitiveSrcFiles) // Gather all the fragments dependencies. - b.fragments = gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag) + b.fragments = gatherApexModulePairDepsWithTag(ctx, fragment) // Check the configuration of the boot modules. // ART modules are checked by the art-bootclasspath-fragment. @@ -283,7 +273,11 @@ func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext // modules is complete. if !ctx.Config().AlwaysUsePrebuiltSdks() { // error: this jar is part of the platform - ctx.ModuleErrorf("module %q from platform is not allowed in the apex boot jars list", name) + if ctx.Config().AllowMissingDependencies() { + ctx.AddMissingDependencies([]string{"module_" + name + "_from_platform_is_not_allowed_in_the_apex_boot_jars_list"}) + } else { + ctx.ModuleErrorf("module %q from platform is not allowed in the apex boot jars list", name) + } } } else { // TODO(b/177892522): Treat this as an error. -- cgit v1.2.3-59-g8ed1b From 92b0eb18e199f44ddc26b32ae993d9909f1fd7fa Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 6 Feb 2025 11:49:52 -0800 Subject: Pass libraryToApex and apexNameToFragment mappings into CreateClasspathElements Remove a usage of ApexInfo.InApexVariants by collecting the libraryToApex and apexToFragment mappings while collecting the fragments and passing them into CreateClasspathElements. Bug: 372543712 Test: CreateClasspathElementTest Change-Id: I03adc821b04bc01828f075f25bbb8124505859a7 --- apex/classpath_element_test.go | 46 +++++++++++-------------- java/bootclasspath.go | 77 ++++++++++++++++++++++++++++++++++++++++-- java/bootclasspath_fragment.go | 2 +- java/classpath_element.go | 58 +++++++++++-------------------- java/dexpreopt_bootjars.go | 4 ++- java/platform_bootclasspath.go | 32 ++++++++++++------ 6 files changed, 140 insertions(+), 79 deletions(-) (limited to 'java/platform_bootclasspath.go') diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go index 55f1475f7..c2f2fc5b9 100644 --- a/apex/classpath_element_test.go +++ b/apex/classpath_element_test.go @@ -205,8 +205,6 @@ func TestCreateClasspathElements(t *testing.T) { myFragment := result.Module("mybootclasspath-fragment", "android_common_myapex") myBar := result.Module("bar", "android_common_apex10000") - other := result.Module("othersdklibrary", "android_common_apex10000") - otherApexLibrary := result.Module("otherapexlibrary", "android_common_apex10000") platformFoo := result.Module("quuz", "android_common") @@ -240,7 +238,11 @@ func TestCreateClasspathElements(t *testing.T) { t.Run("art:baz, art:quuz, my:bar, foo", func(t *testing.T) { t.Parallel() ctx := newCtx() - elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, artQuuz, myBar, platformFoo}, []android.Module{artFragment, myFragment}) + elements := java.CreateClasspathElements(ctx, + []android.Module{artBaz, artQuuz, myBar, platformFoo}, + []android.Module{artFragment, myFragment}, + map[android.Module]string{artBaz: "com.android.art", artQuuz: "com.android.art", myBar: "myapex"}, + map[string]android.Module{"com.android.art": artFragment, "myapex": myFragment}) expectedElements := java.ClasspathElements{ expectFragmentElement(artFragment, artBaz, artQuuz), expectFragmentElement(myFragment, myBar), @@ -249,32 +251,16 @@ func TestCreateClasspathElements(t *testing.T) { assertElementsEquals(t, "elements", expectedElements, elements) }) - // Verify that CreateClasspathElements detects when an apex has multiple fragments. - t.Run("multiple fragments for same apex", func(t *testing.T) { - t.Parallel() - ctx := newCtx() - elements := java.CreateClasspathElements(ctx, []android.Module{}, []android.Module{artFragment, artFragment}) - android.FailIfNoMatchingErrors(t, "apex com.android.art has multiple fragments, art-bootclasspath-fragment{.*} and art-bootclasspath-fragment{.*}", ctx.errs) - expectedElements := java.ClasspathElements{} - assertElementsEquals(t, "elements", expectedElements, elements) - }) - - // Verify that CreateClasspathElements detects when a library is in multiple fragments. - t.Run("library from multiple fragments", func(t *testing.T) { - t.Parallel() - ctx := newCtx() - elements := java.CreateClasspathElements(ctx, []android.Module{other}, []android.Module{artFragment, myFragment}) - android.FailIfNoMatchingErrors(t, "library othersdklibrary{.*} is in two separate fragments, art-bootclasspath-fragment{.*} and mybootclasspath-fragment{.*}", ctx.errs) - expectedElements := java.ClasspathElements{} - assertElementsEquals(t, "elements", expectedElements, elements) - }) - // Verify that CreateClasspathElements detects when a fragment's contents are not contiguous and // are separated by a library from another fragment. t.Run("discontiguous separated by fragment", func(t *testing.T) { t.Parallel() ctx := newCtx() - elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, myBar, artQuuz, platformFoo}, []android.Module{artFragment, myFragment}) + elements := java.CreateClasspathElements(ctx, + []android.Module{artBaz, myBar, artQuuz, platformFoo}, + []android.Module{artFragment, myFragment}, + map[android.Module]string{artBaz: "com.android.art", artQuuz: "com.android.art", myBar: "myapex"}, + map[string]android.Module{"com.android.art": artFragment, "myapex": myFragment}) expectedElements := java.ClasspathElements{ expectFragmentElement(artFragment, artBaz, artQuuz), expectFragmentElement(myFragment, myBar), @@ -289,7 +275,11 @@ func TestCreateClasspathElements(t *testing.T) { t.Run("discontiguous separated by library", func(t *testing.T) { t.Parallel() ctx := newCtx() - elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, platformFoo, artQuuz, myBar}, []android.Module{artFragment, myFragment}) + elements := java.CreateClasspathElements(ctx, + []android.Module{artBaz, platformFoo, artQuuz, myBar}, + []android.Module{artFragment, myFragment}, + map[android.Module]string{artBaz: "com.android.art", artQuuz: "com.android.art", myBar: "myapex"}, + map[string]android.Module{"com.android.art": artFragment, "myapex": myFragment}) expectedElements := java.ClasspathElements{ expectFragmentElement(artFragment, artBaz, artQuuz), expectLibraryElement(platformFoo), @@ -305,7 +295,11 @@ func TestCreateClasspathElements(t *testing.T) { t.Run("no fragment for apex", func(t *testing.T) { t.Parallel() ctx := newCtx() - elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, otherApexLibrary}, []android.Module{artFragment}) + elements := java.CreateClasspathElements(ctx, + []android.Module{artBaz, otherApexLibrary}, + []android.Module{artFragment}, + map[android.Module]string{artBaz: "com.android.art", otherApexLibrary: "otherapex"}, + map[string]android.Module{"com.android.art": artFragment}) expectedElements := java.ClasspathElements{ expectFragmentElement(artFragment, artBaz), } diff --git a/java/bootclasspath.go b/java/bootclasspath.go index 5500926e8..98fb417d0 100644 --- a/java/bootclasspath.go +++ b/java/bootclasspath.go @@ -68,10 +68,78 @@ func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex st } +// gatherFragments collects fragments that are direct dependencies of this module, as well as +// any fragments in apexes via the dependency on the apex. It returns a list of the fragment +// modules and map from apex name to the fragment in that apex. +func gatherFragments(ctx android.BaseModuleContext) ([]android.Module, map[string]android.Module) { + var fragments []android.Module + + type fragmentInApex struct { + module string + apex string + } + + var fragmentsInApexes []fragmentInApex + + // Find any direct dependencies, as well as a list of the modules in apexes. + ctx.VisitDirectDeps(func(module android.Module) { + t := ctx.OtherModuleDependencyTag(module) + if bcpTag, ok := t.(bootclasspathDependencyTag); ok && bcpTag.typ == fragment { + if bcpTag.moduleInApex != "" { + fragmentsInApexes = append(fragmentsInApexes, fragmentInApex{bcpTag.moduleInApex, ctx.OtherModuleName(module)}) + } else { + fragments = append(fragments, module) + } + } + }) + + fragmentsMap := make(map[string]android.Module) + for _, fragmentInApex := range fragmentsInApexes { + var found android.Module + // Find a desired module in an apex. + ctx.WalkDeps(func(child, parent android.Module) bool { + t := ctx.OtherModuleDependencyTag(child) + if parent == ctx.Module() { + if bcpTag, ok := t.(bootclasspathDependencyTag); ok && bcpTag.typ == fragment && ctx.OtherModuleName(child) == fragmentInApex.apex { + // This is the dependency from this module to the apex, recurse into it. + return true + } + } else if android.IsDontReplaceSourceWithPrebuiltTag(t) { + return false + } else if t == android.PrebuiltDepTag { + return false + } else if IsBootclasspathFragmentContentDepTag(t) { + return false + } else if android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child)) == fragmentInApex.module { + // This is the desired module inside the apex. + if found != nil && child != found { + panic(fmt.Errorf("found two conflicting modules %q in apex %q: %s and %s", + fragmentInApex.module, fragmentInApex.apex, found, child)) + } + found = child + } + return false + }) + if found != nil { + if existing, exists := fragmentsMap[fragmentInApex.apex]; exists { + ctx.ModuleErrorf("apex %s has multiple fragments, %s and %s", fragmentInApex.apex, fragmentInApex.module, existing) + } else { + fragmentsMap[fragmentInApex.apex] = found + fragments = append(fragments, found) + } + } else if !ctx.Config().AllowMissingDependencies() { + ctx.ModuleErrorf("failed to find fragment %q in apex %q\n", + fragmentInApex.module, fragmentInApex.apex) + } + } + return fragments, fragmentsMap +} + // gatherApexModulePairDepsWithTag returns the list of dependencies with the supplied tag that was // added by addDependencyOntoApexModulePair. -func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tagType bootclasspathDependencyTagType) []android.Module { +func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tagType bootclasspathDependencyTagType) ([]android.Module, map[android.Module]string) { var modules []android.Module + modulesToApex := make(map[android.Module]string) type moduleInApex struct { module string @@ -119,12 +187,17 @@ func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tagType boot }) if found != nil { modules = append(modules, found) + if existing, exists := modulesToApex[found]; exists && existing != moduleInApex.apex { + ctx.ModuleErrorf("module %s is in two apexes, %s and %s", moduleInApex.module, existing, moduleInApex.apex) + } else { + modulesToApex[found] = moduleInApex.apex + } } else if !ctx.Config().AllowMissingDependencies() { ctx.ModuleErrorf("failed to find module %q in apex %q\n", moduleInApex.module, moduleInApex.apex) } } - return modules + return modules, modulesToApex } // ApexVariantReference specifies a particular apex variant of a module. diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index f3bff12f2..fd4b0a305 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -513,7 +513,7 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo } }) - fragments := gatherApexModulePairDepsWithTag(ctx, fragment) + fragments, _ := gatherFragments(ctx) // Perform hidden API processing. hiddenAPIOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments) diff --git a/java/classpath_element.go b/java/classpath_element.go index abbcae7a3..4af277012 100644 --- a/java/classpath_element.go +++ b/java/classpath_element.go @@ -108,33 +108,18 @@ type ClasspathElementContext interface { // // e.g. Given the following input: // -// libraries: com.android.art:core-oj, com.android.art:core-libart, framework, ext -// fragments: com.android.art:art-bootclasspath-fragment +// libraries: core-oj, core-libart, framework, ext +// fragments: art-bootclasspath-fragment +// libraryToApex: core-oj: com.android.art, core-libart: com.android.art +// apexNameToFragment: com.android.art: art-bootclasspath-fragment // // Then this will return: // // ClasspathFragmentElement(art-bootclasspath-fragment, [core-oj, core-libart]), // ClasspathLibraryElement(framework), // ClasspathLibraryElement(ext), -func CreateClasspathElements(ctx ClasspathElementContext, libraries []android.Module, fragments []android.Module) ClasspathElements { - // Create a map from apex name to the fragment module. This makes it easy to find the fragment - // associated with a particular apex. - apexToFragment := map[string]android.Module{} - for _, fragment := range fragments { - apexInfo, ok := android.OtherModuleProvider(ctx, fragment, android.ApexInfoProvider) - if !ok { - ctx.ModuleErrorf("fragment %s is not part of an apex", fragment) - continue - } - - for _, apex := range apexInfo.InApexVariants { - if existing, ok := apexToFragment[apex]; ok { - ctx.ModuleErrorf("apex %s has multiple fragments, %s and %s", apex, fragment, existing) - continue - } - apexToFragment[apex] = fragment - } - } +func CreateClasspathElements(ctx ClasspathElementContext, libraries []android.Module, fragments []android.Module, + libraryToApex map[android.Module]string, apexNameToFragment map[string]android.Module) ClasspathElements { fragmentToElement := map[android.Module]*ClasspathFragmentElement{} elements := []ClasspathElement{} @@ -144,31 +129,28 @@ skipLibrary: // Iterate over the libraries to construct the ClasspathElements list. for _, library := range libraries { var element ClasspathElement - if apexInfo, ok := android.OtherModuleProvider(ctx, library, android.ApexInfoProvider); ok { - + if libraryApex, ok := libraryToApex[library]; ok { var fragment android.Module // Make sure that the library is in only one fragment of the classpath. - for _, apex := range apexInfo.InApexVariants { - if f, ok := apexToFragment[apex]; ok { - if fragment == nil { - // This is the first fragment so just save it away. - fragment = f - } else if f != fragment { - // This apex variant of the library is in a different fragment. - ctx.ModuleErrorf("library %s is in two separate fragments, %s and %s", library, fragment, f) - // Skip over this library entirely as otherwise the resulting classpath elements would - // be invalid. - continue skipLibrary - } - } else { - // There is no fragment associated with the library's apex. + if f, ok := apexNameToFragment[libraryApex]; ok { + if fragment == nil { + // This is the first fragment so just save it away. + fragment = f + } else if f != fragment { + // This apex variant of the library is in a different fragment. + ctx.ModuleErrorf("library %s is in two separate fragments, %s and %s", library, fragment, f) + // Skip over this library entirely as otherwise the resulting classpath elements would + // be invalid. + continue skipLibrary } + } else { + // There is no fragment associated with the library's apex. } if fragment == nil { ctx.ModuleErrorf("library %s is from apexes %s which have no corresponding fragment in %s", - library, apexInfo.InApexVariants, fragments) + library, []string{libraryApex}, fragments) // Skip over this library entirely as otherwise the resulting classpath elements would // be invalid. continue skipLibrary diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 24bb99d7f..27027f07d 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -734,7 +734,8 @@ func getModulesForImage(ctx android.ModuleContext, imageConfig *bootImageConfig) modules := make([]apexJarModulePair, 0, imageConfig.modules.Len()) for i := 0; i < imageConfig.modules.Len(); i++ { found := false - for _, module := range gatherApexModulePairDepsWithTag(ctx, dexpreoptBootJar) { + dexpreoptBootJarModules, _ := gatherApexModulePairDepsWithTag(ctx, dexpreoptBootJar) + for _, module := range dexpreoptBootJarModules { name := android.RemoveOptionalPrebuiltPrefix(module.Name()) if name == imageConfig.modules.Jar(i) { modules = append(modules, apexJarModulePair{ @@ -817,6 +818,7 @@ func getDexJarForApex(ctx android.ModuleContext, pair apexJarModulePair, apexNam "APEX '%[2]s' doesn't exist or is not added as a dependency of dex_bootjars", pair.jarModule.Name(), pair.apex) + return nil } bootclasspathFragmentInfo, _ := android.OtherModuleProvider(ctx, fragment, BootclasspathFragmentApexContentInfoProvider) jar, err := bootclasspathFragmentInfo.DexBootJarPathForContentModule(pair.jarModule) diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index 3b05b16e3..39b54e3e8 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -15,6 +15,9 @@ package java import ( + "maps" + "slices" + "github.com/google/blueprint" "android/soong/android" @@ -53,6 +56,12 @@ type platformBootclasspathModule struct { // The apex:module pairs obtained from the fragments. fragments []android.Module + // The map of apex to the fragments they contain. + apexNameToFragment map[string]android.Module + + // The map of library modules in the bootclasspath to the fragments that contain them. + libraryToApex map[android.Module]string + // Path to the monolithic hiddenapi-flags.csv file. hiddenAPIFlagsCSV android.OutputPath @@ -159,16 +168,16 @@ func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, mod func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Gather all the dependencies from the art, platform, and apex boot jars. - artModules := gatherApexModulePairDepsWithTag(ctx, artBootJar) - platformModules := gatherApexModulePairDepsWithTag(ctx, platformBootJar) - apexModules := gatherApexModulePairDepsWithTag(ctx, apexBootJar) + artModules, artModulesToApex := gatherApexModulePairDepsWithTag(ctx, artBootJar) + platformModules, platformModulesToApex := gatherApexModulePairDepsWithTag(ctx, platformBootJar) + apexModules, apexModulesToApex := gatherApexModulePairDepsWithTag(ctx, apexBootJar) // Concatenate them all, in order as they would appear on the bootclasspath. - var allModules []android.Module - allModules = append(allModules, artModules...) - allModules = append(allModules, platformModules...) - allModules = append(allModules, apexModules...) + allModules := slices.Concat(artModules, platformModules, apexModules) b.configuredModules = allModules + b.libraryToApex = maps.Clone(artModulesToApex) + maps.Copy(b.libraryToApex, platformModulesToApex) + maps.Copy(b.libraryToApex, apexModulesToApex) // Do not add implLibModule to allModules as the impl lib is only used to collect the // transitive source files @@ -189,7 +198,7 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo TransformResourcesToJar(ctx, srcjar, jarArgs, transitiveSrcFiles) // Gather all the fragments dependencies. - b.fragments = gatherApexModulePairDepsWithTag(ctx, fragment) + b.fragments, b.apexNameToFragment = gatherFragments(ctx) // Check the configuration of the boot modules. // ART modules are checked by the art-bootclasspath-fragment. @@ -198,7 +207,7 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo b.generateClasspathProtoBuildActions(ctx) - bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments) + bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments, b.libraryToApex, b.apexNameToFragment) buildRuleForBootJarsPackageCheck(ctx, bootDexJarByModule) ctx.SetOutputFiles(android.Paths{b.hiddenAPIFlagsCSV}, "hiddenapi-flags.csv") @@ -289,7 +298,8 @@ func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext } // generateHiddenAPIBuildActions generates all the hidden API related build rules. -func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, fragments []android.Module) bootDexJarByModule { +func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, + fragments []android.Module, libraryToApex map[android.Module]string, apexNameToFragment map[string]android.Module) bootDexJarByModule { createEmptyHiddenApiFiles := func() { paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV} for _, path := range paths { @@ -316,7 +326,7 @@ func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android. } // Construct a list of ClasspathElement objects from the modules and fragments. - classpathElements := CreateClasspathElements(ctx, modules, fragments) + classpathElements := CreateClasspathElements(ctx, modules, fragments, libraryToApex, apexNameToFragment) monolithicInfo := b.createAndProvideMonolithicHiddenAPIInfo(ctx, classpathElements) -- cgit v1.2.3-59-g8ed1b From 1cea5308a7915665d8d3480021ca2da00f5206eb Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Tue, 3 Dec 2024 16:40:08 -0800 Subject: Convert android.TransitionMutator to TransitionInfo Use the ApexInfo instead of a string as the TransitionInfo for apex variations. This removes the need for apexInfoMutator, which is the last remaining top down mutator. This has a variety of ramifications. One is that it is no longer possible to add a dependency onto the apex variation of a module, as that would require constructing a matching ApexInfo. Instead, anything that wants to add a dependency on the apex variation has to depend on the apex instead, and get to the module by walking its transistive dependencies. Another ramification is that modules in apexes can no longer determine which apexes they are in (unless they set UniqueApexVariations so that each variation is in exactly one apex). This prevents some of the existing container violation checks from working after this CL, tracked in b/394955484. It also requires using unique variation names for the prebuilt and source dependencies of apexes, so the apex variations for dependencies of prebuilts now have a prebuilt_ prefix. Bug: 372543712 Bug: 394955484 Test: go test ./... Change-Id: I3d08aca1ac956ab0e343ec3f235a736cd93be0e1 --- android/Android.bp | 1 - android/apex.go | 315 +++++++++------------------ android/apex_test.go | 277 ----------------------- android/api_levels.go | 6 +- android/container.go | 14 +- android/deapexer.go | 2 - apex/apex.go | 168 +++++--------- apex/apex_test.go | 94 +++----- apex/bootclasspath_fragment_test.go | 7 +- apex/builder.go | 2 +- apex/container_test.go | 3 + apex/dexpreopt_bootjars_test.go | 6 +- apex/platform_bootclasspath_test.go | 32 +-- apex/prebuilt.go | 121 ++++------ apex/systemserver_classpath_fragment_test.go | 12 +- cc/cc.go | 4 +- java/bootclasspath_fragment.go | 12 + java/dexpreopt.go | 3 - java/hiddenapi_singleton.go | 4 +- java/java.go | 1 - java/platform_bootclasspath.go | 2 +- java/systemserver_classpath_fragment.go | 1 + java/testing.go | 53 ++++- rust/rust.go | 3 + sdk/bootclasspath_fragment_sdk_test.go | 5 +- sdk/testing.go | 7 +- 26 files changed, 344 insertions(+), 811 deletions(-) delete mode 100644 android/apex_test.go (limited to 'java/platform_bootclasspath.go') diff --git a/android/Android.bp b/android/Android.bp index d27a8facf..babc91341 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -125,7 +125,6 @@ bootstrap_go_package { "all_teams_test.go", "android_test.go", "androidmk_test.go", - "apex_test.go", "arch_test.go", "blueprint_e2e_test.go", "build_prop_test.go", diff --git a/android/apex.go b/android/apex.go index 4917149dd..68d0ce8a2 100644 --- a/android/apex.go +++ b/android/apex.go @@ -17,7 +17,6 @@ package android import ( "fmt" "slices" - "sort" "strconv" "strings" "sync" @@ -55,18 +54,30 @@ type ApexInfo struct { // to true. UsePlatformApis bool - // List of Apex variant names that this module is associated with. This initially is the - // same as the `ApexVariationName` field. Then when multiple apex variants are merged in - // mergeApexVariations, ApexInfo struct of the merged variant holds the list of apexBundles - // that are merged together. - InApexVariants []string - // True if this is for a prebuilt_apex. // // If true then this will customize the apex processing to make it suitable for handling // prebuilt_apex, e.g. it will prevent ApexInfos from being merged together. // - // See Prebuilt.ApexInfoMutator for more information. + // Unlike the source apex module type the prebuilt_apex module type cannot share compatible variants + // across prebuilt_apex modules. That is because there is no way to determine whether two + // prebuilt_apex modules that export files for the same module are compatible. e.g. they could have + // been built from different source at different times or they could have been built with different + // build options that affect the libraries. + // + // While it may be possible to provide sufficient information to determine whether two prebuilt_apex + // modules were compatible it would be a lot of work and would not provide much benefit for a couple + // of reasons: + // - The number of prebuilt_apex modules that will be exporting files for the same module will be + // low as the prebuilt_apex only exports files for the direct dependencies that require it and + // very few modules are direct dependencies of multiple prebuilt_apex modules, e.g. there are a + // few com.android.art* apex files that contain the same contents and could export files for the + // same modules but only one of them needs to do so. Contrast that with source apex modules which + // need apex specific variants for every module that contributes code to the apex, whether direct + // or indirect. + // - The build cost of a prebuilt_apex variant is generally low as at worst it will involve some + // extra copying of files. Contrast that with source apex modules that has to build each variant + // from source. ForPrebuiltApex bool // Returns the name of the overridden apex (com.android.foo) @@ -74,24 +85,36 @@ type ApexInfo struct { // Returns the value of `apex_available_name` ApexAvailableName string +} - // Returns the apex names that this module is available for - ApexAvailableFor []string +func (a ApexInfo) Variation() string { + return a.ApexVariationName } -// AllApexInfo holds the ApexInfo of all apexes that include this module. -type AllApexInfo struct { - ApexInfos []ApexInfo +// Minimize is called during a transition from a module with a unique variation per apex to a module that should +// share variations between apexes. It returns a minimized ApexInfo that removes any apex names and replaces +// the variation name with one computed from the remaining properties. +func (a ApexInfo) Minimize() ApexInfo { + info := ApexInfo{ + MinSdkVersion: a.MinSdkVersion, + UsePlatformApis: a.UsePlatformApis, + } + info.ApexVariationName = info.mergedName() + return info +} + +type ApexAvailableInfo struct { + // Returns the apex names that this module is available for + ApexAvailableFor []string } var ApexInfoProvider = blueprint.NewMutatorProvider[ApexInfo]("apex_mutate") -var AllApexInfoProvider = blueprint.NewMutatorProvider[*AllApexInfo]("apex_info") +var ApexAvailableInfoProvider = blueprint.NewMutatorProvider[ApexAvailableInfo]("apex_mutate") func (i ApexInfo) AddJSONData(d *map[string]interface{}) { (*d)["Apex"] = map[string]interface{}{ "ApexVariationName": i.ApexVariationName, "MinSdkVersion": i.MinSdkVersion, - "InApexVariants": i.InApexVariants, "ForPrebuiltApex": i.ForPrebuiltApex, } } @@ -117,32 +140,20 @@ func (i ApexInfo) IsForPlatform() bool { return i.ApexVariationName == "" } -// InApexVariant tells whether this apex variant of the module is part of the given apexVariant or -// not. -func (i ApexInfo) InApexVariant(apexVariant string) bool { - for _, a := range i.InApexVariants { - if a == apexVariant { - return true - } - } - return false -} - // To satisfy the comparable interface func (i ApexInfo) Equal(other any) bool { otherApexInfo, ok := other.(ApexInfo) return ok && i.ApexVariationName == otherApexInfo.ApexVariationName && i.MinSdkVersion == otherApexInfo.MinSdkVersion && i.Updatable == otherApexInfo.Updatable && - i.UsePlatformApis == otherApexInfo.UsePlatformApis && - slices.Equal(i.InApexVariants, otherApexInfo.InApexVariants) + i.UsePlatformApis == otherApexInfo.UsePlatformApis } // ApexBundleInfo contains information about the dependencies of an apex type ApexBundleInfo struct { } -var ApexBundleInfoProvider = blueprint.NewMutatorProvider[ApexBundleInfo]("apex_info") +var ApexBundleInfoProvider = blueprint.NewMutatorProvider[ApexBundleInfo]("apex_mutate") // DepIsInSameApex defines an interface that should be used to determine whether a given dependency // should be considered as part of the same APEX as the current module or not. Note: this was @@ -315,6 +326,61 @@ type ApexModuleBase struct { apexInfosLock sync.Mutex // protects apexInfos during parallel apexInfoMutator } +func (m *ApexModuleBase) ApexTransitionMutatorSplit(ctx BaseModuleContext) []ApexInfo { + return []ApexInfo{{}} +} + +func (m *ApexModuleBase) ApexTransitionMutatorOutgoing(ctx OutgoingTransitionContext, info ApexInfo) ApexInfo { + if !ctx.Module().(DepIsInSameApex).OutgoingDepIsInSameApex(ctx.DepTag()) { + return ApexInfo{} + } + return info +} + +func (m *ApexModuleBase) ApexTransitionMutatorIncoming(ctx IncomingTransitionContext, info ApexInfo) ApexInfo { + module := ctx.Module().(ApexModule) + if !module.CanHaveApexVariants() { + return ApexInfo{} + } + + if !ctx.Module().(DepIsInSameApex).IncomingDepIsInSameApex(ctx.DepTag()) { + return ApexInfo{} + } + + if info.ApexVariationName == "" { + return ApexInfo{} + } + + if !ctx.Module().(ApexModule).UniqueApexVariations() && !m.ApexProperties.UniqueApexVariationsForDeps && !info.ForPrebuiltApex { + return info.Minimize() + } + return info +} + +func (m *ApexModuleBase) ApexTransitionMutatorMutate(ctx BottomUpMutatorContext, info ApexInfo) { + SetProvider(ctx, ApexInfoProvider, info) + + module := ctx.Module().(ApexModule) + base := module.apexModuleBase() + + platformVariation := info.ApexVariationName == "" + if !platformVariation { + // Do some validity checks. + // TODO(jiyong): is this the right place? + base.checkApexAvailableProperty(ctx) + + SetProvider(ctx, ApexAvailableInfoProvider, ApexAvailableInfo{ + ApexAvailableFor: module.ApexAvailableFor(), + }) + } + if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) && module.NotAvailableForPlatform() { + // Do not install the module for platform, but still allow it to output + // uninstallable AndroidMk entries in certain cases when they have side + // effects. TODO(jiyong): move this routine to somewhere else + module.MakeUninstallable() + } +} + // Initializes ApexModuleBase struct. Not calling this (even when inheriting from ApexModuleBase) // prevents the module from being mutated for apexBundle. func InitApexModule(m ApexModule) { @@ -514,195 +580,14 @@ func AvailableToSameApexes(mod1, mod2 ApexModule) bool { return true } -// mergeApexVariations deduplicates apex variations that would build identically into a common -// variation. It returns the reduced list of variations and a list of aliases from the original -// variation names to the new variation names. -func mergeApexVariations(apexInfos []ApexInfo) (merged []ApexInfo, aliases [][2]string) { - seen := make(map[string]int) - for _, apexInfo := range apexInfos { - // If this is for a prebuilt apex then use the actual name of the apex variation to prevent this - // from being merged with other ApexInfo. See Prebuilt.ApexInfoMutator for more information. - if apexInfo.ForPrebuiltApex { - merged = append(merged, apexInfo) - continue - } - - // Merge the ApexInfo together. If a compatible ApexInfo exists then merge the information from - // this one into it, otherwise create a new merged ApexInfo from this one and save it away so - // other ApexInfo instances can be merged into it. - variantName := apexInfo.ApexVariationName - mergedName := apexInfo.mergedName() - if index, exists := seen[mergedName]; exists { - // Variants having the same mergedName are deduped - merged[index].InApexVariants = append(merged[index].InApexVariants, variantName) - merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable - // Platform APIs is allowed for this module only when all APEXes containing - // the module are with `use_platform_apis: true`. - merged[index].UsePlatformApis = merged[index].UsePlatformApis && apexInfo.UsePlatformApis - } else { - seen[mergedName] = len(merged) - apexInfo.ApexVariationName = mergedName - apexInfo.InApexVariants = CopyOf(apexInfo.InApexVariants) - merged = append(merged, apexInfo) - } - aliases = append(aliases, [2]string{variantName, mergedName}) - } - return merged, aliases -} - -// IncomingApexTransition is called by apexTransitionMutator.IncomingTransition on modules that can be in apexes. -// The incomingVariation can be either the name of an apex if the dependency is coming directly from an apex -// module, or it can be the name of an apex variation (e.g. apex10000) if it is coming from another module that -// is in the apex. -func IncomingApexTransition(ctx IncomingTransitionContext, incomingVariation string) string { - module := ctx.Module().(ApexModule) - base := module.apexModuleBase() - - var apexInfos []ApexInfo - if allApexInfos, ok := ModuleProvider(ctx, AllApexInfoProvider); ok { - apexInfos = allApexInfos.ApexInfos - } - - // Dependencies from platform variations go to the platform variation. - if incomingVariation == "" { - return "" - } - - if len(apexInfos) == 0 { - if ctx.IsAddingDependency() { - // If this module has no apex variations we can't do any mapping on the incoming variation, just return it - // and let the caller get a "missing variant" error. - return incomingVariation - } else { - // If this module has no apex variations the use the platform variation. - return "" - } - } - - // Convert the list of apex infos into from the AllApexInfoProvider into the merged list - // of apex variations and the aliases from apex names to apex variations. - var aliases [][2]string - if !module.UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps { - apexInfos, aliases = mergeApexVariations(apexInfos) - } - - // Check if the incoming variation matches an apex name, and if so use the corresponding - // apex variation. - aliasIndex := slices.IndexFunc(aliases, func(alias [2]string) bool { - return alias[0] == incomingVariation - }) - if aliasIndex >= 0 { - return aliases[aliasIndex][1] - } - - // Check if the incoming variation matches an apex variation. - apexIndex := slices.IndexFunc(apexInfos, func(info ApexInfo) bool { - return info.ApexVariationName == incomingVariation - }) - if apexIndex >= 0 { - return incomingVariation - } - - return "" -} - -func MutateApexTransition(ctx BaseModuleContext, variation string) { - module := ctx.Module().(ApexModule) - base := module.apexModuleBase() - platformVariation := variation == "" - - var apexInfos []ApexInfo - if allApexInfos, ok := ModuleProvider(ctx, AllApexInfoProvider); ok { - apexInfos = allApexInfos.ApexInfos - } - - if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) && module.NotAvailableForPlatform() { - // Do not install the module for platform, but still allow it to output - // uninstallable AndroidMk entries in certain cases when they have side - // effects. TODO(jiyong): move this routine to somewhere else - module.MakeUninstallable() - } - - // Do some validity checks. - // TODO(jiyong): is this the right place? - base.checkApexAvailableProperty(ctx) - - // Shortcut - if len(apexInfos) == 0 { - return - } - - if !module.UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps { - apexInfos, _ = mergeApexVariations(apexInfos) - } - - if !platformVariation { - var thisApexInfo ApexInfo - - apexIndex := slices.IndexFunc(apexInfos, func(info ApexInfo) bool { - return info.ApexVariationName == variation - }) - if apexIndex >= 0 { - thisApexInfo = apexInfos[apexIndex] - } else { - panic(fmt.Errorf("failed to find apexInfo for incoming variation %q", variation)) - } - thisApexInfo.ApexAvailableFor = module.ApexAvailableFor() - - SetProvider(ctx, ApexInfoProvider, thisApexInfo) - } -} - -func ApexInfoMutator(ctx TopDownMutatorContext, module ApexModule) { - base := module.apexModuleBase() - if len(base.apexInfos) > 0 { - apexInfos := slices.Clone(base.apexInfos) - slices.SortFunc(apexInfos, func(a, b ApexInfo) int { - return strings.Compare(a.ApexVariationName, b.ApexVariationName) - }) - SetProvider(ctx, AllApexInfoProvider, &AllApexInfo{apexInfos}) - // base.apexInfos is only needed to propagate the list of apexes from the apex module to its - // contents within apexInfoMutator. Clear it so it doesn't accidentally get used later. - base.apexInfos = nil - } -} - // UpdateUniqueApexVariationsForDeps sets UniqueApexVariationsForDeps if any dependencies that are // in the same APEX have unique APEX variations so that the module can link against the right // variant. func UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext, am ApexModule) { - // anyInSameApex returns true if the two ApexInfo lists contain any values in an - // InApexVariants list in common. It is used instead of OutgoingDepIsInSameApex because it needs to - // determine if the dep is in the same APEX due to being directly included, not only if it - // is included _because_ it is a dependency. - anyInSameApex := func(a, b ApexModule) bool { - collectApexes := func(m ApexModule) []string { - if allApexInfo, ok := OtherModuleProvider(mctx, m, AllApexInfoProvider); ok { - var ret []string - for _, info := range allApexInfo.ApexInfos { - ret = append(ret, info.InApexVariants...) - } - return ret - } - return nil - } - - aApexes := collectApexes(a) - bApexes := collectApexes(b) - sort.Strings(bApexes) - for _, aApex := range aApexes { - index := sort.SearchStrings(bApexes, aApex) - if index < len(bApexes) && bApexes[index] == aApex { - return true - } - } - return false - } - // If any of the dependencies requires unique apex variations, so does this module. mctx.VisitDirectDeps(func(dep Module) { if depApexModule, ok := dep.(ApexModule); ok { - if anyInSameApex(depApexModule, am) && + if IsDepInSameApex(mctx, am, depApexModule) && (depApexModule.UniqueApexVariations() || depApexModule.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps) { am.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps = true @@ -849,8 +734,14 @@ func CheckMinSdkVersion(ctx ModuleContext, minSdkVersion ApiLevel, walk WalkPayl }) } +type MinSdkVersionFromValueContext interface { + Config() Config + DeviceConfig() DeviceConfig + ModuleErrorContext +} + // Construct ApiLevel object from min_sdk_version string value -func MinSdkVersionFromValue(ctx EarlyModuleContext, value string) ApiLevel { +func MinSdkVersionFromValue(ctx MinSdkVersionFromValueContext, value string) ApiLevel { if value == "" { return NoneApiLevel } diff --git a/android/apex_test.go b/android/apex_test.go deleted file mode 100644 index acc195de2..000000000 --- a/android/apex_test.go +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package android - -import ( - "reflect" - "testing" -) - -func Test_mergeApexVariations(t *testing.T) { - const ( - ForPrebuiltApex = true - NotForPrebuiltApex = false - ) - tests := []struct { - name string - in []ApexInfo - wantMerged []ApexInfo - wantAliases [][2]string - }{ - { - name: "single", - in: []ApexInfo{ - { - ApexVariationName: "foo", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantMerged: []ApexInfo{ - { - ApexVariationName: "apex10000", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantAliases: [][2]string{ - {"foo", "apex10000"}, - }, - }, - { - name: "merge", - in: []ApexInfo{ - { - ApexVariationName: "foo", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "bar", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantMerged: []ApexInfo{ - { - ApexVariationName: "apex10000", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo", "bar"}, - }}, - wantAliases: [][2]string{ - {"foo", "apex10000"}, - {"bar", "apex10000"}, - }, - }, - { - name: "don't merge version", - in: []ApexInfo{ - { - ApexVariationName: "foo", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "bar", - MinSdkVersion: uncheckedFinalApiLevel(30), - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantMerged: []ApexInfo{ - { - ApexVariationName: "apex10000", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "apex30", - MinSdkVersion: uncheckedFinalApiLevel(30), - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantAliases: [][2]string{ - {"foo", "apex10000"}, - {"bar", "apex30"}, - }, - }, - { - name: "merge updatable", - in: []ApexInfo{ - { - ApexVariationName: "foo", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "bar", - MinSdkVersion: FutureApiLevel, - Updatable: true, - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantMerged: []ApexInfo{ - { - ApexVariationName: "apex10000", - MinSdkVersion: FutureApiLevel, - Updatable: true, - InApexVariants: []string{"foo", "bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantAliases: [][2]string{ - {"foo", "apex10000"}, - {"bar", "apex10000"}, - }, - }, - { - name: "don't merge when for prebuilt_apex", - in: []ApexInfo{ - { - ApexVariationName: "foo", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "bar", - MinSdkVersion: FutureApiLevel, - Updatable: true, - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - // This one should not be merged in with the others because it is for - // a prebuilt_apex. - { - ApexVariationName: "baz", - MinSdkVersion: FutureApiLevel, - Updatable: true, - InApexVariants: []string{"baz"}, - ForPrebuiltApex: ForPrebuiltApex, - }, - }, - wantMerged: []ApexInfo{ - { - ApexVariationName: "apex10000", - MinSdkVersion: FutureApiLevel, - Updatable: true, - InApexVariants: []string{"foo", "bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "baz", - MinSdkVersion: FutureApiLevel, - Updatable: true, - InApexVariants: []string{"baz"}, - ForPrebuiltApex: ForPrebuiltApex, - }, - }, - wantAliases: [][2]string{ - {"foo", "apex10000"}, - {"bar", "apex10000"}, - }, - }, - { - name: "don't merge different UsePlatformApis", - in: []ApexInfo{ - { - ApexVariationName: "foo", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "bar", - MinSdkVersion: FutureApiLevel, - UsePlatformApis: true, - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantMerged: []ApexInfo{ - { - ApexVariationName: "apex10000", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "apex10000_p", - MinSdkVersion: FutureApiLevel, - UsePlatformApis: true, - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantAliases: [][2]string{ - {"foo", "apex10000"}, - {"bar", "apex10000_p"}, - }, - }, - { - name: "merge same UsePlatformApis and allow using platform api", - in: []ApexInfo{ - { - ApexVariationName: "foo", - MinSdkVersion: FutureApiLevel, - UsePlatformApis: true, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "bar", - MinSdkVersion: FutureApiLevel, - UsePlatformApis: true, - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantMerged: []ApexInfo{ - { - ApexVariationName: "apex10000_p", - MinSdkVersion: FutureApiLevel, - UsePlatformApis: true, - InApexVariants: []string{"foo", "bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantAliases: [][2]string{ - {"foo", "apex10000_p"}, - {"bar", "apex10000_p"}, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotMerged, gotAliases := mergeApexVariations(tt.in) - if !reflect.DeepEqual(gotMerged, tt.wantMerged) { - t.Errorf("mergeApexVariations() gotMerged = %v, want %v", gotMerged, tt.wantMerged) - } - if !reflect.DeepEqual(gotAliases, tt.wantAliases) { - t.Errorf("mergeApexVariations() gotAliases = %v, want %v", gotAliases, tt.wantAliases) - } - }) - } -} diff --git a/android/api_levels.go b/android/api_levels.go index 2b1d01d8b..b4fa251bc 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -311,7 +311,7 @@ func ReplaceFinalizedCodenames(config Config, raw string) (string, error) { // ApiLevelFrom converts the given string `raw` to an ApiLevel. // If `raw` is invalid (empty string, unrecognized codename etc.) it returns an invalid ApiLevel -func ApiLevelFrom(ctx PathContext, raw string) ApiLevel { +func ApiLevelFrom(ctx ConfigContext, raw string) ApiLevel { ret, err := ApiLevelFromUser(ctx, raw) if err != nil { return NewInvalidApiLevel(raw) @@ -333,7 +333,7 @@ func ApiLevelFrom(ctx PathContext, raw string) ApiLevel { // // Inputs that are not "current", known previews, or convertible to an integer // will return an error. -func ApiLevelFromUser(ctx PathContext, raw string) (ApiLevel, error) { +func ApiLevelFromUser(ctx ConfigContext, raw string) (ApiLevel, error) { return ApiLevelFromUserWithConfig(ctx.Config(), raw) } @@ -413,7 +413,7 @@ func ApiLevelForTest(raw string) ApiLevel { // Converts an API level string `raw` into an ApiLevel in the same method as // `ApiLevelFromUser`, but the input is assumed to have no errors and any errors // will panic instead of returning an error. -func ApiLevelOrPanic(ctx PathContext, raw string) ApiLevel { +func ApiLevelOrPanic(ctx ConfigContext, raw string) ApiLevel { value, err := ApiLevelFromUser(ctx, raw) if err != nil { panic(err.Error()) diff --git a/android/container.go b/android/container.go index eb2fc1874..5dc97d38e 100644 --- a/android/container.go +++ b/android/container.go @@ -167,8 +167,8 @@ var productContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext } var apexContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool { - _, ok := ModuleProvider(mctx, AllApexInfoProvider) - return ok + // TODO(b/394955484): a module can't determine the apexes it belongs to any more + return false } var ctsContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool { @@ -380,7 +380,7 @@ func (c *ContainersInfo) BelongingContainers() []*container { func (c *ContainersInfo) ApexNames() (ret []string) { for _, apex := range c.belongingApexes { - ret = append(ret, apex.InApexVariants...) + ret = append(ret, apex.BaseApexName) } slices.Sort(ret) return ret @@ -441,14 +441,10 @@ func generateContainerInfo(ctx ModuleContext) ContainersInfo { } } - var belongingApexes []ApexInfo - if apexInfo, ok := ModuleProvider(ctx, AllApexInfoProvider); ok { - belongingApexes = apexInfo.ApexInfos - } - return ContainersInfo{ belongingContainers: containers, - belongingApexes: belongingApexes, + // TODO(b/394955484): a module can't determine the apexes it belongs to any more + belongingApexes: nil, } } diff --git a/android/deapexer.go b/android/deapexer.go index 4049d2b2a..6d00dcd72 100644 --- a/android/deapexer.go +++ b/android/deapexer.go @@ -75,8 +75,6 @@ type DeapexerInfo struct { // map from the name of an exported file from a prebuilt_apex to the path to that file. The // exported file name is the apex relative path, e.g. javalib/core-libart.jar. - // - // See Prebuilt.ApexInfoMutator for more information. exports map[string]WritablePath // name of the java libraries exported from the apex diff --git a/apex/apex.go b/apex/apex.go index 24b3118a4..33538fb13 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -61,12 +61,11 @@ func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) { } func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { - ctx.TopDown("apex_info", apexInfoMutator) ctx.BottomUp("apex_unique", apexUniqueVariationsMutator) // Run mark_platform_availability before the apexMutator as the apexMutator needs to know whether // it should create a platform variant. ctx.BottomUp("mark_platform_availability", markPlatformAvailability) - ctx.Transition("apex", &apexTransitionMutator{}) + ctx.InfoBasedTransition("apex", android.NewGenericTransitionMutatorAdapter(&apexTransitionMutator{})) } type apexBundleProperties struct { @@ -996,45 +995,29 @@ func (a *apexBundle) OverridablePropertiesDepsMutator(ctx android.BottomUpMutato } } -var _ ApexInfoMutator = (*apexBundle)(nil) +var _ ApexTransitionMutator = (*apexBundle)(nil) func (a *apexBundle) ApexVariationName() string { return a.properties.ApexVariationName } -// ApexInfoMutator is responsible for collecting modules that need to have apex variants. They are -// identified by doing a graph walk starting from an apexBundle. Basically, all the (direct and -// indirect) dependencies are collected. But a few types of modules that shouldn't be included in -// the apexBundle (e.g. stub libraries) are not collected. Note that a single module can be depended -// on by multiple apexBundles. In that case, the module is collected for all of the apexBundles. -// -// For each dependency between an apex and an ApexModule an ApexInfo object describing the apex -// is passed to that module's BuildForApex(ApexInfo) method which collates them all in a list. -// The apexMutator uses that list to create module variants for the apexes to which it belongs. -// The relationship between module variants and apexes is not one-to-one as variants will be -// shared between compatible apexes. -func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) { +type generateApexInfoContext interface { + android.MinSdkVersionFromValueContext + Module() android.Module + ModuleName() string +} +// generateApexInfo returns an android.ApexInfo configuration that should be used for dependencies of this apex. +func (a *apexBundle) generateApexInfo(ctx generateApexInfoContext) android.ApexInfo { // The VNDK APEX is special. For the APEX, the membership is described in a very different // way. There is no dependency from the VNDK APEX to the VNDK libraries. Instead, VNDK // libraries are self-identified by their vndk.enabled properties. There is no need to run - // this mutator for the APEX as nothing will be collected. So, let's return fast. + // this mutator for the APEX as nothing will be collected so return an empty ApexInfo. if a.vndkApex { - return - } - - continueApexDepsWalk := func(child, parent android.Module) bool { - am, ok := child.(android.ApexModule) - if !ok || !am.CanHaveApexVariants() { - return false - } - - return android.IsDepInSameApex(mctx, parent, child) + return android.ApexInfo{} } - android.SetProvider(mctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{}) - - minSdkVersion := a.minSdkVersion(mctx) + minSdkVersion := a.minSdkVersion(ctx) // When min_sdk_version is not set, the apex is built against FutureApiLevel. if minSdkVersion.IsNone() { minSdkVersion = android.FutureApiLevel @@ -1043,62 +1026,45 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) { // This is the main part of this mutator. Mark the collected dependencies that they need to // be built for this apexBundle. - apexVariationName := mctx.ModuleName() // could be com.android.foo + apexVariationName := ctx.ModuleName() // could be com.android.foo if a.GetOverriddenBy() != "" { // use the overridden name com.mycompany.android.foo apexVariationName = a.GetOverriddenBy() } - a.properties.ApexVariationName = apexVariationName apexInfo := android.ApexInfo{ ApexVariationName: apexVariationName, MinSdkVersion: minSdkVersion, Updatable: a.Updatable(), UsePlatformApis: a.UsePlatformApis(), - InApexVariants: []string{apexVariationName}, - BaseApexName: mctx.ModuleName(), + BaseApexName: ctx.ModuleName(), ApexAvailableName: proptools.String(a.properties.Apex_available_name), } - mctx.WalkDeps(func(child, parent android.Module) bool { - if parent == mctx.Module() { - tag := mctx.OtherModuleDependencyTag(child) - if _, ok := tag.(*dependencyTag); !ok { - return false - } - } - if !continueApexDepsWalk(child, parent) { - return false - } - child.(android.ApexModule).BuildForApex(apexInfo) // leave a mark! - return true - }) + return apexInfo } -type ApexInfoMutator interface { - // ApexVariationName returns the name of the APEX variation to use in the apex - // mutator etc. It is the same name as ApexInfo.ApexVariationName. - ApexVariationName() string +func (a *apexBundle) ApexTransitionMutatorSplit(ctx android.BaseModuleContext) []android.ApexInfo { + return []android.ApexInfo{a.generateApexInfo(ctx)} +} - // ApexInfoMutator implementations must call BuildForApex(ApexInfo) on any modules that are - // depended upon by an apex and which require an apex specific variant. - ApexInfoMutator(android.TopDownMutatorContext) +func (a *apexBundle) ApexTransitionMutatorOutgoing(ctx android.OutgoingTransitionContext, sourceInfo android.ApexInfo) android.ApexInfo { + return sourceInfo } -// apexInfoMutator delegates the work of identifying which modules need an ApexInfo and apex -// specific variant to modules that support the ApexInfoMutator. -// It also propagates updatable=true to apps of updatable apexes -func apexInfoMutator(mctx android.TopDownMutatorContext) { - if !mctx.Module().Enabled(mctx) { - return - } +func (a *apexBundle) ApexTransitionMutatorIncoming(ctx android.IncomingTransitionContext, outgoingInfo android.ApexInfo) android.ApexInfo { + return a.generateApexInfo(ctx) +} - if a, ok := mctx.Module().(ApexInfoMutator); ok { - a.ApexInfoMutator(mctx) - } +func (a *apexBundle) ApexTransitionMutatorMutate(ctx android.BottomUpMutatorContext, info android.ApexInfo) { + android.SetProvider(ctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{}) + a.properties.ApexVariationName = info.ApexVariationName +} - if am, ok := mctx.Module().(android.ApexModule); ok { - android.ApexInfoMutator(mctx, am) - } +type ApexTransitionMutator interface { + ApexTransitionMutatorSplit(ctx android.BaseModuleContext) []android.ApexInfo + ApexTransitionMutatorOutgoing(ctx android.OutgoingTransitionContext, sourceInfo android.ApexInfo) android.ApexInfo + ApexTransitionMutatorIncoming(ctx android.IncomingTransitionContext, outgoingInfo android.ApexInfo) android.ApexInfo + ApexTransitionMutatorMutate(ctx android.BottomUpMutatorContext, info android.ApexInfo) } // TODO: b/215736885 Whittle the denylist @@ -1213,49 +1179,35 @@ func markPlatformAvailability(mctx android.BottomUpMutatorContext) { type apexTransitionMutator struct{} -func (a *apexTransitionMutator) Split(ctx android.BaseModuleContext) []string { - // apexBundle itself is mutated so that it and its dependencies have the same apex variant. - if ai, ok := ctx.Module().(ApexInfoMutator); ok && apexModuleTypeRequiresVariant(ai) { - if overridable, ok := ctx.Module().(android.OverridableModule); ok && overridable.GetOverriddenBy() != "" { - return []string{overridable.GetOverriddenBy()} - } - return []string{ai.ApexVariationName()} +func (a *apexTransitionMutator) Split(ctx android.BaseModuleContext) []android.ApexInfo { + if ai, ok := ctx.Module().(ApexTransitionMutator); ok { + return ai.ApexTransitionMutatorSplit(ctx) } - return []string{""} + return []android.ApexInfo{{}} } -func (a *apexTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { - return sourceVariation -} - -func (a *apexTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { - if am, ok := ctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() { - return android.IncomingApexTransition(ctx, incomingVariation) - } else if ai, ok := ctx.Module().(ApexInfoMutator); ok { - if overridable, ok := ctx.Module().(android.OverridableModule); ok && overridable.GetOverriddenBy() != "" { - return overridable.GetOverriddenBy() - } - return ai.ApexVariationName() +func (a *apexTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceInfo android.ApexInfo) android.ApexInfo { + if ai, ok := ctx.Module().(ApexTransitionMutator); ok { + return ai.ApexTransitionMutatorOutgoing(ctx, sourceInfo) } - - return "" + return android.ApexInfo{} } -func (a *apexTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { - if am, ok := ctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() { - android.MutateApexTransition(ctx, variation) +func (a *apexTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, outgoingInfo android.ApexInfo) android.ApexInfo { + if ai, ok := ctx.Module().(ApexTransitionMutator); ok { + return ai.ApexTransitionMutatorIncoming(ctx, outgoingInfo) } + return android.ApexInfo{} } -// apexModuleTypeRequiresVariant determines whether the module supplied requires an apex specific -// variant. -func apexModuleTypeRequiresVariant(module ApexInfoMutator) bool { - if a, ok := module.(*apexBundle); ok { - // TODO(jiyong): document the reason why the VNDK APEX is an exception here. - return !a.vndkApex +func (a *apexTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, info android.ApexInfo) { + if ai, ok := ctx.Module().(ApexTransitionMutator); ok { + ai.ApexTransitionMutatorMutate(ctx, info) } +} - return true +func (a *apexTransitionMutator) TransitionInfoFromVariation(variation string) android.ApexInfo { + panic(fmt.Errorf("adding dependencies on explicit apex variations is not supported")) } const ( @@ -1677,10 +1629,6 @@ func apexFileForFilesystem(ctx android.BaseModuleContext, buildFile android.Path // to the child modules. Returning false makes the visit to continue in the sibling or the parent // modules. This is used in check* functions below. func (a *apexBundle) WalkPayloadDeps(ctx android.BaseModuleContext, do android.PayloadDepsCallback) { - apexVariationName := ctx.ModuleName() - if overrideName := a.GetOverriddenBy(); overrideName != "" { - apexVariationName = overrideName - } ctx.WalkDeps(func(child, parent android.Module) bool { am, ok := child.(android.ApexModule) if !ok || !am.CanHaveApexVariants() { @@ -1699,8 +1647,7 @@ func (a *apexBundle) WalkPayloadDeps(ctx android.BaseModuleContext, do android.P return false } - ai, _ := android.OtherModuleProvider(ctx, child, android.ApexInfoProvider) - externalDep := !android.InList(apexVariationName, ai.InApexVariants) + externalDep := !android.IsDepInSameApex(ctx, parent, child) // Visit actually return do(ctx, parent, am, externalDep) @@ -1725,8 +1672,7 @@ func (a *apexBundle) WalkPayloadDepsProxy(ctx android.BaseModuleContext, return false } - ai, _ := android.OtherModuleProvider(ctx, child, android.ApexInfoProvider) - externalDep := !android.InList(ctx.ModuleName(), ai.InApexVariants) + externalDep := !android.IsDepInSameApex(ctx, parent, child) // Visit actually return do(ctx, parent, child, externalDep) @@ -2573,7 +2519,7 @@ func (a *apexBundle) CheckMinSdkVersion(ctx android.ModuleContext) { } // Returns apex's min_sdk_version string value, honoring overrides -func (a *apexBundle) minSdkVersionValue(ctx android.EarlyModuleContext) string { +func (a *apexBundle) minSdkVersionValue(ctx android.MinSdkVersionFromValueContext) string { // Only override the minSdkVersion value on Apexes which already specify // a min_sdk_version (it's optional for non-updatable apexes), and that its // min_sdk_version value is lower than the one to override with. @@ -2597,7 +2543,7 @@ func (a *apexBundle) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLe } // Returns apex's min_sdk_version ApiLevel, honoring overrides -func (a *apexBundle) minSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { +func (a *apexBundle) minSdkVersion(ctx android.MinSdkVersionFromValueContext) android.ApiLevel { return android.MinSdkVersionFromValue(ctx, a.minSdkVersionValue(ctx)) } @@ -2613,7 +2559,7 @@ func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext librariesDirectlyInApex[ctx.OtherModuleName(dep)] = true }) - a.WalkPayloadDepsProxy(ctx, func(ctx android.BaseModuleContext, from, to android.ModuleProxy, externalDep bool) bool { + a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from android.Module, to android.ApexModule, externalDep bool) bool { if info, ok := android.OtherModuleProvider(ctx, to, cc.LinkableInfoProvider); ok { // If `to` is not actually in the same APEX as `from` then it does not need // apex_available and neither do any of its dependencies. @@ -2727,7 +2673,7 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { return } - a.WalkPayloadDepsProxy(ctx, func(ctx android.BaseModuleContext, from, to android.ModuleProxy, externalDep bool) bool { + a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from android.Module, to android.ApexModule, externalDep bool) bool { // As soon as the dependency graph crosses the APEX boundary, don't go further. if externalDep { return false @@ -2745,7 +2691,7 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { toName := ctx.OtherModuleName(to) if android.CheckAvailableForApex(apexName, - android.OtherModuleProviderOrDefault(ctx, to, android.ApexInfoProvider).ApexAvailableFor) { + android.OtherModuleProviderOrDefault(ctx, to, android.ApexAvailableInfoProvider).ApexAvailableFor) { return true } diff --git a/apex/apex_test.go b/apex/apex_test.go index 0d6d31999..f88c09ebd 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -5190,7 +5190,7 @@ func TestPrebuilt(t *testing.T) { } `) - testingModule := ctx.ModuleForTests("myapex", "android_common_myapex") + testingModule := ctx.ModuleForTests("myapex", "android_common_prebuilt_myapex") prebuilt := testingModule.Module().(*Prebuilt) expectedInput := "myapex-arm64.apex" @@ -5211,7 +5211,7 @@ func TestPrebuilt(t *testing.T) { func TestPrebuiltMissingSrc(t *testing.T) { t.Parallel() - testApexError(t, `module "myapex" variant "android_common_myapex".*: prebuilt_apex does not support "arm64_armv8-a"`, ` + testApexError(t, `module "myapex" variant "android_common_prebuilt_myapex".*: prebuilt_apex does not support "arm64_armv8-a"`, ` prebuilt_apex { name: "myapex", } @@ -5228,7 +5228,7 @@ func TestPrebuiltFilenameOverride(t *testing.T) { } `) - testingModule := ctx.ModuleForTests("myapex", "android_common_myapex") + testingModule := ctx.ModuleForTests("myapex", "android_common_prebuilt_myapex") p := testingModule.Module().(*Prebuilt) expected := "notmyapex.apex" @@ -5251,7 +5251,7 @@ func TestApexSetFilenameOverride(t *testing.T) { set: "company-myapex.apks", filename: "com.company.android.myapex.apex" } - `).ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex") + `).ModuleForTests("com.company.android.myapex", "android_common_prebuilt_com.android.myapex") testApex(t, ` apex_set { @@ -5260,7 +5260,7 @@ func TestApexSetFilenameOverride(t *testing.T) { set: "company-myapex.apks", filename: "com.company.android.myapex.capex" } - `).ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex") + `).ModuleForTests("com.company.android.myapex", "android_common_prebuilt_com.android.myapex") testApexError(t, `filename should end in .apex or .capex for apex_set`, ` apex_set { @@ -5284,7 +5284,7 @@ func TestPrebuiltOverrides(t *testing.T) { } `) - testingModule := ctx.ModuleForTests("myapex.prebuilt", "android_common_myapex.prebuilt") + testingModule := ctx.ModuleForTests("myapex.prebuilt", "android_common_prebuilt_myapex.prebuilt") p := testingModule.Module().(*Prebuilt) expected := []string{"myapex"} @@ -5307,7 +5307,7 @@ func TestPrebuiltApexName(t *testing.T) { apex_name: "com.android.myapex", src: "company-myapex-arm.apex", } - `).ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex") + `).ModuleForTests("com.company.android.myapex", "android_common_prebuilt_com.android.myapex") testApex(t, ` apex_set { @@ -5315,7 +5315,7 @@ func TestPrebuiltApexName(t *testing.T) { apex_name: "com.android.myapex", set: "company-myapex.apks", } - `).ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex") + `).ModuleForTests("com.company.android.myapex", "android_common_prebuilt_com.android.myapex") } func TestPrebuiltApexNameWithPlatformBootclasspath(t *testing.T) { @@ -5555,7 +5555,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_com.android.art/modular-hiddenapi/index.csv `) - myApex := ctx.ModuleForTests("myapex", "android_common_myapex").Module() + myApex := ctx.ModuleForTests("myapex", "android_common_prebuilt_myapex").Module() overrideNames := []string{ "", @@ -5639,7 +5639,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { // prebuilt_apex module always depends on the prebuilt, and so it doesn't // find the dex boot jar in it. We either need to disable the source libfoo // or make the prebuilt libfoo preferred. - testDexpreoptWithApexes(t, bp, `module "platform-bootclasspath" variant ".*": module "libfoo" from platform is not allowed in the apex boot jars list`, preparer, fragment) + testDexpreoptWithApexes(t, bp, `module "platform-bootclasspath" variant ".*": module libfoo{.*} does not provide a dex jar`, preparer, fragment) // dexbootjar check is skipped if AllowMissingDependencies is true preparerAllowMissingDeps := android.GroupFixturePreparers( preparer, @@ -5675,6 +5675,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { prebuilt_apex { name: "myapex", + prefer: true, arch: { arm64: { src: "myapex-arm64.apex", @@ -6609,16 +6610,10 @@ func TestApexAvailable_IndirectDep(t *testing.T) { testApexError(t, `requires "libbaz" that doesn't list the APEX under 'apex_available'.\n\nDependency path: .*via tag apex\.dependencyTag\{"sharedLib"\} .*-> libfoo.*link:shared.* -.*via tag cc\.dependencyTag.* -.*-> libfoo.*link:static.* .*via tag cc\.libraryDependencyTag.*Kind:sharedLibraryDependency.* .*-> libbar.*link:shared.* -.*via tag cc\.dependencyTag.* -.*-> libbar.*link:static.* .*via tag cc\.libraryDependencyTag.*Kind:sharedLibraryDependency.* -.*-> libbaz.*link:shared.* -.*via tag cc\.dependencyTag.* -.*-> libbaz.*link:static.*`, ` +.*-> libbaz.*link:shared.*`, ` apex { name: "myapex", key: "myapex.key", @@ -7878,7 +7873,7 @@ func TestJavaSDKLibrary_WithinApex(t *testing.T) { }) // The bar library should depend on the implementation jar. - barLibrary := ctx.ModuleForTests("bar", "android_common_myapex").Rule("javac") + barLibrary := ctx.ModuleForTests("bar", "android_common_apex10000").Rule("javac") if expected, actual := `^-classpath [^:]*/turbine-combined/foo\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { t.Errorf("expected %q, found %#q", expected, actual) } @@ -8024,7 +8019,7 @@ func TestJavaSDKLibrary_ImportPreferred(t *testing.T) { }) // The bar library should depend on the implementation jar. - barLibrary := ctx.ModuleForTests("bar", "android_common_myapex").Rule("javac") + barLibrary := ctx.ModuleForTests("bar", "android_common_apex10000").Rule("javac") if expected, actual := `^-classpath [^:]*/turbine-combined/foo\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { t.Errorf("expected %q, found %#q", expected, actual) } @@ -8504,31 +8499,6 @@ func TestApexWithJniLibs(t *testing.T) { ensureListContains(t, names(rule.Args["requireNativeLibs"]), "libfoo.shared_from_rust.so") } -func TestApexMutatorsDontRunIfDisabled(t *testing.T) { - t.Parallel() - ctx := testApex(t, ` - apex { - name: "myapex", - key: "myapex.key", - updatable: false, - } - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - `, - android.FixtureModifyConfig(func(config android.Config) { - delete(config.Targets, android.Android) - config.AndroidCommonTarget = android.Target{} - }), - ) - - if expected, got := []string{""}, ctx.ModuleVariantsForTests("myapex"); !reflect.DeepEqual(expected, got) { - t.Errorf("Expected variants: %v, but got: %v", expected, got) - } -} - func TestAppBundle(t *testing.T) { t.Parallel() ctx := testApex(t, ` @@ -8615,16 +8585,16 @@ 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/android_common_myapex/extracted/myapex.hwasan.apks" + extractorOutput := "out/soong/.intermediates/myapex/android_common_prebuilt_myapex/extracted/myapex.hwasan.apks" - m := ctx.ModuleForTests("myapex", "android_common_myapex") + m := ctx.ModuleForTests("myapex", "android_common_prebuilt_myapex") extractedApex := m.Output(extractorOutput) android.AssertArrayString(t, "extractor input", []string{"myapex.hwasan.apks"}, extractedApex.Inputs.Strings()) // Ditto for the apex. - m = ctx.ModuleForTests("myapex", "android_common_myapex") - copiedApex := m.Output("out/soong/.intermediates/myapex/android_common_myapex/foo_v2.apex") + m = ctx.ModuleForTests("myapex", "android_common_prebuilt_myapex") + copiedApex := m.Output("out/soong/.intermediates/myapex/android_common_prebuilt_myapex/foo_v2.apex") android.AssertStringEquals(t, "myapex input", extractorOutput, copiedApex.Input.String()) } @@ -8643,10 +8613,10 @@ func TestApexSetApksModuleAssignment(t *testing.T) { } `) - m := ctx.ModuleForTests("myapex", "android_common_myapex") + m := ctx.ModuleForTests("myapex", "android_common_prebuilt_myapex") // Check that the extractor produces the correct apks file from the input module - extractorOutput := "out/soong/.intermediates/myapex/android_common_myapex/extracted/myapex.apks" + extractorOutput := "out/soong/.intermediates/myapex/android_common_prebuilt_myapex/extracted/myapex.apks" extractedApex := m.Output(extractorOutput) android.AssertArrayString(t, "extractor input", []string{"myapex.apks"}, extractedApex.Inputs.Strings()) @@ -9035,7 +9005,7 @@ func TestApexSet(t *testing.T) { }), ) - m := ctx.ModuleForTests("myapex", "android_common_myapex") + m := ctx.ModuleForTests("myapex", "android_common_prebuilt_myapex") // Check extract_apks tool parameters. extractedApex := m.Output("extracted/myapex.apks") @@ -9050,7 +9020,7 @@ func TestApexSet(t *testing.T) { t.Errorf("Unexpected abis parameter - expected %q vs actual %q", expected, actual) } - m = ctx.ModuleForTests("myapex", "android_common_myapex") + m = ctx.ModuleForTests("myapex", "android_common_prebuilt_myapex") a := m.Module().(*ApexSet) expectedOverrides := []string{"foo"} actualOverrides := android.AndroidMkEntriesForTest(t, ctx, a)[0].EntryMap["LOCAL_OVERRIDES_MODULES"] @@ -9077,7 +9047,7 @@ func TestApexSet_NativeBridge(t *testing.T) { }), ) - m := ctx.ModuleForTests("myapex", "android_common_myapex") + m := ctx.ModuleForTests("myapex", "android_common_prebuilt_myapex") // Check extract_apks tool parameters. No native bridge arch expected extractedApex := m.Output("extracted/myapex.apks") @@ -9185,7 +9155,7 @@ func TestApexKeysTxtOverrides(t *testing.T) { ctx.ModuleForTests("myapex", "android_common_myapex").Output("apexkeys.txt")) ensureContains(t, content, `name="myapex.apex" public_key="vendor/foo/devkeys/testkey.avbpubkey" private_key="vendor/foo/devkeys/testkey.pem" container_certificate="vendor/foo/devkeys/test.x509.pem" container_private_key="vendor/foo/devkeys/test.pk8" partition="system" sign_tool="sign_myapex"`) content = android.ContentFromFileRuleForTests(t, ctx, - ctx.ModuleForTests("myapex_set", "android_common_myapex_set").Output("apexkeys.txt")) + ctx.ModuleForTests("myapex_set", "android_common_prebuilt_myapex_set").Output("apexkeys.txt")) ensureContains(t, content, `name="myapex_set.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" partition="system"`) } @@ -9364,7 +9334,7 @@ func TestApexSet_ShouldRespectCompressedApexFlag(t *testing.T) { }), ) - build := ctx.ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex").Output("com.company.android.myapex.apex") + build := ctx.ModuleForTests("com.company.android.myapex", "android_common_prebuilt_com.android.myapex").Output("com.company.android.myapex.apex") if compressionEnabled { ensureEquals(t, build.Rule.String(), "android/soong/android.Cp") } else { @@ -11311,12 +11281,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/prebuilt_com.android.foo/android_common_com.android.foo/deapexer/javalib/framework-foo.jar", + expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo/android_common_prebuilt_com.android.foo/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/android_common_com.android.foo/deapexer/javalib/framework-foo.jar", + expectedBootJar: "out/soong/.intermediates/com.android.foo.v2/android_common_prebuilt_com.android.foo/deapexer/javalib/framework-foo.jar", }, } @@ -11361,7 +11331,7 @@ func TestInstallationRulesForMultipleApexPrebuilts(t *testing.T) { // 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" + ret := "android_common_prebuilt_com.android.foo" if moduleName == "com.google.android.foo" { ret = "android_common_com.google.android.foo" } @@ -11508,8 +11478,8 @@ func TestInstallationRulesForMultipleApexPrebuiltsWithoutSource(t *testing.T) { checkHideFromMake := func(t *testing.T, ctx *android.TestContext, visibleModuleNames []string, hiddenModuleNames []string) { variation := func(moduleName string) string { ret := "android_common_com.android.adservices" - if moduleName == "com.google.android.foo" { - ret = "android_common_com.google.android.foo_com.google.android.foo" + if moduleName == "com.google.android.adservices" || moduleName == "com.google.android.adservices.v2" { + ret = "android_common_prebuilt_com.android.adservices" } return ret } @@ -11584,13 +11554,13 @@ func TestInstallationRulesForMultipleApexPrebuiltsWithoutSource(t *testing.T) { expectedHiddenModuleNames: []string{"com.google.android.adservices", "com.google.android.adservices.v2"}, }, { - desc: "Prebuilt apex prebuilt_com.android.foo is selected", + desc: "Prebuilt apex prebuilt_com.android.adservices is selected", selectedApexContributions: "adservices.prebuilt.contributions", expectedVisibleModuleNames: []string{"com.android.adservices", "com.google.android.adservices"}, expectedHiddenModuleNames: []string{"com.google.android.adservices.v2"}, }, { - desc: "Prebuilt apex prebuilt_com.android.foo.v2 is selected", + desc: "Prebuilt apex prebuilt_com.android.adservices.v2 is selected", selectedApexContributions: "adservices.prebuilt.v2.contributions", expectedVisibleModuleNames: []string{"com.android.adservices", "com.google.android.adservices.v2"}, expectedHiddenModuleNames: []string{"com.google.android.adservices"}, diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go index e8e45adfc..60d111f67 100644 --- a/apex/bootclasspath_fragment_test.go +++ b/apex/bootclasspath_fragment_test.go @@ -292,6 +292,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { apex_available: [ "com.android.art", ], + min_sdk_version: "33", compile_dex: true, } `, content, prefer) @@ -420,7 +421,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"), ).RunTest(t) - ensureExactDeapexedContents(t, result.TestContext, "prebuilt_com.android.art", "android_common_com.android.art", []string{ + ensureExactDeapexedContents(t, result.TestContext, "prebuilt_com.android.art", "android_common_prebuilt_com.android.art", []string{ "etc/boot-image.prof", "javalib/bar.jar", "javalib/foo.jar", @@ -590,13 +591,13 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) { t.Parallel() result := preparers.RunTestWithBp(t, fmt.Sprintf(bp, "enabled: false,")) - java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{ + java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_prebuilt_com.android.art", []string{ `all_apex_contributions`, `dex2oatd`, `prebuilt_art-bootclasspath-fragment`, }) - java.CheckModuleDependencies(t, result.TestContext, "art-bootclasspath-fragment", "android_common_com.android.art", []string{ + java.CheckModuleDependencies(t, result.TestContext, "art-bootclasspath-fragment", "android_common_prebuilt_com.android.art", []string{ `all_apex_contributions`, `dex2oatd`, `prebuilt_bar`, diff --git a/apex/builder.go b/apex/builder.go index b40fd0991..b34dc84a6 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -1104,7 +1104,7 @@ func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) { } depInfos := android.DepNameToDepInfoMap{} - a.WalkPayloadDepsProxy(ctx, func(ctx android.BaseModuleContext, from, to android.ModuleProxy, externalDep bool) bool { + a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from android.Module, to android.ApexModule, externalDep bool) bool { if from.Name() == to.Name() { // This can happen for cc.reuseObjTag. We are not interested in tracking this. // As soon as the dependency graph crosses the APEX boundary, don't go further. diff --git a/apex/container_test.go b/apex/container_test.go index 395793f61..bf9445b49 100644 --- a/apex/container_test.go +++ b/apex/container_test.go @@ -29,6 +29,7 @@ var checkContainerMatch = func(t *testing.T, name string, container string, expe func TestApexDepsContainers(t *testing.T) { t.Parallel() + t.Skip("TODO(b/394955484): this probably has to be moved to a check by the apex") result := android.GroupFixturePreparers( prepareForApexTest, java.PrepareForTestWithJavaSdkLibraryFiles, @@ -166,6 +167,7 @@ func TestApexDepsContainers(t *testing.T) { func TestNonUpdatableApexDepsContainers(t *testing.T) { t.Parallel() + t.Skip("TODO(b/394955484): this probably has to be moved to a check by the apex") result := android.GroupFixturePreparers( prepareForApexTest, java.PrepareForTestWithJavaSdkLibraryFiles, @@ -281,6 +283,7 @@ func TestNonUpdatableApexDepsContainers(t *testing.T) { func TestUpdatableAndNonUpdatableApexesIdenticalMinSdkVersion(t *testing.T) { t.Parallel() + t.Skip("TODO(b/394955484): this probably has to be moved to a check by the apex") result := android.GroupFixturePreparers( prepareForApexTest, java.PrepareForTestWithJavaSdkLibraryFiles, diff --git a/apex/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go index 6fa1fe225..5abad81fc 100644 --- a/apex/dexpreopt_bootjars_test.go +++ b/apex/dexpreopt_bootjars_test.go @@ -215,7 +215,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/prebuilt_com.android.art/android_common_com.android.art/deapexer/etc/boot-image.prof", + "out/soong/.intermediates/prebuilt_com.android.art/android_common_prebuilt_com.android.art/deapexer/etc/boot-image.prof", "out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof", "out/soong/dexpreopt/uffd_gc_flag.txt", } @@ -401,12 +401,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/prebuilt_com.android.art/android_common_com.android.art/deapexer/etc/boot-image.prof", + expectedProfile: "out/soong/.intermediates/prebuilt_com.android.art/android_common_prebuilt_com.android.art/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/android_common_com.android.art/deapexer/etc/boot-image.prof", + expectedProfile: "out/soong/.intermediates/com.android.art.v2/android_common_prebuilt_com.android.art/deapexer/etc/boot-image.prof", }, } for _, tc := range testCases { diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go index cd8c320ed..d79af8660 100644 --- a/apex/platform_bootclasspath_test.go +++ b/apex/platform_bootclasspath_test.go @@ -23,7 +23,6 @@ import ( "android/soong/dexpreopt" "android/soong/java" - "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -240,8 +239,8 @@ func TestPlatformBootclasspath_LegacyPrebuiltFragment(t *testing.T) { pbcp := result.Module("myplatform-bootclasspath", "android_common") info, _ := android.OtherModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider) - android.AssertArrayString(t, "stub flags", []string{"prebuilt-stub-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop()) - android.AssertArrayString(t, "all flags", []string{"prebuilt-all-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop()) + android.AssertArrayString(t, "stub flags", []string{"prebuilt-stub-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_prebuilt_myapex/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop()) + android.AssertArrayString(t, "all flags", []string{"prebuilt-all-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_prebuilt_myapex/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop()) } func TestPlatformBootclasspathDependencies(t *testing.T) { @@ -388,7 +387,7 @@ func TestPlatformBootclasspathDependencies(t *testing.T) { }) // Make sure that the myplatform-bootclasspath has the correct dependencies. - CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{ + java.CheckPlatformBootclasspathDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{ // source vs prebuilt selection metadata module `platform:all_apex_contributions`, @@ -479,6 +478,7 @@ func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) { name: "myapex", src: "myapex.apex", exported_bootclasspath_fragments: ["mybootclasspath-fragment"], + prefer: true, } // A prebuilt java_sdk_library_import that is not preferred by default but will be preferred @@ -544,11 +544,11 @@ func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) { java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{ // The configured contents of BootJars. - "myapex:prebuilt_foo", + "prebuilt_myapex:prebuilt_foo", }) // Make sure that the myplatform-bootclasspath has the correct dependencies. - CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{ + java.CheckPlatformBootclasspathDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{ // source vs prebuilt selection metadata module `platform:all_apex_contributions`, @@ -561,32 +561,16 @@ func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) { "platform:legacy.core.platform.api.stubs.exportable", // The prebuilt library via the apex. - "platform:myapex", + "platform:prebuilt_myapex", // The fragments via the apex. - "platform:myapex", + "platform:prebuilt_myapex", // Impl lib of sdk_library for transitive srcjar generation "platform:foo.impl", }) } -// CheckModuleDependencies checks the dependencies of the selected module against the expected list. -// -// The expected list must be a list of strings of the form ":", where is the -// name of the apex, or platform is it is not part of an apex and is the module name. -func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) { - t.Helper() - module := ctx.ModuleForTests(name, variant).Module() - modules := []android.Module{} - ctx.VisitDirectDeps(module, func(m blueprint.Module) { - modules = append(modules, m.(android.Module)) - }) - - pairs := java.ApexNamePairsFromModules(ctx, modules) - android.AssertDeepEquals(t, "module dependencies", expected, pairs) -} - // TestPlatformBootclasspath_IncludesRemainingApexJars verifies that any apex boot jar is present in // platform_bootclasspath's classpaths.proto config, if the apex does not generate its own config // by setting generate_classpaths_proto property to false. diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 85b64e743..e7d92c3a4 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -310,89 +310,34 @@ func (p *prebuiltCommon) IncomingDepIsInSameApex(tag blueprint.DependencyTag) bo return true } -// apexInfoMutator marks any modules for which this apex exports a file as requiring an apex -// specific variant and checks that they are supported. -// -// The apexMutator will ensure that the ApexInfo objects passed to BuildForApex(ApexInfo) are -// associated with the apex specific variant using the ApexInfoProvider for later retrieval. -// -// Unlike the source apex module type the prebuilt_apex module type cannot share compatible variants -// across prebuilt_apex modules. That is because there is no way to determine whether two -// prebuilt_apex modules that export files for the same module are compatible. e.g. they could have -// been built from different source at different times or they could have been built with different -// build options that affect the libraries. -// -// While it may be possible to provide sufficient information to determine whether two prebuilt_apex -// modules were compatible it would be a lot of work and would not provide much benefit for a couple -// of reasons: -// - The number of prebuilt_apex modules that will be exporting files for the same module will be -// low as the prebuilt_apex only exports files for the direct dependencies that require it and -// very few modules are direct dependencies of multiple prebuilt_apex modules, e.g. there are a -// few com.android.art* apex files that contain the same contents and could export files for the -// same modules but only one of them needs to do so. Contrast that with source apex modules which -// need apex specific variants for every module that contributes code to the apex, whether direct -// or indirect. -// - The build cost of a prebuilt_apex variant is generally low as at worst it will involve some -// extra copying of files. Contrast that with source apex modules that has to build each variant -// from source. -func (p *prebuiltCommon) apexInfoMutator(mctx android.TopDownMutatorContext) { - // Collect the list of dependencies. - var dependencies []android.ApexModule - mctx.WalkDeps(func(child, parent android.Module) bool { - // If the child is not in the same apex as the parent then exit immediately and do not visit - // any of the child's dependencies. - if !android.IsDepInSameApex(mctx, parent, child) { - return false - } - - tag := mctx.OtherModuleDependencyTag(child) - depName := mctx.OtherModuleName(child) +func (p *prebuiltCommon) checkExportedDependenciesArePrebuilts(ctx android.ModuleContext) { + ctx.VisitDirectDeps(func(dep android.Module) { + tag := ctx.OtherModuleDependencyTag(dep) + depName := ctx.OtherModuleName(dep) if exportedTag, ok := tag.(exportedDependencyTag); ok { propertyName := exportedTag.name // It is an error if the other module is not a prebuilt. - if !android.IsModulePrebuilt(child) { - mctx.PropertyErrorf(propertyName, "%q is not a prebuilt module", depName) - return false + if !android.IsModulePrebuilt(dep) { + ctx.PropertyErrorf(propertyName, "%q is not a prebuilt module", depName) } // It is an error if the other module is not an ApexModule. - if _, ok := child.(android.ApexModule); !ok { - mctx.PropertyErrorf(propertyName, "%q is not usable within an apex", depName) - return false + if _, ok := dep.(android.ApexModule); !ok { + ctx.PropertyErrorf(propertyName, "%q is not usable within an apex", depName) } } - // Ignore any modules that do not implement ApexModule as they cannot have an APEX specific - // variant. - if _, ok := child.(android.ApexModule); !ok { - return false - } - - // Strip off the prebuilt_ prefix if present before storing content to ensure consistent - // behavior whether there is a corresponding source module present or not. - depName = android.RemoveOptionalPrebuiltPrefix(depName) - - // Add the module to the list of dependencies that need to have an APEX variant. - dependencies = append(dependencies, child.(android.ApexModule)) - - return true }) +} - android.SetProvider(mctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{}) - - // Create an ApexInfo for the prebuilt_apex. - apexVariationName := p.ApexVariationName() - apexInfo := android.ApexInfo{ - ApexVariationName: apexVariationName, - InApexVariants: []string{apexVariationName}, +// generateApexInfo returns an android.ApexInfo configuration suitable for dependencies of this apex. +func (p *prebuiltCommon) generateApexInfo(ctx generateApexInfoContext) android.ApexInfo { + return android.ApexInfo{ + ApexVariationName: "prebuilt_" + p.ApexVariationName(), + BaseApexName: p.ApexVariationName(), ForPrebuiltApex: true, } - - // Mark the dependencies of this module as requiring a variant for this module. - for _, am := range dependencies { - am.BuildForApex(apexInfo) - } } type Prebuilt struct { @@ -596,10 +541,22 @@ func (p *Prebuilt) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { p.prebuiltApexContentsDeps(ctx) } -var _ ApexInfoMutator = (*Prebuilt)(nil) +var _ ApexTransitionMutator = (*Prebuilt)(nil) + +func (p *Prebuilt) ApexTransitionMutatorSplit(ctx android.BaseModuleContext) []android.ApexInfo { + return []android.ApexInfo{p.generateApexInfo(ctx)} +} + +func (p *Prebuilt) ApexTransitionMutatorOutgoing(ctx android.OutgoingTransitionContext, sourceInfo android.ApexInfo) android.ApexInfo { + return sourceInfo +} + +func (p *Prebuilt) ApexTransitionMutatorIncoming(ctx android.IncomingTransitionContext, outgoingInfo android.ApexInfo) android.ApexInfo { + return p.generateApexInfo(ctx) +} -func (p *Prebuilt) ApexInfoMutator(mctx android.TopDownMutatorContext) { - p.apexInfoMutator(mctx) +func (p *Prebuilt) ApexTransitionMutatorMutate(ctx android.BottomUpMutatorContext, info android.ApexInfo) { + android.SetProvider(ctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{}) } // creates the build rules to deapex the prebuilt, and returns a deapexerInfo @@ -665,6 +622,8 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) { validateApexClasspathFragments(ctx) } + p.checkExportedDependenciesArePrebuilts(ctx) + p.apexKeysPath = writeApexKeys(ctx, p) // TODO(jungjw): Check the key validity. p.inputApex = android.PathForModuleSrc(ctx, p.properties.prebuiltApexSelector(ctx, ctx.Module())) @@ -825,10 +784,22 @@ func (a *ApexSet) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { a.prebuiltApexContentsDeps(ctx) } -var _ ApexInfoMutator = (*ApexSet)(nil) +var _ ApexTransitionMutator = (*ApexSet)(nil) + +func (a *ApexSet) ApexTransitionMutatorSplit(ctx android.BaseModuleContext) []android.ApexInfo { + return []android.ApexInfo{a.generateApexInfo(ctx)} +} + +func (a *ApexSet) ApexTransitionMutatorOutgoing(ctx android.OutgoingTransitionContext, sourceInfo android.ApexInfo) android.ApexInfo { + return sourceInfo +} + +func (a *ApexSet) ApexTransitionMutatorIncoming(ctx android.IncomingTransitionContext, outgoingInfo android.ApexInfo) android.ApexInfo { + return a.generateApexInfo(ctx) +} -func (a *ApexSet) ApexInfoMutator(mctx android.TopDownMutatorContext) { - a.apexInfoMutator(mctx) +func (a *ApexSet) ApexTransitionMutatorMutate(ctx android.BottomUpMutatorContext, info android.ApexInfo) { + android.SetProvider(ctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{}) } func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go index c643a8c98..81f287fd6 100644 --- a/apex/systemserver_classpath_fragment_test.go +++ b/apex/systemserver_classpath_fragment_test.go @@ -280,19 +280,19 @@ func TestPrebuiltSystemserverclasspathFragmentContents(t *testing.T) { ctx := result.TestContext - java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{ + java.CheckModuleDependencies(t, ctx, "myapex", "android_common_prebuilt_myapex", []string{ `all_apex_contributions`, `dex2oatd`, `prebuilt_mysystemserverclasspathfragment`, }) - java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_myapex", []string{ + java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_prebuilt_myapex", []string{ `all_apex_contributions`, `prebuilt_bar`, `prebuilt_foo`, }) - ensureExactDeapexedContents(t, ctx, "myapex", "android_common_myapex", []string{ + ensureExactDeapexedContents(t, ctx, "myapex", "android_common_prebuilt_myapex", []string{ "javalib/foo.jar", "javalib/bar.jar", "javalib/bar.jar.prof", @@ -440,13 +440,13 @@ func TestPrebuiltStandaloneSystemserverclasspathFragmentContents(t *testing.T) { ctx := result.TestContext - java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_myapex", []string{ + java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_prebuilt_myapex", []string{ `all_apex_contributions`, `prebuilt_bar`, `prebuilt_foo`, }) - ensureExactDeapexedContents(t, ctx, "myapex", "android_common_myapex", []string{ + ensureExactDeapexedContents(t, ctx, "myapex", "android_common_prebuilt_myapex", []string{ "javalib/foo.jar", "javalib/bar.jar", "javalib/bar.jar.prof", @@ -465,7 +465,7 @@ func assertProfileGuided(t *testing.T, ctx *android.TestContext, moduleName stri } func assertProfileGuidedPrebuilt(t *testing.T, ctx *android.TestContext, apexName string, moduleName string, expected bool) { - dexpreopt := ctx.ModuleForTests(apexName, "android_common_"+apexName).Rule("dexpreopt." + moduleName) + dexpreopt := ctx.ModuleForTests(apexName, "android_common_prebuilt_"+apexName).Rule("dexpreopt." + moduleName) actual := strings.Contains(dexpreopt.RuleParams.Command, "--profile-file=") if expected != actual { t.Fatalf("Expected profile-guided to be %v, got %v", expected, actual) diff --git a/cc/cc.go b/cc/cc.go index dd557b58f..cb11fb845 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -4084,6 +4084,9 @@ func (c *Module) OutgoingDepIsInSameApex(depTag blueprint.DependencyTag) bool { } func (c *Module) IncomingDepIsInSameApex(depTag blueprint.DependencyTag) bool { + if c.Host() { + return false + } if c.HasStubsVariants() { if IsSharedDepTag(depTag) && !IsExplicitImplSharedDepTag(depTag) { // dynamic dep to a stubs lib crosses APEX boundary @@ -4224,7 +4227,6 @@ func (c *Module) typ() moduleType { type Defaults struct { android.ModuleBase android.DefaultsModuleBase - android.ApexModuleBase } // cc_defaults provides a set of properties that can be inherited by other cc diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index fd4b0a305..65a05798a 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -423,6 +423,9 @@ func (b *BootclasspathFragmentModule) OutgoingDepIsInSameApex(tag blueprint.Depe // Cross-cutting metadata dependencies are metadata. return false } + if tag == moduleInFragmentDepTag { + return true + } // Dependency to the bootclasspath fragment of another apex // e.g. concsrypt-bootclasspath-fragment --> art-bootclasspath-fragment if bcpTag, ok := tag.(bootclasspathDependencyTag); ok && bcpTag.typ == fragment { @@ -431,6 +434,15 @@ func (b *BootclasspathFragmentModule) OutgoingDepIsInSameApex(tag blueprint.Depe if tag == moduleInFragmentDepTag { return false } + if tag == dexpreopt.Dex2oatDepTag { + return false + } + if tag == android.PrebuiltDepTag { + return false + } + if _, ok := tag.(hiddenAPIStubsDependencyTag); ok { + return false + } panic(fmt.Errorf("boot_image module %q should not have a dependency tag %s", b, android.PrettyPrintTag(tag))) } diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 15e40ba0d..5755dec23 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -177,10 +177,7 @@ func disableSourceApexVariant(ctx android.BaseModuleContext) bool { // Find the apex variant for this module apexVariants := []string{} if apexInfo.BaseApexName != "" { - // This is a transitive dependency of an override_apex apexVariants = append(apexVariants, apexInfo.BaseApexName) - } else { - apexVariants = append(apexVariants, apexInfo.InApexVariants...) } if apexInfo.ApexAvailableName != "" { apexVariants = append(apexVariants, apexInfo.ApexAvailableName) diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index 7d21b7a61..2c8694237 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -171,11 +171,11 @@ func isModuleInConfiguredList(ctx android.BaseModuleContext, module android.Modu // Now match the apex part of the boot image configuration. requiredApex := configuredBootJars.Apex(index) if android.IsConfiguredJarForPlatform(requiredApex) { - if len(apexInfo.InApexVariants) != 0 { + if apexInfo.ApexVariationName != "" { // A platform variant is required but this is for an apex so ignore it. return false } - } else if !apexInfo.InApexVariant(requiredApex) { + } else if apexInfo.BaseApexName != requiredApex { // An apex variant for a specific apex is required but this is the wrong apex. return false } diff --git a/java/java.go b/java/java.go index d32133972..9e1959a8d 100644 --- a/java/java.go +++ b/java/java.go @@ -3513,7 +3513,6 @@ func DexImportFactory() android.Module { type Defaults struct { android.ModuleBase android.DefaultsModuleBase - android.ApexModuleBase } // java_defaults provides a set of properties that can be inherited by other java or android modules. diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index 39b54e3e8..155afc6c2 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -258,7 +258,7 @@ func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleCon fromUpdatableApex := apexInfo.Updatable if fromUpdatableApex { // error: this jar is part of an updatable apex - ctx.ModuleErrorf("module %q from updatable apexes %q is not allowed in the platform bootclasspath", ctx.OtherModuleName(m), apexInfo.InApexVariants) + ctx.ModuleErrorf("module %q from updatable apex %q is not allowed in the platform bootclasspath", ctx.OtherModuleName(m), apexInfo.BaseApexName) } else { // ok: this jar is part of the platform or a non-updatable apex } diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go index f3074ed0a..6f746b45a 100644 --- a/java/systemserver_classpath_fragment.go +++ b/java/systemserver_classpath_fragment.go @@ -119,6 +119,7 @@ func systemServerClasspathFactory() android.Module { android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) return m } + func (m *SystemServerClasspathModule) UniqueApexVariations() bool { return true } diff --git a/java/testing.go b/java/testing.go index 5ee659c81..b3e552658 100644 --- a/java/testing.go +++ b/java/testing.go @@ -651,7 +651,7 @@ func CheckModuleHasDependencyWithTag(t *testing.T, ctx *android.TestContext, nam func CheckPlatformBootclasspathModules(t *testing.T, result *android.TestResult, name string, expected []string) { t.Helper() platformBootclasspath := result.Module(name, "android_common").(*platformBootclasspathModule) - pairs := ApexNamePairsFromModules(result.TestContext, platformBootclasspath.configuredModules) + pairs := apexNamePairsFromModules(result.TestContext, platformBootclasspath.configuredModules, platformBootclasspath.libraryToApex) android.AssertDeepEquals(t, fmt.Sprintf("%s modules", "platform-bootclasspath"), expected, pairs) } @@ -666,23 +666,54 @@ func CheckClasspathFragmentProtoContentInfoProvider(t *testing.T, result *androi android.AssertPathRelativeToTopEquals(t, "install filepath", installDir, info.ClasspathFragmentProtoInstallDir) } -// ApexNamePairsFromModules returns the apex:module pair for the supplied modules. -func ApexNamePairsFromModules(ctx *android.TestContext, modules []android.Module) []string { +// CheckPlatformBootclasspathDependencies checks the dependencies of the selected module against the expected list. +// +// The expected list must be a list of strings of the form ":", where is the +// name of the apex, or platform is it is not part of an apex and is the module name. +func CheckPlatformBootclasspathDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) { + t.Helper() + platformBootclasspath := ctx.ModuleForTests(name, variant).Module().(*platformBootclasspathModule) + modules := []android.Module{} + ctx.VisitDirectDeps(platformBootclasspath, func(m blueprint.Module) { + modules = append(modules, m.(android.Module)) + }) + + pairs := apexNamePairsFromModules(ctx, modules, platformBootclasspath.libraryToApex) + android.AssertDeepEquals(t, "module dependencies", expected, pairs) +} + +// apexNamePairsFromModules returns the apex:module pair for the supplied modules. +func apexNamePairsFromModules(ctx *android.TestContext, modules []android.Module, modulesToApex map[android.Module]string) []string { pairs := []string{} for _, module := range modules { - pairs = append(pairs, apexNamePairFromModule(ctx, module)) + pairs = append(pairs, apexNamePairFromModule(ctx, module, modulesToApex)) + } + return pairs +} + +// ApexFragmentPairsFromModules returns the apex:fragment pair for the supplied fragments. +func ApexFragmentPairsFromModules(ctx *android.TestContext, fragments []android.Module, apexNameToFragment map[string]android.Module) []string { + pairs := []string{} + for _, fragment := range fragments { + found := false + for apex, apexFragment := range apexNameToFragment { + if apexFragment == fragment { + pairs = append(pairs, apex+":"+ctx.ModuleName(fragment)) + found = true + } + } + if !found { + pairs = append(pairs, "platform:"+ctx.ModuleName(fragment)) + } } return pairs } -func apexNamePairFromModule(ctx *android.TestContext, module android.Module) string { +func apexNamePairFromModule(ctx *android.TestContext, module android.Module, modulesToApex map[android.Module]string) string { name := module.Name() - var apex string - apexInfo, _ := android.OtherModuleProvider(ctx, module, android.ApexInfoProvider) - if apexInfo.IsForPlatform() { + apex := modulesToApex[module] + if apex == "" { apex = "platform" - } else { - apex = apexInfo.InApexVariants[0] } return fmt.Sprintf("%s:%s", apex, name) @@ -693,7 +724,7 @@ func apexNamePairFromModule(ctx *android.TestContext, module android.Module) str func CheckPlatformBootclasspathFragments(t *testing.T, result *android.TestResult, name string, expected []string) { t.Helper() platformBootclasspath := result.Module(name, "android_common").(*platformBootclasspathModule) - pairs := ApexNamePairsFromModules(result.TestContext, platformBootclasspath.fragments) + pairs := ApexFragmentPairsFromModules(result.TestContext, platformBootclasspath.fragments, platformBootclasspath.apexNameToFragment) android.AssertDeepEquals(t, fmt.Sprintf("%s fragments", "platform-bootclasspath"), expected, pairs) } diff --git a/rust/rust.go b/rust/rust.go index 90e5277b0..94f0a683d 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -2124,6 +2124,9 @@ func (mod *Module) OutgoingDepIsInSameApex(depTag blueprint.DependencyTag) bool } func (mod *Module) IncomingDepIsInSameApex(depTag blueprint.DependencyTag) bool { + if mod.Host() { + return false + } // TODO(b/362509506): remove once all apex_exclude uses are switched to stubs. if mod.ApexExclude() { return false diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go index 05915beef..ca630202a 100644 --- a/sdk/bootclasspath_fragment_sdk_test.go +++ b/sdk/bootclasspath_fragment_sdk_test.go @@ -66,6 +66,7 @@ func fixtureAddPrebuiltApexForBootclasspathFragment(apex, fragment string) andro exported_bootclasspath_fragments: [ "%s", ], + prefer: false, } `, apex, apexFile, fragment)), android.FixtureAddFile(filepath.Join(dir, apexFile), nil), @@ -226,8 +227,8 @@ java_import { checkBootJarsPackageCheckRule(t, result, append( []string{ - "out/soong/.intermediates/prebuilts/apex/com.android.art/android_common_com.android.art/deapexer/javalib/core1.jar", - "out/soong/.intermediates/prebuilts/apex/com.android.art/android_common_com.android.art/deapexer/javalib/core2.jar", + "out/soong/.intermediates/prebuilts/apex/com.android.art/android_common_prebuilt_com.android.art/deapexer/javalib/core1.jar", + "out/soong/.intermediates/prebuilts/apex/com.android.art/android_common_prebuilt_com.android.art/deapexer/javalib/core2.jar", "out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar", }, java.ApexBootJarDexJarPaths..., diff --git a/sdk/testing.go b/sdk/testing.go index f5518c46f..cd7bbf58e 100644 --- a/sdk/testing.go +++ b/sdk/testing.go @@ -281,7 +281,7 @@ func CheckSnapshot(t *testing.T, result *android.TestResult, name string, dir st // Run the snapshot with the snapshot preparer and the extra preparer, which must come after as // it may need to modify parts of the MockFS populated by the snapshot preparer. - result := android.GroupFixturePreparers(snapshotPreparer, extraPreparer, customizedPreparers). + result := android.GroupFixturePreparers(snapshotPreparer, customizedPreparers, extraPreparer). ExtendWithErrorHandler(customization.errorHandler). RunTest(t) @@ -314,6 +314,11 @@ func CheckSnapshot(t *testing.T, result *android.TestResult, name string, dir st snapshotBpFile := filepath.Join(snapshotSubDir, "Android.bp") unpreferred := string(fs[snapshotBpFile]) fs[snapshotBpFile] = []byte(strings.ReplaceAll(unpreferred, "prefer: false,", "prefer: true,")) + + prebuiltApexBpFile := "prebuilts/apex/Android.bp" + if prebuiltApexBp, ok := fs[prebuiltApexBpFile]; ok { + fs[prebuiltApexBpFile] = []byte(strings.ReplaceAll(string(prebuiltApexBp), "prefer: false,", "prefer: true,")) + } }) runSnapshotTestWithCheckers(t, checkSnapshotPreferredWithSource, preferPrebuilts) -- cgit v1.2.3-59-g8ed1b