diff --git a/android/apex.go b/android/apex.go index dc0aeed17..fcbd13ea2 100644 --- a/android/apex.go +++ b/android/apex.go @@ -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/` 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 diff --git a/apex/apex.go b/apex/apex.go index bc2b032bf..1dec61b6d 100644 --- a/apex/apex.go +++ b/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 "" } diff --git a/apex/apex_test.go b/apex/apex_test.go index b14600e80..a2c889647 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -6476,7 +6476,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) @@ -6856,7 +6856,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()) } @@ -6864,7 +6864,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"] @@ -8956,7 +8956,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) } @@ -11294,7 +11294,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 } @@ -11598,3 +11598,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()) +} diff --git a/java/app.go b/java/app.go index f05b8a7cd..bab413097 100644 --- a/java/app.go +++ b/java/app.go @@ -338,23 +338,12 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.generateJavaUsedByApex(ctx) } -func (a *AndroidApp) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { - defaultMinSdkVersion := a.Module.MinSdkVersion(ctx) - if proptools.Bool(a.appProperties.Updatable) { - overrideApiLevel := android.MinSdkVersionFromValue(ctx, ctx.DeviceConfig().ApexGlobalMinSdkVersionOverride()) - if !overrideApiLevel.IsNone() && overrideApiLevel.CompareTo(defaultMinSdkVersion) > 0 { - return overrideApiLevel - } - } - return defaultMinSdkVersion -} - func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { if a.Updatable() { if !a.SdkVersion(ctx).Stable() { ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.SdkVersion(ctx)) } - if String(a.deviceProperties.Min_sdk_version) == "" { + if String(a.overridableProperties.Min_sdk_version) == "" { ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.") } diff --git a/java/app_test.go b/java/app_test.go index a7c48a1ed..804949435 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -4322,52 +4322,6 @@ func TestPrivappAllowlistAndroidMk(t *testing.T) { ) } -func TestApexGlobalMinSdkVersionOverride(t *testing.T) { - result := android.GroupFixturePreparers( - PrepareForTestWithJavaDefaultModules, - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.ApexGlobalMinSdkVersionOverride = proptools.StringPtr("Tiramisu") - }), - ).RunTestWithBp(t, ` - android_app { - name: "com.android.bar", - srcs: ["a.java"], - sdk_version: "current", - } - android_app { - name: "com.android.foo", - srcs: ["a.java"], - sdk_version: "current", - min_sdk_version: "S", - updatable: true, - } - override_android_app { - name: "com.android.go.foo", - base: "com.android.foo", - } - `) - foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer") - fooOverride := result.ModuleForTests("com.android.foo", "android_common_com.android.go.foo").Rule("manifestFixer") - bar := result.ModuleForTests("com.android.bar", "android_common").Rule("manifestFixer") - - android.AssertStringDoesContain(t, - "expected manifest fixer to set com.android.bar minSdkVersion to S", - bar.BuildParams.Args["args"], - "--minSdkVersion S", - ) - android.AssertStringDoesContain(t, - "com.android.foo: expected manifest fixer to set minSdkVersion to T", - foo.BuildParams.Args["args"], - "--minSdkVersion T", - ) - android.AssertStringDoesContain(t, - "com.android.go.foo: expected manifest fixer to set minSdkVersion to T", - fooOverride.BuildParams.Args["args"], - "--minSdkVersion T", - ) - -} - func TestAppFlagsPackages(t *testing.T) { ctx := testApp(t, ` android_app { @@ -4492,3 +4446,36 @@ func TestAppStem(t *testing.T) { t.Errorf("Module output does not contain expected apk %s", "foo-new.apk") } } + +func TestAppMinSdkVersionOverride(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + ).RunTestWithBp(t, ` + android_app { + name: "com.android.foo", + srcs: ["a.java"], + sdk_version: "current", + min_sdk_version: "31", + updatable: true, + } + override_android_app { + name: "com.android.go.foo", + base: "com.android.foo", + min_sdk_version: "33", + } + `) + foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer") + fooOverride := result.ModuleForTests("com.android.foo", "android_common_com.android.go.foo").Rule("manifestFixer") + + android.AssertStringDoesContain(t, + "com.android.foo: expected manifest fixer to set minSdkVersion to T", + foo.BuildParams.Args["args"], + "--minSdkVersion 31", + ) + android.AssertStringDoesContain(t, + "com.android.go.foo: expected manifest fixer to set minSdkVersion to T", + fooOverride.BuildParams.Args["args"], + "--minSdkVersion 33", + ) + +} diff --git a/java/base.go b/java/base.go index 0c2867177..e97d28de2 100644 --- a/java/base.go +++ b/java/base.go @@ -229,10 +229,6 @@ type DeviceProperties struct { // If the SDK kind is empty, it will be set to public. Sdk_version *string - // if not blank, set the minimum version of the sdk that the compiled artifacts will run against. - // Defaults to sdk_version if not set. See sdk_version for possible values. - Min_sdk_version *string - // if not blank, set the maximum version of the sdk that the compiled artifacts will run against. // Defaults to empty string "". See sdk_version for possible values. Max_sdk_version *string @@ -312,6 +308,10 @@ type OverridableProperties struct { // Otherwise, both the overridden and the overriding modules will have the same output name, which // can cause the duplicate output error. Stem *string + + // if not blank, set the minimum version of the sdk that the compiled artifacts will run against. + // Defaults to sdk_version if not set. See sdk_version for possible values. + Min_sdk_version *string } // Functionality common to Module and Import @@ -738,8 +738,8 @@ func (j *Module) SystemModules() string { } func (j *Module) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { - if j.deviceProperties.Min_sdk_version != nil { - return android.ApiLevelFrom(ctx, *j.deviceProperties.Min_sdk_version) + if j.overridableProperties.Min_sdk_version != nil { + return android.ApiLevelFrom(ctx, *j.overridableProperties.Min_sdk_version) } return j.SdkVersion(ctx).ApiLevel } diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 1acac1b40..4d6dbffe1 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -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 { diff --git a/java/java.go b/java/java.go index 0df96a3a5..f038f634b 100644 --- a/java/java.go +++ b/java/java.go @@ -908,7 +908,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Check min_sdk_version of the transitive dependencies if this module is created from // java_sdk_library. - if j.deviceProperties.Min_sdk_version != nil && j.SdkLibraryName() != nil { + if j.overridableProperties.Min_sdk_version != nil && j.SdkLibraryName() != nil { j.CheckDepsMinSdkVersion(ctx) } @@ -1096,7 +1096,7 @@ func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberCo // If the min_sdk_version was set then add the canonical representation of the API level to the // snapshot. - if j.deviceProperties.Min_sdk_version != nil { + if j.overridableProperties.Min_sdk_version != nil { canonical, err := android.ReplaceFinalizedCodenames(ctx.SdkModuleContext().Config(), j.minSdkVersion.String()) if err != nil { ctx.ModuleErrorf("%s", err) diff --git a/java/sdk_library.go b/java/sdk_library.go index 677b32a5e..2d7ea6351 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -1842,6 +1842,7 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) &module.dexProperties, &module.dexpreoptProperties, &module.linter.properties, + &module.overridableProperties, &props, module.sdkComponentPropertiesForChildLibrary(), }