From 5ef7d7b7778ef073f07cddcf8bc71f9754784401 Mon Sep 17 00:00:00 2001 From: Pedro Loureiro Date: Thu, 17 Mar 2022 12:41:31 +0000 Subject: [PATCH] Allow unknown codenames in target sdk version for APK-in-apexes This is currently a recurring issue every new Android release as a few of our apps will be targeting new platforms and they also get installed on devices running older SDKs. This change only changes behaviour for APK in apexes. Test: atest com.android.server.pm.parsing.PackageParserLegacyCoreTest Bug: 208239394 Merged-In: If1195c8ec39ac88a605e25dfb1c78d49a5aa3e7c Change-Id: If1195c8ec39ac88a605e25dfb1c78d49a5aa3e7c --- Android.bp | 1 + .../content/pm/parsing/ApkLiteParseUtils.java | 3 +- .../parsing/FrameworkParsingPackageUtils.java | 28 ++++-- framework-jarjar-rules.txt | 3 + .../com/android/server/pm/InitAppsHelper.java | 4 +- .../pm/pkg/parsing/ParsingPackageUtils.java | 13 ++- .../parsing/PackageParserLegacyCoreTest.java | 98 ++++++++++++++----- 7 files changed, 105 insertions(+), 45 deletions(-) diff --git a/Android.bp b/Android.bp index 149b22355c58..a6fe4616e8e3 100644 --- a/Android.bp +++ b/Android.bp @@ -326,6 +326,7 @@ java_defaults { "av-types-aidl-java", "tv_tuner_resource_manager_aidl_interface-java", "soundtrigger_middleware-aidl-java", + "modules-utils-build", "modules-utils-preconditions", "modules-utils-synchronous-result-receiver", "modules-utils-os", diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 5680bcd2e2e6..cb55e303e778 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -568,7 +568,8 @@ public class ApkLiteParseUtils { } ParseResult targetResult = FrameworkParsingPackageUtils.computeTargetSdkVersion( - targetVer, targetCode, SDK_CODENAMES, input); + targetVer, targetCode, SDK_CODENAMES, input, + /* allowUnknownCodenames= */ false); if (targetResult.isError()) { return input.error(targetResult); } diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java index a65b6815f8ad..6d74b819301d 100644 --- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java @@ -36,6 +36,7 @@ import android.util.Slog; import android.util.apk.ApkSignatureVerifier; import com.android.internal.util.ArrayUtils; +import com.android.modules.utils.build.UnboundedSdkLevel; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; @@ -334,8 +335,9 @@ public class FrameworkParsingPackageUtils { * If {@code targetCode} is not specified, e.g. the value is {@code null}, then the {@code * targetVers} will be returned unmodified. *

- * Otherwise, the behavior varies based on whether the current platform is a pre-release - * version, e.g. the {@code platformSdkCodenames} array has length > 0: + * When {@code allowUnknownCodenames} is false, the behavior varies based on whether the + * current platform is a pre-release version, e.g. the {@code platformSdkCodenames} array has + * length > 0: *

+ *

+ * When {@code allowUnknownCodenames} is true, any codename that is not known (presumed to be + * a codename announced after the build of the current device) is allowed and this method will + * return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}. * - * @param targetVers targetSdkVersion number, if specified in the application - * manifest, or 0 otherwise - * @param targetCode targetSdkVersion code, if specified in the application manifest, - * or {@code null} otherwise - * @param platformSdkCodenames array of allowed pre-release SDK codenames for this platform + * @param targetVers targetSdkVersion number, if specified in the application + * manifest, or 0 otherwise + * @param targetCode targetSdkVersion code, if specified in the application manifest, + * or {@code null} otherwise + * @param platformSdkCodenames array of allowed pre-release SDK codenames for this platform + * @param allowUnknownCodenames allow unknown codenames, if true this method will accept unknown + * (presumed to be future) codenames * @return the targetSdkVersion to use at runtime if successful */ public static ParseResult computeTargetSdkVersion(@IntRange(from = 0) int targetVers, @Nullable String targetCode, @NonNull String[] platformSdkCodenames, - @NonNull ParseInput input) { + @NonNull ParseInput input, boolean allowUnknownCodenames) { // If it's a release SDK, return the version number unmodified. if (targetCode == null) { return input.success(targetVers); } + if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) { + return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT); + } + // If it's a pre-release SDK and the codename matches this platform, it // definitely targets this SDK. if (matchTargetCode(platformSdkCodenames, targetCode)) { diff --git a/framework-jarjar-rules.txt b/framework-jarjar-rules.txt index be21f4e87101..03b268d87d01 100644 --- a/framework-jarjar-rules.txt +++ b/framework-jarjar-rules.txt @@ -5,3 +5,6 @@ rule android.hidl.** android.internal.hidl.@1 # Framework-specific renames. rule android.net.wifi.WifiAnnotations* android.internal.wifi.WifiAnnotations@1 rule com.android.server.vcn.util.** com.android.server.vcn.repackaged.util.@1 + +# for modules-utils-build dependency +rule com.android.modules.utils.build.** android.internal.modules.utils.build.@1 diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java index 15f26e7a6d6c..154f32a2e436 100644 --- a/services/core/java/com/android/server/pm/InitAppsHelper.java +++ b/services/core/java/com/android/server/pm/InitAppsHelper.java @@ -30,7 +30,7 @@ import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX; import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN; import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS; import static com.android.server.pm.PackageManagerService.TAG; -import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_CHECK_MAX_SDK_VERSION; +import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_APK_IN_APEX; import android.annotation.NonNull; import android.annotation.Nullable; @@ -359,7 +359,7 @@ final class InitAppsHelper { try { if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) { // when scanning apk in apexes, we want to check the maxSdkVersion - parseFlags |= PARSE_CHECK_MAX_SDK_VERSION; + parseFlags |= PARSE_APK_IN_APEX; } mInstallPackageHelper.installPackagesFromDir(scanDir, frameworkSplits, parseFlags, scanFlags, packageParser, executorService); diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java index f255db4a9801..9897c42e4cec 100644 --- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java +++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java @@ -209,8 +209,6 @@ public class ParsingPackageUtils { public static final int SDK_VERSION = Build.VERSION.SDK_INT; public static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES; - public static final String[] PREVIOUS_CODENAMES = - Build.VERSION.KNOWN_CODENAMES.toArray(new String[]{}); public static boolean sCompatibilityModeEnabled = true; public static boolean sUseRoundIcon = false; @@ -238,7 +236,7 @@ public class ParsingPackageUtils { */ public static final int PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY = 1 << 7; public static final int PARSE_FRAMEWORK_RES_SPLITS = 1 << 8; - public static final int PARSE_CHECK_MAX_SDK_VERSION = 1 << 9; + public static final int PARSE_APK_IN_APEX = 1 << 9; public static final int PARSE_CHATTY = 1 << 31; @@ -1534,7 +1532,7 @@ public class ParsingPackageUtils { ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags) throws IOException, XmlPullParserException { if (SDK_VERSION > 0) { - final boolean checkMaxSdkVersion = (flags & PARSE_CHECK_MAX_SDK_VERSION) != 0; + final boolean isApkInApex = (flags & PARSE_APK_IN_APEX) != 0; TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk); try { int minVers = ParsingUtils.DEFAULT_MIN_SDK_VERSION; @@ -1569,7 +1567,7 @@ public class ParsingPackageUtils { targetCode = minCode; } - if (checkMaxSdkVersion) { + if (isApkInApex) { val = sa.peekValue(R.styleable.AndroidManifestUsesSdk_maxSdkVersion); if (val != null) { // maxSdkVersion only supports integer @@ -1578,7 +1576,8 @@ public class ParsingPackageUtils { } ParseResult targetSdkVersionResult = FrameworkParsingPackageUtils - .computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, input); + .computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, input, + isApkInApex); if (targetSdkVersionResult.isError()) { return input.error(targetSdkVersionResult); } @@ -1601,7 +1600,7 @@ public class ParsingPackageUtils { pkg.setMinSdkVersion(minSdkVersion) .setTargetSdkVersion(targetSdkVersion); - if (checkMaxSdkVersion) { + if (isApkInApex) { ParseResult maxSdkVersionResult = FrameworkParsingPackageUtils .computeMaxSdkVersion(maxVers, SDK_VERSION, input); if (maxSdkVersionResult.isError()) { diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java index 004d7bc2707c..07cca0ca6ba0 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java @@ -84,15 +84,15 @@ import java.util.function.Function; @RunWith(AndroidJUnit4.class) public class PackageParserLegacyCoreTest { private static final String RELEASED = null; - private static final String OLDER_PRE_RELEASE = "A"; - private static final String PRE_RELEASE = "B"; - private static final String NEWER_PRE_RELEASE = "C"; + private static final String OLDER_PRE_RELEASE = "Q"; + private static final String PRE_RELEASE = "R"; + private static final String NEWER_PRE_RELEASE = "Z"; // Codenames with a fingerprint attached to them. These may only be present in the apps // declared min SDK and not as platform codenames. - private static final String OLDER_PRE_RELEASE_WITH_FINGERPRINT = "A.fingerprint"; - private static final String PRE_RELEASE_WITH_FINGERPRINT = "B.fingerprint"; - private static final String NEWER_PRE_RELEASE_WITH_FINGERPRINT = "C.fingerprint"; + private static final String OLDER_PRE_RELEASE_WITH_FINGERPRINT = "Q.fingerprint"; + private static final String PRE_RELEASE_WITH_FINGERPRINT = "R.fingerprint"; + private static final String NEWER_PRE_RELEASE_WITH_FINGERPRINT = "Z.fingerprint"; private static final String[] CODENAMES_RELEASED = { /* empty */}; private static final String[] CODENAMES_PRE_RELEASE = {PRE_RELEASE}; @@ -199,13 +199,14 @@ public class PackageParserLegacyCoreTest { } private void verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename, - boolean isPlatformReleased, int expectedTargetSdk) { + boolean isPlatformReleased, boolean allowUnknownCodenames, int expectedTargetSdk) { final ParseTypeImpl input = ParseTypeImpl.forParsingWithoutPlatformCompat(); final ParseResult result = FrameworkParsingPackageUtils.computeTargetSdkVersion( targetSdkVersion, targetSdkCodename, isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE, - input); + input, + allowUnknownCodenames); if (expectedTargetSdk == -1) { assertTrue(result.isError()); @@ -220,40 +221,61 @@ public class PackageParserLegacyCoreTest { // Do allow older release targetSdkVersion on pre-release platform. // APP: Released API 10 // DEV: Pre-release API 20 - verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, false, OLDER_VERSION); + verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, false, false, OLDER_VERSION); // Do allow same release targetSdkVersion on pre-release platform. // APP: Released API 20 // DEV: Pre-release API 20 - verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, false, PLATFORM_VERSION); + verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, false, false, PLATFORM_VERSION); // Do allow newer release targetSdkVersion on pre-release platform. // APP: Released API 30 // DEV: Pre-release API 20 - verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, false, NEWER_VERSION); + verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, false, false, NEWER_VERSION); // Don't allow older pre-release targetSdkVersion on pre-release platform. // APP: Pre-release API 10 // DEV: Pre-release API 20 - verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1); - verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, -1); + verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, false, -1); + verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, + false, -1 + ); + // Don't allow older pre-release targetSdkVersion on pre-release platform when + // allowUnknownCodenames is true. + // APP: Pre-release API 10 + // DEV: Pre-release API 20 + verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, + true, -1); + verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, + true, -1); // Do allow same pre-release targetSdkVersion on pre-release platform, // but overwrite the specified version with CUR_DEVELOPMENT. // APP: Pre-release API 20 // DEV: Pre-release API 20 verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false, - Build.VERSION_CODES.CUR_DEVELOPMENT); + false, Build.VERSION_CODES.CUR_DEVELOPMENT); verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, false, - Build.VERSION_CODES.CUR_DEVELOPMENT); - + false, Build.VERSION_CODES.CUR_DEVELOPMENT); // Don't allow newer pre-release targetSdkVersion on pre-release platform. // APP: Pre-release API 30 // DEV: Pre-release API 20 - verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1); - verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, -1); + verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, false, -1); + verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, + false, -1 + ); + + // Do allow newer pre-release targetSdkVersion on pre-release platform when + // allowUnknownCodenames is true. + // APP: Pre-release API 30 + // DEV: Pre-release API 20 + verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, + true, Build.VERSION_CODES.CUR_DEVELOPMENT); + verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, + true, Build.VERSION_CODES.CUR_DEVELOPMENT); + } @Test @@ -261,36 +283,58 @@ public class PackageParserLegacyCoreTest { // Do allow older release targetSdkVersion on released platform. // APP: Released API 10 // DEV: Released API 20 - verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, true, OLDER_VERSION); + verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, true, false, OLDER_VERSION); // Do allow same release targetSdkVersion on released platform. // APP: Released API 20 // DEV: Released API 20 - verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, true, PLATFORM_VERSION); + verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, true, false, PLATFORM_VERSION); // Do allow newer release targetSdkVersion on released platform. // APP: Released API 30 // DEV: Released API 20 - verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, true, NEWER_VERSION); + verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, true, false, NEWER_VERSION); // Don't allow older pre-release targetSdkVersion on released platform. // APP: Pre-release API 10 // DEV: Released API 20 - verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1); - verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, -1); + verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, false, -1); + verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, + false, -1 + ); // Don't allow same pre-release targetSdkVersion on released platform. // APP: Pre-release API 20 // DEV: Released API 20 - verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1); - verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, -1); + verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, false, -1); + verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, false, + -1 + ); + // Don't allow same pre-release targetSdkVersion on released platform when + // allowUnknownCodenames is true. + // APP: Pre-release API 20 + // DEV: Released API 20 + verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, true, + -1); + verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, true, + -1); // Don't allow newer pre-release targetSdkVersion on released platform. // APP: Pre-release API 30 // DEV: Released API 20 - verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1); - verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, -1); + verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, false, -1); + verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, + false, -1 + ); + // Do allow newer pre-release targetSdkVersion on released platform when + // allowUnknownCodenames is true. + // APP: Pre-release API 30 + // DEV: Released API 20 + verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, true, + Build.VERSION_CODES.CUR_DEVELOPMENT); + verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, + true, Build.VERSION_CODES.CUR_DEVELOPMENT); } /**