[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.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6011e07..3d5bc58 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -65,6 +65,7 @@
import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN;
import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
@@ -14048,6 +14049,11 @@
});
}
+ @Override
+ public boolean isPackageDeviceAdminOnAnyUser(String packageName) {
+ return isPackageDeviceAdmin(packageName, UserHandle.USER_ALL);
+ }
+
private boolean isPackageDeviceAdmin(String packageName, int userId) {
IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
@@ -18114,6 +18120,10 @@
throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
"Package already moved to " + volumeUuid);
}
+ if (pkg.applicationInfo.isInternal() && isPackageDeviceAdminOnAnyUser(packageName)) {
+ throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
+ "Device admin cannot be moved");
+ }
if (ps.frozen) {
throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8a2a578..2a0e1ac 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2701,6 +2701,10 @@
if (info == null) {
throw new IllegalArgumentException("Bad admin: " + adminReceiver);
}
+ if (!info.getActivityInfo().applicationInfo.isInternal()) {
+ throw new IllegalArgumentException("Only apps in internal storage can be active admin: "
+ + adminReceiver);
+ }
synchronized (this) {
long ident = mInjector.binderClearCallingIdentity();
try {