Merge "Do not allow opting out from the new permission model." into mnc-dev
diff --git a/api/system-current.txt b/api/system-current.txt
index cc4ea27..6f4ec48 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -9671,6 +9671,7 @@
     field public static final int INSTALL_FAILED_NO_SHARED_USER = -6; // 0xfffffffa
     field public static final int INSTALL_FAILED_OLDER_SDK = -12; // 0xfffffff4
     field public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23; // 0xffffffe9
+    field public static final int INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE = -26; // 0xffffffe6
     field public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10; // 0xfffffff6
     field public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8; // 0xfffffff8
     field public static final int INSTALL_FAILED_TEST_ONLY = -15; // 0xfffffff1
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 202a8a7..2ca0306 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -653,6 +653,16 @@
     public static final int INSTALL_FAILED_VERSION_DOWNGRADE = -25;
 
     /**
+     * Installation return code: this is passed to the {@link IPackageInstallObserver} by
+     * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
+     * the old package has target SDK high enough to support runtime permission and
+     * the new package has target SDK low enough to not support runtime permissions.
+     * @hide
+     */
+    @SystemApi
+    public static final int INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE = -26;
+
+    /**
      * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
      * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
      * if the parser was given a path that is not a file, or does not end with the expected
@@ -4512,6 +4522,7 @@
             case INSTALL_FAILED_PACKAGE_CHANGED: return PackageInstaller.STATUS_FAILURE_INVALID;
             case INSTALL_FAILED_UID_CHANGED: return PackageInstaller.STATUS_FAILURE_INVALID;
             case INSTALL_FAILED_VERSION_DOWNGRADE: return PackageInstaller.STATUS_FAILURE_INVALID;
+            case INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE: return PackageInstaller.STATUS_FAILURE_INVALID;
             case INSTALL_PARSE_FAILED_NOT_APK: return PackageInstaller.STATUS_FAILURE_INVALID;
             case INSTALL_PARSE_FAILED_BAD_MANIFEST: return PackageInstaller.STATUS_FAILURE_INVALID;
             case INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: return PackageInstaller.STATUS_FAILURE_INVALID;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 01aa0e6..145786f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -11461,6 +11461,21 @@
                     replace = true;
                     if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
                 }
+
+                // Prevent apps opting out from runtime permissions
+                if (replace) {
+                    PackageParser.Package oldPackage = mPackages.get(pkgName);
+                    final int oldTargetSdk = oldPackage.applicationInfo.targetSdkVersion;
+                    final int newTargetSdk = pkg.applicationInfo.targetSdkVersion;
+                    if (oldTargetSdk > Build.VERSION_CODES.LOLLIPOP_MR1
+                            && newTargetSdk <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+                        res.setError(PackageManager.INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE,
+                                "Package " + pkg.packageName + " new target SDK " + newTargetSdk
+                                        + " doesn't support runtime permissions but the old"
+                                        + " target SDK " + oldTargetSdk + " does.");
+                        return;
+                    }
+                }
             }
 
             PackageSetting ps = mSettings.mPackages.get(pkgName);