/* * Copyright (C) 2018 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 android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; import android.os.Binder; import android.os.Process; import android.permission.IPermissionChecker; import android.permission.PermissionCheckerManager; import android.permission.PermissionCheckerManager.PermissionResult; /** * This class provides permission check APIs that verify both the * permission and the associated app op for this permission if * such is defined. *

* In the new permission model permissions with protection level * dangerous are runtime permissions. For apps targeting {@link android.os.Build.VERSION_CODES#M} * and above the user may not grant such permissions or revoke * them at any time. For apps targeting API lower than {@link android.os.Build.VERSION_CODES#M} * these permissions are always granted as such apps do not expect * permission revocations and would crash. Therefore, when the * user disables a permission for a legacy app in the UI the * platform disables the APIs guarded by this permission making * them a no-op which is doing nothing or returning an empty * result or default error. *

*

* It is important that when you perform an operation on behalf of * another app you use these APIs to check for permissions as the * app may be a legacy app that does not participate in the new * permission model for which the user had disabled the "permission" * which is achieved by disallowing the corresponding app op. *

*

* This class has two types of methods and you should be careful which * type to call based on whether permission protected data is being * passed to the app or you are just checking whether the app holds a * permission. The reason is that a permission check requires checking * the runtime permission and if it is granted checking the corresponding * app op as for apps not supporting the runtime mode we never revoke * permissions but disable app ops. Since there are two types of app op * checks, one that does not leave a record an action was performed and * another the does, one needs to call the preflight flavor of the checks * named xxxForPreflight only if no private data is being delivered but * a permission check is what is needed and the xxxForDataDelivery where * the permission check is right before private data delivery. * * @hide */ public final class PermissionChecker { /** * The permission is granted. * * @hide */ public static final int PERMISSION_GRANTED = PermissionCheckerManager.PERMISSION_GRANTED; /** * The permission is denied. Applicable only to runtime permissions. * *

Returned when: *

* * @hide */ public static final int PERMISSION_SOFT_DENIED = PermissionCheckerManager.PERMISSION_SOFT_DENIED; /** * The permission is denied. * *

Returned when: *

* * @hide */ public static final int PERMISSION_HARD_DENIED = PermissionCheckerManager.PERMISSION_HARD_DENIED; /** Constant when the PID for which we check permissions is unknown. */ public static final int PID_UNKNOWN = -1; private static volatile IPermissionChecker sService; private PermissionChecker() { /* do nothing */ } /** * Checks whether a given package in a UID and PID has a given permission * and whether the app op that corresponds to this permission is allowed. * * NOTE: Use this method only for permission checks at the * point where you will deliver the permission protected data to clients. * *

For example, if an app registers a location listener it should have the location * permission but no data is actually sent to the app at the moment of registration * and you should use {@link #checkPermissionForPreflight(Context, String, int, int, String)} * to determine if the app has or may have location permission (if app has only foreground * location the grant state depends on the app's fg/gb state) and this check will not * leave a trace that permission protected data was delivered. When you are about to * deliver the location data to a registered listener you should use this method which * will evaluate the permission access based on the current fg/bg state of the app and * leave a record that the data was accessed. * *

For more details how to determine the {@code packageName}, {@code attributionTag}, and * {@code message}, please check the description in * {@link AppOpsManager#noteOp(String, int, String, String, String)} * * @param context Context for accessing resources. * @param permission The permission to check. * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID * is not known. * @param uid The uid for which to check. * @param packageName The package name for which to check. If null the * the first package for the calling UID will be used. * @param attributionTag attribution tag * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * @param message A message describing the reason the permission was checked * @param startDataDelivery Whether this is the start of data delivery. * * @see #checkPermissionForPreflight(Context, String, int, int, String) */ @PermissionCheckerManager.PermissionResult public static int checkPermissionForDataDelivery(@NonNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message, boolean startDataDelivery) { return checkPermissionForDataDelivery(context, permission, pid, new AttributionSource(uid, pid, packageName, attributionTag), message, startDataDelivery); } /** * Checks whether a given package in a UID and PID has a given permission * and whether the app op that corresponds to this permission is allowed. * * NOTE: Use this method only for permission checks at the * point where you will deliver the permission protected data to clients. * *

For example, if an app registers a location listener it should have the location * permission but no data is actually sent to the app at the moment of registration * and you should use {@link #checkPermissionForPreflight(Context, String, int, int, String)} * to determine if the app has or may have location permission (if app has only foreground * location the grant state depends on the app's fg/gb state) and this check will not * leave a trace that permission protected data was delivered. When you are about to * deliver the location data to a registered listener you should use this method which * will evaluate the permission access based on the current fg/bg state of the app and * leave a record that the data was accessed. * *

For more details how to determine the {@code packageName}, {@code attributionTag}, and * {@code message}, please check the description in * {@link AppOpsManager#noteOp(String, int, String, String, String)} * * @param context Context for accessing resources. * @param permission The permission to check. * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID * is not known. * @param uid The uid for which to check. * @param packageName The package name for which to check. If null the * the first package for the calling UID will be used. * @param attributionTag attribution tag * @return The permission check result which is either {@link #PERMISSION_GRANTED} * 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) */ @PermissionResult public static int checkPermissionForDataDelivery(@NonNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message) { return checkPermissionForDataDelivery(context, permission, pid, uid, packageName, attributionTag, message, false /*startDataDelivery*/); } /** * Checks whether a given data access chain described by the given {@link AttributionSource} * has a given permission and whether the app op that corresponds to this permission * is allowed. Call this method if you are the datasource which would not blame you for * access to the data since you are the data. * * NOTE: Use this method only for permission checks at the * point where you will deliver the permission protected data to clients. * *

For example, if an app registers a location listener it should have the location * permission but no data is actually sent to the app at the moment of registration * and you should use {@link #checkPermissionForPreflight(Context, String, int, int, String)} * to determine if the app has or may have location permission (if app has only foreground * location the grant state depends on the app's fg/gb state) and this check will not * leave a trace that permission protected data was delivered. When you are about to * deliver the location data to a registered listener you should use this method which * will evaluate the permission access based on the current fg/bg state of the app and * leave a record that the data was accessed. * * @param context Context for accessing resources. * @param permission The permission to check. * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID * is not known. * @param attributionSource the permission identity * @return The permission check result which is either {@link #PERMISSION_GRANTED} * 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, AttributionSource) */ @PermissionResult public static int checkPermissionForDataDeliveryFromDataSource(@NonNull Context context, @NonNull String permission, int pid, @NonNull AttributionSource attributionSource, @Nullable String message) { return checkPermissionForDataDeliveryCommon(context, permission, attributionSource, message, false /*startDataDelivery*/, /*fromDatasource*/ true); } /** * Checks whether a given data access chain described by the given {@link AttributionSource} * has a given permission and whether the app op that corresponds to this permission * is allowed. * * NOTE: Use this method only for permission checks at the * point where you will deliver the permission protected data to clients. * *

For example, if an app registers a location listener it should have the location * permission but no data is actually sent to the app at the moment of registration * and you should use {@link #checkPermissionForPreflight(Context, String, AttributionSource)} * to determine if the app has or may have location permission (if app has only foreground * location the grant state depends on the app's fg/gb state) and this check will not * leave a trace that permission protected data was delivered. When you are about to * deliver the location data to a registered listener you should use this method which * will evaluate the permission access based on the current fg/bg state of the app and * leave a record that the data was accessed. * * @param context Context for accessing resources. * @param permission The permission to check. * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID * is not known. * @param attributionSource the permission identity * @param message A message describing the reason the permission was checked * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkPermissionForPreflight(Context, String, AttributionSource) */ @PermissionResult public static int checkPermissionForDataDelivery(@NonNull Context context, @NonNull String permission, int pid, @NonNull AttributionSource attributionSource, @Nullable String message) { return checkPermissionForDataDelivery(context, permission, pid, attributionSource, message, false /*startDataDelivery*/); } /** * Checks whether a given data access chain described by the given {@link AttributionSource} * has a given permission and whether the app op that corresponds to this permission * is allowed. * * NOTE: Use this method only for permission checks at the * point where you will deliver the permission protected data to clients. * *

For example, if an app registers a data listener it should have the required * permission but no data is actually sent to the app at the moment of registration * and you should use {@link #checkPermissionForPreflight(Context, String, * AttributionSource)} * to determine if the app has or may have permission and this check will not * leave a trace that permission protected data was delivered. When you are about to * deliver the data to a registered listener you should use this method which * will evaluate the permission access based on the current fg/bg state of the app and * leave a record that the data was accessed. * * @param context Context for accessing resources. * @param permission The permission to check. * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID * is not known. * @param attributionSource The identity for which to check the permission. * @param message A message describing the reason the permission was checked * @param startDataDelivery Whether this is the start of data delivery. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkPermissionForPreflight(Context, String, AttributionSource) */ @PermissionResult public static int checkPermissionForDataDelivery(@NonNull Context context, @NonNull String permission, int pid, @NonNull AttributionSource attributionSource, @Nullable String message, boolean startDataDelivery) { return checkPermissionForDataDeliveryCommon(context, permission, attributionSource, message, startDataDelivery, /*fromDatasource*/ false); } @SuppressWarnings("ConstantConditions") private static int checkPermissionForDataDeliveryCommon(@NonNull Context context, @NonNull String permission, @NonNull AttributionSource attributionSource, @Nullable String message, boolean startDataDelivery, boolean fromDatasource) { return context.getSystemService(PermissionCheckerManager.class).checkPermission(permission, attributionSource.asState(), message, true /*forDataDelivery*/, startDataDelivery, fromDatasource, AppOpsManager.OP_NONE); } /** * Checks whether a given data access chain described by the given {@link AttributionSource} * has a given permission and whether the app op that corresponds to this permission * is allowed. The app ops area also marked as started. This is useful for long running * permissions like camera. * * NOTE: Use this method only for permission checks at the * point where you will deliver the permission protected data to clients. * *

For example, if an app registers a data listener it should have the required * permission but no data is actually sent to the app at the moment of registration * and you should use {@link #checkPermissionForPreflight(Context, String, * AttributionSource)} * to determine if the app has or may have permission and this check will not * leave a trace that permission protected data was delivered. When you are about to * deliver the data to a registered listener you should use this method which * will evaluate the permission access based on the current fg/bg state of the app and * leave a record that the data was accessed. * * @param context Context for accessing resources. * @param permission The permission to check. * @param attributionSource The identity for which to check the permission. * @param message A message describing the reason the permission was checked * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkPermissionForPreflight(Context, String, AttributionSource) */ @PermissionResult @SuppressWarnings("ConstantConditions") public static int checkPermissionAndStartDataDelivery(@NonNull Context context, @NonNull String permission, @NonNull AttributionSource attributionSource, @Nullable String message) { return context.getSystemService(PermissionCheckerManager.class).checkPermission( permission, attributionSource.asState(), message, true /*forDataDelivery*/, /*startDataDelivery*/ true, /*fromDatasource*/ false, AppOpsManager.OP_NONE); } /** * Checks whether a given data access chain described by the given {@link * AttributionSource} has a given app op allowed and marks the op as started. * * NOTE: Use this method only for app op checks at the * point where you will deliver the protected data to clients. * *

For example, if an app registers a data listener it should have the data * op but no data is actually sent to the app at the moment of registration * and you should use {@link #checkOpForPreflight(Context, String, AttributionSource, String)} * to determine if the app has or may have op access and this check will not * leave a trace that op protected data was delivered. When you are about to * deliver the data to a registered listener you should use this method which * will evaluate the op access based on the current fg/bg state of the app and * leave a record that the data was accessed. * * @param context Context for accessing resources. * @param opName THe op to start. * @param attributionSource The identity for which to check the permission. * @param message A message describing the reason the permission was checked * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #finishDataDelivery(Context, String, AttributionSource) */ @PermissionResult @SuppressWarnings("ConstantConditions") public static int startOpForDataDelivery(@NonNull Context context, @NonNull String opName, @NonNull AttributionSource attributionSource, @Nullable String message) { return context.getSystemService(PermissionCheckerManager.class).checkOp( AppOpsManager.strOpToOp(opName), attributionSource.asState(), message, true /*forDataDelivery*/, true /*startDataDelivery*/); } /** * Finishes an ongoing op for data access chain described by the given {@link * AttributionSource}. * * @param context Context for accessing resources. * @param op The op to finish. * @param attributionSource The identity for which finish op. * * @see #startOpForDataDelivery(Context, String, AttributionSource, String) * @see #checkPermissionAndStartDataDelivery(Context, String, AttributionSource, String) */ @SuppressWarnings("ConstantConditions") public static void finishDataDelivery(@NonNull Context context, @NonNull String op, @NonNull AttributionSource attributionSource) { context.getSystemService(PermissionCheckerManager.class).finishDataDelivery( AppOpsManager.strOpToOp(op), attributionSource.asState(), /*fromDatasource*/ false); } /** * Finishes an ongoing op for data access chain described by the given {@link * AttributionSource}. Call this method if you are the datasource which would * not finish an op for your attribution source as it was not started. * * @param context Context for accessing resources. * @param op The op to finish. * @param attributionSource The identity for which finish op. * * @see #startOpForDataDelivery(Context, String, AttributionSource, String) * @see #checkPermissionAndStartDataDelivery(Context, String, AttributionSource, String) */ @SuppressWarnings("ConstantConditions") public static void finishDataDeliveryFromDatasource(@NonNull Context context, @NonNull String op, @NonNull AttributionSource attributionSource) { context.getSystemService(PermissionCheckerManager.class).finishDataDelivery( AppOpsManager.strOpToOp(op), attributionSource.asState(), /*fromDatasource*/ true); } /** * Checks whether a given data access chain described by the given {@link * AttributionSource} has a given app op allowed. * * NOTE: Use this method only for op checks at the * preflight point where you will not deliver the protected data * to clients but schedule a data delivery, apps register listeners, * etc. * *

For example, if an app registers a data listener it should have the op * but no data is actually sent to the app at the moment of registration * and you should use this method to determine if the app has or may have data * access and this check will not leave a trace that protected data * was delivered. When you are about to deliver the data to a registered * listener you should use {@link #checkOpForDataDelivery(Context, String, * AttributionSource, String)} which will evaluate the op access based * on the current fg/bg state of the app and leave a record that the data was * accessed. * * @param context Context for accessing resources. * @param opName The op to check. * @param attributionSource The identity for which to check the permission. * @param message A message describing the reason the permission was checked * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkOpForDataDelivery(Context, String, AttributionSource, String) */ @PermissionResult @SuppressWarnings("ConstantConditions") public static int checkOpForPreflight(@NonNull Context context, @NonNull String opName, @NonNull AttributionSource attributionSource, @Nullable String message) { return context.getSystemService(PermissionCheckerManager.class).checkOp( AppOpsManager.strOpToOp(opName), attributionSource.asState(), message, false /*forDataDelivery*/, false /*startDataDelivery*/); } /** * Checks whether a given data access chain described by the given {@link AttributionSource} * has an allowed app op. * * NOTE: Use this method only for op checks at the * point where you will deliver the permission protected data to clients. * *

For example, if an app registers a data listener it should have the data * permission but no data is actually sent to the app at the moment of registration * and you should use {@link #checkOpForPreflight(Context, String, AttributionSource, String)} * to determine if the app has or may have data access and this check will not * leave a trace that op protected data was delivered. When you are about to * deliver the data to a registered listener you should use this method which * will evaluate the op access based on the current fg/bg state of the app and * leave a record that the data was accessed. * * @param context Context for accessing resources. * @param opName The op to check. * @param attributionSource The identity for which to check the op. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * @param message A message describing the reason the permission was checked * * @see #checkOpForPreflight(Context, String, AttributionSource, String) */ @PermissionResult @SuppressWarnings("ConstantConditions") public static int checkOpForDataDelivery(@NonNull Context context, @NonNull String opName, @NonNull AttributionSource attributionSource, @Nullable String message) { return context.getSystemService(PermissionCheckerManager.class).checkOp( AppOpsManager.strOpToOp(opName), attributionSource.asState(), message, true /*forDataDelivery*/, false /*startDataDelivery*/); } /** * Checks whether a given package in a UID and PID has a given permission * and whether the app op that corresponds to this permission is allowed. * * NOTE: Use this method only for permission checks at the * preflight point where you will not deliver the permission protected data * to clients but schedule permission data delivery, apps register listeners, * etc. * *

For example, if an app registers a location listener it should have the location * permission but no data is actually sent to the app at the moment of registration * and you should use this method to determine if the app has or may have location * permission (if app has only foreground location the grant state depends on the app's * fg/gb state) and this check will not leave a trace that permission protected data * was delivered. When you are about to deliver the location data to a registered * listener you should use {@link #checkPermissionForDataDelivery(Context, String, * int, int, String, String, String)} which will evaluate the permission access based * on the currentfg/bg state of the app and leave a record that the data was accessed. * * @param context Context for accessing resources. * @param permission The permission to check. * @param pid The process id for which to check. * @param uid The uid for which to check. * @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_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkPermissionForDataDelivery(Context, String, int, int, String, String, String) */ @PermissionResult public static int checkPermissionForPreflight(@NonNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName) { return checkPermissionForPreflight(context, permission, new AttributionSource( uid, packageName, null /*attributionTag*/)); } /** * Checks whether a given data access chain described by the given {@link AttributionSource} * has a given permission and whether the app op that corresponds to this permission * is allowed. * * NOTE: Use this method only for permission checks at the * preflight point where you will not deliver the permission protected data * to clients but schedule permission data delivery, apps register listeners, * etc. * *

For example, if an app registers a data listener it should have the required * permission but no data is actually sent to the app at the moment of registration * and you should use this method to determine if the app has or may have the * permission and this check will not leave a trace that permission protected data * was delivered. When you are about to deliver the protected data to a registered * listener you should use {@link #checkPermissionForDataDelivery(Context, String, * int, AttributionSource, String, boolean)} which will evaluate the permission access based * on the current fg/bg state of the app and leave a record that the data was accessed. * * @param context Context for accessing resources. * @param permission The permission to check. * @param attributionSource The identity for which to check the permission. * @return The permission check result which is either {@link #PERMISSION_GRANTED} * or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkPermissionForDataDelivery(Context, String, int, AttributionSource, * String, boolean) */ @PermissionResult @SuppressWarnings("ConstantConditions") public static int checkPermissionForPreflight(@NonNull Context context, @NonNull String permission, @NonNull AttributionSource attributionSource) { return context.getSystemService(PermissionCheckerManager.class) .checkPermission(permission, attributionSource.asState(), null /*message*/, false /*forDataDelivery*/, /*startDataDelivery*/ false, /*fromDatasource*/ false, AppOpsManager.OP_NONE); } /** * Checks whether your app has a given permission and whether the app op * that corresponds to this permission is allowed. * * NOTE: Use this method only for permission checks at the * point where you will deliver the permission protected data to clients. * *

For example, if an app registers a location listener it should have the location * permission but no data is actually sent to the app at the moment of registration * and you should use {@link #checkSelfPermissionForPreflight(Context, String)} * to determine if the app has or may have location permission (if app has only foreground * location the grant state depends on the app's fg/gb state) and this check will not * leave a trace that permission protected data was delivered. When you are about to * deliver the location data to a registered listener you should use this method * which will evaluate the permission access based on the current fg/bg state of the * app and leave a record that the data was accessed. * *

This API assumes the {@link Binder#getCallingUid()} is the same as * {@link Process#myUid()}. * * @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_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * @param message A message describing the reason the permission was checked * * @see #checkSelfPermissionForPreflight(Context, String) */ @PermissionResult public static int checkSelfPermissionForDataDelivery(@NonNull Context context, @NonNull String permission, @Nullable String message) { return checkPermissionForDataDelivery(context, permission, Process.myPid(), Process.myUid(), context.getPackageName(), context.getAttributionTag(), message, /*startDataDelivery*/ false); } /** * Checks whether your app has a given permission and whether the app op * that corresponds to this permission is allowed. * * NOTE: Use this method only for permission checks at the * preflight point where you will not deliver the permission protected data * to clients but schedule permission data delivery, apps register listeners, * etc. * *

For example, if an app registers a location listener it should have the location * permission but no data is actually sent to the app at the moment of registration * and you should use this method to determine if the app has or may have location * permission (if app has only foreground location the grant state depends on the * app's fg/gb state) and this check will not leave a trace that permission protected * data was delivered. When you are about to deliver the location data to a registered * listener you should use this method which will evaluate the permission access based * on the current fg/bg state of the app and leave a record that the data was accessed. * *

This API assumes the {@link Binder#getCallingUid()} is the same as * {@link Process#myUid()}. * * @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_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkSelfPermissionForDataDelivery(Context, String, String) */ @PermissionResult public static int checkSelfPermissionForPreflight(@NonNull Context context, @NonNull String permission) { return checkPermissionForPreflight(context, permission, Process.myPid(), Process.myUid(), context.getPackageName()); } /** * Checks whether the IPC you are handling has a given permission and whether * the app op that corresponds to this permission is allowed. * * NOTE: Use this method only for permission checks at the * point where you will deliver the permission protected data to clients. * *

For example, if an app registers a location listener it should have the location * permission but no data is actually sent to the app at the moment of registration * and you should use {@link #checkCallingPermissionForPreflight(Context, String, String)} * to determine if the app has or may have location permission (if app has only foreground * location the grant state depends on the app's fg/gb state) and this check will not * leave a trace that permission protected data was delivered. When you are about to * deliver the location data to a registered listener you should use this method which * will evaluate the permission access based on the current fg/bg state of the app and * leave a record that the data was accessed. * *

For more details how to determine the {@code callingPackageName}, * {@code callingAttributionTag}, and {@code message}, please check the description in * {@link AppOpsManager#noteOp(String, int, String, String, String)} * * @param context Context for accessing resources. * @param permission The permission to check. * @param callingPackageName The package name making the IPC. If null the * the first package for the calling UID will be used. * @param callingAttributionTag attribution tag * @return The permission check result which is either {@link #PERMISSION_GRANTED} * 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) */ @PermissionResult public static int checkCallingPermissionForDataDelivery(@NonNull Context context, @NonNull String permission, @Nullable String callingPackageName, @Nullable String callingAttributionTag, @Nullable String message) { if (Binder.getCallingPid() == Process.myPid()) { return PERMISSION_HARD_DENIED; } return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(), Binder.getCallingUid(), callingPackageName, callingAttributionTag, message, /*startDataDelivery*/ false); } /** * Checks whether the IPC you are handling has a given permission and whether * the app op that corresponds to this permission is allowed. * * NOTE: Use this method only for permission checks at the * preflight point where you will not deliver the permission protected data * to clients but schedule permission data delivery, apps register listeners, * etc. * *

For example, if an app registers a location listener it should have the location * permission but no data is actually sent to the app at the moment of registration * and you should use this method to determine if the app has or may have location * permission (if app has only foreground location the grant state depends on the app's * fg/gb state) and this check will not leave a trace that permission protected data * was delivered. When you are about to deliver the location data to a registered * listener you should use {@link #checkCallingOrSelfPermissionForDataDelivery(Context, * String, String, String, String)} which will evaluate the permission access based on the * current fg/bg stateof the app and leave a record that the data was accessed. * * @param context Context for accessing resources. * @param permission The permission to check. * @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_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkCallingPermissionForDataDelivery(Context, String, String, String, String) */ @PermissionResult public static int checkCallingPermissionForPreflight(@NonNull Context context, @NonNull String permission, @Nullable String packageName) { if (Binder.getCallingPid() == Process.myPid()) { return PERMISSION_HARD_DENIED; } return checkPermissionForPreflight(context, permission, Binder.getCallingPid(), Binder.getCallingUid(), packageName); } /** * Checks whether the IPC you are handling or your app has a given permission * and whether the app op that corresponds to this permission is allowed. * * NOTE: Use this method only for permission checks at the * point where you will deliver the permission protected data to clients. * *

For example, if an app registers a location listener it should have the location * permission but no data is actually sent to the app at the moment of registration * and you should use {@link #checkCallingOrSelfPermissionForPreflight(Context, String)} * to determine if the app has or may have location permission (if app has only foreground * location the grant state depends on the app's fg/gb state) and this check will not * leave a trace that permission protected data was delivered. When you are about to * deliver the location data to a registered listener you should use this method which * will evaluate the permission access based on the current fg/bg state of the app and * leave a record that the data was accessed. * *

For more details how to determine the {@code callingPackageName}, * {@code callingAttributionTag}, and {@code message}, please check the description in * {@link AppOpsManager#noteOp(String, int, String, String, String)} * * @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_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * @param callingPackageName package name tag of caller (if not self) * @param callingAttributionTag attribution tag of caller (if not self) * @param message A message describing the reason the permission was checked * * @see #checkCallingOrSelfPermissionForPreflight(Context, String) */ @PermissionResult public static int checkCallingOrSelfPermissionForDataDelivery(@NonNull Context context, @NonNull String permission, @Nullable String callingPackageName, @Nullable String callingAttributionTag, @Nullable String message) { callingPackageName = (Binder.getCallingPid() == Process.myPid()) ? context.getPackageName() : callingPackageName; callingAttributionTag = (Binder.getCallingPid() == Process.myPid()) ? context.getAttributionTag() : callingAttributionTag; return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(), Binder.getCallingUid(), callingPackageName, callingAttributionTag, message, /*startDataDelivery*/ false); } /** * Checks whether the IPC you are handling or your app has a given permission * and whether the app op that corresponds to this permission is allowed. * * NOTE: Use this method only for permission checks at the * preflight point where you will not deliver the permission protected data * to clients but schedule permission data delivery, apps register listeners, * etc. * *

For example, if an app registers a location listener it should have the location * permission but no data is actually sent to the app at the moment of registration * and you should use this method to determine if the app has or may have location * permission (if app has only foreground location the grant state depends on the * app's fg/gb state) and this check will not leave a trace that permission protected * data was delivered. When you are about to deliver the location data to a registered * listener you should use {@link #checkCallingOrSelfPermissionForDataDelivery(Context, * String, String, String, String)} which will evaluate the permission access based on the * current fg/bg state of the app and leave a record that the data was accessed. * * @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_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}. * * @see #checkCallingOrSelfPermissionForDataDelivery(Context, String, String, String, String) */ @PermissionResult public static int checkCallingOrSelfPermissionForPreflight(@NonNull Context context, @NonNull String permission) { String packageName = (Binder.getCallingPid() == Process.myPid()) ? context.getPackageName() : null; return checkPermissionForPreflight(context, permission, Binder.getCallingPid(), Binder.getCallingUid(), packageName); } }