Merge "Allow apps with pre-release SDK in REL configuration." into main
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c15b3e0..09b9bda 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1949,6 +1949,8 @@
         int type;
         boolean foundApp = false;
 
+        String pkgName = (pkg != null) ? pkg.packageName : "<unknown>";
+
         TypedArray sa = res.obtainAttributes(parser,
                 com.android.internal.R.styleable.AndroidManifest);
 
@@ -2218,14 +2220,14 @@
                     sa.recycle();
 
                     final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, minCode,
-                            SDK_VERSION, SDK_CODENAMES, outError);
+                            SDK_VERSION, SDK_CODENAMES, outError, pkgName);
                     if (minSdkVersion < 0) {
                         mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
                         return null;
                     }
 
                     final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers,
-                            targetCode, SDK_CODENAMES, outError);
+                            targetCode, SDK_CODENAMES, outError, pkgName);
                     if (targetSdkVersion < 0) {
                         mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
                         return null;
@@ -2610,13 +2612,15 @@
      * @param platformSdkCodenames array of allowed pre-release SDK codenames
      *                             for this platform
      * @param outError output array to populate with error, if applicable
+     * @param pkgName for debug logging
      * @return the targetSdkVersion to use at runtime, or -1 if the package is
      *         not compatible with this platform
      * @hide Exposed for unit testing only.
      */
     public static int computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
             @Nullable String targetCode, @NonNull String[] platformSdkCodenames,
-            @NonNull String[] outError) {
+            @NonNull String[] outError,
+            String pkgName) {
         // If it's a release SDK, return the version number unmodified.
         if (targetCode == null) {
             return targetVers;
@@ -2628,6 +2632,15 @@
             return Build.VERSION_CODES.CUR_DEVELOPMENT;
         }
 
+        // TODO(b/294161396): add a check for a "true REL" flag.
+        if (platformSdkCodenames.length == 0
+                && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+                targetCode)) {
+            Slog.w(TAG, "Package " + pkgName + " requires development platform " + targetCode
+                    + ", returning current version " + Build.VERSION.SDK_INT);
+            return Build.VERSION.SDK_INT;
+        }
+
         // Otherwise, we're looking at an incompatible pre-release SDK.
         if (platformSdkCodenames.length > 0) {
             outError[0] = "Requires development platform " + targetCode
@@ -2674,13 +2687,15 @@
      * @param platformSdkCodenames array of allowed prerelease SDK codenames
      *                             for this platform
      * @param outError output array to populate with error, if applicable
+     * @param pkgName for debug logging
      * @return the minSdkVersion to use at runtime, or -1 if the package is not
      *         compatible with this platform
      * @hide Exposed for unit testing only.
      */
     public static int computeMinSdkVersion(@IntRange(from = 1) int minVers,
             @Nullable String minCode, @IntRange(from = 1) int platformSdkVersion,
-            @NonNull String[] platformSdkCodenames, @NonNull String[] outError) {
+            @NonNull String[] platformSdkCodenames, @NonNull String[] outError,
+            String pkgName) {
         // If it's a release SDK, make sure we meet the minimum SDK requirement.
         if (minCode == null) {
             if (minVers <= platformSdkVersion) {
@@ -2699,6 +2714,15 @@
             return Build.VERSION_CODES.CUR_DEVELOPMENT;
         }
 
+        // TODO(b/294161396): add a check for a "true REL" flag.
+        if (platformSdkCodenames.length == 0
+                && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+                minCode)) {
+            Slog.w(TAG, "Package " + pkgName + " requires min development platform " + minCode
+                    + ", returning current version " + Build.VERSION.SDK_INT);
+            return Build.VERSION.SDK_INT;
+        }
+
         // Otherwise, we're looking at an incompatible pre-release SDK.
         if (platformSdkCodenames.length > 0) {
             outError[0] = "Requires development platform " + minCode
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 10d6f2d..7d995d0 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -577,14 +577,14 @@
 
                 ParseResult<Integer> targetResult = FrameworkParsingPackageUtils.computeTargetSdkVersion(
                         targetVer, targetCode, SDK_CODENAMES, input,
-                        allowUnknownCodenames);
+                        allowUnknownCodenames, codePath);
                 if (targetResult.isError()) {
                     return input.error(targetResult);
                 }
                 targetSdkVersion = targetResult.getResult();
 
                 ParseResult<Integer> minResult = FrameworkParsingPackageUtils.computeMinSdkVersion(
-                        minVer, minCode, SDK_VERSION, SDK_CODENAMES, input);
+                        minVer, minCode, SDK_VERSION, SDK_CODENAMES, input, codePath);
                 if (minResult.isError()) {
                     return input.error(minResult);
                 }
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 3e1c5bb..30e289f 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -293,11 +293,14 @@
      *                             {@code null} otherwise
      * @param platformSdkVersion   platform SDK version number, typically Build.VERSION.SDK_INT
      * @param platformSdkCodenames array of allowed prerelease SDK codenames for this platform
+     * @param input                parsing context
+     * @param pkgName              for debug logging
      * @return the minSdkVersion to use at runtime if successful
      */
     public static ParseResult<Integer> computeMinSdkVersion(@IntRange(from = 1) int minVers,
             @Nullable String minCode, @IntRange(from = 1) int platformSdkVersion,
-            @NonNull String[] platformSdkCodenames, @NonNull ParseInput input) {
+            @NonNull String[] platformSdkCodenames, @NonNull ParseInput input,
+            String pkgName) {
         // If it's a release SDK, make sure we meet the minimum SDK requirement.
         if (minCode == null) {
             if (minVers <= platformSdkVersion) {
@@ -316,6 +319,15 @@
             return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
         }
 
+        // TODO(b/294161396): add a check for a "true REL" flag.
+        if (platformSdkCodenames.length == 0
+                && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+                        minCode)) {
+            Slog.w(TAG, "Parsed package " + pkgName + " requires min development platform "
+                    + minCode + ", returning current version " + Build.VERSION.SDK_INT);
+            return input.success(Build.VERSION.SDK_INT);
+        }
+
         // Otherwise, we're looking at an incompatible pre-release SDK.
         if (platformSdkCodenames.length > 0) {
             return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
@@ -358,29 +370,38 @@
      * @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
+     * @param pkgName               for debug logging
      * @return the targetSdkVersion to use at runtime if successful
      */
     public static ParseResult<Integer> computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
             @Nullable String targetCode, @NonNull String[] platformSdkCodenames,
-            @NonNull ParseInput input, boolean allowUnknownCodenames) {
+            @NonNull ParseInput input, boolean allowUnknownCodenames,
+            String pkgName) {
         // If it's a release SDK, return the version number unmodified.
         if (targetCode == null) {
             return input.success(targetVers);
         }
 
+        // TODO(b/294161396): add a check for a "true REL" flag.
+        // If it's a pre-release SDK and the codename matches this platform, it
+        // definitely targets this SDK.
+        if (matchTargetCode(platformSdkCodenames, targetCode)) {
+            return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+        }
+        if (platformSdkCodenames.length == 0
+                && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+                        targetCode)) {
+            Slog.w(TAG, "Parsed package " + pkgName + " requires development platform " + targetCode
+                    + ", returning current version " + Build.VERSION.SDK_INT);
+            return input.success(Build.VERSION.SDK_INT);
+        }
+
         try {
             if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) {
                 return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
             }
         } catch (IllegalArgumentException e) {
-            // isAtMost() throws it when encountering an older SDK codename
-            return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, e.getMessage());
-        }
-
-        // If it's a pre-release SDK and the codename matches this platform, it
-        // definitely targets this SDK.
-        if (matchTargetCode(platformSdkCodenames, targetCode)) {
-            return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+            return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, "Bad package SDK");
         }
 
         // Otherwise, we're looking at an incompatible pre-release SDK.
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 810fa5f..9dae523 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
@@ -1546,6 +1546,7 @@
     private static ParseResult<ParsingPackage> parseUsesSdk(ParseInput input,
             ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
             throws IOException, XmlPullParserException {
+        String pkgName = (pkg != null) ? pkg.getPackageName() : "<unknown>";
         if (SDK_VERSION > 0) {
             final boolean isApkInApex = (flags & PARSE_APK_IN_APEX) != 0;
             TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestUsesSdk);
@@ -1595,7 +1596,7 @@
 
                 ParseResult<Integer> targetSdkVersionResult = FrameworkParsingPackageUtils
                         .computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, input,
-                                isApkInApex);
+                                isApkInApex, pkgName);
                 if (targetSdkVersionResult.isError()) {
                     return input.error(targetSdkVersionResult);
                 }
@@ -1609,7 +1610,8 @@
                 }
 
                 ParseResult<Integer> minSdkVersionResult = FrameworkParsingPackageUtils
-                        .computeMinSdkVersion(minVers, minCode, SDK_VERSION, SDK_CODENAMES, input);
+                        .computeMinSdkVersion(minVers, minCode, SDK_VERSION, SDK_CODENAMES,
+                                input, pkgName);
                 if (minSdkVersionResult.isError()) {
                     return input.error(minSdkVersionResult);
                 }
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/parsing/PackageParserLegacyCoreTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/parsing/PackageParserLegacyCoreTest.java
index c6a6340..8961072d 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/parsing/PackageParserLegacyCoreTest.java
@@ -111,7 +111,8 @@
                 minSdkCodename,
                 PLATFORM_VERSION,
                 isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
-                input);
+                input,
+                null);
 
         if (expectedMinSdk == -1) {
             assertTrue(result.isError());
@@ -206,7 +207,7 @@
                 targetSdkCodename,
                 isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
                 input,
-                allowUnknownCodenames);
+                allowUnknownCodenames, null);
 
         if (expectedTargetSdk == -1) {
             assertTrue(result.isError());
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index 92c7871..687e8f7 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -446,14 +446,14 @@
                         + "    <library \n"
                         + "        name=\"foo\"\n"
                         + "        file=\"" + mFooJar + "\"\n"
-                        + "        on-bootclasspath-before=\"Q\"\n"
+                        + "        on-bootclasspath-before=\"A\"\n"
                         + "        on-bootclasspath-since=\"W\"\n"
                         + "     />\n\n"
                         + " </permissions>";
         parseSharedLibraries(contents);
         assertFooIsOnlySharedLibrary();
         SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo");
-        assertThat(entry.onBootclasspathBefore).isEqualTo("Q");
+        assertThat(entry.onBootclasspathBefore).isEqualTo("A");
         assertThat(entry.onBootclasspathSince).isEqualTo("W");
     }