Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 757e88a9 authored by Colin Cross's avatar Colin Cross Committed by Gerrit Code Review
Browse files

Merge "Convert apex mutator to a TransitionMutator" into main

parents 68305164 7c035064
Loading
Loading
Loading
Loading
+118 −53
Original line number Diff line number Diff line
@@ -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()

	// Shortcut
	if len(base.apexInfos) == 0 {
		return nil
	var apexInfos []ApexInfo
	if allApexInfos, ok := ModuleProvider(ctx, AllApexInfoProvider); ok {
		apexInfos = allApexInfos.ApexInfos
	}

	// Do some validity checks.
	// TODO(jiyong): is this the right place?
	base.checkApexAvailableProperty(mctx)

	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
	// Dependencies from platform variations go to the platform variation.
	if incomingVariation == "" {
		return ""
	}

	slices.SortFunc(apexInfos, func(a, b ApexInfo) int {
		return strings.Compare(a.ApexVariationName, b.ApexVariationName)
	})
	// 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 !mctx.Module().(ApexModule).UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps {
	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(apexInfos) == 0 {
		return
	}

	// Do some validity checks.
	// TODO(jiyong): is this the right place?
	base.checkApexAvailableProperty(ctx)

	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)

	variations := []string{defaultVariation}
	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) {
	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
			mod.MakeUninstallable()
		module.MakeUninstallable()
	}
	if !platformVariation {
			mctx.SetVariationProvider(mod, ApexInfoProvider, apexInfos[i-1])
		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))
		}

		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.
		mod.(ApexModule).apexModuleBase().ApexProperties.TestApexes = testApexes
	var testApexes []string
	for _, a := range apexInfos {
		testApexes = append(testApexes, a.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,14 +727,17 @@ 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 {
	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 infos {
				for _, info := range allApexInfo.ApexInfos {
					ret = append(ret, info.InApexVariants...)
				}
				return ret
			}
			return nil
		}

		aApexes := collectApexes(a)
		bApexes := collectApexes(b)
@@ -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
+35 −30
Original line number Diff line number Diff line
@@ -73,7 +73,7 @@ func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
	// 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).Parallel()
	ctx.BottomUp("apex", apexMutator).Parallel()
	ctx.Transition("apex", &apexTransitionMutator{})
	ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).Parallel()
	ctx.BottomUp("apex_dcla_deps", apexDCLADepsMutator).Parallel()
	// Register after apex_info mutator so that it can use ApexVariationName
@@ -1084,6 +1084,10 @@ func apexInfoMutator(mctx android.TopDownMutatorContext) {
	if a, ok := mctx.Module().(ApexInfoMutator); ok {
		a.ApexInfoMutator(mctx)
	}

	if am, ok := mctx.Module().(android.ApexModule); ok {
		android.ApexInfoMutator(mctx, am)
	}
	enforceAppUpdatability(mctx)
}

@@ -1284,40 +1288,41 @@ func markPlatformAvailability(mctx android.BottomUpMutatorContext) {
	}
}

// apexMutator visits each module and creates apex variations if the module was marked in the
// previous run of apexInfoMutator.
func apexMutator(mctx android.BottomUpMutatorContext) {
	if !mctx.Module().Enabled() {
		return
	}

	// This is the usual path.
	if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
		android.CreateApexVariations(mctx, am)
		return
	}
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.
	// Note that a default variation "" is also created as an alias, and the default dependency
	// variation is set to the default variation. This is to allow an apex to depend on another
	// module which is outside of the apex. This is because the dependent module is not mutated
	// for this apex variant.
	createApexVariation := func(apexBundleName string) {
		defaultVariation := ""
		mctx.SetDefaultDependencyVariation(&defaultVariation)
		mctx.CreateVariations(apexBundleName)
		mctx.CreateAliasVariation(defaultVariation, apexBundleName)
	}

	if ai, ok := mctx.Module().(ApexInfoMutator); ok && apexModuleTypeRequiresVariant(ai) {
		createApexVariation(ai.ApexVariationName())
	} else if o, ok := mctx.Module().(*OverrideApex); ok {
	if ai, ok := ctx.Module().(ApexInfoMutator); ok && apexModuleTypeRequiresVariant(ai) {
		return []string{ai.ApexVariationName()}
	} else if o, ok := ctx.Module().(*OverrideApex); ok {
		apexBundleName := o.GetOverriddenModuleName()
		if apexBundleName == "" {
			mctx.ModuleErrorf("base property is not set")
			return
			ctx.ModuleErrorf("base property is not set")
		}
		createApexVariation(apexBundleName)
		return []string{apexBundleName}
	}
	return []string{""}
}

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 {
		return ai.ApexVariationName()
	} else if o, ok := ctx.Module().(*OverrideApex); ok {
		return o.GetOverriddenModuleName()
	}

	return ""
}

func (a *apexTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
	if am, ok := ctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
		android.MutateApexTransition(ctx, variation)
	}
}

+23 −9
Original line number Diff line number Diff line
@@ -711,7 +711,7 @@ var PrepareForTestWithFakeApexMutator = android.GroupFixturePreparers(

func registerFakeApexMutator(ctx android.RegistrationContext) {
	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
		ctx.BottomUp("apex", fakeApexMutator).Parallel()
		ctx.Transition("apex", &fakeApexMutator{})
	})
}

@@ -726,16 +726,30 @@ var _ apexModuleBase = (*SdkLibrary)(nil)
// `apex_available`. It helps us avoid a dependency on the real mutator defined in "soong-apex",
// which will cause a cyclic dependency, and it provides an easy way to create an APEX variant for
// testing without dealing with all the complexities in the real mutator.
func fakeApexMutator(mctx android.BottomUpMutatorContext) {
	switch mctx.Module().(type) {
type fakeApexMutator struct{}

func (f *fakeApexMutator) Split(ctx android.BaseModuleContext) []string {
	switch ctx.Module().(type) {
	case *Library, *SdkLibrary:
		if len(mctx.Module().(apexModuleBase).ApexAvailable()) > 0 {
			modules := mctx.CreateVariations("", "apex1000")
		return []string{"", "apex1000"}
	}
	return []string{""}
}

func (f *fakeApexMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
	return sourceVariation
}

func (f *fakeApexMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
	return incomingVariation
}

func (f *fakeApexMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
	if variation != "" {
		apexInfo := android.ApexInfo{
			ApexVariationName: "apex1000",
		}
			mctx.SetVariationProvider(modules[1], android.ApexInfoProvider, apexInfo)
		}
		android.SetProvider(ctx, android.ApexInfoProvider, apexInfo)
	}
}