diff options
| author | 2019-06-11 09:01:59 -0700 | |
|---|---|---|
| committer | 2019-06-12 11:19:27 -0700 | |
| commit | 404b51c2894426d3486b960b8e591d839368c45c (patch) | |
| tree | db33565a73d29c41f5dfe0dc372376c90623a0fe | |
| parent | 11110b74ac884bc130cc518ae2de494cdc79f689 (diff) | |
Set app-op for restricted pre-22 apps
For these apps the permission is always granted and the grant state is
encoded into the app-op.
Also, unify syncOps* for restricted and foreground permissions into one.
Test: atest RestrictedPermissionsTest
SplitPermissionTest
Bug: 134500512
Change-Id: I2250a52d2250752c74907b3a9789ed45a4c75390
3 files changed, 143 insertions, 102 deletions
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 1d01a84138a4..6882afb6285d 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -19,6 +19,7 @@ package com.android.server.policy; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_DEFAULT; import static android.app.AppOpsManager.MODE_ERRORED; +import static android.app.AppOpsManager.MODE_FOREGROUND; import static android.app.AppOpsManager.MODE_IGNORED; import static android.app.AppOpsManager.OP_NONE; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; @@ -290,7 +291,7 @@ public final class PermissionPolicyService extends SystemService { * * Currently, only used by the restricted permissions logic. * - * @see #syncRestrictedOps + * @see #syncPackages */ private final @NonNull ArrayList<OpToRestrict> mOpsToDefault = new ArrayList<>(); @@ -299,16 +300,14 @@ public final class PermissionPolicyService extends SystemService { * * Currently, only used by the restricted permissions logic. * - * @see #syncRestrictedOps + * @see #syncPackages */ private final @NonNull ArrayList<OpToUnrestrict> mOpsToAllowIfDefault = new ArrayList<>(); /** * All ops that need to be flipped to allow. * - * Currently, only used by the restricted permissions logic. - * - * @see #syncRestrictedOps + * @see #syncPackages */ private final @NonNull ArrayList<OpToUnrestrict> mOpsToAllow = new ArrayList<>(); @@ -317,16 +316,25 @@ public final class PermissionPolicyService extends SystemService { * * Currently, only used by the restricted permissions logic. * - * @see #syncRestrictedOps + * @see #syncPackages */ private final @NonNull ArrayList<OpToUnrestrict> mOpsToIgnoreIfDefault = new ArrayList<>(); /** - * All foreground permissions + * All ops that need to be flipped to ignore. * - * @see #syncOpsOfFgPermissions() + * @see #syncPackages */ - private final @NonNull ArrayList<FgPermission> mFgPermOps = new ArrayList<>(); + private final @NonNull ArrayList<OpToUnrestrict> mOpsToIgnore = new ArrayList<>(); + + /** + * All ops that need to be flipped to foreground. + * + * Currently, only used by the foreground/background permissions logic. + * + * @see #syncPackages + */ + private final @NonNull ArrayList<OpToUnrestrict> mOpsToForeground = new ArrayList<>(); PermissionToOpSynchroniser(@NonNull Context context) { mContext = context; @@ -335,11 +343,11 @@ public final class PermissionPolicyService extends SystemService { } /** - * Set app ops that belong to restricted permissions. + * Set app ops that were added in {@link #addPackage}. * * <p>This processes ops previously added by {@link #addOpIfRestricted} */ - private void syncRestrictedOps() { + private void syncPackages() { final int allowCount = mOpsToAllow.size(); for (int i = 0; i < allowCount; i++) { final OpToUnrestrict op = mOpsToAllow.get(i); @@ -350,6 +358,16 @@ public final class PermissionPolicyService extends SystemService { final OpToUnrestrict op = mOpsToAllowIfDefault.get(i); setUidModeAllowedIfDefault(op.code, op.uid, op.packageName); } + final int foregroundCount = mOpsToForeground.size(); + for (int i = 0; i < foregroundCount; i++) { + final OpToUnrestrict op = mOpsToForeground.get(i); + setUidModeForeground(op.code, op.uid); + } + final int ignoreCount = mOpsToIgnore.size(); + for (int i = 0; i < ignoreCount; i++) { + final OpToUnrestrict op = mOpsToIgnore.get(i); + setUidModeIgnored(op.code, op.uid); + } final int ignoreIfDefaultCount = mOpsToIgnoreIfDefault.size(); for (int i = 0; i < ignoreIfDefaultCount; i++) { final OpToUnrestrict op = mOpsToIgnoreIfDefault.get(i); @@ -363,46 +381,8 @@ public final class PermissionPolicyService extends SystemService { } /** - * Set app ops that belong to restricted permissions. - * - * <p>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(); - } - - /** * Add op that belong to a restricted permission for later processing in - * {@link #syncRestrictedOps}. + * {@link #syncPackages()}. * * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager. * @@ -424,19 +404,29 @@ public final class PermissionPolicyService extends SystemService { mContext.getUser()) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; if (permissionInfo.isHardRestricted()) { - if (applyRestriction) { - mOpsToDefault.add(new OpToRestrict(uid, opCode)); - } else { - mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, opCode)); + if (opCode != OP_NONE) { + if (applyRestriction) { + mOpsToDefault.add(new OpToRestrict(uid, opCode)); + } else { + mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, opCode)); + } } } else if (permissionInfo.isSoftRestricted()) { final SoftRestrictedPermissionPolicy policy = SoftRestrictedPermissionPolicy.forPermission(mContext, pkg.applicationInfo, permission); - final int op = policy.getAppOp(); + if (opCode != OP_NONE) { + if (policy.canBeGranted()) { + mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, opCode)); + } else { + mOpsToDefault.add(new OpToRestrict(uid, opCode)); + } + } + + final int op = policy.resolveAppOp(); if (op != OP_NONE) { - switch (policy.getAppOpMode()) { + switch (policy.getDesiredOpMode()) { case MODE_DEFAULT: mOpsToDefault.add(new OpToRestrict(uid, op)); break; @@ -444,16 +434,22 @@ public final class PermissionPolicyService extends SystemService { if (policy.shouldSetAppOpIfNotDefault()) { mOpsToAllow.add(new OpToUnrestrict(uid, pkg.packageName, op)); } else { - mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, - op)); + mOpsToAllowIfDefault.add( + new OpToUnrestrict(uid, pkg.packageName, + op)); } break; + case MODE_FOREGROUND: + Slog.wtf(LOG_TAG, + "Setting appop to foreground is not implemented"); + break; case MODE_IGNORED: if (policy.shouldSetAppOpIfNotDefault()) { - Slog.wtf(LOG_TAG, "Always ignoring appops is not implemented"); + mOpsToIgnore.add(new OpToUnrestrict(uid, pkg.packageName, op)); } else { - mOpsToIgnoreIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, - op)); + mOpsToIgnoreIfDefault.add( + new OpToUnrestrict(uid, pkg.packageName, + op)); } break; case MODE_ERRORED: @@ -463,19 +459,59 @@ public final class PermissionPolicyService extends SystemService { } } + /** + * Add op that belong to a foreground permission for later processing in + * {@link #syncPackages()}. + * + * <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 + */ 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; - } + final String bgPermissionName = permissionInfo.backgroundPermission; - if (permissionInfo.backgroundPermission == null) { + if (bgPermissionName == null) { return; } - mFgPermOps.add(new FgPermission(pkg.applicationInfo.uid, pkg.packageName, - permissionInfo.name, permissionInfo.backgroundPermission)); + final String permission = permissionInfo.name; + final int opCode = AppOpsManager.permissionToOpCode(permission); + final String pkgName = pkg.packageName; + final int uid = pkg.applicationInfo.uid; + + if (mPackageManager.checkPermission(permission, pkgName) + == PackageManager.PERMISSION_GRANTED) { + boolean isBgHardRestricted = false; + try { + final PermissionInfo bgPermInfo = mPackageManager.getPermissionInfo( + bgPermissionName, 0); + + if (bgPermInfo.isSoftRestricted()) { + Slog.wtf(LOG_TAG, "Support for soft restricted background permissions not " + + "implemented"); + } + + isBgHardRestricted = + bgPermInfo.isHardRestricted() && (mPackageManager.getPermissionFlags( + bgPermissionName, pkgName, UserHandle.getUserHandleForUid(uid)) + & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; + } catch (NameNotFoundException e) { + Slog.w(LOG_TAG, "Cannot read permission state of " + bgPermissionName, e); + } + + final boolean isBgPermGranted = mPackageManager.checkPermission(bgPermissionName, + pkgName) == PackageManager.PERMISSION_GRANTED; + + if (!isBgHardRestricted && isBgPermGranted) { + mOpsToAllow.add(new OpToUnrestrict(uid, pkgName, opCode)); + } else { + mOpsToForeground.add(new OpToUnrestrict(uid, pkgName, opCode)); + } + } else { + mOpsToIgnore.add(new OpToUnrestrict(uid, pkgName, opCode)); + } } /** @@ -525,14 +561,33 @@ public final class PermissionPolicyService extends SystemService { mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED); } + private void setUidModeForeground(int opCode, int uid) { + mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_FOREGROUND); + } + private void setUidModeIgnoredIfDefault(int opCode, int uid, @NonNull String packageName) { setUidModeIfDefault(opCode, uid, AppOpsManager.MODE_IGNORED, packageName); } + private void setUidModeIgnored(int opCode, int uid) { + mAppOpsManager.setUidMode(opCode, uid, MODE_IGNORED); + } + private void setUidModeIfDefault(int opCode, int uid, int mode, @NonNull String packageName) { - final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager - .opToPublicName(opCode), uid, packageName); + final int currentMode; + try { + currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager + .opToPublicName(opCode), uid, packageName); + } catch (SecurityException e) { + // This might happen if the app was uninstalled in between the add and sync step. + // In this case the package name cannot be resolved inside appops service and hence + // the uid does not match. + Slog.w(LOG_TAG, "Cannot set mode of uid=" + uid + " op=" + opCode + " to " + mode, + e); + return; + } + if (currentMode == MODE_DEFAULT) { mAppOpsManager.setUidMode(opCode, uid, mode); } @@ -563,21 +618,6 @@ 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; - } - } } private class Internal extends PermissionPolicyInternal { diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java index e19b708bcdae..d44761728c16 100644 --- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java +++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java @@ -33,7 +33,6 @@ import android.app.AppOpsManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.os.Build; -import android.util.Log; /** * The behavior of soft restricted permissions is different for each permission. This class collects @@ -43,8 +42,6 @@ import android.util.Log; * {@link com.android.packageinstaller.permission.utils.SoftRestrictedPermissionPolicy} */ public abstract class SoftRestrictedPermissionPolicy { - private static final String LOG_TAG = SoftRestrictedPermissionPolicy.class.getSimpleName(); - private static final int FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT = FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT @@ -53,12 +50,12 @@ public abstract class SoftRestrictedPermissionPolicy { private static final SoftRestrictedPermissionPolicy DUMMY_POLICY = new SoftRestrictedPermissionPolicy() { @Override - public int getAppOp() { + public int resolveAppOp() { return OP_NONE; } @Override - public int getAppOpMode() { + public int getDesiredOpMode() { return MODE_DEFAULT; } @@ -100,12 +97,12 @@ public abstract class SoftRestrictedPermissionPolicy { return new SoftRestrictedPermissionPolicy() { @Override - public int getAppOp() { + public int resolveAppOp() { return OP_LEGACY_STORAGE; } @Override - public int getAppOpMode() { + public int getDesiredOpMode() { if (applyRestriction) { return MODE_DEFAULT; } else if (hasRequestedLegacyExternalStorage) { @@ -119,7 +116,7 @@ public abstract class SoftRestrictedPermissionPolicy { public boolean shouldSetAppOpIfNotDefault() { // Do not switch from allowed -> ignored as this would mean to retroactively // turn on isolated storage. This will make the app loose all its files. - return getAppOpMode() != MODE_IGNORED; + return getDesiredOpMode() != MODE_IGNORED; } @Override @@ -127,10 +124,6 @@ public abstract class SoftRestrictedPermissionPolicy { if (isWhiteListed || targetSDK >= Build.VERSION_CODES.Q) { return true; } else { - Log.w(LOG_TAG, permission + " for " + appInfo.packageName - + " is not whitelisted and targetSDK " + targetSDK + "<" - + Build.VERSION_CODES.Q); - return false; } } @@ -145,16 +138,16 @@ public abstract class SoftRestrictedPermissionPolicy { * @return An app op to be changed based on the state of the permission or * {@link AppOpsManager#OP_NONE} if not app-op should be set. */ - public abstract int getAppOp(); + public abstract int resolveAppOp(); /** - * @return The mode the {@link #getAppOp() app op} should be in. + * @return The mode the {@link #resolveAppOp() app op} should be in. */ - public abstract @AppOpsManager.Mode int getAppOpMode(); + public abstract @AppOpsManager.Mode int getDesiredOpMode(); /** - * @return If the {@link #getAppOp() app op} should be set even if the app-op is currently not - * {@link AppOpsManager#MODE_DEFAULT}. + * @return If the {@link #resolveAppOp() app op} should be set even if the app-op is currently + * not {@link AppOpsManager#MODE_DEFAULT}. */ public abstract boolean shouldSetAppOpIfNotDefault(); diff --git a/services/core/java/com/android/server/policy/TEST_MAPPING b/services/core/java/com/android/server/policy/TEST_MAPPING index 02b0e21a33c0..c7f8c07432a8 100644 --- a/services/core/java/com/android/server/policy/TEST_MAPPING +++ b/services/core/java/com/android/server/policy/TEST_MAPPING @@ -35,6 +35,14 @@ "include-filter": "android.permission2.cts.RestrictedPermissionsTest" } ] + }, + { + "name": "CtsPermissionTestCases", + "options": [ + { + "include-filter": "android.permission.cts.SplitPermissionTest" + } + ] } ], "postsubmit": [ |