diff --git a/java/aar.go b/java/aar.go index d5996ba02..3aa95d428 100644 --- a/java/aar.go +++ b/java/aar.go @@ -270,7 +270,7 @@ var extractAssetsRule = pctx.AndroidStaticRule("extractAssets", func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap, excludedLibs []string, - extraLinkFlags ...string) { + enforceDefaultTargetSdkVersion bool, extraLinkFlags ...string) { transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags := aaptLibs(ctx, sdkContext, classLoaderContexts) @@ -283,15 +283,16 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkCon manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile) manifestPath := ManifestFixer(ctx, manifestSrcPath, ManifestFixerParams{ - SdkContext: sdkContext, - ClassLoaderContexts: classLoaderContexts, - IsLibrary: a.isLibrary, - DefaultManifestVersion: a.defaultManifestVersion, - UseEmbeddedNativeLibs: a.useEmbeddedNativeLibs, - UsesNonSdkApis: a.usesNonSdkApis, - UseEmbeddedDex: a.useEmbeddedDex, - HasNoCode: a.hasNoCode, - LoggingParent: a.LoggingParent, + SdkContext: sdkContext, + ClassLoaderContexts: classLoaderContexts, + IsLibrary: a.isLibrary, + DefaultManifestVersion: a.defaultManifestVersion, + UseEmbeddedNativeLibs: a.useEmbeddedNativeLibs, + UsesNonSdkApis: a.usesNonSdkApis, + UseEmbeddedDex: a.useEmbeddedDex, + HasNoCode: a.hasNoCode, + LoggingParent: a.LoggingParent, + EnforceDefaultTargetSdkVersion: enforceDefaultTargetSdkVersion, }) // Add additional manifest files to transitive manifests. @@ -535,7 +536,7 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.aapt.isLibrary = true a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx) - a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, nil) + a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, nil, false) a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() diff --git a/java/android_manifest.go b/java/android_manifest.go index 522b6647a..c7853103f 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -43,13 +43,12 @@ var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger", // targetSdkVersion for manifest_fixer // When TARGET_BUILD_APPS is not empty, this method returns 10000 for modules targeting an unreleased SDK // This enables release builds (that run with TARGET_BUILD_APPS=[val...]) to target APIs that have not yet been finalized as part of an SDK -func targetSdkVersionForManifestFixer(ctx android.ModuleContext, sdkContext android.SdkContext) string { - targetSdkVersionSpec := sdkContext.TargetSdkVersion(ctx) - // Return 10000 for modules targeting "current" if either - // 1. The module is built in unbundled mode (TARGET_BUILD_APPS not empty) - // 2. The module is run as part of MTS, and should be testable on stable branches +func targetSdkVersionForManifestFixer(ctx android.ModuleContext, params ManifestFixerParams) string { + targetSdkVersionSpec := params.SdkContext.TargetSdkVersion(ctx) + + // Check if we want to return 10000 // TODO(b/240294501): Determine the rules for handling test apexes - if targetSdkVersionSpec.ApiLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module())) { + if shouldReturnFinalOrFutureInt(ctx, targetSdkVersionSpec, params.EnforceDefaultTargetSdkVersion) { return strconv.Itoa(android.FutureApiLevel.FinalOrFutureInt()) } targetSdkVersion, err := targetSdkVersionSpec.EffectiveVersionString(ctx) @@ -59,6 +58,17 @@ func targetSdkVersionForManifestFixer(ctx android.ModuleContext, sdkContext andr return targetSdkVersion } +// Return true for modules targeting "current" if either +// 1. The module is built in unbundled mode (TARGET_BUILD_APPS not empty) +// 2. The module is run as part of MTS, and should be testable on stable branches +// Do not return 10000 if we are enforcing default targetSdkVersion and sdk has been finalised +func shouldReturnFinalOrFutureInt(ctx android.ModuleContext, targetSdkVersionSpec android.SdkSpec, enforceDefaultTargetSdkVersion bool) bool { + if enforceDefaultTargetSdkVersion && ctx.Config().PlatformSdkFinal() { + return false + } + return targetSdkVersionSpec.ApiLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module())) +} + // Helper function that casts android.Module to java.androidTestApp // If this type conversion is possible, it queries whether the test app is included in an MTS suite func includedInMts(module android.Module) bool { @@ -69,16 +79,17 @@ func includedInMts(module android.Module) bool { } type ManifestFixerParams struct { - SdkContext android.SdkContext - ClassLoaderContexts dexpreopt.ClassLoaderContextMap - IsLibrary bool - DefaultManifestVersion string - UseEmbeddedNativeLibs bool - UsesNonSdkApis bool - UseEmbeddedDex bool - HasNoCode bool - TestOnly bool - LoggingParent string + SdkContext android.SdkContext + ClassLoaderContexts dexpreopt.ClassLoaderContextMap + IsLibrary bool + DefaultManifestVersion string + UseEmbeddedNativeLibs bool + UsesNonSdkApis bool + UseEmbeddedDex bool + HasNoCode bool + TestOnly bool + LoggingParent string + EnforceDefaultTargetSdkVersion bool } // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml @@ -137,7 +148,7 @@ func ManifestFixer(ctx android.ModuleContext, manifest android.Path, var argsMapper = make(map[string]string) if params.SdkContext != nil { - targetSdkVersion := targetSdkVersionForManifestFixer(ctx, params.SdkContext) + targetSdkVersion := targetSdkVersionForManifestFixer(ctx, params) args = append(args, "--targetSdkVersion ", targetSdkVersion) if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" { diff --git a/java/app.go b/java/app.go index dc02c683c..1955e2a73 100755 --- a/java/app.go +++ b/java/app.go @@ -101,6 +101,15 @@ type appProperties struct { PreventInstall bool `blueprint:"mutated"` IsCoverageVariant bool `blueprint:"mutated"` + // It can be set to test the behaviour of default target sdk version. + // Only required when updatable: false. It is an error if updatable: true and this is false. + Enforce_default_target_sdk_version *bool + + // If set, the targetSdkVersion for the target is set to the latest default API level. + // This would be by default false, unless updatable: true or + // enforce_default_target_sdk_version: true in which case this defaults to true. + EnforceDefaultTargetSdkVersion bool `blueprint:"mutated"` + // Whether this app is considered mainline updatable or not. When set to true, this will enforce // additional rules to make sure an app can safely be updated. Default is false. // Prefer using other specific properties if build behaviour must be changed; avoid using this @@ -296,6 +305,18 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { } else { ctx.PropertyErrorf("min_sdk_version", "%s", err.Error()) } + + if !BoolDefault(a.appProperties.Enforce_default_target_sdk_version, true) { + ctx.PropertyErrorf("enforce_default_target_sdk_version", "Updatable apps must enforce default target sdk version") + } + // TODO(b/227460469) after all the modules removes the target sdk version, throw an error if the target sdk version is explicitly set. + if a.deviceProperties.Target_sdk_version == nil { + a.SetEnforceDefaultTargetSdkVersion(true) + } + } + + if Bool(a.appProperties.Enforce_default_target_sdk_version) { + a.SetEnforceDefaultTargetSdkVersion(true) } a.checkPlatformAPI(ctx) @@ -427,7 +448,7 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { a.aapt.defaultManifestVersion = android.DefaultUpdatableModuleVersion } a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, - a.usesLibraryProperties.Exclude_uses_libs, aaptLinkFlags...) + a.usesLibraryProperties.Exclude_uses_libs, a.enforceDefaultTargetSdkVersion(), aaptLinkFlags...) // apps manifests are handled by aapt, don't let Module see them a.properties.Manifest = nil @@ -865,6 +886,14 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(ctx).String(), depsInfo) } +func (a *AndroidApp) enforceDefaultTargetSdkVersion() bool { + return a.appProperties.EnforceDefaultTargetSdkVersion +} + +func (a *AndroidApp) SetEnforceDefaultTargetSdkVersion(val bool) { + a.appProperties.EnforceDefaultTargetSdkVersion = val +} + func (a *AndroidApp) Updatable() bool { return Bool(a.appProperties.Updatable) } diff --git a/java/app_test.go b/java/app_test.go index 23635b960..e216c630b 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -3057,6 +3057,179 @@ func TestTargetSdkVersionManifestFixer(t *testing.T) { } } +func TestDefaultAppTargetSdkVersionForUpdatableModules(t *testing.T) { + platform_sdk_codename := "Tiramisu" + platform_sdk_version := 33 + testCases := []struct { + name string + platform_sdk_final bool + targetSdkVersionInBp *string + targetSdkVersionExpected *string + updatable bool + }{ + { + name: "Non-Updatable Module: Android.bp has older targetSdkVersion", + targetSdkVersionInBp: proptools.StringPtr("29"), + targetSdkVersionExpected: proptools.StringPtr("29"), + updatable: false, + }, + { + name: "Updatable Module: Android.bp has older targetSdkVersion", + targetSdkVersionInBp: proptools.StringPtr("30"), + targetSdkVersionExpected: proptools.StringPtr("30"), + updatable: true, + }, + { + name: "Updatable Module: Android.bp has no targetSdkVersion", + targetSdkVersionExpected: proptools.StringPtr("10000"), + updatable: true, + }, + { + name: "[SDK finalised] Non-Updatable Module: Android.bp has older targetSdkVersion", + platform_sdk_final: true, + targetSdkVersionInBp: proptools.StringPtr("30"), + targetSdkVersionExpected: proptools.StringPtr("30"), + updatable: false, + }, + { + name: "[SDK finalised] Updatable Module: Android.bp has older targetSdkVersion", + platform_sdk_final: true, + targetSdkVersionInBp: proptools.StringPtr("30"), + targetSdkVersionExpected: proptools.StringPtr("30"), + updatable: true, + }, + { + name: "[SDK finalised] Updatable Module: Android.bp has targetSdkVersion as platform sdk codename", + platform_sdk_final: true, + targetSdkVersionInBp: proptools.StringPtr(platform_sdk_codename), + targetSdkVersionExpected: proptools.StringPtr("33"), + updatable: true, + }, + { + name: "[SDK finalised] Updatable Module: Android.bp has no targetSdkVersion", + platform_sdk_final: true, + targetSdkVersionExpected: proptools.StringPtr("33"), + updatable: true, + }, + } + for _, testCase := range testCases { + bp := fmt.Sprintf(` + android_app { + name: "foo", + sdk_version: "current", + min_sdk_version: "29", + target_sdk_version: "%v", + updatable: %t, + enforce_default_target_sdk_version: %t + } + `, proptools.String(testCase.targetSdkVersionInBp), testCase.updatable, testCase.updatable) // enforce default target sdk version if app is updatable + + fixture := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.PrepareForTestWithAllowMissingDependencies, + android.PrepareForTestWithAndroidMk, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + // explicitly set following platform variables to make the test deterministic + variables.Platform_sdk_final = &testCase.platform_sdk_final + variables.Platform_sdk_version = &platform_sdk_version + variables.Platform_sdk_codename = &platform_sdk_codename + variables.Platform_version_active_codenames = []string{platform_sdk_codename} + variables.Unbundled_build_apps = []string{"sampleModule"} + }), + ) + + result := fixture.RunTestWithBp(t, bp) + foo := result.ModuleForTests("foo", "android_common") + + manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] + android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+*testCase.targetSdkVersionExpected) + } +} + +func TestEnforceDefaultAppTargetSdkVersionFlag(t *testing.T) { + platform_sdk_codename := "Tiramisu" + platform_sdk_version := 33 + testCases := []struct { + name string + enforceDefaultTargetSdkVersion bool + expectedError string + platform_sdk_final bool + targetSdkVersionInBp string + targetSdkVersionExpected string + updatable bool + }{ + { + name: "Not enforcing Target SDK Version: Android.bp has older targetSdkVersion", + enforceDefaultTargetSdkVersion: false, + targetSdkVersionInBp: "29", + targetSdkVersionExpected: "29", + updatable: false, + }, + { + name: "[SDK finalised] Enforce Target SDK Version: Android.bp has current targetSdkVersion", + enforceDefaultTargetSdkVersion: true, + platform_sdk_final: true, + targetSdkVersionInBp: "current", + targetSdkVersionExpected: "33", + updatable: true, + }, + { + name: "[SDK finalised] Enforce Target SDK Version: Android.bp has current targetSdkVersion", + enforceDefaultTargetSdkVersion: true, + platform_sdk_final: false, + targetSdkVersionInBp: "current", + targetSdkVersionExpected: "10000", + updatable: false, + }, + { + name: "Not enforcing Target SDK Version for Updatable app", + enforceDefaultTargetSdkVersion: false, + expectedError: "Updatable apps must enforce default target sdk version", + targetSdkVersionInBp: "29", + targetSdkVersionExpected: "29", + updatable: true, + }, + } + for _, testCase := range testCases { + errExpected := testCase.expectedError != "" + bp := fmt.Sprintf(` + android_app { + name: "foo", + enforce_default_target_sdk_version: %t, + sdk_version: "current", + min_sdk_version: "29", + target_sdk_version: "%v", + updatable: %t + } + `, testCase.enforceDefaultTargetSdkVersion, testCase.targetSdkVersionInBp, testCase.updatable) + + fixture := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.PrepareForTestWithAllowMissingDependencies, + android.PrepareForTestWithAndroidMk, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + // explicitly set following platform variables to make the test deterministic + variables.Platform_sdk_final = &testCase.platform_sdk_final + variables.Platform_sdk_version = &platform_sdk_version + variables.Platform_sdk_codename = &platform_sdk_codename + variables.Unbundled_build_apps = []string{"sampleModule"} + }), + ) + + errorHandler := android.FixtureExpectsNoErrors + if errExpected { + errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.expectedError) + } + result := fixture.ExtendWithErrorHandler(errorHandler).RunTestWithBp(t, bp) + + if !errExpected { + foo := result.ModuleForTests("foo", "android_common") + manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] + android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) + } + } +} + func TestAppMissingCertificateAllowMissingDependencies(t *testing.T) { result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, diff --git a/java/rro.go b/java/rro.go index 3a92b0cf2..cd8c635ff 100644 --- a/java/rro.go +++ b/java/rro.go @@ -142,7 +142,7 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC aaptLinkFlags = append(aaptLinkFlags, "--rename-overlay-target-package "+*r.overridableProperties.Target_package_name) } - r.aapt.buildActions(ctx, r, nil, nil, aaptLinkFlags...) + r.aapt.buildActions(ctx, r, nil, nil, false, aaptLinkFlags...) // Sign the built package _, _, certificates := collectAppDeps(ctx, r, false, false)