Merge "Respect role granted app op permissions when resetting all op modes." into udc-dev

This commit is contained in:
Hai Zhang
2023-03-12 23:39:04 +00:00
committed by Android (Google) Code Review
2 changed files with 88 additions and 9 deletions

View File

@@ -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)}.
*

View File

@@ -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.