Convert apex mutator to a TransitionMutator

Replace the apex mutator with a TransitionMutator.  Requires moving the
base.apexInfo value into a provider so that it is still present for the
Mutate pass.

Test: go test ./...
Test: no change to out/soong/build-${TARGET_PRODUCT}.ninja
Change-Id: I1c898eaf30b4021f0f96f439cc0b3b3173710fc7
This commit is contained in:
Colin Cross
2024-03-28 12:18:42 -07:00
parent 17b9a5b8b4
commit 7c035064db
3 changed files with 176 additions and 92 deletions

View File

@@ -90,7 +90,13 @@ type ApexInfo struct {
TestApexes []string
}
var ApexInfoProvider = blueprint.NewMutatorProvider[ApexInfo]("apex")
// AllApexInfo holds the ApexInfo of all apexes that include this module.
type AllApexInfo struct {
ApexInfos []ApexInfo
}
var ApexInfoProvider = blueprint.NewMutatorProvider[ApexInfo]("apex_mutate")
var AllApexInfoProvider = blueprint.NewMutatorProvider[*AllApexInfo]("apex_info")
func (i ApexInfo) AddJSONData(d *map[string]interface{}) {
(*d)["Apex"] = map[string]interface{}{
@@ -586,75 +592,131 @@ func mergeApexVariations(apexInfos []ApexInfo) (merged []ApexInfo, aliases [][2]
return merged, aliases
}
// CreateApexVariations mutates a given module into multiple apex variants each of which is for an
// apexBundle (and/or the platform) where the module is part of.
func CreateApexVariations(mctx BottomUpMutatorContext, module ApexModule) []Module {
// 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 this module has no apex variations the use the platform variation.
if len(apexInfos) == 0 {
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
}
// Shortcut
if len(base.apexInfos) == 0 {
return nil
if len(apexInfos) == 0 {
return
}
// Do some validity checks.
// TODO(jiyong): is this the right place?
base.checkApexAvailableProperty(mctx)
base.checkApexAvailableProperty(ctx)
apexInfos := base.apexInfos
// base.apexInfos is only needed to propagate the list of apexes from apexInfoMutator to
// apexMutator. It is no longer accurate after mergeApexVariations, and won't be copied to
// all but the first created variant. Clear it so it doesn't accidentally get used later.
base.apexInfos = nil
slices.SortFunc(apexInfos, func(a, b ApexInfo) int {
return strings.Compare(a.ApexVariationName, b.ApexVariationName)
})
var aliases [][2]string
if !mctx.Module().(ApexModule).UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps {
apexInfos, aliases = mergeApexVariations(apexInfos)
if !module.UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps {
apexInfos, _ = mergeApexVariations(apexInfos)
}
var inApex ApexMembership
for _, a := range apexInfos {
for _, apexContents := range a.ApexContents {
inApex = inApex.merge(apexContents.contents[mctx.ModuleName()])
inApex = inApex.merge(apexContents.contents[ctx.ModuleName()])
}
}
base.ApexProperties.InAnyApex = true
base.ApexProperties.DirectlyInAnyApex = inApex == directlyInApex
defaultVariation := ""
mctx.SetDefaultDependencyVariation(&defaultVariation)
if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) {
// 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()
}
if !platformVariation {
var thisApexInfo ApexInfo
variations := []string{defaultVariation}
testApexes := []string{}
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))
}
SetProvider(ctx, ApexInfoProvider, thisApexInfo)
}
// Set the value of TestApexes in every single apex variant.
// This allows each apex variant to be aware of the test apexes in the user provided apex_available.
var testApexes []string
for _, a := range apexInfos {
variations = append(variations, a.ApexVariationName)
testApexes = append(testApexes, a.TestApexes...)
}
modules := mctx.CreateVariations(variations...)
for i, mod := range modules {
platformVariation := i == 0
if platformVariation && !mctx.Host() && !mod.(ApexModule).AvailableFor(AvailableToPlatform) {
// 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
mod.MakeUninstallable()
}
if !platformVariation {
mctx.SetVariationProvider(mod, ApexInfoProvider, apexInfos[i-1])
}
// Set the value of TestApexes in every single apex variant.
// This allows each apex variant to be aware of the test apexes in the user provided apex_available.
mod.(ApexModule).apexModuleBase().ApexProperties.TestApexes = testApexes
}
base.ApexProperties.TestApexes = testApexes
for _, alias := range aliases {
mctx.CreateAliasVariation(alias[0], alias[1])
}
}
return modules
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
@@ -665,13 +727,16 @@ func UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext, am ApexModul
// InApexVariants list in common. It is used instead of DepIsInSameApex 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 []ApexInfo) bool {
collectApexes := func(infos []ApexInfo) []string {
var ret []string
for _, info := range infos {
ret = append(ret, info.InApexVariants...)
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 ret
return nil
}
aApexes := collectApexes(a)
@@ -689,7 +754,7 @@ func UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext, am ApexModul
// 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.apexModuleBase().apexInfos, am.apexModuleBase().apexInfos) &&
if anyInSameApex(depApexModule, am) &&
(depApexModule.UniqueApexVariations() ||
depApexModule.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps) {
am.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps = true