Runtime permissions cannot be set on legacy apps by device policy
Clarify docs that runtime permissions can be granted or revoked by
a profile owner/device owner only for MNC apps and not legacy apps.
Check the targetSdkVersion and return false if legacy app.
Remove all policy flags from permissions when cleaning up
a device or profile owner.
Bug: 21835304
Bug: 21889278
Change-Id: I4271394737990983449048d112a1830f9d0f2d78
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index b859dca..4d1cff5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4350,6 +4350,12 @@
* group that the runtime permission belongs to. This method can only be called
* by a profile or device owner.
*
+ * <p/>Setting the grant state to {@link #PERMISSION_GRANT_STATE_DEFAULT default} does not
+ * revoke the permission. It retains the previous grant, if any.
+ *
+ * <p/>Permissions can be granted or revoked only for applications built with a
+ * {@code targetSdkVersion} of {@link android.os.Build.VERSION_CODES#MNC} or later.
+ *
* @param admin Which profile or device owner this request is associated with.
* @param packageName The application to grant or revoke a permission to.
* @param permission The permission to grant or revoke.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 2dbcde9..34e4701 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -106,6 +106,8 @@
void updatePermissionFlags(String permissionName, String packageName, int flagMask,
int flagValues, int userId);
+ void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId);
+
boolean shouldShowRequestPermissionRationale(String permissionName,
String packageName, int userId);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 41d3ffd..7a39c2b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3354,11 +3354,8 @@
enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
"updatePermissionFlags");
- // Only the system can change policy and system fixed flags.
+ // Only the system can change system fixed flags.
if (getCallingUid() != Process.SYSTEM_UID) {
- flagMask &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
- flagValues &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
-
flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
}
@@ -3387,18 +3384,63 @@
return;
}
+ boolean hadState = permissionsState.getRuntimePermissionState(name, userId) != null;
+
if (permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues)) {
// Install and runtime permissions are stored in different places,
// so figure out what permission changed and persist the change.
if (permissionsState.getInstallPermissionState(name) != null) {
scheduleWriteSettingsLocked();
- } else if (permissionsState.getRuntimePermissionState(name, userId) != null) {
+ } else if (permissionsState.getRuntimePermissionState(name, userId) != null
+ || hadState) {
mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
}
}
}
+ /**
+ * Update the permission flags for all packages and runtime permissions of a user in order
+ * to allow device or profile owner to remove POLICY_FIXED.
+ */
+ @Override
+ public void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId) {
+ if (!sUserManager.exists(userId)) {
+ return;
+ }
+
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
+ "updatePermissionFlagsForAllApps");
+
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+ "updatePermissionFlagsForAllApps");
+
+ // Only the system can change system fixed flags.
+ if (getCallingUid() != Process.SYSTEM_UID) {
+ flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+ flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+ }
+
+ synchronized (mPackages) {
+ boolean changed = false;
+ final int packageCount = mPackages.size();
+ for (int pkgIndex = 0; pkgIndex < packageCount; pkgIndex++) {
+ final PackageParser.Package pkg = mPackages.valueAt(pkgIndex);
+ SettingBase sb = (SettingBase) pkg.mExtras;
+ if (sb == null) {
+ continue;
+ }
+ PermissionsState permissionsState = sb.getPermissionsState();
+ changed |= permissionsState.updatePermissionFlagsForAllPermissions(
+ userId, flagMask, flagValues);
+ }
+ if (changed) {
+ mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+ }
+ }
+ }
+
@Override
public boolean shouldShowRequestPermissionRationale(String permissionName,
String packageName, int userId) {
diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java
index ad662be..04beafd 100644
--- a/services/core/java/com/android/server/pm/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/PermissionsState.java
@@ -344,6 +344,22 @@
return permissionData.updateFlags(userId, flagMask, flagValues);
}
+ public boolean updatePermissionFlagsForAllPermissions(
+ int userId, int flagMask, int flagValues) {
+ enforceValidUserId(userId);
+
+ if (mPermissions == null) {
+ return false;
+ }
+ boolean changed = false;
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ PermissionData permissionData = mPermissions.valueAt(i);
+ changed |= permissionData.updateFlags(userId, flagMask, flagValues);
+ }
+ return changed;
+ }
+
/**
* Compute the Linux gids for a given device user from the permissions
* granted to this user. Note that these are computed to avoid additional
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 74adc6b..e44a7ab87 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4217,11 +4217,15 @@
long ident = Binder.clearCallingIdentity();
try {
clearUserRestrictions(new UserHandle(UserHandle.USER_OWNER));
+ AppGlobals.getPackageManager().updatePermissionFlagsForAllApps(
+ PackageManager.FLAG_PERMISSION_POLICY_FIXED,
+ 0, UserHandle.USER_OWNER);
if (mDeviceOwner != null) {
mDeviceOwner.clearDeviceOwner();
mDeviceOwner.writeOwnerFile();
updateDeviceOwnerLocked();
}
+ } catch (RemoteException re) {
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -4388,10 +4392,14 @@
long ident = Binder.clearCallingIdentity();
try {
clearUserRestrictions(callingUser);
+ AppGlobals.getPackageManager().updatePermissionFlagsForAllApps(
+ PackageManager.FLAG_PERMISSION_POLICY_FIXED,
+ 0, callingUser.getIdentifier());
if (mDeviceOwner != null) {
mDeviceOwner.removeProfileOwner(userId);
mDeviceOwner.writeOwnerFile();
}
+ } catch (RemoteException re) {
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -6390,21 +6398,27 @@
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
long ident = Binder.clearCallingIdentity();
try {
- PackageManager packageManager = mContext.getPackageManager();
+ final ApplicationInfo ai = AppGlobals.getPackageManager()
+ .getApplicationInfo(packageName, 0, user.getIdentifier());
+ final int targetSdkVersion = ai == null ? 0 : ai.targetSdkVersion;
+ if (targetSdkVersion < android.os.Build.VERSION_CODES.MNC) {
+ return false;
+ }
+ final PackageManager packageManager = mContext.getPackageManager();
switch (grantState) {
case DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED: {
+ packageManager.grantRuntimePermission(packageName, permission, user);
packageManager.updatePermissionFlags(permission, packageName,
PackageManager.FLAG_PERMISSION_POLICY_FIXED,
PackageManager.FLAG_PERMISSION_POLICY_FIXED, user);
- packageManager.grantRuntimePermission(packageName, permission, user);
} break;
case DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED: {
+ packageManager.revokeRuntimePermission(packageName,
+ permission, user);
packageManager.updatePermissionFlags(permission, packageName,
PackageManager.FLAG_PERMISSION_POLICY_FIXED,
PackageManager.FLAG_PERMISSION_POLICY_FIXED, user);
- packageManager.revokeRuntimePermission(packageName,
- permission, user);
} break;
case DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT: {