From bd4943b44ecb1e724e7118a963a1c6998a2f6a44 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Thu, 11 Apr 2019 10:05:48 -0700 Subject: [PATCH] Make perm policy sve ready for additional usages We want to use the permission policy services for other things than restriction of permissions. Hence factor out the restriction code from the framework. Also add some comments Test: atest CtsAppOpsTestCases:android.app.appops.cts.AppOpsTest CtsPermission2TestCases:android.permission2.cts.RestrictedPermissionsTest Bug: 124731615 Change-Id: Ic32f2097af805c3f06dd9cf625b3160f62a576b2 --- .../policy/PermissionPolicyService.java | 199 ++++++++++++------ 1 file changed, 136 insertions(+), 63 deletions(-) diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 67f30dc2e9fc4..b960e580bd484 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -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( @@ -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) { @@ -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(); } @@ -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; - private final @NonNull SparseIntArray mUids = new SparseIntArray(); - private final @NonNull SparseArray mPackageNames = new SparseArray<>(); - private final @NonNull SparseIntArray mAllowedUidOps = new SparseIntArray(); - private final @NonNull SparseIntArray mDefaultUidOps = new SparseIntArray(); + /** All uid that need to be synchronized */ + private final @NonNull SparseIntArray mAllUids = new SparseIntArray(); + + /** + * All ops that need to be restricted + * + * @see #syncRestrictedOps + */ + private final @NonNull ArrayList mOpsToRestrict = new ArrayList<>(); + /** + * All ops that need to be unrestricted + * + * @see #syncRestrictedOps + */ + private final @NonNull ArrayList 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. + * + *

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 @@ -222,52 +250,48 @@ public final class PermissionPolicyService extends SystemService { final SparseArray> 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 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 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)); } @@ -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); } } @@ -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}. + * + *

Note: Called with the package lock held. Do not 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. + * + *

Note: Called with the package lock held. Do not 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++) { @@ -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; - } - - 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. - } + addOpIfRestricted(permissionInfo, pkg, userId); } } - private static void setUidModeAllowed(@NonNull AppOpsManager appOpsManager, - int opCode, int uid, @NonNull String packageName) { - final int currentMode = appOpsManager.unsafeCheckOpRaw(AppOpsManager + 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) { - appOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED); + mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED); } } - private static void setUidModeDefault(@NonNull AppOpsManager appOpsManager, - int opCode, int uid) { - appOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT); + private void setUidModeDefault(int opCode, int uid) { + mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT); + } + + private class OpToRestrict { + final int uid; + final int code; + + OpToRestrict(int uid, int code) { + this.uid = uid; + this.code = code; + } + } + + 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; + } } } }