Loading services/core/java/com/android/server/policy/PermissionPolicyService.java +137 −64 Original line number Diff line number Diff line Loading @@ -158,6 +158,9 @@ public final class PermissionPolicyService extends SystemService { }); } /** * Synchronize a single package. */ private static void synchronizePackagePermissionsAndAppOpsForUser(@NonNull Context context, @NonNull String packageName, @UserIdInt int userId) { final PackageManagerInternal packageManagerInternal = LocalServices.getService( Loading @@ -167,7 +170,7 @@ public final class PermissionPolicyService extends SystemService { return; } final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(context); synchroniser.addPackage(context, pkg, userId); synchroniser.addPackage(pkg, userId); final String[] sharedPkgNames = packageManagerInternal.getPackagesForSharedUserId( pkg.mSharedUserId, userId); if (sharedPkgNames != null) { Loading @@ -175,20 +178,23 @@ public final class PermissionPolicyService extends SystemService { final PackageParser.Package sharedPkg = packageManagerInternal .getPackage(sharedPkgName); if (sharedPkg != null) { synchroniser.addPackage(context, sharedPkg, userId); synchroniser.addPackage(sharedPkg, userId); } } } synchroniser.syncPackages(); } /** * Synchronize all packages */ private static void synchronizePermissionsAndAppOpsForUser(@NonNull Context context, @UserIdInt int userId) { final PackageManagerInternal packageManagerInternal = LocalServices.getService( PackageManagerInternal.class); final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(context); packageManagerInternal.forEachPackage((pkg) -> synchronizer.addPackage(context, pkg, userId)); synchronizer.addPackage(pkg, userId)); synchronizer.syncPackages(); } Loading @@ -198,17 +204,39 @@ public final class PermissionPolicyService extends SystemService { */ private static class PermissionToOpSynchroniser { private final @NonNull Context mContext; private final @NonNull PackageManager mPackageManager; private final @NonNull AppOpsManager mAppOpsManager; /** All uid that need to be synchronized */ private final @NonNull SparseIntArray mAllUids = new SparseIntArray(); private final @NonNull SparseIntArray mUids = new SparseIntArray(); private final @NonNull SparseArray<String> mPackageNames = new SparseArray<>(); private final @NonNull SparseIntArray mAllowedUidOps = new SparseIntArray(); private final @NonNull SparseIntArray mDefaultUidOps = new SparseIntArray(); /** * All ops that need to be restricted * * @see #syncRestrictedOps */ private final @NonNull ArrayList<OpToRestrict> mOpsToRestrict = new ArrayList<>(); /** * All ops that need to be unrestricted * * @see #syncRestrictedOps */ private final @NonNull ArrayList<OpToUnrestrict> mOpsToUnrestrict = new ArrayList<>(); PermissionToOpSynchroniser(@NonNull Context context) { mContext = context; mPackageManager = context.getPackageManager(); mAppOpsManager = context.getSystemService(AppOpsManager.class); } void syncPackages() { /** * Set app ops that belong to restricted permissions. * * <p>This processes ops previously added by {@link #addOpIfRestricted} */ private void syncRestrictedOps() { final SparseIntArray unprocessedUids = mAllUids.clone(); // TRICKY: we set the app op for a restricted permission to allow if the app // requesting the permission is whitelisted and to deny if the app requesting // the permission is not whitelisted. However, there is another case where an Loading @@ -222,52 +250,48 @@ public final class PermissionPolicyService extends SystemService { final SparseArray<List<String>> unrequestedRestrictedPermissionsForUid = new SparseArray<>(); final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class); final int allowedCount = mAllowedUidOps.size(); for (int i = 0; i < allowedCount; i++) { final int opCode = mAllowedUidOps.keyAt(i); final int uid = mAllowedUidOps.valueAt(i); final String packageName = mPackageNames.valueAt(i); setUidModeAllowed(appOpsManager, opCode, uid, packageName); final int unrestrictCount = mOpsToUnrestrict.size(); for (int i = 0; i < unrestrictCount; i++) { final OpToUnrestrict op = mOpsToUnrestrict.get(i); setUidModeAllowed(op.code, op.uid, op.packageName); // Keep track this permission was requested by the UID. List<String> unrequestedRestrictedPermissions = unrequestedRestrictedPermissionsForUid.get(uid); unrequestedRestrictedPermissionsForUid.get(op.uid); if (unrequestedRestrictedPermissions == null) { unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions); unrequestedRestrictedPermissionsForUid.put(uid, unrequestedRestrictedPermissionsForUid.put(op.uid, unrequestedRestrictedPermissions); } unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(opCode)); unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(op.code)); mUids.delete(uid); unprocessedUids.delete(op.uid); } final int defaultCount = mDefaultUidOps.size(); for (int i = 0; i < defaultCount; i++) { final int opCode = mDefaultUidOps.keyAt(i); final int uid = mDefaultUidOps.valueAt(i); setUidModeDefault(appOpsManager, opCode, uid); final int restrictCount = mOpsToRestrict.size(); for (int i = 0; i < restrictCount; i++) { final OpToRestrict op = mOpsToRestrict.get(i); setUidModeDefault(op.code, op.uid); // Keep track this permission was requested by the UID. List<String> unrequestedRestrictedPermissions = unrequestedRestrictedPermissionsForUid.get(uid); unrequestedRestrictedPermissionsForUid.get(op.uid); if (unrequestedRestrictedPermissions == null) { unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions); unrequestedRestrictedPermissionsForUid.put(uid, unrequestedRestrictedPermissionsForUid.put(op.uid, unrequestedRestrictedPermissions); } unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(opCode)); unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(op.code)); mUids.delete(uid); unprocessedUids.delete(op.uid); } // Give root access mUids.put(Process.ROOT_UID, Process.ROOT_UID); unprocessedUids.put(Process.ROOT_UID, Process.ROOT_UID); // Add records for UIDs that don't use any restricted permissions. final int uidCount = mUids.size(); final int uidCount = unprocessedUids.size(); for (int i = 0; i < uidCount; i++) { final int uid = mUids.keyAt(i); final int uid = unprocessedUids.keyAt(i); unrequestedRestrictedPermissionsForUid.put(uid, new ArrayList<>(sAllRestrictedPermissions)); } Loading @@ -289,8 +313,7 @@ public final class PermissionPolicyService extends SystemService { for (int j = 0; j < permissionCount; j++) { final String permission = unrequestedRestrictedPermissions.get(j); for (String packageName : packageNames) { setUidModeAllowed(appOpsManager, AppOpsManager.permissionToOpCode(permission), uid, setUidModeAllowed(AppOpsManager.permissionToOpCode(permission), uid, packageName); } } Loading @@ -298,14 +321,61 @@ public final class PermissionPolicyService extends SystemService { } } private void addPackage(@NonNull Context context, @NonNull PackageParser.Package pkg, @UserIdInt int userId) { final PackageManager packageManager = context.getPackageManager(); /** * Synchronize all previously {@link #addPackage added} packages. */ void syncPackages() { syncRestrictedOps(); } /** * Add op that belong to a restricted permission for later processing in * {@link #syncRestrictedOps}. * * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager. * * @param permissionInfo The permission that is currently looked at * @param pkg The package looked at * @param userId The user the package belongs to */ private void addOpIfRestricted(@NonNull PermissionInfo permissionInfo, @NonNull PackageParser.Package pkg, @UserIdInt int userId) { final String permission = permissionInfo.name; final int opCode = AppOpsManager.permissionToOpCode(permission); final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.applicationInfo.uid)); final UserHandle userHandle = UserHandle.of(userId); mUids.put(uid, uid); if (!permissionInfo.isRestricted()) { return; } final boolean applyRestriction = PackageManager.RESTRICTED_PERMISSIONS_ENABLED && (mPackageManager.getPermissionFlags(permission, pkg.packageName, userHandle) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; if (permissionInfo.isHardRestricted()) { if (applyRestriction) { mOpsToRestrict.add(new OpToRestrict(uid, opCode)); } else { mOpsToUnrestrict.add(new OpToUnrestrict(uid, pkg.packageName, opCode)); } } else if (permissionInfo.isSoftRestricted()) { //TODO: Implement soft restrictions like storage here. } } /** * Add a package for {@link #syncPackages() processing} later. * * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager. * * @param pkg The package to add for later processing * @param userId The user the package belongs to */ void addPackage(@NonNull PackageParser.Package pkg, @UserIdInt int userId) { final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.applicationInfo.uid)); mAllUids.put(uid, uid); final int permissionCount = pkg.requestedPermissions.size(); for (int i = 0; i < permissionCount; i++) { Loading @@ -318,44 +388,47 @@ public final class PermissionPolicyService extends SystemService { final PermissionInfo permissionInfo; try { permissionInfo = packageManager.getPermissionInfo(permission, 0); permissionInfo = mPackageManager.getPermissionInfo(permission, 0); } catch (PackageManager.NameNotFoundException e) { continue; } if (!permissionInfo.isRestricted()) { continue; addOpIfRestricted(permissionInfo, pkg, userId); } final boolean applyRestriction = PackageManager.RESTRICTED_PERMISSIONS_ENABLED && (packageManager.getPermissionFlags(permission, pkg.packageName, userHandle) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; if (permissionInfo.isHardRestricted()) { if (applyRestriction) { mDefaultUidOps.put(opCode, uid); } else { mPackageNames.put(opCode, pkg.packageName); mAllowedUidOps.put(opCode, uid); } } else if (permissionInfo.isSoftRestricted()) { //TODO: Implement soft restrictions like storage here. private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) { final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager .opToPublicName(opCode), uid, packageName); if (currentMode == AppOpsManager.MODE_DEFAULT) { mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED); } } private void setUidModeDefault(int opCode, int uid) { mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT); } private static void setUidModeAllowed(@NonNull AppOpsManager appOpsManager, int opCode, int uid, @NonNull String packageName) { final int currentMode = appOpsManager.unsafeCheckOpRaw(AppOpsManager .opToPublicName(opCode), uid, packageName); if (currentMode == AppOpsManager.MODE_DEFAULT) { appOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED); private class OpToRestrict { final int uid; final int code; OpToRestrict(int uid, int code) { this.uid = uid; this.code = code; } } private static void setUidModeDefault(@NonNull AppOpsManager appOpsManager, int opCode, int uid) { appOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT); private class OpToUnrestrict { final int uid; final @NonNull String packageName; final int code; OpToUnrestrict(int uid, @NonNull String packageName, int code) { this.uid = uid; this.packageName = packageName; this.code = code; } } } } Loading
services/core/java/com/android/server/policy/PermissionPolicyService.java +137 −64 Original line number Diff line number Diff line Loading @@ -158,6 +158,9 @@ public final class PermissionPolicyService extends SystemService { }); } /** * Synchronize a single package. */ private static void synchronizePackagePermissionsAndAppOpsForUser(@NonNull Context context, @NonNull String packageName, @UserIdInt int userId) { final PackageManagerInternal packageManagerInternal = LocalServices.getService( Loading @@ -167,7 +170,7 @@ public final class PermissionPolicyService extends SystemService { return; } final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(context); synchroniser.addPackage(context, pkg, userId); synchroniser.addPackage(pkg, userId); final String[] sharedPkgNames = packageManagerInternal.getPackagesForSharedUserId( pkg.mSharedUserId, userId); if (sharedPkgNames != null) { Loading @@ -175,20 +178,23 @@ public final class PermissionPolicyService extends SystemService { final PackageParser.Package sharedPkg = packageManagerInternal .getPackage(sharedPkgName); if (sharedPkg != null) { synchroniser.addPackage(context, sharedPkg, userId); synchroniser.addPackage(sharedPkg, userId); } } } synchroniser.syncPackages(); } /** * Synchronize all packages */ private static void synchronizePermissionsAndAppOpsForUser(@NonNull Context context, @UserIdInt int userId) { final PackageManagerInternal packageManagerInternal = LocalServices.getService( PackageManagerInternal.class); final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(context); packageManagerInternal.forEachPackage((pkg) -> synchronizer.addPackage(context, pkg, userId)); synchronizer.addPackage(pkg, userId)); synchronizer.syncPackages(); } Loading @@ -198,17 +204,39 @@ public final class PermissionPolicyService extends SystemService { */ private static class PermissionToOpSynchroniser { private final @NonNull Context mContext; private final @NonNull PackageManager mPackageManager; private final @NonNull AppOpsManager mAppOpsManager; /** All uid that need to be synchronized */ private final @NonNull SparseIntArray mAllUids = new SparseIntArray(); private final @NonNull SparseIntArray mUids = new SparseIntArray(); private final @NonNull SparseArray<String> mPackageNames = new SparseArray<>(); private final @NonNull SparseIntArray mAllowedUidOps = new SparseIntArray(); private final @NonNull SparseIntArray mDefaultUidOps = new SparseIntArray(); /** * All ops that need to be restricted * * @see #syncRestrictedOps */ private final @NonNull ArrayList<OpToRestrict> mOpsToRestrict = new ArrayList<>(); /** * All ops that need to be unrestricted * * @see #syncRestrictedOps */ private final @NonNull ArrayList<OpToUnrestrict> mOpsToUnrestrict = new ArrayList<>(); PermissionToOpSynchroniser(@NonNull Context context) { mContext = context; mPackageManager = context.getPackageManager(); mAppOpsManager = context.getSystemService(AppOpsManager.class); } void syncPackages() { /** * Set app ops that belong to restricted permissions. * * <p>This processes ops previously added by {@link #addOpIfRestricted} */ private void syncRestrictedOps() { final SparseIntArray unprocessedUids = mAllUids.clone(); // TRICKY: we set the app op for a restricted permission to allow if the app // requesting the permission is whitelisted and to deny if the app requesting // the permission is not whitelisted. However, there is another case where an Loading @@ -222,52 +250,48 @@ public final class PermissionPolicyService extends SystemService { final SparseArray<List<String>> unrequestedRestrictedPermissionsForUid = new SparseArray<>(); final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class); final int allowedCount = mAllowedUidOps.size(); for (int i = 0; i < allowedCount; i++) { final int opCode = mAllowedUidOps.keyAt(i); final int uid = mAllowedUidOps.valueAt(i); final String packageName = mPackageNames.valueAt(i); setUidModeAllowed(appOpsManager, opCode, uid, packageName); final int unrestrictCount = mOpsToUnrestrict.size(); for (int i = 0; i < unrestrictCount; i++) { final OpToUnrestrict op = mOpsToUnrestrict.get(i); setUidModeAllowed(op.code, op.uid, op.packageName); // Keep track this permission was requested by the UID. List<String> unrequestedRestrictedPermissions = unrequestedRestrictedPermissionsForUid.get(uid); unrequestedRestrictedPermissionsForUid.get(op.uid); if (unrequestedRestrictedPermissions == null) { unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions); unrequestedRestrictedPermissionsForUid.put(uid, unrequestedRestrictedPermissionsForUid.put(op.uid, unrequestedRestrictedPermissions); } unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(opCode)); unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(op.code)); mUids.delete(uid); unprocessedUids.delete(op.uid); } final int defaultCount = mDefaultUidOps.size(); for (int i = 0; i < defaultCount; i++) { final int opCode = mDefaultUidOps.keyAt(i); final int uid = mDefaultUidOps.valueAt(i); setUidModeDefault(appOpsManager, opCode, uid); final int restrictCount = mOpsToRestrict.size(); for (int i = 0; i < restrictCount; i++) { final OpToRestrict op = mOpsToRestrict.get(i); setUidModeDefault(op.code, op.uid); // Keep track this permission was requested by the UID. List<String> unrequestedRestrictedPermissions = unrequestedRestrictedPermissionsForUid.get(uid); unrequestedRestrictedPermissionsForUid.get(op.uid); if (unrequestedRestrictedPermissions == null) { unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions); unrequestedRestrictedPermissionsForUid.put(uid, unrequestedRestrictedPermissionsForUid.put(op.uid, unrequestedRestrictedPermissions); } unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(opCode)); unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(op.code)); mUids.delete(uid); unprocessedUids.delete(op.uid); } // Give root access mUids.put(Process.ROOT_UID, Process.ROOT_UID); unprocessedUids.put(Process.ROOT_UID, Process.ROOT_UID); // Add records for UIDs that don't use any restricted permissions. final int uidCount = mUids.size(); final int uidCount = unprocessedUids.size(); for (int i = 0; i < uidCount; i++) { final int uid = mUids.keyAt(i); final int uid = unprocessedUids.keyAt(i); unrequestedRestrictedPermissionsForUid.put(uid, new ArrayList<>(sAllRestrictedPermissions)); } Loading @@ -289,8 +313,7 @@ public final class PermissionPolicyService extends SystemService { for (int j = 0; j < permissionCount; j++) { final String permission = unrequestedRestrictedPermissions.get(j); for (String packageName : packageNames) { setUidModeAllowed(appOpsManager, AppOpsManager.permissionToOpCode(permission), uid, setUidModeAllowed(AppOpsManager.permissionToOpCode(permission), uid, packageName); } } Loading @@ -298,14 +321,61 @@ public final class PermissionPolicyService extends SystemService { } } private void addPackage(@NonNull Context context, @NonNull PackageParser.Package pkg, @UserIdInt int userId) { final PackageManager packageManager = context.getPackageManager(); /** * Synchronize all previously {@link #addPackage added} packages. */ void syncPackages() { syncRestrictedOps(); } /** * Add op that belong to a restricted permission for later processing in * {@link #syncRestrictedOps}. * * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager. * * @param permissionInfo The permission that is currently looked at * @param pkg The package looked at * @param userId The user the package belongs to */ private void addOpIfRestricted(@NonNull PermissionInfo permissionInfo, @NonNull PackageParser.Package pkg, @UserIdInt int userId) { final String permission = permissionInfo.name; final int opCode = AppOpsManager.permissionToOpCode(permission); final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.applicationInfo.uid)); final UserHandle userHandle = UserHandle.of(userId); mUids.put(uid, uid); if (!permissionInfo.isRestricted()) { return; } final boolean applyRestriction = PackageManager.RESTRICTED_PERMISSIONS_ENABLED && (mPackageManager.getPermissionFlags(permission, pkg.packageName, userHandle) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; if (permissionInfo.isHardRestricted()) { if (applyRestriction) { mOpsToRestrict.add(new OpToRestrict(uid, opCode)); } else { mOpsToUnrestrict.add(new OpToUnrestrict(uid, pkg.packageName, opCode)); } } else if (permissionInfo.isSoftRestricted()) { //TODO: Implement soft restrictions like storage here. } } /** * Add a package for {@link #syncPackages() processing} later. * * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager. * * @param pkg The package to add for later processing * @param userId The user the package belongs to */ void addPackage(@NonNull PackageParser.Package pkg, @UserIdInt int userId) { final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.applicationInfo.uid)); mAllUids.put(uid, uid); final int permissionCount = pkg.requestedPermissions.size(); for (int i = 0; i < permissionCount; i++) { Loading @@ -318,44 +388,47 @@ public final class PermissionPolicyService extends SystemService { final PermissionInfo permissionInfo; try { permissionInfo = packageManager.getPermissionInfo(permission, 0); permissionInfo = mPackageManager.getPermissionInfo(permission, 0); } catch (PackageManager.NameNotFoundException e) { continue; } if (!permissionInfo.isRestricted()) { continue; addOpIfRestricted(permissionInfo, pkg, userId); } final boolean applyRestriction = PackageManager.RESTRICTED_PERMISSIONS_ENABLED && (packageManager.getPermissionFlags(permission, pkg.packageName, userHandle) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; if (permissionInfo.isHardRestricted()) { if (applyRestriction) { mDefaultUidOps.put(opCode, uid); } else { mPackageNames.put(opCode, pkg.packageName); mAllowedUidOps.put(opCode, uid); } } else if (permissionInfo.isSoftRestricted()) { //TODO: Implement soft restrictions like storage here. private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) { final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager .opToPublicName(opCode), uid, packageName); if (currentMode == AppOpsManager.MODE_DEFAULT) { mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED); } } private void setUidModeDefault(int opCode, int uid) { mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT); } private static void setUidModeAllowed(@NonNull AppOpsManager appOpsManager, int opCode, int uid, @NonNull String packageName) { final int currentMode = appOpsManager.unsafeCheckOpRaw(AppOpsManager .opToPublicName(opCode), uid, packageName); if (currentMode == AppOpsManager.MODE_DEFAULT) { appOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED); private class OpToRestrict { final int uid; final int code; OpToRestrict(int uid, int code) { this.uid = uid; this.code = code; } } private static void setUidModeDefault(@NonNull AppOpsManager appOpsManager, int opCode, int uid) { appOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT); private class OpToUnrestrict { final int uid; final @NonNull String packageName; final int code; OpToUnrestrict(int uid, @NonNull String packageName, int code) { this.uid = uid; this.packageName = packageName; this.code = code; } } } }