From bd4943b44ecb1e724e7118a963a1c6998a2f6a44 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Thu, 11 Apr 2019 10:05:48 -0700 Subject: [PATCH 1/3] 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; + } } } } From 4868772bf14e48a65a140c75a20992157f96a289 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Thu, 11 Apr 2019 10:40:30 -0700 Subject: [PATCH 2/3] Make perm policy synchronizer per user Test: atest CtsAppOpsTestCases:android.app.appops.cts.AppOpsTest CtsPermission2TestCases:android.permission2.cts.RestrictedPermissionsTest Bug: 124731615 Change-Id: Idac97b37d1f1268d211109a70d1b1627d4893342 --- .../policy/PermissionPolicyService.java | 67 ++++++++++++------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index b960e580bd484..3bdcbab869ae0 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -17,8 +17,10 @@ package com.android.server.policy; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; +import static android.content.pm.PackageManager.GET_PERMISSIONS; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.content.Context; @@ -158,6 +160,20 @@ public final class PermissionPolicyService extends SystemService { }); } + private static @Nullable Context getUserContext(@NonNull Context context, + @NonNull UserHandle user) { + if (context.getUser().equals(user)) { + return context; + } else { + try { + return context.createPackageContextAsUser(context.getPackageName(), 0, user); + } catch (NameNotFoundException e) { + Slog.e(LOG_TAG, "Cannot create context for user " + user, e); + return null; + } + } + } + /** * Synchronize a single package. */ @@ -165,20 +181,22 @@ public final class PermissionPolicyService extends SystemService { @NonNull String packageName, @UserIdInt int userId) { final PackageManagerInternal packageManagerInternal = LocalServices.getService( PackageManagerInternal.class); - final PackageParser.Package pkg = packageManagerInternal.getPackage(packageName); + final PackageInfo pkg = packageManagerInternal.getPackageInfo(packageName, 0, + Process.SYSTEM_UID, userId); if (pkg == null) { return; } - final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(context); - synchroniser.addPackage(pkg, userId); + final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser( + getUserContext(context, UserHandle.of(userId))); + synchroniser.addPackage(pkg.packageName); final String[] sharedPkgNames = packageManagerInternal.getPackagesForSharedUserId( - pkg.mSharedUserId, userId); + pkg.sharedUserId, userId); if (sharedPkgNames != null) { for (String sharedPkgName : sharedPkgNames) { final PackageParser.Package sharedPkg = packageManagerInternal .getPackage(sharedPkgName); if (sharedPkg != null) { - synchroniser.addPackage(sharedPkg, userId); + synchroniser.addPackage(sharedPkg.packageName); } } } @@ -192,9 +210,9 @@ public final class PermissionPolicyService extends SystemService { @UserIdInt int userId) { final PackageManagerInternal packageManagerInternal = LocalServices.getService( PackageManagerInternal.class); - final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(context); - packageManagerInternal.forEachPackage((pkg) -> - synchronizer.addPackage(pkg, userId)); + final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser( + getUserContext(context, UserHandle.of(userId))); + packageManagerInternal.forEachPackage((pkg) -> synchronizer.addPackage(pkg.packageName)); synchronizer.syncPackages(); } @@ -304,7 +322,7 @@ public final class PermissionPolicyService extends SystemService { if (unrequestedRestrictedPermissions != null) { final int uid = unrequestedRestrictedPermissionsForUid.keyAt(i); final String[] packageNames = (uid != Process.ROOT_UID) - ? mContext.getPackageManager().getPackagesForUid(uid) + ? mPackageManager.getPackagesForUid(uid) : new String[] {"root"}; if (packageNames == null) { continue; @@ -336,14 +354,12 @@ public final class PermissionPolicyService extends SystemService { * * @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) { + @NonNull PackageInfo pkg) { 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); + final int uid = pkg.applicationInfo.uid; if (!permissionInfo.isRestricted()) { return; @@ -351,7 +367,7 @@ public final class PermissionPolicyService extends SystemService { final boolean applyRestriction = PackageManager.RESTRICTED_PERMISSIONS_ENABLED && (mPackageManager.getPermissionFlags(permission, pkg.packageName, - userHandle) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; + mContext.getUser()) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; if (permissionInfo.isHardRestricted()) { if (applyRestriction) { @@ -369,18 +385,23 @@ public final class PermissionPolicyService extends SystemService { * *

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 + * @param pkgName The package to add for later processing. */ - void addPackage(@NonNull PackageParser.Package pkg, @UserIdInt int userId) { - final int uid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.applicationInfo.uid)); + void addPackage(@NonNull String pkgName) { + final PackageInfo pkg; + try { + pkg = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS); + } catch (NameNotFoundException e) { + return; + } - mAllUids.put(uid, uid); + mAllUids.put(pkg.applicationInfo.uid, pkg.applicationInfo.uid); - final int permissionCount = pkg.requestedPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - final String permission = pkg.requestedPermissions.get(i); + if (pkg.requestedPermissions == null) { + return; + } + for (String permission : pkg.requestedPermissions) { final int opCode = AppOpsManager.permissionToOpCode(permission); if (opCode == AppOpsManager.OP_NONE) { continue; @@ -393,7 +414,7 @@ public final class PermissionPolicyService extends SystemService { continue; } - addOpIfRestricted(permissionInfo, pkg, userId); + addOpIfRestricted(permissionInfo, pkg); } } From 9408f5804de69cc6da5108f7c548b47f3dc32564 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Wed, 10 Apr 2019 16:58:24 -0700 Subject: [PATCH 3/3] Use PermissionPolicySve for fg perm app-ops This avoids having to call into app-ops manager while holding the package manager lock Fixes: 124731615, 123436301 Test: atest CtsPermissionTestCases:android.permission.cts.SplitPermissionTest Change-Id: Ie7d5302b4265ed012e2303f3c6e6c7219ff3afa9 --- .../permission/PermissionManagerService.java | 193 +++--------------- .../policy/PermissionPolicyService.java | 71 +++++++ 2 files changed, 96 insertions(+), 168 deletions(-) diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index c75a462d5bc15..dd63e3ca290e0 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -18,12 +18,6 @@ package com.android.server.pm.permission; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; -import static android.app.AppOpsManager.MODE_ALLOWED; -import static android.app.AppOpsManager.MODE_ERRORED; -import static android.app.AppOpsManager.MODE_FOREGROUND; -import static android.app.AppOpsManager.OP_NONE; -import static android.app.AppOpsManager.permissionToOp; -import static android.app.AppOpsManager.permissionToOpCode; import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT; @@ -40,8 +34,6 @@ import static android.content.pm.PackageManager.FLAG_PERMISSION_WHITELIST_UPGRAD import static android.content.pm.PackageManager.MASK_PERMISSION_FLAGS_ALL; import static android.content.pm.PackageManager.RESTRICTED_PERMISSIONS_ENABLED; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; -import static android.os.UserHandle.getAppId; -import static android.os.UserHandle.getUid; import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING; @@ -56,8 +48,6 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; -import android.app.AppOpsManager; -import android.app.AppOpsManagerInternal; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManager.PermissionWhitelistFlags; @@ -1309,9 +1299,6 @@ public class PermissionManagerService { updatedUserIds); updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions, permissionsState, pkg, updatedUserIds); - - // TODO: Move to PermissionPolicyService - setAppOpsLocked(permissionsState, pkg); } // Persist the runtime permissions state for users with changes. If permissions @@ -1326,23 +1313,6 @@ public class PermissionManagerService { } } - /** - * Set app op for a app-op related to a permission. - * - * @param permission The permission the app-op belongs to - * @param pkg The package the permission belongs to - * @param userId The user to be changed - * @param mode The new mode to set - */ - private void setAppOpMode(@NonNull String permission, @NonNull PackageParser.Package pkg, - @UserIdInt int userId, int mode) { - AppOpsManagerInternal appOpsInternal = LocalServices.getService( - AppOpsManagerInternal.class); - - appOpsInternal.setUidMode(permissionToOpCode(permission), - getUid(userId, getAppId(pkg.applicationInfo.uid)), mode); - } - /** * Revoke permissions that are not implicit anymore and that have * {@link PackageManager#FLAG_PERMISSION_REVOKE_WHEN_REQUESTED} set. @@ -1357,8 +1327,6 @@ public class PermissionManagerService { private @NonNull int[] revokePermissionsNoLongerImplicitLocked( @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg, @NonNull int[] updatedUserIds) { - AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class); - String pkgName = pkg.packageName; boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M; @@ -1390,23 +1358,6 @@ public class PermissionManagerService { } flagsToRemove |= USER_PERMISSION_FLAGS; - - List fgPerms = mBackgroundPermissions.get(permission); - if (fgPerms != null) { - int numFgPerms = fgPerms.size(); - for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) { - String fgPerm = fgPerms.get(fgPermNum); - - int mode = appOpsManager.unsafeCheckOpRaw( - permissionToOp(fgPerm), - getUid(userId, getAppId(pkg.applicationInfo.uid)), - pkgName); - - if (mode == MODE_ALLOWED) { - setAppOpMode(fgPerm, pkg, userId, MODE_FOREGROUND); - } - } - } } ps.updatePermissionFlags(bp, userId, flagsToRemove, 0); @@ -1438,91 +1389,39 @@ public class PermissionManagerService { @NonNull ArraySet sourcePerms, @NonNull String newPerm, @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg, @UserIdInt int userId) { - AppOpsManagerInternal appOpsManager = LocalServices.getService(AppOpsManagerInternal.class); String pkgName = pkg.packageName; + boolean isGranted = false; + int flags = 0; - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { - if (permissionToOp(newPerm) != null) { - int mostLenientSourceMode = MODE_ERRORED; - int flags = 0; - - // Find most lenient source permission state. - int numSourcePerms = sourcePerms.size(); - for (int i = 0; i < numSourcePerms; i++) { - String sourcePerm = sourcePerms.valueAt(i); - - if (ps.hasRuntimePermission(sourcePerm, userId)) { - int sourceOp = permissionToOpCode(sourcePerm); - - if (sourceOp != OP_NONE) { - int mode = appOpsManager.checkOperationUnchecked(sourceOp, - getUid(userId, getAppId(pkg.applicationInfo.uid)), pkgName); - - if (mode == MODE_FOREGROUND || mode == MODE_ERRORED) { - Log.wtf(TAG, "split permission" + sourcePerm + " has app-op state " - + AppOpsManager.MODE_NAMES[mode]); - - continue; - } - - // Leniency order: allowed < ignored < default - if (mode < mostLenientSourceMode) { - mostLenientSourceMode = mode; - flags = ps.getPermissionFlags(sourcePerm, userId); - } else if (mode == mostLenientSourceMode) { - flags |= ps.getPermissionFlags(sourcePerm, userId); - } - } - } + int numSourcePerm = sourcePerms.size(); + for (int i = 0; i < numSourcePerm; i++) { + String sourcePerm = sourcePerms.valueAt(i); + if ((ps.hasRuntimePermission(sourcePerm, userId)) + || ps.hasInstallPermission(sourcePerm)) { + if (!isGranted) { + flags = 0; } - if (mostLenientSourceMode != MODE_ERRORED) { - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, newPerm + " inherits app-ops state " + mostLenientSourceMode - + " from " + sourcePerms + " for " + pkgName); - } - - setAppOpMode(newPerm, pkg, userId, mostLenientSourceMode); - - // Add permission flags - ps.updatePermissionFlags(mSettings.getPermission(newPerm), userId, flags, - flags); - } - } - } else { - boolean isGranted = false; - int flags = 0; - - int numSourcePerm = sourcePerms.size(); - for (int i = 0; i < numSourcePerm; i++) { - String sourcePerm = sourcePerms.valueAt(i); - if ((ps.hasRuntimePermission(sourcePerm, userId)) - || ps.hasInstallPermission(sourcePerm)) { - if (!isGranted) { - flags = 0; - } - - isGranted = true; + isGranted = true; + flags |= ps.getPermissionFlags(sourcePerm, userId); + } else { + if (!isGranted) { flags |= ps.getPermissionFlags(sourcePerm, userId); - } else { - if (!isGranted) { - flags |= ps.getPermissionFlags(sourcePerm, userId); - } } } - - if (isGranted) { - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, newPerm + " inherits runtime perm grant from " + sourcePerms - + " for " + pkgName); - } - - ps.grantRuntimePermission(mSettings.getPermissionLocked(newPerm), userId); - } - - // Add permission flags - ps.updatePermissionFlags(mSettings.getPermission(newPerm), userId, flags, flags); } + + if (isGranted) { + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, newPerm + " inherits runtime perm grant from " + sourcePerms + + " for " + pkgName); + } + + ps.grantRuntimePermission(mSettings.getPermissionLocked(newPerm), userId); + } + + // Add permission flags + ps.updatePermissionFlags(mSettings.getPermission(newPerm), userId, flags, flags); } /** @@ -1632,48 +1531,6 @@ public class PermissionManagerService { return updatedUserIds; } - /** - * Fix app-op modes for runtime permissions. - * - * @param permsState The state of the permissions of the package - * @param pkg The package information - */ - private void setAppOpsLocked(@NonNull PermissionsState permsState, - @NonNull PackageParser.Package pkg) { - for (int userId : UserManagerService.getInstance().getUserIds()) { - int numPerms = pkg.requestedPermissions.size(); - for (int i = 0; i < numPerms; i++) { - String permission = pkg.requestedPermissions.get(i); - - // For pre-M apps the runtime permission do not store the state - if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { - continue; - } - - PermissionState state = permsState.getRuntimePermissionState(permission, userId); - if (state == null) { - continue; - } - - // Adjust app-op mods for foreground/background permissions. If an package used to - // have both fg and bg permission granted and it lost the bg permission during an - // upgrade the app-op mode should get downgraded to foreground. - if (state.isGranted()) { - BasePermission bp = mSettings.getPermission(permission); - - if (bp != null && bp.perm != null && bp.perm.info != null - && bp.perm.info.backgroundPermission != null) { - PermissionState bgState = permsState.getRuntimePermissionState( - bp.perm.info.backgroundPermission, userId); - - setAppOpMode(permission, pkg, userId, bgState != null && bgState.isGranted() - ? MODE_ALLOWED : MODE_FOREGROUND); - } - } - } - } - } - private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) { boolean allowed = false; final int NP = PackageParser.NEW_PERMISSIONS.length; diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 3bdcbab869ae0..1fd8b711d3482 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -31,6 +31,7 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal.PackageListObserver; import android.content.pm.PackageParser; import android.content.pm.PermissionInfo; +import android.os.Build; import android.os.Process; import android.os.UserHandle; import android.permission.PermissionControllerManager; @@ -234,6 +235,7 @@ public final class PermissionPolicyService extends SystemService { * @see #syncRestrictedOps */ private final @NonNull ArrayList mOpsToRestrict = new ArrayList<>(); + /** * All ops that need to be unrestricted * @@ -241,6 +243,13 @@ public final class PermissionPolicyService extends SystemService { */ private final @NonNull ArrayList mOpsToUnrestrict = new ArrayList<>(); + /** + * All foreground permissions + * + * @see #syncOpsOfFgPermissions() + */ + private final @NonNull ArrayList mFgPermOps = new ArrayList<>(); + PermissionToOpSynchroniser(@NonNull Context context) { mContext = context; mPackageManager = context.getPackageManager(); @@ -339,11 +348,42 @@ public final class PermissionPolicyService extends SystemService { } } + /** + * Set app ops that belong to restricted permissions. + * + *

This processed ops previously added by {@link #addOpIfRestricted} + */ + private void syncOpsOfFgPermissions() { + int numFgPermOps = mFgPermOps.size(); + for (int i = 0; i < numFgPermOps; i++) { + FgPermission perm = mFgPermOps.get(i); + + if (mPackageManager.checkPermission(perm.fgPermissionName, perm.packageName) + == PackageManager.PERMISSION_GRANTED) { + if (mPackageManager.checkPermission(perm.bgPermissionName, perm.packageName) + == PackageManager.PERMISSION_GRANTED) { + mAppOpsManager.setUidMode( + AppOpsManager.permissionToOpCode(perm.fgPermissionName), perm.uid, + AppOpsManager.MODE_ALLOWED); + } else { + mAppOpsManager.setUidMode( + AppOpsManager.permissionToOpCode(perm.fgPermissionName), perm.uid, + AppOpsManager.MODE_FOREGROUND); + } + } else { + mAppOpsManager.setUidMode( + AppOpsManager.permissionToOpCode(perm.fgPermissionName), perm.uid, + AppOpsManager.MODE_IGNORED); + } + } + } + /** * Synchronize all previously {@link #addPackage added} packages. */ void syncPackages() { syncRestrictedOps(); + syncOpsOfFgPermissions(); } /** @@ -380,6 +420,21 @@ public final class PermissionPolicyService extends SystemService { } } + private void addOpIfFgPermissions(@NonNull PermissionInfo permissionInfo, + @NonNull PackageInfo pkg) { + if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { + // Pre-M apps do not store their fg/bg state in the permissions + return; + } + + if (permissionInfo.backgroundPermission == null) { + return; + } + + mFgPermOps.add(new FgPermission(pkg.applicationInfo.uid, pkg.packageName, + permissionInfo.name, permissionInfo.backgroundPermission)); + } + /** * Add a package for {@link #syncPackages() processing} later. * @@ -415,6 +470,7 @@ public final class PermissionPolicyService extends SystemService { } addOpIfRestricted(permissionInfo, pkg); + addOpIfFgPermissions(permissionInfo, pkg); } } @@ -451,5 +507,20 @@ public final class PermissionPolicyService extends SystemService { this.code = code; } } + + private class FgPermission { + final int uid; + final @NonNull String packageName; + final @NonNull String fgPermissionName; + final @NonNull String bgPermissionName; + + private FgPermission(int uid, @NonNull String packageName, + @NonNull String fgPermissionName, @NonNull String bgPermissionName) { + this.uid = uid; + this.packageName = packageName; + this.fgPermissionName = fgPermissionName; + this.bgPermissionName = bgPermissionName; + } + } } }