diff options
author | 2025-02-11 11:40:13 -0800 | |
---|---|---|
committer | 2025-02-11 11:40:13 -0800 | |
commit | 1dc3511441bae21a32481a22ef7ce8f61a7a2388 (patch) | |
tree | 4ef8d45c9ba3ab91eff15d5b8e4840b093dc017e | |
parent | 434953e9547aaa6d21c7a124a89f9a3695a9fc4d (diff) | |
parent | 6db3e6ffd9b89424d1c78917f80bfaf071c41902 (diff) |
Merge changes from topics "apex_transition_info", "bcp_dependency_through_apex" into main am: 5c846d8349 am: 6db3e6ffd9
Original change: https://android-review.googlesource.com/c/platform/build/soong/+/3470502
Change-Id: I9557fe50d5bdae792487fbc06e64c4b9473c65a9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | android/Android.bp | 1 | ||||
-rw-r--r-- | android/apex.go | 315 | ||||
-rw-r--r-- | android/apex_test.go | 277 | ||||
-rw-r--r-- | android/api_levels.go | 6 | ||||
-rw-r--r-- | android/container.go | 14 | ||||
-rw-r--r-- | android/deapexer.go | 2 | ||||
-rw-r--r-- | apex/apex.go | 168 | ||||
-rw-r--r-- | apex/apex_test.go | 94 | ||||
-rw-r--r-- | apex/bootclasspath_fragment_test.go | 7 | ||||
-rw-r--r-- | apex/builder.go | 2 | ||||
-rw-r--r-- | apex/container_test.go | 3 | ||||
-rw-r--r-- | apex/dexpreopt_bootjars_test.go | 6 | ||||
-rw-r--r-- | apex/platform_bootclasspath_test.go | 32 | ||||
-rw-r--r-- | apex/prebuilt.go | 121 | ||||
-rw-r--r-- | apex/systemserver_classpath_fragment_test.go | 12 | ||||
-rw-r--r-- | cc/cc.go | 4 | ||||
-rw-r--r-- | java/bootclasspath_fragment.go | 12 | ||||
-rw-r--r-- | java/dexpreopt.go | 3 | ||||
-rw-r--r-- | java/hiddenapi_singleton.go | 4 | ||||
-rw-r--r-- | java/java.go | 1 | ||||
-rw-r--r-- | java/platform_bootclasspath.go | 2 | ||||
-rw-r--r-- | java/systemserver_classpath_fragment.go | 1 | ||||
-rw-r--r-- | java/testing.go | 53 | ||||
-rw-r--r-- | rust/rust.go | 3 | ||||
-rw-r--r-- | sdk/bootclasspath_fragment_sdk_test.go | 5 | ||||
-rw-r--r-- | sdk/testing.go | 7 |
26 files changed, 344 insertions, 811 deletions
diff --git a/android/Android.bp b/android/Android.bp index 75027b182..540d65bd4 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 d86fea60c..601961f06 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 911d133dc..04816580d 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 ( @@ -1683,10 +1635,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() { @@ -1705,8 +1653,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) @@ -1731,8 +1678,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) @@ -2585,7 +2531,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. @@ -2609,7 +2555,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)) } @@ -2625,7 +2571,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. @@ -2739,7 +2685,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 @@ -2757,7 +2703,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 06f1cdf05..6c1a2d66b 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 63efa6332..03a0bb902 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -1105,7 +1105,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 "<apex>:<module>", where <apex> is the -// name of the apex, or platform is it is not part of an apex and <module> 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) @@ -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 c1ce880d6..846e32237 100644 --- a/java/java.go +++ b/java/java.go @@ -3546,7 +3546,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 7f1698646..0a032526c 100644 --- a/java/testing.go +++ b/java/testing.go @@ -650,7 +650,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) } @@ -665,23 +665,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 "<apex>:<module>", where <apex> is the +// name of the apex, or platform is it is not part of an apex and <module> 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) @@ -692,7 +723,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 dfd39f739..ad68d6041 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) |