Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 84b224f1 authored by Hai Zhang's avatar Hai Zhang Committed by Android (Google) Code Review
Browse files

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

parents b0dea6b1 f5d24431
Loading
Loading
Loading
Loading
+42 −5
Original line number Diff line number Diff line
@@ -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)}.
     *
+46 −4
Original line number Diff line number Diff line
@@ -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.