Loading core/java/android/app/AppOpsManager.java +42 −5 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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, Loading @@ -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, Loading Loading @@ -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); } Loading Loading @@ -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)}. * Loading services/core/java/com/android/server/appop/AppOpsService.java +46 −4 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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; Loading Loading @@ -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. Loading Loading
core/java/android/app/AppOpsManager.java +42 −5 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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, Loading @@ -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, Loading Loading @@ -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); } Loading Loading @@ -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)}. * Loading
services/core/java/com/android/server/appop/AppOpsService.java +46 −4 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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; Loading Loading @@ -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. Loading