Loading services/core/java/com/android/server/pm/permission/PermissionManagerService.java +9 −1 Original line number Original line Diff line number Diff line Loading @@ -97,6 +97,7 @@ import com.android.server.pm.SharedUserSetting; import com.android.server.pm.UserManagerService; import com.android.server.pm.UserManagerService; import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback; import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback; import com.android.server.pm.permission.PermissionsState.PermissionState; import com.android.server.pm.permission.PermissionsState.PermissionState; import com.android.server.policy.SoftRestrictedPermissionPolicy; import libcore.util.EmptyArray; import libcore.util.EmptyArray; Loading Loading @@ -2121,11 +2122,18 @@ public class PermissionManagerService { if (bp.isHardRestricted() if (bp.isHardRestricted() && (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) { && (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) { Log.e(TAG, "Cannot grant restricted non-exempt permission " Log.e(TAG, "Cannot grant hard restricted non-exempt permission " + permName + " for package " + packageName); + permName + " for package " + packageName); return; return; } } if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext, pkg.applicationInfo, permName).canBeGranted()) { Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package " + packageName); return; } if (bp.isDevelopment()) { if (bp.isDevelopment()) { // Development permissions must be handled specially, since they are not // Development permissions must be handled specially, since they are not // normal runtime permissions. For now they apply to all users. // normal runtime permissions. For now they apply to all users. Loading services/core/java/com/android/server/policy/PermissionPolicyService.java +36 −18 Original line number Original line Diff line number Diff line Loading @@ -16,10 +16,14 @@ package com.android.server.policy; 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_IGNORED; import static android.app.AppOpsManager.OP_NONE; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.GET_PERMISSIONS; import android.Manifest; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.annotation.UserIdInt; Loading Loading @@ -426,20 +430,34 @@ public final class PermissionPolicyService extends SystemService { mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, opCode)); mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, opCode)); } } } else if (permissionInfo.isSoftRestricted()) { } else if (permissionInfo.isSoftRestricted()) { // Storage uses a special app op to decide the mount state and final SoftRestrictedPermissionPolicy policy = // supports soft restriction where the restricted state allows SoftRestrictedPermissionPolicy.forPermission(mContext, pkg.applicationInfo, // the permission but only for accessing the medial collections. permission); if (Manifest.permission.READ_EXTERNAL_STORAGE.equals(permission) || Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission)) { final int op = policy.getAppOp(); if (applyRestriction) { if (op != OP_NONE) { mOpsToDefault.add(new OpToRestrict(uid, switch (policy.getAppOpMode()) { AppOpsManager.OP_LEGACY_STORAGE)); case MODE_DEFAULT: } else if (pkg.applicationInfo.hasRequestedLegacyExternalStorage()) { mOpsToDefault.add(new OpToRestrict(uid, op)); mOpsToAllow.add(new OpToUnrestrict(uid, pkg.packageName, break; AppOpsManager.OP_LEGACY_STORAGE)); case MODE_ALLOWED: if (policy.shouldSetAppOpIfNotDefault()) { mOpsToAllow.add(new OpToUnrestrict(uid, pkg.packageName, op)); } else { mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, op)); } break; case MODE_IGNORED: if (policy.shouldSetAppOpIfNotDefault()) { Slog.wtf(LOG_TAG, "Always ignoring appops is not implemented"); } else { } else { mOpsToIgnoreIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, mOpsToIgnoreIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, AppOpsManager.OP_LEGACY_STORAGE)); op)); } break; case MODE_ERRORED: Slog.wtf(LOG_TAG, "Setting appop to errored is not implemented"); } } } } } } Loading Loading @@ -483,7 +501,7 @@ public final class PermissionPolicyService extends SystemService { for (String permission : pkg.requestedPermissions) { for (String permission : pkg.requestedPermissions) { final int opCode = AppOpsManager.permissionToOpCode(permission); final int opCode = AppOpsManager.permissionToOpCode(permission); if (opCode == AppOpsManager.OP_NONE) { if (opCode == OP_NONE) { continue; continue; } } Loading Loading @@ -515,13 +533,13 @@ public final class PermissionPolicyService extends SystemService { @NonNull String packageName) { @NonNull String packageName) { final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager .opToPublicName(opCode), uid, packageName); .opToPublicName(opCode), uid, packageName); if (currentMode == AppOpsManager.MODE_DEFAULT) { if (currentMode == MODE_DEFAULT) { mAppOpsManager.setUidMode(opCode, uid, mode); mAppOpsManager.setUidMode(opCode, uid, mode); } } } } private void setUidModeDefault(int opCode, int uid) { private void setUidModeDefault(int opCode, int uid) { mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT); mAppOpsManager.setUidMode(opCode, uid, MODE_DEFAULT); } } private class OpToRestrict { private class OpToRestrict { Loading services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java 0 → 100644 +165 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.policy; 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_DEFAULT; import static android.app.AppOpsManager.MODE_IGNORED; import static android.app.AppOpsManager.OP_LEGACY_STORAGE; import static android.app.AppOpsManager.OP_NONE; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT; import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT; import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; import android.annotation.NonNull; 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 * the policies in one place. * * This is the twin of * {@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 | FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT; private static final SoftRestrictedPermissionPolicy DUMMY_POLICY = new SoftRestrictedPermissionPolicy() { @Override public int getAppOp() { return OP_NONE; } @Override public int getAppOpMode() { return MODE_DEFAULT; } @Override public boolean shouldSetAppOpIfNotDefault() { return false; } @Override public boolean canBeGranted() { return true; } }; /** * Get the policy for a soft restricted permission. * * @param context A context to use * @param appInfo The application the permission belongs to * @param permission The name of the permission * * @return The policy for this permission */ public static @NonNull SoftRestrictedPermissionPolicy forPermission(@NonNull Context context, @NonNull ApplicationInfo appInfo, @NonNull String permission) { switch (permission) { // Storage uses a special app op to decide the mount state and supports soft restriction // where the restricted state allows the permission but only for accessing the medial // collections. case READ_EXTERNAL_STORAGE: case WRITE_EXTERNAL_STORAGE: { int flags = context.getPackageManager().getPermissionFlags( permission, appInfo.packageName, context.getUser()); boolean applyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; boolean isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0; boolean hasRequestedLegacyExternalStorage = appInfo.hasRequestedLegacyExternalStorage(); int targetSDK = appInfo.targetSdkVersion; return new SoftRestrictedPermissionPolicy() { @Override public int getAppOp() { return OP_LEGACY_STORAGE; } @Override public int getAppOpMode() { if (applyRestriction) { return MODE_DEFAULT; } else if (hasRequestedLegacyExternalStorage) { return MODE_ALLOWED; } else { return MODE_IGNORED; } } @Override 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; } @Override public boolean canBeGranted() { 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; } } }; } default: return DUMMY_POLICY; } } /** * @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(); /** * @return The mode the {@link #getAppOp() app op} should be in. */ public abstract @AppOpsManager.Mode int getAppOpMode(); /** * @return If the {@link #getAppOp() app op} should be set even if the app-op is currently not * {@link AppOpsManager#MODE_DEFAULT}. */ public abstract boolean shouldSetAppOpIfNotDefault(); /** * @return If the permission can be granted */ public abstract boolean canBeGranted(); } services/core/java/com/android/server/policy/TEST_MAPPING +8 −0 Original line number Original line Diff line number Diff line Loading @@ -27,6 +27,14 @@ "exclude-annotation": "androidx.test.filters.FlakyTest" "exclude-annotation": "androidx.test.filters.FlakyTest" } } ] ] }, { "name": "CtsPermission2TestCases", "options": [ { "include-filter": "android.permission2.cts.RestrictedPermissionsTest" } ] } } ], ], "postsubmit": [ "postsubmit": [ Loading Loading
services/core/java/com/android/server/pm/permission/PermissionManagerService.java +9 −1 Original line number Original line Diff line number Diff line Loading @@ -97,6 +97,7 @@ import com.android.server.pm.SharedUserSetting; import com.android.server.pm.UserManagerService; import com.android.server.pm.UserManagerService; import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback; import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback; import com.android.server.pm.permission.PermissionsState.PermissionState; import com.android.server.pm.permission.PermissionsState.PermissionState; import com.android.server.policy.SoftRestrictedPermissionPolicy; import libcore.util.EmptyArray; import libcore.util.EmptyArray; Loading Loading @@ -2121,11 +2122,18 @@ public class PermissionManagerService { if (bp.isHardRestricted() if (bp.isHardRestricted() && (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) { && (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) { Log.e(TAG, "Cannot grant restricted non-exempt permission " Log.e(TAG, "Cannot grant hard restricted non-exempt permission " + permName + " for package " + packageName); + permName + " for package " + packageName); return; return; } } if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext, pkg.applicationInfo, permName).canBeGranted()) { Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package " + packageName); return; } if (bp.isDevelopment()) { if (bp.isDevelopment()) { // Development permissions must be handled specially, since they are not // Development permissions must be handled specially, since they are not // normal runtime permissions. For now they apply to all users. // normal runtime permissions. For now they apply to all users. Loading
services/core/java/com/android/server/policy/PermissionPolicyService.java +36 −18 Original line number Original line Diff line number Diff line Loading @@ -16,10 +16,14 @@ package com.android.server.policy; 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_IGNORED; import static android.app.AppOpsManager.OP_NONE; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.GET_PERMISSIONS; import android.Manifest; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.annotation.UserIdInt; Loading Loading @@ -426,20 +430,34 @@ public final class PermissionPolicyService extends SystemService { mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, opCode)); mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, opCode)); } } } else if (permissionInfo.isSoftRestricted()) { } else if (permissionInfo.isSoftRestricted()) { // Storage uses a special app op to decide the mount state and final SoftRestrictedPermissionPolicy policy = // supports soft restriction where the restricted state allows SoftRestrictedPermissionPolicy.forPermission(mContext, pkg.applicationInfo, // the permission but only for accessing the medial collections. permission); if (Manifest.permission.READ_EXTERNAL_STORAGE.equals(permission) || Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission)) { final int op = policy.getAppOp(); if (applyRestriction) { if (op != OP_NONE) { mOpsToDefault.add(new OpToRestrict(uid, switch (policy.getAppOpMode()) { AppOpsManager.OP_LEGACY_STORAGE)); case MODE_DEFAULT: } else if (pkg.applicationInfo.hasRequestedLegacyExternalStorage()) { mOpsToDefault.add(new OpToRestrict(uid, op)); mOpsToAllow.add(new OpToUnrestrict(uid, pkg.packageName, break; AppOpsManager.OP_LEGACY_STORAGE)); case MODE_ALLOWED: if (policy.shouldSetAppOpIfNotDefault()) { mOpsToAllow.add(new OpToUnrestrict(uid, pkg.packageName, op)); } else { mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, op)); } break; case MODE_IGNORED: if (policy.shouldSetAppOpIfNotDefault()) { Slog.wtf(LOG_TAG, "Always ignoring appops is not implemented"); } else { } else { mOpsToIgnoreIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, mOpsToIgnoreIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, AppOpsManager.OP_LEGACY_STORAGE)); op)); } break; case MODE_ERRORED: Slog.wtf(LOG_TAG, "Setting appop to errored is not implemented"); } } } } } } Loading Loading @@ -483,7 +501,7 @@ public final class PermissionPolicyService extends SystemService { for (String permission : pkg.requestedPermissions) { for (String permission : pkg.requestedPermissions) { final int opCode = AppOpsManager.permissionToOpCode(permission); final int opCode = AppOpsManager.permissionToOpCode(permission); if (opCode == AppOpsManager.OP_NONE) { if (opCode == OP_NONE) { continue; continue; } } Loading Loading @@ -515,13 +533,13 @@ public final class PermissionPolicyService extends SystemService { @NonNull String packageName) { @NonNull String packageName) { final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager .opToPublicName(opCode), uid, packageName); .opToPublicName(opCode), uid, packageName); if (currentMode == AppOpsManager.MODE_DEFAULT) { if (currentMode == MODE_DEFAULT) { mAppOpsManager.setUidMode(opCode, uid, mode); mAppOpsManager.setUidMode(opCode, uid, mode); } } } } private void setUidModeDefault(int opCode, int uid) { private void setUidModeDefault(int opCode, int uid) { mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT); mAppOpsManager.setUidMode(opCode, uid, MODE_DEFAULT); } } private class OpToRestrict { private class OpToRestrict { Loading
services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java 0 → 100644 +165 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.policy; 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_DEFAULT; import static android.app.AppOpsManager.MODE_IGNORED; import static android.app.AppOpsManager.OP_LEGACY_STORAGE; import static android.app.AppOpsManager.OP_NONE; import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION; import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT; import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT; import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT; import android.annotation.NonNull; 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 * the policies in one place. * * This is the twin of * {@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 | FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT; private static final SoftRestrictedPermissionPolicy DUMMY_POLICY = new SoftRestrictedPermissionPolicy() { @Override public int getAppOp() { return OP_NONE; } @Override public int getAppOpMode() { return MODE_DEFAULT; } @Override public boolean shouldSetAppOpIfNotDefault() { return false; } @Override public boolean canBeGranted() { return true; } }; /** * Get the policy for a soft restricted permission. * * @param context A context to use * @param appInfo The application the permission belongs to * @param permission The name of the permission * * @return The policy for this permission */ public static @NonNull SoftRestrictedPermissionPolicy forPermission(@NonNull Context context, @NonNull ApplicationInfo appInfo, @NonNull String permission) { switch (permission) { // Storage uses a special app op to decide the mount state and supports soft restriction // where the restricted state allows the permission but only for accessing the medial // collections. case READ_EXTERNAL_STORAGE: case WRITE_EXTERNAL_STORAGE: { int flags = context.getPackageManager().getPermissionFlags( permission, appInfo.packageName, context.getUser()); boolean applyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0; boolean isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0; boolean hasRequestedLegacyExternalStorage = appInfo.hasRequestedLegacyExternalStorage(); int targetSDK = appInfo.targetSdkVersion; return new SoftRestrictedPermissionPolicy() { @Override public int getAppOp() { return OP_LEGACY_STORAGE; } @Override public int getAppOpMode() { if (applyRestriction) { return MODE_DEFAULT; } else if (hasRequestedLegacyExternalStorage) { return MODE_ALLOWED; } else { return MODE_IGNORED; } } @Override 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; } @Override public boolean canBeGranted() { 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; } } }; } default: return DUMMY_POLICY; } } /** * @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(); /** * @return The mode the {@link #getAppOp() app op} should be in. */ public abstract @AppOpsManager.Mode int getAppOpMode(); /** * @return If the {@link #getAppOp() app op} should be set even if the app-op is currently not * {@link AppOpsManager#MODE_DEFAULT}. */ public abstract boolean shouldSetAppOpIfNotDefault(); /** * @return If the permission can be granted */ public abstract boolean canBeGranted(); }
services/core/java/com/android/server/policy/TEST_MAPPING +8 −0 Original line number Original line Diff line number Diff line Loading @@ -27,6 +27,14 @@ "exclude-annotation": "androidx.test.filters.FlakyTest" "exclude-annotation": "androidx.test.filters.FlakyTest" } } ] ] }, { "name": "CtsPermission2TestCases", "options": [ { "include-filter": "android.permission2.cts.RestrictedPermissionsTest" } ] } } ], ], "postsubmit": [ "postsubmit": [ Loading