[framework] Don't allow apps on external storage to be active admin

Bug 27149287

Change-Id: I6d959d2e66dc0b19f78e6135fbdcf45ca8551958
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7e50518..68118fc 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.annotation.XmlRes;
+import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Intent;
@@ -1759,7 +1760,7 @@
         return candidates;
     }
 
-    private static boolean isPackageCandidateVolume(
+    private boolean isPackageCandidateVolume(
             ContextImpl context, ApplicationInfo app, VolumeInfo vol) {
         final boolean forceAllowOnExternal = Settings.Global.getInt(
                 context.getContentResolver(), Settings.Global.FORCE_ALLOW_ON_EXTERNAL, 0) != 0;
@@ -1789,6 +1790,15 @@
             return app.isInternal();
         }
 
+        // Some apps can't be moved. (e.g. device admins)
+        try {
+            if (mPM.isPackageDeviceAdminOnAnyUser(app.packageName)) {
+                return false;
+            }
+        } catch (RemoteException e) {
+            throw new RuntimeException("Package manager has died", e);
+        }
+
         // Otherwise we can move to any private volume
         return (vol.getType() == VolumeInfo.TYPE_PRIVATE);
     }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c71a603..b9d5ef6 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -536,4 +536,6 @@
     boolean setRequiredForSystemUser(String packageName, boolean systemUserApp);
 
     String getServicesSystemSharedLibraryPackageName();
+
+    boolean isPackageDeviceAdminOnAnyUser(String packageName);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 36b902c..7cf7df5 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1233,6 +1233,14 @@
     public static final int MOVE_FAILED_OPERATION_PENDING = -7;
 
     /**
+     * Error code that is passed to the {@link IPackageMoveObserver} if the
+     * specified package cannot be moved since it contains a device admin.
+     *
+     * @hide
+     */
+    public static final int MOVE_FAILED_DEVICE_ADMIN = -8;
+
+    /**
      * Flag parameter for {@link #movePackage} to indicate that
      * the package should be moved to internal storage if its
      * been installed on external media.