• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.content;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.app.AppOpsManager;
22 import android.os.Binder;
23 import android.os.Process;
24 import android.permission.IPermissionChecker;
25 import android.permission.PermissionCheckerManager;
26 import android.permission.PermissionCheckerManager.PermissionResult;
27 
28 /**
29  * This class provides permission check APIs that verify both the
30  * permission and the associated app op for this permission if
31  * such is defined.
32  * <p>
33  * In the new permission model permissions with protection level
34  * dangerous are runtime permissions. For apps targeting {@link android.os.Build.VERSION_CODES#M}
35  * and above the user may not grant such permissions or revoke
36  * them at any time. For apps targeting API lower than {@link android.os.Build.VERSION_CODES#M}
37  * these permissions are always granted as such apps do not expect
38  * permission revocations and would crash. Therefore, when the
39  * user disables a permission for a legacy app in the UI the
40  * platform disables the APIs guarded by this permission making
41  * them a no-op which is doing nothing or returning an empty
42  * result or default error.
43  * </p>
44  * <p>
45  * It is important that when you perform an operation on behalf of
46  * another app you use these APIs to check for permissions as the
47  * app may be a legacy app that does not participate in the new
48  * permission model for which the user had disabled the "permission"
49  * which is achieved by disallowing the corresponding app op.
50  * </p>
51  * <p>
52  * This class has two types of methods and you should be careful which
53  * type to call based on whether permission protected data is being
54  * passed to the app or you are just checking whether the app holds a
55  * permission. The reason is that a permission check requires checking
56  * the runtime permission and if it is granted checking the corresponding
57  * app op as for apps not supporting the runtime mode we never revoke
58  * permissions but disable app ops. Since there are two types of app op
59  * checks, one that does not leave a record an action was performed and
60  * another the does, one needs to call the preflight flavor of the checks
61  * named xxxForPreflight only if no private data is being delivered but
62  * a permission check is what is needed and the xxxForDataDelivery where
63  * the permission check is right before private data delivery.
64  *
65  * @hide
66  */
67 public final class PermissionChecker {
68     /**
69      * The permission is granted.
70      *
71      * @hide
72      */
73     public static final int PERMISSION_GRANTED = PermissionCheckerManager.PERMISSION_GRANTED;
74 
75     /**
76      * The permission is denied. Applicable only to runtime and app op permissions.
77      *
78      * <p>Returned when:
79      * <ul>
80      *   <li>the runtime permission is granted, but the corresponding app op is denied
81      *       for runtime permissions.</li>
82      *   <li>the app ops is ignored for app op permissions.</li>
83      * </ul>
84      *
85      * @hide
86      */
87     public static final int PERMISSION_SOFT_DENIED =
88             PermissionCheckerManager.PERMISSION_SOFT_DENIED;
89 
90     /**
91      * The permission is denied.
92      *
93      * <p>Returned when:
94      * <ul>
95      *   <li>the permission is denied for non app op permissions.</li>
96      *   <li>the app op is denied or app op is {@link AppOpsManager#MODE_DEFAULT}
97      *   and permission is denied.</li>
98      * </ul>
99      *
100      * @hide
101      */
102     public static final int PERMISSION_HARD_DENIED =
103             PermissionCheckerManager.PERMISSION_HARD_DENIED;
104 
105     /** Constant when the PID for which we check permissions is unknown. */
106     public static final int PID_UNKNOWN = -1;
107 
108     private static volatile IPermissionChecker sService;
109 
PermissionChecker()110     private PermissionChecker() {
111         /* do nothing */
112     }
113 
114     /**
115      * Checks whether a given package in a UID and PID has a given permission
116      * and whether the app op that corresponds to this permission is allowed.
117      *
118      * <strong>NOTE:</strong> Use this method only for permission checks at the
119      * point where you will deliver the permission protected data to clients.
120      *
121      * <p>For example, if an app registers a location listener it should have the location
122      * permission but no data is actually sent to the app at the moment of registration
123      * and you should use {@link #checkPermissionForPreflight(Context, String, int, int, String)}
124      * to determine if the app has or may have location permission (if app has only foreground
125      * location the grant state depends on the app's fg/gb state) and this check will not
126      * leave a trace that permission protected data was delivered. When you are about to
127      * deliver the location data to a registered listener you should use this method which
128      * will evaluate the permission access based on the current fg/bg state of the app and
129      * leave a record that the data was accessed.
130      *
131      * <p>For more details how to determine the {@code packageName}, {@code attributionTag}, and
132      * {@code message}, please check the description in
133      * {@link AppOpsManager#noteOp(String, int, String, String, String)}
134      *
135      * @param context Context for accessing resources.
136      * @param permission The permission to check.
137      * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID
138      *    is not known.
139      * @param uid The uid for which to check.
140      * @param packageName The package name for which to check. If null the
141      *     the first package for the calling UID will be used.
142      * @param attributionTag attribution tag
143      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
144      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
145      * @param message A message describing the reason the permission was checked
146      * @param startDataDelivery Whether this is the start of data delivery.
147      *
148      * @see #checkPermissionForPreflight(Context, String, int, int, String)
149      */
150     @PermissionCheckerManager.PermissionResult
checkPermissionForDataDelivery(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message, boolean startDataDelivery)151     public static int checkPermissionForDataDelivery(@NonNull Context context,
152             @NonNull String permission, int pid, int uid, @Nullable String packageName,
153             @Nullable String attributionTag, @Nullable String message, boolean startDataDelivery) {
154         return checkPermissionForDataDelivery(context, permission, pid, new AttributionSource(uid,
155                 packageName, attributionTag), message, startDataDelivery);
156     }
157 
158     /**
159      * Checks whether a given package in a UID and PID has a given permission
160      * and whether the app op that corresponds to this permission is allowed.
161      *
162      * <strong>NOTE:</strong> Use this method only for permission checks at the
163      * point where you will deliver the permission protected data to clients.
164      *
165      * <p>For example, if an app registers a location listener it should have the location
166      * permission but no data is actually sent to the app at the moment of registration
167      * and you should use {@link #checkPermissionForPreflight(Context, String, int, int, String)}
168      * to determine if the app has or may have location permission (if app has only foreground
169      * location the grant state depends on the app's fg/gb state) and this check will not
170      * leave a trace that permission protected data was delivered. When you are about to
171      * deliver the location data to a registered listener you should use this method which
172      * will evaluate the permission access based on the current fg/bg state of the app and
173      * leave a record that the data was accessed.
174      *
175      * <p>For more details how to determine the {@code packageName}, {@code attributionTag}, and
176      * {@code message}, please check the description in
177      * {@link AppOpsManager#noteOp(String, int, String, String, String)}
178      *
179      * @param context Context for accessing resources.
180      * @param permission The permission to check.
181      * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID
182      *    is not known.
183      * @param uid The uid for which to check.
184      * @param packageName The package name for which to check. If null the
185      *     the first package for the calling UID will be used.
186      * @param attributionTag attribution tag
187      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
188      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
189      * @param message A message describing the reason the permission was checked
190      *
191      * @see #checkPermissionForPreflight(Context, String, int, int, String)
192      */
193     @PermissionResult
checkPermissionForDataDelivery(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message)194     public static int checkPermissionForDataDelivery(@NonNull Context context,
195             @NonNull String permission, int pid, int uid, @Nullable String packageName,
196             @Nullable String attributionTag, @Nullable String message) {
197         return checkPermissionForDataDelivery(context, permission, pid, uid,
198                 packageName, attributionTag, message, false /*startDataDelivery*/);
199     }
200 
201     /**
202      * Checks whether a given data access chain described by the given {@link AttributionSource}
203      * has a given permission and whether the app op that corresponds to this permission
204      * is allowed. Call this method if you are the datasource which would not blame you for
205      * access to the data since you are the data.
206      *
207      * <strong>NOTE:</strong> Use this method only for permission checks at the
208      * point where you will deliver the permission protected data to clients.
209      *
210      * <p>For example, if an app registers a location listener it should have the location
211      * permission but no data is actually sent to the app at the moment of registration
212      * and you should use {@link #checkPermissionForPreflight(Context, String, int, int, String)}
213      * to determine if the app has or may have location permission (if app has only foreground
214      * location the grant state depends on the app's fg/gb state) and this check will not
215      * leave a trace that permission protected data was delivered. When you are about to
216      * deliver the location data to a registered listener you should use this method which
217      * will evaluate the permission access based on the current fg/bg state of the app and
218      * leave a record that the data was accessed.
219      *
220      * @param context Context for accessing resources.
221      * @param permission The permission to check.
222      * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID
223      *    is not known.
224      * @param attributionSource the permission identity
225      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
226      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
227      * @param message A message describing the reason the permission was checked
228      *
229      * @see #checkPermissionForPreflight(Context, String, AttributionSource)
230      */
231     @PermissionResult
checkPermissionForDataDeliveryFromDataSource(@onNull Context context, @NonNull String permission, int pid, @NonNull AttributionSource attributionSource, @Nullable String message)232     public static int checkPermissionForDataDeliveryFromDataSource(@NonNull Context context,
233             @NonNull String permission, int pid, @NonNull AttributionSource attributionSource,
234             @Nullable String message) {
235         return checkPermissionForDataDeliveryCommon(context, permission, attributionSource,
236                 message, false /*startDataDelivery*/, /*fromDatasource*/ true);
237     }
238 
239     /**
240      * Checks whether a given data access chain described by the given {@link AttributionSource}
241      * has a given permission and whether the app op that corresponds to this permission
242      * is allowed.
243      *
244      * <strong>NOTE:</strong> Use this method only for permission checks at the
245      * point where you will deliver the permission protected data to clients.
246      *
247      * <p>For example, if an app registers a location listener it should have the location
248      * permission but no data is actually sent to the app at the moment of registration
249      * and you should use {@link #checkPermissionForPreflight(Context, String, AttributionSource)}
250      * to determine if the app has or may have location permission (if app has only foreground
251      * location the grant state depends on the app's fg/gb state) and this check will not
252      * leave a trace that permission protected data was delivered. When you are about to
253      * deliver the location data to a registered listener you should use this method which
254      * will evaluate the permission access based on the current fg/bg state of the app and
255      * leave a record that the data was accessed.
256      *
257      * @param context Context for accessing resources.
258      * @param permission The permission to check.
259      * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID
260      *    is not known.
261      * @param attributionSource the permission identity
262      * @param message A message describing the reason the permission was checked
263      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
264      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
265      *
266      * @see #checkPermissionForPreflight(Context, String, AttributionSource)
267      */
268     @PermissionResult
checkPermissionForDataDelivery(@onNull Context context, @NonNull String permission, int pid, @NonNull AttributionSource attributionSource, @Nullable String message)269     public static int checkPermissionForDataDelivery(@NonNull Context context,
270             @NonNull String permission, int pid, @NonNull AttributionSource attributionSource,
271             @Nullable String message) {
272         return checkPermissionForDataDelivery(context, permission, pid, attributionSource,
273                 message, false /*startDataDelivery*/);
274     }
275 
276     /**
277      * Checks whether a given data access chain described by the given {@link AttributionSource}
278      * has a given permission and whether the app op that corresponds to this permission
279      * is allowed.
280      *
281      * <strong>NOTE:</strong> Use this method only for permission checks at the
282      * point where you will deliver the permission protected data to clients.
283      *
284      * <p>For example, if an app registers a data listener it should have the required
285      * permission but no data is actually sent to the app at the moment of registration
286      * and you should use {@link #checkPermissionForPreflight(Context, String,
287      * AttributionSource)}
288      * to determine if the app has or may have permission and this check will not
289      * leave a trace that permission protected data was delivered. When you are about to
290      * deliver the data to a registered listener you should use this method which
291      * will evaluate the permission access based on the current fg/bg state of the app and
292      * leave a record that the data was accessed.
293      *
294      * @param context Context for accessing resources.
295      * @param permission The permission to check.
296      * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID
297      *    is not known.
298      * @param attributionSource The identity for which to check the permission.
299      * @param message A message describing the reason the permission was checked
300      * @param startDataDelivery Whether this is the start of data delivery.
301      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
302      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
303      *
304      * @see #checkPermissionForPreflight(Context, String, AttributionSource)
305      */
306     @PermissionResult
checkPermissionForDataDelivery(@onNull Context context, @NonNull String permission, int pid, @NonNull AttributionSource attributionSource, @Nullable String message, boolean startDataDelivery)307     public static int checkPermissionForDataDelivery(@NonNull Context context,
308             @NonNull String permission, int pid, @NonNull AttributionSource attributionSource,
309             @Nullable String message, boolean startDataDelivery) {
310         return checkPermissionForDataDeliveryCommon(context, permission, attributionSource,
311                 message, startDataDelivery, /*fromDatasource*/ false);
312     }
313 
314     @SuppressWarnings("ConstantConditions")
checkPermissionForDataDeliveryCommon(@onNull Context context, @NonNull String permission, @NonNull AttributionSource attributionSource, @Nullable String message, boolean startDataDelivery, boolean fromDatasource)315     private static int checkPermissionForDataDeliveryCommon(@NonNull Context context,
316             @NonNull String permission, @NonNull AttributionSource attributionSource,
317             @Nullable String message, boolean startDataDelivery, boolean fromDatasource) {
318         return context.getSystemService(PermissionCheckerManager.class).checkPermission(permission,
319                 attributionSource.asState(), message, true /*forDataDelivery*/, startDataDelivery,
320                 fromDatasource, AppOpsManager.OP_NONE);
321     }
322 
323     /**
324      * Checks whether a given data access chain described by the given {@link AttributionSource}
325      * has a given permission and whether the app op that corresponds to this permission
326      * is allowed. The app ops area also marked as started. This is useful for long running
327      * permissions like camera.
328      *
329      * <strong>NOTE:</strong> Use this method only for permission checks at the
330      * point where you will deliver the permission protected data to clients.
331      *
332      * <p>For example, if an app registers a data listener it should have the required
333      * permission but no data is actually sent to the app at the moment of registration
334      * and you should use {@link #checkPermissionForPreflight(Context, String,
335      * AttributionSource)}
336      * to determine if the app has or may have permission and this check will not
337      * leave a trace that permission protected data was delivered. When you are about to
338      * deliver the data to a registered listener you should use this method which
339      * will evaluate the permission access based on the current fg/bg state of the app and
340      * leave a record that the data was accessed.
341      *
342      * @param context Context for accessing resources.
343      * @param permission The permission to check.
344      * @param attributionSource The identity for which to check the permission.
345      * @param message A message describing the reason the permission was checked
346      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
347      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
348      *
349      * @see #checkPermissionForPreflight(Context, String, AttributionSource)
350      */
351     @PermissionResult
352     @SuppressWarnings("ConstantConditions")
checkPermissionAndStartDataDelivery(@onNull Context context, @NonNull String permission, @NonNull AttributionSource attributionSource, @Nullable String message)353     public static int checkPermissionAndStartDataDelivery(@NonNull Context context,
354             @NonNull String permission, @NonNull AttributionSource attributionSource,
355             @Nullable String message) {
356         return context.getSystemService(PermissionCheckerManager.class).checkPermission(
357                 permission, attributionSource.asState(), message, true /*forDataDelivery*/,
358                 /*startDataDelivery*/ true, /*fromDatasource*/ false, AppOpsManager.OP_NONE);
359     }
360 
361     /**
362      * Checks whether a given data access chain described by the given {@link
363      * AttributionSource} has a given app op allowed and marks the op as started.
364      *
365      * <strong>NOTE:</strong> Use this method only for app op checks at the
366      * point where you will deliver the protected data to clients.
367      *
368      * <p>For example, if an app registers a data listener it should have the data
369      * op but no data is actually sent to the app at the moment of registration
370      * and you should use {@link #checkOpForPreflight(Context, String, AttributionSource, String)}
371      * to determine if the app has or may have op access and this check will not
372      * leave a trace that op protected data was delivered. When you are about to
373      * deliver the data to a registered listener you should use this method which
374      * will evaluate the op access based on the current fg/bg state of the app and
375      * leave a record that the data was accessed.
376      *
377      * @param context Context for accessing resources.
378      * @param opName THe op to start.
379      * @param attributionSource The identity for which to check the permission.
380      * @param message A message describing the reason the permission was checked
381      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
382      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
383      *
384      * @see #finishDataDelivery(Context, String, AttributionSource)
385      */
386     @PermissionResult
387     @SuppressWarnings("ConstantConditions")
startOpForDataDelivery(@onNull Context context, @NonNull String opName, @NonNull AttributionSource attributionSource, @Nullable String message)388     public static int startOpForDataDelivery(@NonNull Context context,
389             @NonNull String opName, @NonNull AttributionSource attributionSource,
390             @Nullable String message) {
391         return context.getSystemService(PermissionCheckerManager.class).checkOp(
392                 AppOpsManager.strOpToOp(opName), attributionSource.asState(), message,
393                 true /*forDataDelivery*/, true /*startDataDelivery*/);
394     }
395 
396     /**
397      * Finishes an ongoing op for data access chain described by the given {@link
398      * AttributionSource}.
399      *
400      * @param context Context for accessing resources.
401      * @param op The op to finish.
402      * @param attributionSource The identity for which finish op.
403      *
404      * @see #startOpForDataDelivery(Context, String, AttributionSource, String)
405      * @see #checkPermissionAndStartDataDelivery(Context, String, AttributionSource, String)
406      */
407     @SuppressWarnings("ConstantConditions")
finishDataDelivery(@onNull Context context, @NonNull String op, @NonNull AttributionSource attributionSource)408     public static void finishDataDelivery(@NonNull Context context, @NonNull String op,
409             @NonNull AttributionSource attributionSource) {
410         context.getSystemService(PermissionCheckerManager.class).finishDataDelivery(
411                 AppOpsManager.strOpToOp(op), attributionSource.asState(),
412                 /*fromDatasource*/ false);
413     }
414 
415     /**
416      * Finishes an ongoing op for data access chain described by the given {@link
417      * AttributionSource}. Call this method if you are the datasource which would
418      * not finish an op for your attribution source as it was not started.
419      *
420      * @param context Context for accessing resources.
421      * @param op The op to finish.
422      * @param attributionSource The identity for which finish op.
423      *
424      * @see #startOpForDataDelivery(Context, String, AttributionSource, String)
425      * @see #checkPermissionAndStartDataDelivery(Context, String, AttributionSource, String)
426      */
427     @SuppressWarnings("ConstantConditions")
finishDataDeliveryFromDatasource(@onNull Context context, @NonNull String op, @NonNull AttributionSource attributionSource)428     public static void finishDataDeliveryFromDatasource(@NonNull Context context,
429             @NonNull String op, @NonNull AttributionSource attributionSource) {
430         context.getSystemService(PermissionCheckerManager.class).finishDataDelivery(
431                 AppOpsManager.strOpToOp(op), attributionSource.asState(),
432                 /*fromDatasource*/ true);
433     }
434 
435     /**
436      * Checks whether a given data access chain described by the given {@link
437      * AttributionSource} has a given app op allowed.
438      *
439      * <strong>NOTE:</strong> Use this method only for op checks at the
440      * preflight point where you will not deliver the protected data
441      * to clients but schedule a data delivery, apps register listeners,
442      * etc.
443      *
444      * <p>For example, if an app registers a data listener it should have the op
445      * but no data is actually sent to the app at the moment of registration
446      * and you should use this method to determine if the app has or may have data
447      * access and this check will not leave a trace that protected data
448      * was delivered. When you are about to deliver the data to a registered
449      * listener you should use {@link #checkOpForDataDelivery(Context, String,
450      * AttributionSource, String)} which will evaluate the op access based
451      * on the current fg/bg state of the app and leave a record that the data was
452      * accessed.
453      *
454      * @param context Context for accessing resources.
455      * @param opName The op to check.
456      * @param attributionSource The identity for which to check the permission.
457      * @param message A message describing the reason the permission was checked
458      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
459      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
460      *
461      * @see #checkOpForDataDelivery(Context, String, AttributionSource, String)
462      */
463     @PermissionResult
464     @SuppressWarnings("ConstantConditions")
checkOpForPreflight(@onNull Context context, @NonNull String opName, @NonNull AttributionSource attributionSource, @Nullable String message)465     public static int checkOpForPreflight(@NonNull Context context,
466             @NonNull String opName, @NonNull AttributionSource attributionSource,
467             @Nullable String message) {
468         return context.getSystemService(PermissionCheckerManager.class).checkOp(
469                 AppOpsManager.strOpToOp(opName), attributionSource.asState(), message,
470                 false /*forDataDelivery*/, false /*startDataDelivery*/);
471     }
472 
473     /**
474      * Checks whether a given data access chain described by the given {@link AttributionSource}
475      * has an allowed app op.
476      *
477      * <strong>NOTE:</strong> Use this method only for op checks at the
478      * point where you will deliver the permission protected data to clients.
479      *
480      * <p>For example, if an app registers a data listener it should have the data
481      * permission but no data is actually sent to the app at the moment of registration
482      * and you should use {@link #checkOpForPreflight(Context, String, AttributionSource, String)}
483      * to determine if the app has or may have data access and this check will not
484      * leave a trace that op protected data was delivered. When you are about to
485      * deliver the  data to a registered listener you should use this method which
486      * will evaluate the op access based on the current fg/bg state of the app and
487      * leave a record that the data was accessed.
488      *
489      * @param context Context for accessing resources.
490      * @param opName The op to check.
491      * @param attributionSource The identity for which to check the op.
492      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
493      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
494      * @param message A message describing the reason the permission was checked
495      *
496      * @see #checkOpForPreflight(Context, String, AttributionSource, String)
497      */
498     @PermissionResult
499     @SuppressWarnings("ConstantConditions")
checkOpForDataDelivery(@onNull Context context, @NonNull String opName, @NonNull AttributionSource attributionSource, @Nullable String message)500     public static int checkOpForDataDelivery(@NonNull Context context,
501             @NonNull String opName, @NonNull AttributionSource attributionSource,
502             @Nullable String message) {
503         return context.getSystemService(PermissionCheckerManager.class).checkOp(
504                 AppOpsManager.strOpToOp(opName), attributionSource.asState(), message,
505                 true /*forDataDelivery*/, false /*startDataDelivery*/);
506     }
507 
508     /**
509      * Checks whether a given package in a UID and PID has a given permission
510      * and whether the app op that corresponds to this permission is allowed.
511      *
512      * <strong>NOTE:</strong> Use this method only for permission checks at the
513      * preflight point where you will not deliver the permission protected data
514      * to clients but schedule permission data delivery, apps register listeners,
515      * etc.
516      *
517      * <p>For example, if an app registers a location listener it should have the location
518      * permission but no data is actually sent to the app at the moment of registration
519      * and you should use this method to determine if the app has or may have location
520      * permission (if app has only foreground location the grant state depends on the app's
521      * fg/gb state) and this check will not leave a trace that permission protected data
522      * was delivered. When you are about to deliver the location data to a registered
523      * listener you should use {@link #checkPermissionForDataDelivery(Context, String,
524      * int, int, String, String, String)} which will evaluate the permission access based
525      * on the currentfg/bg state of the app and leave a record that the data was accessed.
526      *
527      * @param context Context for accessing resources.
528      * @param permission The permission to check.
529      * @param pid The process id for which to check.
530      * @param uid The uid for which to check.
531      * @param packageName The package name for which to check. If null the
532      *     the first package for the calling UID will be used.
533      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
534      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
535      *
536      * @see #checkPermissionForDataDelivery(Context, String, int, int, String, String, String)
537      */
538     @PermissionResult
checkPermissionForPreflight(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName)539     public static int checkPermissionForPreflight(@NonNull Context context,
540             @NonNull String permission, int pid, int uid, @Nullable String packageName) {
541         return checkPermissionForPreflight(context, permission, new AttributionSource(
542                 uid, packageName, null /*attributionTag*/));
543     }
544 
545     /**
546      * Checks whether a given data access chain described by the given {@link AttributionSource}
547      * has a given permission and whether the app op that corresponds to this permission
548      * is allowed.
549      *
550      * <strong>NOTE:</strong> Use this method only for permission checks at the
551      * preflight point where you will not deliver the permission protected data
552      * to clients but schedule permission data delivery, apps register listeners,
553      * etc.
554      *
555      * <p>For example, if an app registers a data listener it should have the required
556      * permission but no data is actually sent to the app at the moment of registration
557      * and you should use this method to determine if the app has or may have the
558      * permission and this check will not leave a trace that permission protected data
559      * was delivered. When you are about to deliver the protected data to a registered
560      * listener you should use {@link #checkPermissionForDataDelivery(Context, String,
561      * int, AttributionSource, String, boolean)} which will evaluate the permission access based
562      * on the current fg/bg state of the app and leave a record that the data was accessed.
563      *
564      * @param context Context for accessing resources.
565      * @param permission The permission to check.
566      * @param attributionSource The identity for which to check the permission.
567      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
568      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
569      *
570      * @see #checkPermissionForDataDelivery(Context, String, int, AttributionSource,
571      *     String, boolean)
572      */
573     @PermissionResult
574     @SuppressWarnings("ConstantConditions")
checkPermissionForPreflight(@onNull Context context, @NonNull String permission, @NonNull AttributionSource attributionSource)575     public static int checkPermissionForPreflight(@NonNull Context context,
576             @NonNull String permission, @NonNull AttributionSource attributionSource) {
577         return context.getSystemService(PermissionCheckerManager.class)
578                 .checkPermission(permission, attributionSource.asState(), null /*message*/,
579                 false /*forDataDelivery*/, /*startDataDelivery*/ false, /*fromDatasource*/ false,
580                 AppOpsManager.OP_NONE);
581     }
582 
583     /**
584      * Checks whether your app has a given permission and whether the app op
585      * that corresponds to this permission is allowed.
586      *
587      * <strong>NOTE:</strong> Use this method only for permission checks at the
588      * point where you will deliver the permission protected data to clients.
589      *
590      * <p>For example, if an app registers a location listener it should have the location
591      * permission but no data is actually sent to the app at the moment of registration
592      * and you should use {@link #checkSelfPermissionForPreflight(Context, String)}
593      * to determine if the app has or may have location permission (if app has only foreground
594      * location the grant state depends on the app's fg/gb state) and this check will not
595      * leave a trace that permission protected data was delivered. When you are about to
596      * deliver the location data to a registered listener you should use this method
597      * which will evaluate the permission access based on the current fg/bg state of the
598      * app and leave a record that the data was accessed.
599      *
600      * <p>This API assumes the the {@link Binder#getCallingUid()} is the same as
601      * {@link Process#myUid()}.
602      *
603      * @param context Context for accessing resources.
604      * @param permission The permission to check.
605      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
606      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
607      * @param message A message describing the reason the permission was checked
608      *
609      * @see #checkSelfPermissionForPreflight(Context, String)
610      */
611     @PermissionResult
checkSelfPermissionForDataDelivery(@onNull Context context, @NonNull String permission, @Nullable String message)612     public static int checkSelfPermissionForDataDelivery(@NonNull Context context,
613             @NonNull String permission, @Nullable String message) {
614         return checkPermissionForDataDelivery(context, permission, Process.myPid(),
615                 Process.myUid(), context.getPackageName(), context.getAttributionTag(), message,
616                 /*startDataDelivery*/ false);
617     }
618 
619     /**
620      * Checks whether your app has a given permission and whether the app op
621      * that corresponds to this permission is allowed.
622      *
623      * <strong>NOTE:</strong> Use this method only for permission checks at the
624      * preflight point where you will not deliver the permission protected data
625      * to clients but schedule permission data delivery, apps register listeners,
626      * etc.
627      *
628      * <p>For example, if an app registers a location listener it should have the location
629      * permission but no data is actually sent to the app at the moment of registration
630      * and you should use this method to determine if the app has or may have location
631      * permission (if app has only foreground location the grant state depends on the
632      * app's fg/gb state) and this check will not leave a trace that permission protected
633      * data was delivered. When you are about to deliver the location data to a registered
634      * listener you should use this method which will evaluate the permission access based
635      * on the current fg/bg state of the app and leave a record that the data was accessed.
636      *
637      * <p>This API assumes the the {@link Binder#getCallingUid()} is the same as
638      * {@link Process#myUid()}.
639      *
640      * @param context Context for accessing resources.
641      * @param permission The permission to check.
642      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
643      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
644      *
645      * @see #checkSelfPermissionForDataDelivery(Context, String, String)
646      */
647     @PermissionResult
checkSelfPermissionForPreflight(@onNull Context context, @NonNull String permission)648     public static int checkSelfPermissionForPreflight(@NonNull Context context,
649             @NonNull String permission) {
650         return checkPermissionForPreflight(context, permission, Process.myPid(),
651                 Process.myUid(), context.getPackageName());
652     }
653 
654     /**
655      * Checks whether the IPC you are handling has a given permission and whether
656      * the app op that corresponds to this permission is allowed.
657      *
658      * <strong>NOTE:</strong> Use this method only for permission checks at the
659      * point where you will deliver the permission protected data to clients.
660      *
661      * <p>For example, if an app registers a location listener it should have the location
662      * permission but no data is actually sent to the app at the moment of registration
663      * and you should use {@link #checkCallingPermissionForPreflight(Context, String, String)}
664      * to determine if the app has or may have location permission (if app has only foreground
665      * location the grant state depends on the app's fg/gb state) and this check will not
666      * leave a trace that permission protected data was delivered. When you are about to
667      * deliver the location data to a registered listener you should use this method which
668      * will evaluate the permission access based on the current fg/bg state of the app and
669      * leave a record that the data was accessed.
670      *
671      * <p>For more details how to determine the {@code callingPackageName},
672      * {@code callingAttributionTag}, and {@code message}, please check the description in
673      * {@link AppOpsManager#noteOp(String, int, String, String, String)}
674      *
675      * @param context Context for accessing resources.
676      * @param permission The permission to check.
677      * @param callingPackageName The package name making the IPC. If null the
678      *     the first package for the calling UID will be used.
679      * @param callingAttributionTag attribution tag
680      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
681      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
682      * @param message A message describing the reason the permission was checked
683      *
684      * @see #checkCallingPermissionForPreflight(Context, String, String)
685      */
686     @PermissionResult
checkCallingPermissionForDataDelivery(@onNull Context context, @NonNull String permission, @Nullable String callingPackageName, @Nullable String callingAttributionTag, @Nullable String message)687     public static int checkCallingPermissionForDataDelivery(@NonNull Context context,
688             @NonNull String permission, @Nullable String callingPackageName,
689             @Nullable String callingAttributionTag, @Nullable String message) {
690         if (Binder.getCallingPid() == Process.myPid()) {
691             return PERMISSION_HARD_DENIED;
692         }
693         return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(),
694                 Binder.getCallingUid(), callingPackageName, callingAttributionTag, message,
695                 /*startDataDelivery*/ false);
696     }
697 
698     /**
699      * Checks whether the IPC you are handling has a given permission and whether
700      * the app op that corresponds to this permission is allowed.
701      *
702      * <strong>NOTE:</strong> Use this method only for permission checks at the
703      * preflight point where you will not deliver the permission protected data
704      * to clients but schedule permission data delivery, apps register listeners,
705      * etc.
706      *
707      * <p>For example, if an app registers a location listener it should have the location
708      * permission but no data is actually sent to the app at the moment of registration
709      * and you should use this method to determine if the app has or may have location
710      * permission (if app has only foreground location the grant state depends on the app's
711      * fg/gb state) and this check will not leave a trace that permission protected data
712      * was delivered. When you are about to deliver the location data to a registered
713      * listener you should use {@link #checkCallingOrSelfPermissionForDataDelivery(Context,
714      * String, String, String, String)} which will evaluate the permission access based on the
715      * current fg/bg stateof the app and leave a record that the data was accessed.
716      *
717      * @param context Context for accessing resources.
718      * @param permission The permission to check.
719      * @param packageName The package name making the IPC. If null the
720      *     the first package for the calling UID will be used.
721      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
722      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
723      *
724      * @see #checkCallingPermissionForDataDelivery(Context, String, String, String, String)
725      */
726     @PermissionResult
checkCallingPermissionForPreflight(@onNull Context context, @NonNull String permission, @Nullable String packageName)727     public static int checkCallingPermissionForPreflight(@NonNull Context context,
728             @NonNull String permission, @Nullable String packageName) {
729         if (Binder.getCallingPid() == Process.myPid()) {
730             return PERMISSION_HARD_DENIED;
731         }
732         return checkPermissionForPreflight(context, permission, Binder.getCallingPid(),
733                 Binder.getCallingUid(), packageName);
734     }
735 
736     /**
737      * Checks whether the IPC you are handling or your app has a given permission
738      * and whether the app op that corresponds to this permission is allowed.
739      *
740      * <strong>NOTE:</strong> Use this method only for permission checks at the
741      * point where you will deliver the permission protected data to clients.
742      *
743      * <p>For example, if an app registers a location listener it should have the location
744      * permission but no data is actually sent to the app at the moment of registration
745      * and you should use {@link #checkCallingOrSelfPermissionForPreflight(Context, String)}
746      * to determine if the app has or may have location permission (if app has only foreground
747      * location the grant state depends on the app's fg/gb state) and this check will not
748      * leave a trace that permission protected data was delivered. When you are about to
749      * deliver the location data to a registered listener you should use this method which
750      * will evaluate the permission access based on the current fg/bg state of the app and
751      * leave a record that the data was accessed.
752      *
753      * <p>For more details how to determine the {@code callingPackageName},
754      * {@code callingAttributionTag}, and {@code message}, please check the description in
755      * {@link AppOpsManager#noteOp(String, int, String, String, String)}
756      *
757      * @param context Context for accessing resources.
758      * @param permission The permission to check.
759      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
760      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
761      * @param callingPackageName package name tag of caller (if not self)
762      * @param callingAttributionTag attribution tag of caller (if not self)
763      * @param message A message describing the reason the permission was checked
764      *
765      * @see #checkCallingOrSelfPermissionForPreflight(Context, String)
766      */
767     @PermissionResult
checkCallingOrSelfPermissionForDataDelivery(@onNull Context context, @NonNull String permission, @Nullable String callingPackageName, @Nullable String callingAttributionTag, @Nullable String message)768     public static int checkCallingOrSelfPermissionForDataDelivery(@NonNull Context context,
769             @NonNull String permission, @Nullable String callingPackageName,
770             @Nullable String callingAttributionTag, @Nullable String message) {
771         callingPackageName = (Binder.getCallingPid() == Process.myPid())
772                 ? context.getPackageName() : callingPackageName;
773         callingAttributionTag = (Binder.getCallingPid() == Process.myPid())
774                 ? context.getAttributionTag() : callingAttributionTag;
775         return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(),
776                 Binder.getCallingUid(), callingPackageName, callingAttributionTag, message,
777                 /*startDataDelivery*/ false);
778     }
779 
780     /**
781      * Checks whether the IPC you are handling or your app has a given permission
782      * and whether the app op that corresponds to this permission is allowed.
783      *
784      * <strong>NOTE:</strong> Use this method only for permission checks at the
785      * preflight point where you will not deliver the permission protected data
786      * to clients but schedule permission data delivery, apps register listeners,
787      * etc.
788      *
789      * <p>For example, if an app registers a location listener it should have the location
790      * permission but no data is actually sent to the app at the moment of registration
791      * and you should use this method to determine if the app has or may have location
792      * permission (if app has only foreground location the grant state depends on the
793      * app's fg/gb state) and this check will not leave a trace that permission protected
794      * data was delivered. When you are about to deliver the location data to a registered
795      * listener you should use {@link #checkCallingOrSelfPermissionForDataDelivery(Context,
796      * String, String, String, String)} which will evaluate the permission access based on the
797      * current fg/bg state of the app and leave a record that the data was accessed.
798      *
799      * @param context Context for accessing resources.
800      * @param permission The permission to check.
801      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
802      *     or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
803      *
804      * @see #checkCallingOrSelfPermissionForDataDelivery(Context, String, String, String, String)
805      */
806     @PermissionResult
checkCallingOrSelfPermissionForPreflight(@onNull Context context, @NonNull String permission)807     public static int checkCallingOrSelfPermissionForPreflight(@NonNull Context context,
808             @NonNull String permission) {
809         String packageName = (Binder.getCallingPid() == Process.myPid())
810                 ? context.getPackageName() : null;
811         return checkPermissionForPreflight(context, permission, Binder.getCallingPid(),
812                 Binder.getCallingUid(), packageName);
813     }
814 }
815