Merge "Allow RollbackManager to downgrade apks on user builds"
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 0304f19..b20cce9 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1343,6 +1343,7 @@
          */
         public boolean areHiddenOptionsSet() {
             return (installFlags & (PackageManager.INSTALL_ALLOW_DOWNGRADE
+                    | PackageManager.INSTALL_RESPECT_ALLOW_DOWNGRADE
                     | PackageManager.INSTALL_DONT_KILL_APP
                     | PackageManager.INSTALL_INSTANT_APP
                     | PackageManager.INSTALL_FULL_APP
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a5464c2..c133fba 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -721,6 +721,7 @@
             INSTALL_VIRTUAL_PRELOAD,
             INSTALL_APEX,
             INSTALL_ENABLE_ROLLBACK,
+            INSTALL_RESPECT_ALLOW_DOWNGRADE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface InstallFlags {}
@@ -865,6 +866,15 @@
      */
     public static final int INSTALL_DISABLE_VERIFICATION = 0x00080000;
 
+    /**
+     * Flag parameter for {@link #installPackage} to indicate that
+     * {@link #INSTALL_ALLOW_DOWNGRADE} should be respected.
+     *
+     * @hide
+     */
+    // TODO(b/127322579): rename
+    public static final int INSTALL_RESPECT_ALLOW_DOWNGRADE = 0x00100000;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = {
             DONT_KILL_APP
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index b72e836..a3b72fd 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -481,6 +481,12 @@
             }
         }
 
+        if (callingUid == Process.SYSTEM_UID) {
+            params.installFlags |= PackageManager.INSTALL_RESPECT_ALLOW_DOWNGRADE;
+        } else {
+            params.installFlags &= ~PackageManager.INSTALL_RESPECT_ALLOW_DOWNGRADE;
+        }
+
         boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;
         if (params.isStaged || isApex) {
             mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG);
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 3218c86..ff81ad5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -806,7 +806,7 @@
      */
     public static boolean isDowngradePermitted(int installFlags, int applicationFlags) {
         // If installed, the package will get access to data left on the device by its
-        // predecessor. As a security measure, this is permited only if this is not a
+        // predecessor. As a security measure, this is permitted only if this is not a
         // version downgrade or if the predecessor package is marked as debuggable and
         // a downgrade is explicitly requested.
         //
@@ -818,12 +818,21 @@
         // installFlags. This is because we aim to keep the behavior of debuggable
         // platform builds as close as possible to the behavior of non-debuggable
         // platform builds.
+        //
+        // In case of user builds, downgrade is permitted only for the system server initiated
+        // sessions. This is enforced by INSTALL_RESPECT_ALLOW_DOWNGRADE flag parameter.
         final boolean downgradeRequested =
                 (installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) != 0;
-        final boolean packageDebuggable =
-                (applicationFlags
-                        & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
-        return (downgradeRequested) && ((Build.IS_DEBUGGABLE) || (packageDebuggable));
+        if (!downgradeRequested) {
+            return false;
+        }
+        final boolean isDebuggable =
+                Build.IS_DEBUGGABLE || ((applicationFlags
+                        & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
+        if (isDebuggable) {
+            return true;
+        }
+        return (installFlags & PackageManager.INSTALL_RESPECT_ALLOW_DOWNGRADE) != 0;
     }
 
     /**