Support min_sdk_version overrides in apexes
The use case for this are go apexes which are only installed in T and above, even though the base AOSP apexes might be installable on < T devices. If provided, the overridden min_sdk_version will be 1. Used as the `min_sdk_version` in the manifest file of the top-level override apex binary 2. Used to build the transitive closure of its dependency with that min_sdk_version, i.e. with a different apex variant. (2) requires some special handling. At ToT, the outgoing transition value is the base apex name (e.g. com.android.foo). Since min_sdk_version of the overridding apex can be different than the overridden apex, the base apex name is no longer sufficient. Instead, transition to the name of the overriding apex com.mycompany.android.foo. If deduping is possible, transitive deps will get deduped to `apex_<min_sdk_version>` later. Test: added a unit test Test: in internal, modified min_sdk_version of com.google.android.go.art locally, built BA and Go apexes, and used `aapt2 dump badging` to verify that BA has minSdkVersion of 31 and Go has minSdkVersion of 33 Bug: 295311875 Change-Id: Ifbe123d1517fccbc0c058042b8a6eeb3609b6787
This commit is contained in:
parent
b9c58350ca
commit
50801e20a3
4 changed files with 121 additions and 27 deletions
|
@ -37,11 +37,7 @@ var (
|
|||
// Accessible via `ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)`
|
||||
type ApexInfo struct {
|
||||
// Name of the apex variation that this module (i.e. the apex variant of the module) is
|
||||
// mutated into, or "" for a platform (i.e. non-APEX) variant. Note that this name and the
|
||||
// Soong module name of the APEX can be different. That happens when there is
|
||||
// `override_apex` that overrides `apex`. In that case, both Soong modules have the same
|
||||
// apex variation name which usually is `com.android.foo`. This name is also the `name`
|
||||
// in the path `/apex/<name>` where this apex is activated on at runtime.
|
||||
// mutated into, or "" for a platform (i.e. non-APEX) variant.
|
||||
//
|
||||
// Also note that a module can be included in multiple APEXes, in which case, the module is
|
||||
// mutated into one or more variants, each of which is for an APEX. The variants then can
|
||||
|
|
40
apex/apex.go
40
apex/apex.go
|
@ -137,10 +137,6 @@ type apexBundleProperties struct {
|
|||
// Rust binaries with prefer_rlib:true add unnecessary dependencies.
|
||||
Unwanted_transitive_deps []string
|
||||
|
||||
// The minimum SDK version that this APEX must support at minimum. This is usually set to
|
||||
// the SDK version that the APEX was first introduced.
|
||||
Min_sdk_version *string
|
||||
|
||||
// Whether this APEX is considered updatable or not. When set to true, this will enforce
|
||||
// additional rules for making sure that the APEX is truly updatable. To be updatable,
|
||||
// min_sdk_version should be set as well. This will also disable the size optimizations like
|
||||
|
@ -388,6 +384,10 @@ type overridableProperties struct {
|
|||
|
||||
// Trim against a specific Dynamic Common Lib APEX
|
||||
Trim_against *string
|
||||
|
||||
// The minimum SDK version that this APEX must support at minimum. This is usually set to
|
||||
// the SDK version that the APEX was first introduced.
|
||||
Min_sdk_version *string
|
||||
}
|
||||
|
||||
type apexBundle struct {
|
||||
|
@ -1035,6 +1035,11 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) {
|
|||
// be built for this apexBundle.
|
||||
|
||||
apexVariationName := mctx.ModuleName() // could be com.android.foo
|
||||
if overridable, ok := mctx.Module().(android.OverridableModule); ok && overridable.GetOverriddenBy() != "" {
|
||||
// use the overridden name com.mycompany.android.foo
|
||||
apexVariationName = overridable.GetOverriddenBy()
|
||||
}
|
||||
|
||||
a.properties.ApexVariationName = apexVariationName
|
||||
testApexes := []string{}
|
||||
if a.testApex {
|
||||
|
@ -1099,7 +1104,7 @@ func apexStrictUpdatibilityLintMutator(mctx android.TopDownMutatorContext) {
|
|||
if !mctx.Module().Enabled(mctx) {
|
||||
return
|
||||
}
|
||||
if apex, ok := mctx.Module().(*apexBundle); ok && apex.checkStrictUpdatabilityLinting() {
|
||||
if apex, ok := mctx.Module().(*apexBundle); ok && apex.checkStrictUpdatabilityLinting(mctx) {
|
||||
mctx.WalkDeps(func(child, parent android.Module) bool {
|
||||
// b/208656169 Do not propagate strict updatability linting to libcore/
|
||||
// These libs are available on the classpath during compilation
|
||||
|
@ -1193,8 +1198,9 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
func (a *apexBundle) checkStrictUpdatabilityLinting() bool {
|
||||
return a.Updatable() && !android.InList(a.ApexVariationName(), skipStrictUpdatabilityLintAllowlist)
|
||||
func (a *apexBundle) checkStrictUpdatabilityLinting(mctx android.TopDownMutatorContext) bool {
|
||||
// The allowlist contains the base apex name, so use that instead of the ApexVariationName
|
||||
return a.Updatable() && !android.InList(mctx.ModuleName(), skipStrictUpdatabilityLintAllowlist)
|
||||
}
|
||||
|
||||
// apexUniqueVariationsMutator checks if any dependencies use unique apex variations. If so, use
|
||||
|
@ -1295,13 +1301,12 @@ 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) {
|
||||
return []string{ai.ApexVariationName()}
|
||||
} else if o, ok := ctx.Module().(*OverrideApex); ok {
|
||||
apexBundleName := o.GetOverriddenModuleName()
|
||||
if apexBundleName == "" {
|
||||
ctx.ModuleErrorf("base property is not set")
|
||||
if overridable, ok := ctx.Module().(android.OverridableModule); ok && overridable.GetOverriddenBy() != "" {
|
||||
return []string{overridable.GetOverriddenBy()}
|
||||
}
|
||||
return []string{apexBundleName}
|
||||
return []string{ai.ApexVariationName()}
|
||||
} else if _, ok := ctx.Module().(*OverrideApex); ok {
|
||||
return []string{ctx.ModuleName()}
|
||||
}
|
||||
return []string{""}
|
||||
}
|
||||
|
@ -1314,9 +1319,12 @@ func (a *apexTransitionMutator) IncomingTransition(ctx android.IncomingTransitio
|
|||
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()
|
||||
} else if o, ok := ctx.Module().(*OverrideApex); ok {
|
||||
return o.GetOverriddenModuleName()
|
||||
} else if _, ok := ctx.Module().(*OverrideApex); ok {
|
||||
return ctx.Module().Name()
|
||||
}
|
||||
|
||||
return ""
|
||||
|
@ -2652,7 +2660,7 @@ func (a *apexBundle) minSdkVersionValue(ctx android.EarlyModuleContext) 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.
|
||||
minApiLevel := android.MinSdkVersionFromValue(ctx, proptools.String(a.properties.Min_sdk_version))
|
||||
minApiLevel := android.MinSdkVersionFromValue(ctx, proptools.String(a.overridableProperties.Min_sdk_version))
|
||||
if minApiLevel.IsNone() {
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -6463,7 +6463,7 @@ func TestApexAvailable_ApexAvailableNameWithVersionCode(t *testing.T) {
|
|||
t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion)
|
||||
}
|
||||
|
||||
overrideBarManifestRule := result.ModuleForTests("bar", "android_common_myoverrideapex_bar").Rule("apexManifestRule")
|
||||
overrideBarManifestRule := result.ModuleForTests("bar", "android_common_myoverrideapex_myoverrideapex").Rule("apexManifestRule")
|
||||
overrideBarActualDefaultVersion := overrideBarManifestRule.Args["default_version"]
|
||||
if overrideBarActualDefaultVersion != barExpectedDefaultVersion {
|
||||
t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion)
|
||||
|
@ -6843,7 +6843,7 @@ func TestOverrideApex(t *testing.T) {
|
|||
`, withManifestPackageNameOverrides([]string{"myapex:com.android.myapex"}))
|
||||
|
||||
originalVariant := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(android.OverridableModule)
|
||||
overriddenVariant := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex").Module().(android.OverridableModule)
|
||||
overriddenVariant := ctx.ModuleForTests("myapex", "android_common_override_myapex_override_myapex").Module().(android.OverridableModule)
|
||||
if originalVariant.GetOverriddenBy() != "" {
|
||||
t.Errorf("GetOverriddenBy should be empty, but was %q", originalVariant.GetOverriddenBy())
|
||||
}
|
||||
|
@ -6851,7 +6851,7 @@ func TestOverrideApex(t *testing.T) {
|
|||
t.Errorf("GetOverriddenBy should be \"override_myapex\", but was %q", overriddenVariant.GetOverriddenBy())
|
||||
}
|
||||
|
||||
module := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex")
|
||||
module := ctx.ModuleForTests("myapex", "android_common_override_myapex_override_myapex")
|
||||
apexRule := module.Rule("apexRule")
|
||||
copyCmds := apexRule.Args["copy_commands"]
|
||||
|
||||
|
@ -8943,7 +8943,7 @@ func TestAllowedFiles(t *testing.T) {
|
|||
t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
|
||||
}
|
||||
|
||||
rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex").Rule("diffApexContentRule")
|
||||
rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_override_myapex").Rule("diffApexContentRule")
|
||||
if expected, actual := "sub/allowed.txt", rule2.Args["allowed_files_file"]; expected != actual {
|
||||
t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
|
||||
}
|
||||
|
@ -11267,7 +11267,7 @@ func TestInstallationRulesForMultipleApexPrebuilts(t *testing.T) {
|
|||
variation := func(moduleName string) string {
|
||||
ret := "android_common_com.android.foo"
|
||||
if moduleName == "com.google.android.foo" {
|
||||
ret = "android_common_com.google.android.foo_com.android.foo"
|
||||
ret = "android_common_com.google.android.foo_com.google.android.foo"
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
@ -11571,3 +11571,79 @@ func TestMultiplePrebuiltsWithSameBase(t *testing.T) {
|
|||
android.AssertStringDoesContain(t, "not found", androidMk, "LOCAL_MODULE := etc_myfilename.myapex")
|
||||
android.AssertStringDoesContain(t, "not found", androidMk, "LOCAL_MODULE := etc_mysubdir_myfilename.myapex")
|
||||
}
|
||||
|
||||
func TestApexMinSdkVersionOverride(t *testing.T) {
|
||||
checkMinSdkVersion := func(t *testing.T, module android.TestingModule, expectedMinSdkVersion string) {
|
||||
args := module.Rule("apexRule").Args
|
||||
optFlags := args["opt_flags"]
|
||||
if !strings.Contains(optFlags, "--min_sdk_version "+expectedMinSdkVersion) {
|
||||
t.Errorf("%s: Expected min_sdk_version=%s, got: %s", module.Module(), expectedMinSdkVersion, optFlags)
|
||||
}
|
||||
}
|
||||
|
||||
checkHasDep := func(t *testing.T, ctx *android.TestContext, m android.Module, wantDep android.Module) {
|
||||
t.Helper()
|
||||
found := false
|
||||
ctx.VisitDirectDeps(m, func(dep blueprint.Module) {
|
||||
if dep == wantDep {
|
||||
found = true
|
||||
}
|
||||
})
|
||||
if !found {
|
||||
t.Errorf("Could not find a dependency from %v to %v\n", m, wantDep)
|
||||
}
|
||||
}
|
||||
|
||||
ctx := testApex(t, `
|
||||
apex {
|
||||
name: "com.android.apex30",
|
||||
min_sdk_version: "30",
|
||||
key: "apex30.key",
|
||||
java_libs: ["javalib"],
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "javalib",
|
||||
srcs: ["A.java"],
|
||||
apex_available: ["com.android.apex30"],
|
||||
min_sdk_version: "30",
|
||||
sdk_version: "current",
|
||||
}
|
||||
|
||||
override_apex {
|
||||
name: "com.mycompany.android.apex30",
|
||||
base: "com.android.apex30",
|
||||
}
|
||||
|
||||
override_apex {
|
||||
name: "com.mycompany.android.apex31",
|
||||
base: "com.android.apex30",
|
||||
min_sdk_version: "31",
|
||||
}
|
||||
|
||||
apex_key {
|
||||
name: "apex30.key",
|
||||
public_key: "testkey.avbpubkey",
|
||||
private_key: "testkey.pem",
|
||||
}
|
||||
|
||||
`, android.FixtureMergeMockFs(android.MockFS{
|
||||
"system/sepolicy/apex/com.android.apex30-file_contexts": nil,
|
||||
}),
|
||||
)
|
||||
|
||||
baseModule := ctx.ModuleForTests("com.android.apex30", "android_common_com.android.apex30")
|
||||
checkMinSdkVersion(t, baseModule, "30")
|
||||
|
||||
// Override module, but uses same min_sdk_version
|
||||
overridingModuleSameMinSdkVersion := ctx.ModuleForTests("com.android.apex30", "android_common_com.mycompany.android.apex30_com.mycompany.android.apex30")
|
||||
javalibApex30Variant := ctx.ModuleForTests("javalib", "android_common_apex30")
|
||||
checkMinSdkVersion(t, overridingModuleSameMinSdkVersion, "30")
|
||||
checkHasDep(t, ctx, overridingModuleSameMinSdkVersion.Module(), javalibApex30Variant.Module())
|
||||
|
||||
// Override module, uses different min_sdk_version
|
||||
overridingModuleDifferentMinSdkVersion := ctx.ModuleForTests("com.android.apex30", "android_common_com.mycompany.android.apex31_com.mycompany.android.apex31")
|
||||
javalibApex31Variant := ctx.ModuleForTests("javalib", "android_common_apex31")
|
||||
checkMinSdkVersion(t, overridingModuleDifferentMinSdkVersion, "31")
|
||||
checkHasDep(t, ctx, overridingModuleDifferentMinSdkVersion.Module(), javalibApex31Variant.Module())
|
||||
}
|
||||
|
|
|
@ -262,6 +262,20 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext, libName s
|
|||
if !isApexSystemServerJar {
|
||||
return true
|
||||
}
|
||||
ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
|
||||
allApexInfos := []android.ApexInfo{}
|
||||
if allApexInfosProvider, ok := android.ModuleProvider(ctx, android.AllApexInfoProvider); ok {
|
||||
allApexInfos = allApexInfosProvider.ApexInfos
|
||||
}
|
||||
if len(allApexInfos) > 0 && !ai.MinSdkVersion.EqualTo(allApexInfos[0].MinSdkVersion) {
|
||||
// Apex system server jars are dexpreopted and installed on to the system image.
|
||||
// Since we can have BigAndroid and Go variants of system server jar providing apexes,
|
||||
// and these two variants can have different min_sdk_versions, hide one of the apex variants
|
||||
// from make to prevent collisions.
|
||||
//
|
||||
// Unlike cc, min_sdk_version does not have an effect on the build actions of java libraries.
|
||||
ctx.Module().MakeUninstallable()
|
||||
}
|
||||
} else {
|
||||
// Don't preopt the platform variant of an APEX system server jar to avoid conflicts.
|
||||
if isApexSystemServerJar {
|
||||
|
@ -502,7 +516,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJa
|
|||
// Prebuilts are active, do not copy the dexpreopt'd source javalib to out/soong/system_server_dexjars
|
||||
// The javalib from the deapexed prebuilt will be copied to this location.
|
||||
// TODO (b/331665856): Implement a principled solution for this.
|
||||
copyApexSystemServerJarDex := !disableSourceApexVariant(ctx)
|
||||
copyApexSystemServerJarDex := !disableSourceApexVariant(ctx) && !ctx.Module().IsHideFromMake()
|
||||
dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
|
||||
ctx, globalSoong, global, dexpreoptConfig, appProductPackages, copyApexSystemServerJarDex)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in a new issue