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 a758caf5b..b9c2f9286 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -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()) +} 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 {