Loading core/java/android/content/PermissionChecker.java +93 −38 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.os.Binder; import android.os.Process; Loading Loading @@ -67,22 +68,30 @@ import java.lang.annotation.RetentionPolicy; * @hide */ public final class PermissionChecker { /** Permission result: The permission is granted. */ /** The permission is granted. */ public static final int PERMISSION_GRANTED = PackageManager.PERMISSION_GRANTED; /** Permission result: The permission is denied. */ public static final int PERMISSION_DENIED = PackageManager.PERMISSION_DENIED; /** Returned when: * <ul> * <li>For non app op permissions, returned when the permission is denied.</li> * <li>For app op permissions, returned when the app op is denied or app op is * {@link AppOpsManager#MODE_DEFAULT} and permission is denied.</li> * </ul> * */ public static final int PERMISSION_HARD_DENIED = PackageManager.PERMISSION_DENIED; /** Permission result: The permission is denied because the app op is not allowed. */ public static final int PERMISSION_DENIED_APP_OP = PackageManager.PERMISSION_DENIED - 1; /** Only for runtime permissions, its returned when the runtime permission * is granted, but the corresponding app op is denied. */ public static final int PERMISSION_SOFT_DENIED = PackageManager.PERMISSION_DENIED - 1; /** Constant when the PID for which we check permissions is unknown. */ public static final int PID_UNKNOWN = -1; /** @hide */ @IntDef({PERMISSION_GRANTED, PERMISSION_DENIED, PERMISSION_DENIED_APP_OP}) PERMISSION_SOFT_DENIED, PERMISSION_HARD_DENIED}) @Retention(RetentionPolicy.SOURCE) public @interface PermissionResult {} Loading Loading @@ -116,7 +125,7 @@ public final class PermissionChecker { * the first package for the calling UID will be used. * @param featureId Feature in the package * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * @param message A message describing the reason the permission was checked * * @see #checkPermissionForPreflight(Context, String, int, int, String) Loading Loading @@ -155,7 +164,7 @@ public final class PermissionChecker { * @param packageName The package name for which to check. If null the * the first package for the calling UID will be used. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkPermissionForDataDelivery(Context, String, int, int, String, String) */ Loading Loading @@ -189,7 +198,7 @@ public final class PermissionChecker { * @param context Context for accessing resources. * @param permission The permission to check. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * @param message A message describing the reason the permission was checked * * @see #checkSelfPermissionForPreflight(Context, String) Loading Loading @@ -225,7 +234,7 @@ public final class PermissionChecker { * @param context Context for accessing resources. * @param permission The permission to check. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkSelfPermissionForDataDelivery(Context, String, String) */ Loading Loading @@ -259,7 +268,7 @@ public final class PermissionChecker { * the first package for the calling UID will be used. * @param featureId The feature inside of the app * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * @param message A message describing the reason the permission was checked * * @see #checkCallingPermissionForPreflight(Context, String, String) Loading @@ -269,7 +278,7 @@ public final class PermissionChecker { @NonNull String permission, @Nullable String packageName, @Nullable String featureId, @Nullable String message) { if (Binder.getCallingPid() == Process.myPid()) { return PERMISSION_DENIED; return PERMISSION_HARD_DENIED; } return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(), Binder.getCallingUid(), packageName, featureId, message); Loading Loading @@ -299,7 +308,7 @@ public final class PermissionChecker { * @param packageName The package name making the IPC. If null the * the first package for the calling UID will be used. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkCallingPermissionForDataDelivery(Context, String, String, String) */ Loading @@ -307,7 +316,7 @@ public final class PermissionChecker { public static int checkCallingPermissionForPreflight(@NonNull Context context, @NonNull String permission, @Nullable String packageName) { if (Binder.getCallingPid() == Process.myPid()) { return PERMISSION_DENIED; return PERMISSION_HARD_DENIED; } return checkPermissionForPreflight(context, permission, Binder.getCallingPid(), Binder.getCallingUid(), packageName); Loading @@ -333,7 +342,7 @@ public final class PermissionChecker { * @param context Context for accessing resources. * @param permission The permission to check. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * @param featureId feature Id of caller (if not self) * @param message A message describing the reason the permission was checked * Loading Loading @@ -372,7 +381,7 @@ public final class PermissionChecker { * @param context Context for accessing resources. * @param permission The permission to check. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkCallingOrSelfPermissionForDataDelivery(Context, String, String, String) */ Loading @@ -385,39 +394,85 @@ public final class PermissionChecker { Binder.getCallingUid(), packageName); } private static int checkPermissionCommon(@NonNull Context context, @NonNull String permission, static int checkPermissionCommon(@NonNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String featureId, @Nullable String message, boolean forDataDelivery) { if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) { return PERMISSION_DENIED; } AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); String op = appOpsManager.permissionToOp(permission); if (op == null) { return PERMISSION_GRANTED; final PermissionInfo permissionInfo; try { // TODO(b/147869157): Cache platform defined app op and runtime permissions to avoid // calling into the package manager every time. permissionInfo = context.getPackageManager().getPermissionInfo(permission, 0); } catch (PackageManager.NameNotFoundException ignored) { return PERMISSION_HARD_DENIED; } if (packageName == null) { String[] packageNames = context.getPackageManager().getPackagesForUid(uid); if (packageNames == null || packageNames.length <= 0) { return PERMISSION_DENIED; } if (packageNames != null && packageNames.length > 0) { packageName = packageNames[0]; } } if (forDataDelivery) { if (appOpsManager.noteProxyOpNoThrow(op, packageName, uid, featureId, message) != AppOpsManager.MODE_ALLOWED) { return PERMISSION_DENIED_APP_OP; if (permissionInfo.isAppOp()) { return checkAppOpPermission(context, permission, pid, uid, packageName, featureId, message, forDataDelivery); } } else { final int mode = appOpsManager.unsafeCheckOpRawNoThrow(op, uid, packageName); if (mode != AppOpsManager.MODE_ALLOWED && mode != AppOpsManager.MODE_FOREGROUND) { return PERMISSION_DENIED_APP_OP; if (permissionInfo.isRuntime()) { return checkRuntimePermission(context, permission, pid, uid, packageName, featureId, message, forDataDelivery); } return context.checkPermission(permission, pid, uid); } private static int checkAppOpPermission(@NonNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String featureId, @Nullable String message, boolean forDataDelivery) { final String op = AppOpsManager.permissionToOp(permission); if (op == null || packageName == null) { return PERMISSION_HARD_DENIED; } final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); final int opMode = (forDataDelivery) ? appOpsManager.noteProxyOpNoThrow(op, packageName, uid, featureId, message) : appOpsManager.unsafeCheckOpNoThrow(op, uid, packageName); switch (opMode) { case AppOpsManager.MODE_ALLOWED: { return PERMISSION_GRANTED; } case AppOpsManager.MODE_DEFAULT: { return context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED ? PERMISSION_GRANTED : PERMISSION_HARD_DENIED; } default: { return PERMISSION_HARD_DENIED; } } } private static int checkRuntimePermission(@NonNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String featureId, @Nullable String message, boolean forDataDelivery) { if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) { return PERMISSION_HARD_DENIED; } final String op = AppOpsManager.permissionToOp(permission); if (op == null || packageName == null) { return PERMISSION_GRANTED; } final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); final int opMode = (forDataDelivery) ? appOpsManager.noteProxyOpNoThrow(op, packageName, uid, featureId, message) : appOpsManager.unsafeCheckOpNoThrow(op, uid, packageName); if (opMode == AppOpsManager.MODE_ALLOWED) { return PERMISSION_GRANTED; } else { return PERMISSION_SOFT_DENIED; } } } core/tests/coretests/src/android/content/PermissionCheckerTest.java 0 → 100644 +195 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 android.content; import static com.google.common.truth.Truth.assertThat; import android.app.AppOpsManager; import android.app.UiAutomation; import android.os.Binder; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; // TODO(b/147877945): Add missing tests. @RunWith(AndroidJUnit4.class) public class PermissionCheckerTest { private static final String INTERACT_ACROSS_PROFILES_PERMISSION = "android.permission.INTERACT_ACROSS_PROFILES"; private static final String MANAGE_APP_OPS_MODE = "android.permission.MANAGE_APP_OPS_MODES"; private final Context mContext = InstrumentationRegistry.getContext();; private final AppOpsManager mAppOpsManager = mContext.getSystemService(AppOpsManager.class); private UiAutomation mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); @After public void tearDown() { InstrumentationRegistry.getInstrumentation().getUiAutomation() .dropShellPermissionIdentity(); } @Test public void testCheckPermissionForPreflight_appOpPermission_modeDefaultAndPermissionGranted_returnsGranted() { mUiAutomation.adoptShellPermissionIdentity( INTERACT_ACROSS_PROFILES_PERMISSION, MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_DEFAULT); assertThat(PermissionChecker.checkPermissionForPreflight( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName())) .isEqualTo(PermissionChecker.PERMISSION_GRANTED); } @Test public void testCheckPermissionForPreflight_appOpPermission_modeDefaultAndPermissionNotGranted_returnsHardDenied() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_DEFAULT); assertThat(PermissionChecker.checkPermissionForPreflight( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName())) .isEqualTo(PermissionChecker.PERMISSION_HARD_DENIED); } @Test public void testCheckPermissionForPreflight_appOpPermission_modeAllowed_returnsGranted() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_ALLOWED); assertThat(PermissionChecker.checkPermissionForPreflight( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName())) .isEqualTo(PermissionChecker.PERMISSION_GRANTED); } @Test public void testCheckPermissionForPreflight_appOpPermission_packageNameIsNull_returnsGranted() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_ALLOWED); assertThat(PermissionChecker.checkPermissionForPreflight( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), /* packageName= */ null)) .isEqualTo(PermissionChecker.PERMISSION_GRANTED); } @Test public void testCheckPermissionForPreflight_appOpPermission_modeIgnored_returnsHardDenied() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_IGNORED); assertThat(PermissionChecker.checkPermissionForPreflight( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName())) .isEqualTo(PermissionChecker.PERMISSION_HARD_DENIED); } @Test public void testCheckPermissionForPreflight_appOpPermission_modeErrored_returnsHardDenied() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_ERRORED); assertThat(PermissionChecker.checkPermissionForPreflight( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName())) .isEqualTo(PermissionChecker.PERMISSION_HARD_DENIED); } @Test public void testCheckPermissionForDataDelivery_appOpPermission_modeDefaultAndPermissionGranted_returnsGranted() { mUiAutomation.adoptShellPermissionIdentity( INTERACT_ACROSS_PROFILES_PERMISSION, MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_DEFAULT); assertThat(PermissionChecker.checkPermissionForDataDelivery( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName(), /* featureId= */null, /* message= */null)).isEqualTo(PermissionChecker.PERMISSION_GRANTED); } @Test public void testCheckPermissionForDataDelivery_appOpPermission_modeDefaultAndPermissionNotGranted_returnsHardDenied() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_DEFAULT); assertThat(PermissionChecker.checkPermissionForDataDelivery( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName(), /* featureId= */null, /* message= */null)).isEqualTo(PermissionChecker.PERMISSION_HARD_DENIED); } @Test public void testCheckPermissionForDataDelivery_appOpPermission_modeAllowed_returnsGranted() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_ALLOWED); assertThat(PermissionChecker.checkPermissionForDataDelivery( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName(), /* featureId= */null, /* message= */null)).isEqualTo(PermissionChecker.PERMISSION_GRANTED); } @Test public void testCheckPermissionForDataDelivery_appOpPermission_packageNameIsNull_returnsGranted() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_ALLOWED); assertThat(PermissionChecker.checkPermissionForDataDelivery( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), /* packageName= */ null, /* featureId= */null, /* message= */null)).isEqualTo(PermissionChecker.PERMISSION_GRANTED); } @Test public void testCheckPermissionForDataDelivery_appOpPermission_modeIgnored_returnsHardDenied() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_IGNORED); assertThat(PermissionChecker.checkPermissionForDataDelivery( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName(), /* featureId= */null, /* message= */null)).isEqualTo(PermissionChecker.PERMISSION_HARD_DENIED); } @Test public void testCheckPermissionForDataDelivery_appOpPermission_modeErrored_returnsHardDenied() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_ERRORED); assertThat(PermissionChecker.checkPermissionForDataDelivery( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName(), /* featureId= */null, /* message= */null)).isEqualTo(PermissionChecker.PERMISSION_HARD_DENIED); } } services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java +2 −2 Original line number Diff line number Diff line Loading @@ -257,10 +257,10 @@ public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareServic switch (status) { case PermissionChecker.PERMISSION_GRANTED: return; case PermissionChecker.PERMISSION_DENIED: case PermissionChecker.PERMISSION_HARD_DENIED: throw new SecurityException( String.format("Caller must have the %s permission.", permission)); case PermissionChecker.PERMISSION_DENIED_APP_OP: case PermissionChecker.PERMISSION_SOFT_DENIED: throw new ServiceSpecificException(Status.TEMPORARY_PERMISSION_DENIED, String.format("Caller must have the %s permission.", permission)); default: Loading Loading
core/java/android/content/PermissionChecker.java +93 −38 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.os.Binder; import android.os.Process; Loading Loading @@ -67,22 +68,30 @@ import java.lang.annotation.RetentionPolicy; * @hide */ public final class PermissionChecker { /** Permission result: The permission is granted. */ /** The permission is granted. */ public static final int PERMISSION_GRANTED = PackageManager.PERMISSION_GRANTED; /** Permission result: The permission is denied. */ public static final int PERMISSION_DENIED = PackageManager.PERMISSION_DENIED; /** Returned when: * <ul> * <li>For non app op permissions, returned when the permission is denied.</li> * <li>For app op permissions, returned when the app op is denied or app op is * {@link AppOpsManager#MODE_DEFAULT} and permission is denied.</li> * </ul> * */ public static final int PERMISSION_HARD_DENIED = PackageManager.PERMISSION_DENIED; /** Permission result: The permission is denied because the app op is not allowed. */ public static final int PERMISSION_DENIED_APP_OP = PackageManager.PERMISSION_DENIED - 1; /** Only for runtime permissions, its returned when the runtime permission * is granted, but the corresponding app op is denied. */ public static final int PERMISSION_SOFT_DENIED = PackageManager.PERMISSION_DENIED - 1; /** Constant when the PID for which we check permissions is unknown. */ public static final int PID_UNKNOWN = -1; /** @hide */ @IntDef({PERMISSION_GRANTED, PERMISSION_DENIED, PERMISSION_DENIED_APP_OP}) PERMISSION_SOFT_DENIED, PERMISSION_HARD_DENIED}) @Retention(RetentionPolicy.SOURCE) public @interface PermissionResult {} Loading Loading @@ -116,7 +125,7 @@ public final class PermissionChecker { * the first package for the calling UID will be used. * @param featureId Feature in the package * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * @param message A message describing the reason the permission was checked * * @see #checkPermissionForPreflight(Context, String, int, int, String) Loading Loading @@ -155,7 +164,7 @@ public final class PermissionChecker { * @param packageName The package name for which to check. If null the * the first package for the calling UID will be used. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkPermissionForDataDelivery(Context, String, int, int, String, String) */ Loading Loading @@ -189,7 +198,7 @@ public final class PermissionChecker { * @param context Context for accessing resources. * @param permission The permission to check. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * @param message A message describing the reason the permission was checked * * @see #checkSelfPermissionForPreflight(Context, String) Loading Loading @@ -225,7 +234,7 @@ public final class PermissionChecker { * @param context Context for accessing resources. * @param permission The permission to check. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkSelfPermissionForDataDelivery(Context, String, String) */ Loading Loading @@ -259,7 +268,7 @@ public final class PermissionChecker { * the first package for the calling UID will be used. * @param featureId The feature inside of the app * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * @param message A message describing the reason the permission was checked * * @see #checkCallingPermissionForPreflight(Context, String, String) Loading @@ -269,7 +278,7 @@ public final class PermissionChecker { @NonNull String permission, @Nullable String packageName, @Nullable String featureId, @Nullable String message) { if (Binder.getCallingPid() == Process.myPid()) { return PERMISSION_DENIED; return PERMISSION_HARD_DENIED; } return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(), Binder.getCallingUid(), packageName, featureId, message); Loading Loading @@ -299,7 +308,7 @@ public final class PermissionChecker { * @param packageName The package name making the IPC. If null the * the first package for the calling UID will be used. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkCallingPermissionForDataDelivery(Context, String, String, String) */ Loading @@ -307,7 +316,7 @@ public final class PermissionChecker { public static int checkCallingPermissionForPreflight(@NonNull Context context, @NonNull String permission, @Nullable String packageName) { if (Binder.getCallingPid() == Process.myPid()) { return PERMISSION_DENIED; return PERMISSION_HARD_DENIED; } return checkPermissionForPreflight(context, permission, Binder.getCallingPid(), Binder.getCallingUid(), packageName); Loading @@ -333,7 +342,7 @@ public final class PermissionChecker { * @param context Context for accessing resources. * @param permission The permission to check. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * @param featureId feature Id of caller (if not self) * @param message A message describing the reason the permission was checked * Loading Loading @@ -372,7 +381,7 @@ public final class PermissionChecker { * @param context Context for accessing resources. * @param permission The permission to check. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkCallingOrSelfPermissionForDataDelivery(Context, String, String, String) */ Loading @@ -385,39 +394,85 @@ public final class PermissionChecker { Binder.getCallingUid(), packageName); } private static int checkPermissionCommon(@NonNull Context context, @NonNull String permission, static int checkPermissionCommon(@NonNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String featureId, @Nullable String message, boolean forDataDelivery) { if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) { return PERMISSION_DENIED; } AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); String op = appOpsManager.permissionToOp(permission); if (op == null) { return PERMISSION_GRANTED; final PermissionInfo permissionInfo; try { // TODO(b/147869157): Cache platform defined app op and runtime permissions to avoid // calling into the package manager every time. permissionInfo = context.getPackageManager().getPermissionInfo(permission, 0); } catch (PackageManager.NameNotFoundException ignored) { return PERMISSION_HARD_DENIED; } if (packageName == null) { String[] packageNames = context.getPackageManager().getPackagesForUid(uid); if (packageNames == null || packageNames.length <= 0) { return PERMISSION_DENIED; } if (packageNames != null && packageNames.length > 0) { packageName = packageNames[0]; } } if (forDataDelivery) { if (appOpsManager.noteProxyOpNoThrow(op, packageName, uid, featureId, message) != AppOpsManager.MODE_ALLOWED) { return PERMISSION_DENIED_APP_OP; if (permissionInfo.isAppOp()) { return checkAppOpPermission(context, permission, pid, uid, packageName, featureId, message, forDataDelivery); } } else { final int mode = appOpsManager.unsafeCheckOpRawNoThrow(op, uid, packageName); if (mode != AppOpsManager.MODE_ALLOWED && mode != AppOpsManager.MODE_FOREGROUND) { return PERMISSION_DENIED_APP_OP; if (permissionInfo.isRuntime()) { return checkRuntimePermission(context, permission, pid, uid, packageName, featureId, message, forDataDelivery); } return context.checkPermission(permission, pid, uid); } private static int checkAppOpPermission(@NonNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String featureId, @Nullable String message, boolean forDataDelivery) { final String op = AppOpsManager.permissionToOp(permission); if (op == null || packageName == null) { return PERMISSION_HARD_DENIED; } final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); final int opMode = (forDataDelivery) ? appOpsManager.noteProxyOpNoThrow(op, packageName, uid, featureId, message) : appOpsManager.unsafeCheckOpNoThrow(op, uid, packageName); switch (opMode) { case AppOpsManager.MODE_ALLOWED: { return PERMISSION_GRANTED; } case AppOpsManager.MODE_DEFAULT: { return context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED ? PERMISSION_GRANTED : PERMISSION_HARD_DENIED; } default: { return PERMISSION_HARD_DENIED; } } } private static int checkRuntimePermission(@NonNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String featureId, @Nullable String message, boolean forDataDelivery) { if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) { return PERMISSION_HARD_DENIED; } final String op = AppOpsManager.permissionToOp(permission); if (op == null || packageName == null) { return PERMISSION_GRANTED; } final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); final int opMode = (forDataDelivery) ? appOpsManager.noteProxyOpNoThrow(op, packageName, uid, featureId, message) : appOpsManager.unsafeCheckOpNoThrow(op, uid, packageName); if (opMode == AppOpsManager.MODE_ALLOWED) { return PERMISSION_GRANTED; } else { return PERMISSION_SOFT_DENIED; } } }
core/tests/coretests/src/android/content/PermissionCheckerTest.java 0 → 100644 +195 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 android.content; import static com.google.common.truth.Truth.assertThat; import android.app.AppOpsManager; import android.app.UiAutomation; import android.os.Binder; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; // TODO(b/147877945): Add missing tests. @RunWith(AndroidJUnit4.class) public class PermissionCheckerTest { private static final String INTERACT_ACROSS_PROFILES_PERMISSION = "android.permission.INTERACT_ACROSS_PROFILES"; private static final String MANAGE_APP_OPS_MODE = "android.permission.MANAGE_APP_OPS_MODES"; private final Context mContext = InstrumentationRegistry.getContext();; private final AppOpsManager mAppOpsManager = mContext.getSystemService(AppOpsManager.class); private UiAutomation mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); @After public void tearDown() { InstrumentationRegistry.getInstrumentation().getUiAutomation() .dropShellPermissionIdentity(); } @Test public void testCheckPermissionForPreflight_appOpPermission_modeDefaultAndPermissionGranted_returnsGranted() { mUiAutomation.adoptShellPermissionIdentity( INTERACT_ACROSS_PROFILES_PERMISSION, MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_DEFAULT); assertThat(PermissionChecker.checkPermissionForPreflight( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName())) .isEqualTo(PermissionChecker.PERMISSION_GRANTED); } @Test public void testCheckPermissionForPreflight_appOpPermission_modeDefaultAndPermissionNotGranted_returnsHardDenied() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_DEFAULT); assertThat(PermissionChecker.checkPermissionForPreflight( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName())) .isEqualTo(PermissionChecker.PERMISSION_HARD_DENIED); } @Test public void testCheckPermissionForPreflight_appOpPermission_modeAllowed_returnsGranted() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_ALLOWED); assertThat(PermissionChecker.checkPermissionForPreflight( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName())) .isEqualTo(PermissionChecker.PERMISSION_GRANTED); } @Test public void testCheckPermissionForPreflight_appOpPermission_packageNameIsNull_returnsGranted() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_ALLOWED); assertThat(PermissionChecker.checkPermissionForPreflight( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), /* packageName= */ null)) .isEqualTo(PermissionChecker.PERMISSION_GRANTED); } @Test public void testCheckPermissionForPreflight_appOpPermission_modeIgnored_returnsHardDenied() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_IGNORED); assertThat(PermissionChecker.checkPermissionForPreflight( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName())) .isEqualTo(PermissionChecker.PERMISSION_HARD_DENIED); } @Test public void testCheckPermissionForPreflight_appOpPermission_modeErrored_returnsHardDenied() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_ERRORED); assertThat(PermissionChecker.checkPermissionForPreflight( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName())) .isEqualTo(PermissionChecker.PERMISSION_HARD_DENIED); } @Test public void testCheckPermissionForDataDelivery_appOpPermission_modeDefaultAndPermissionGranted_returnsGranted() { mUiAutomation.adoptShellPermissionIdentity( INTERACT_ACROSS_PROFILES_PERMISSION, MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_DEFAULT); assertThat(PermissionChecker.checkPermissionForDataDelivery( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName(), /* featureId= */null, /* message= */null)).isEqualTo(PermissionChecker.PERMISSION_GRANTED); } @Test public void testCheckPermissionForDataDelivery_appOpPermission_modeDefaultAndPermissionNotGranted_returnsHardDenied() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_DEFAULT); assertThat(PermissionChecker.checkPermissionForDataDelivery( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName(), /* featureId= */null, /* message= */null)).isEqualTo(PermissionChecker.PERMISSION_HARD_DENIED); } @Test public void testCheckPermissionForDataDelivery_appOpPermission_modeAllowed_returnsGranted() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_ALLOWED); assertThat(PermissionChecker.checkPermissionForDataDelivery( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName(), /* featureId= */null, /* message= */null)).isEqualTo(PermissionChecker.PERMISSION_GRANTED); } @Test public void testCheckPermissionForDataDelivery_appOpPermission_packageNameIsNull_returnsGranted() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_ALLOWED); assertThat(PermissionChecker.checkPermissionForDataDelivery( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), /* packageName= */ null, /* featureId= */null, /* message= */null)).isEqualTo(PermissionChecker.PERMISSION_GRANTED); } @Test public void testCheckPermissionForDataDelivery_appOpPermission_modeIgnored_returnsHardDenied() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_IGNORED); assertThat(PermissionChecker.checkPermissionForDataDelivery( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName(), /* featureId= */null, /* message= */null)).isEqualTo(PermissionChecker.PERMISSION_HARD_DENIED); } @Test public void testCheckPermissionForDataDelivery_appOpPermission_modeErrored_returnsHardDenied() { mUiAutomation.adoptShellPermissionIdentity(MANAGE_APP_OPS_MODE); mAppOpsManager.setMode(AppOpsManager.permissionToOp(INTERACT_ACROSS_PROFILES_PERMISSION), Binder.getCallingUid(), mContext.getPackageName(), AppOpsManager.MODE_ERRORED); assertThat(PermissionChecker.checkPermissionForDataDelivery( mContext, INTERACT_ACROSS_PROFILES_PERMISSION, Binder.getCallingPid(), Binder.getCallingUid(), mContext.getPackageName(), /* featureId= */null, /* message= */null)).isEqualTo(PermissionChecker.PERMISSION_HARD_DENIED); } }
services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareService.java +2 −2 Original line number Diff line number Diff line Loading @@ -257,10 +257,10 @@ public class SoundTriggerMiddlewareService extends ISoundTriggerMiddlewareServic switch (status) { case PermissionChecker.PERMISSION_GRANTED: return; case PermissionChecker.PERMISSION_DENIED: case PermissionChecker.PERMISSION_HARD_DENIED: throw new SecurityException( String.format("Caller must have the %s permission.", permission)); case PermissionChecker.PERMISSION_DENIED_APP_OP: case PermissionChecker.PERMISSION_SOFT_DENIED: throw new ServiceSpecificException(Status.TEMPORARY_PERMISSION_DENIED, String.format("Caller must have the %s permission.", permission)); default: Loading