Respect role granted app op permissions when resetting all op modes.
We already respect role (or DPGP) granted runtime permissions when resetting permission states, and role won't proactively come and grant the permission again, so we should do the same for app ops to avoid breaking apps. Bug: 272371913 Test: manual Change-Id: Id561ca9c02a7f4c2a140434abf5503420490e443
This commit is contained in:
@@ -2217,8 +2217,7 @@ public class AppOpsManager {
|
||||
/** Whether noting for an appop should be collected */
|
||||
private static final @ShouldCollectNoteOp byte[] sAppOpsToNote = new byte[_NUM_OP];
|
||||
|
||||
private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = {
|
||||
// RUNTIME PERMISSIONS
|
||||
private static final int[] RUNTIME_PERMISSION_OPS = {
|
||||
// Contacts
|
||||
OP_READ_CONTACTS,
|
||||
OP_WRITE_CONTACTS,
|
||||
@@ -2275,8 +2274,13 @@ public class AppOpsManager {
|
||||
OP_NEARBY_WIFI_DEVICES,
|
||||
// Notifications
|
||||
OP_POST_NOTIFICATION,
|
||||
};
|
||||
|
||||
// APPOP PERMISSIONS
|
||||
/**
|
||||
* Ops for app op permissions that are setting the per-package mode for certain reasons. Most
|
||||
* app op permissions should set the per-UID mode instead.
|
||||
*/
|
||||
private static final int[] APP_OP_PERMISSION_PACKAGE_OPS = {
|
||||
OP_ACCESS_NOTIFICATIONS,
|
||||
OP_SYSTEM_ALERT_WINDOW,
|
||||
OP_WRITE_SETTINGS,
|
||||
@@ -2285,9 +2289,16 @@ public class AppOpsManager {
|
||||
OP_SMS_FINANCIAL_TRANSACTIONS,
|
||||
OP_MANAGE_IPSEC_TUNNELS,
|
||||
OP_INSTANT_APP_START_FOREGROUND,
|
||||
OP_LOADER_USAGE_STATS
|
||||
};
|
||||
|
||||
/**
|
||||
* Ops for app op permissions that are setting the per-UID mode for certain reasons. This should
|
||||
* be preferred over the per-package mode for new app op permissions.
|
||||
*/
|
||||
private static final int[] APP_OP_PERMISSION_UID_OPS = {
|
||||
OP_MANAGE_EXTERNAL_STORAGE,
|
||||
OP_INTERACT_ACROSS_PROFILES,
|
||||
OP_LOADER_USAGE_STATS,
|
||||
OP_MANAGE_ONGOING_CALLS,
|
||||
OP_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER,
|
||||
OP_SCHEDULE_EXACT_ALARM,
|
||||
@@ -2777,7 +2788,17 @@ public class AppOpsManager {
|
||||
sOpStrToOp.put(sAppOpInfos[i].name, i);
|
||||
}
|
||||
}
|
||||
for (int op : RUNTIME_AND_APPOP_PERMISSIONS_OPS) {
|
||||
for (int op : RUNTIME_PERMISSION_OPS) {
|
||||
if (sAppOpInfos[op].permission != null) {
|
||||
sPermToOp.put(sAppOpInfos[op].permission, op);
|
||||
}
|
||||
}
|
||||
for (int op : APP_OP_PERMISSION_PACKAGE_OPS) {
|
||||
if (sAppOpInfos[op].permission != null) {
|
||||
sPermToOp.put(sAppOpInfos[op].permission, op);
|
||||
}
|
||||
}
|
||||
for (int op : APP_OP_PERMISSION_UID_OPS) {
|
||||
if (sAppOpInfos[op].permission != null) {
|
||||
sPermToOp.put(sAppOpInfos[op].permission, op);
|
||||
}
|
||||
@@ -2946,6 +2967,22 @@ public class AppOpsManager {
|
||||
return !sAppOpInfos[op].disableReset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve whether the op is a per-package op for an app op permission.
|
||||
* @hide
|
||||
*/
|
||||
public static boolean opIsPackageAppOpPermission(int op) {
|
||||
return ArrayUtils.contains(APP_OP_PERMISSION_PACKAGE_OPS, op);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve whether the op is a per-package op for an app op permission.
|
||||
* @hide
|
||||
*/
|
||||
public static boolean opIsUidAppOpPermission(int op) {
|
||||
return ArrayUtils.contains(APP_OP_PERMISSION_UID_OPS, op);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a listenerId suitable for use with {@link #noteOp(int, int, String, String, String)}.
|
||||
*
|
||||
|
||||
@@ -2096,7 +2096,9 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
final int code = opModes.keyAt(j);
|
||||
if (AppOpsManager.opAllowsReset(code)) {
|
||||
int previousMode = opModes.valueAt(j);
|
||||
uidState.setUidMode(code, AppOpsManager.opToDefaultMode(code));
|
||||
int newMode = isUidOpGrantedByRole(uidState.uid, code) ? MODE_ALLOWED :
|
||||
AppOpsManager.opToDefaultMode(code);
|
||||
uidState.setUidMode(code, newMode);
|
||||
for (String packageName : getPackagesForUid(uidState.uid)) {
|
||||
callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
|
||||
previousMode,
|
||||
@@ -2139,10 +2141,15 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
deferResetOpToDpm(curOp.op, reqPackageName, reqUserId);
|
||||
continue;
|
||||
}
|
||||
if (AppOpsManager.opAllowsReset(curOp.op)
|
||||
&& curOp.getMode() != AppOpsManager.opToDefaultMode(curOp.op)) {
|
||||
if (AppOpsManager.opAllowsReset(curOp.op)) {
|
||||
int previousMode = curOp.getMode();
|
||||
curOp.setMode(AppOpsManager.opToDefaultMode(curOp.op));
|
||||
int newMode = isPackageOpGrantedByRole(packageName, uidState.uid,
|
||||
curOp.op) ? MODE_ALLOWED : AppOpsManager.opToDefaultMode(
|
||||
curOp.op);
|
||||
if (previousMode == newMode) {
|
||||
continue;
|
||||
}
|
||||
curOp.setMode(newMode);
|
||||
changed = true;
|
||||
uidChanged = true;
|
||||
final int uid = curOp.uidState.uid;
|
||||
@@ -2198,6 +2205,41 @@ public class AppOpsService extends IAppOpsService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUidOpGrantedByRole(int uid, int code) {
|
||||
if (!AppOpsManager.opIsUidAppOpPermission(code)) {
|
||||
return false;
|
||||
}
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
// Permissions are managed by UIDs, but unfortunately a package name is required in API.
|
||||
String packageName = ArrayUtils.firstOrNull(packageManager.getPackagesForUid(uid));
|
||||
if (packageName == null) {
|
||||
return false;
|
||||
}
|
||||
int permissionFlags = packageManager.getPermissionFlags(AppOpsManager.opToPermission(
|
||||
code), packageName, UserHandle.getUserHandleForUid(uid));
|
||||
return (permissionFlags & PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE) != 0;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPackageOpGrantedByRole(@NonNull String packageName, int uid, int code) {
|
||||
if (!AppOpsManager.opIsPackageAppOpPermission(code)) {
|
||||
return false;
|
||||
}
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
int permissionFlags = packageManager.getPermissionFlags(AppOpsManager.opToPermission(
|
||||
code), packageName, UserHandle.getUserHandleForUid(uid));
|
||||
return (permissionFlags & PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE) != 0;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldDeferResetOpToDpm(int op) {
|
||||
// TODO(b/174582385): avoid special-casing app-op resets by migrating app-op permission
|
||||
// pre-grants to a role-based mechanism or another general-purpose mechanism.
|
||||
|
||||
Reference in New Issue
Block a user