File: PermissionChecker.java

package info (click to toggle)
android-platform-frameworks-base 1%3A14~beta1-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 326,084 kB
  • sloc: java: 2,032,373; xml: 343,016; cpp: 304,181; python: 3,683; ansic: 2,090; sh: 1,871; makefile: 120; sed: 19
file content (814 lines) | stat: -rw-r--r-- 45,116 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
/*
 * 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.
 * <p>
 * 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.
 * </p>
 * <p>
 * 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.
 * </p>
 * <p>
 * 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 and app op permissions.
     *
     * <p>Returned when:
     * <ul>
     *   <li>the runtime permission is granted, but the corresponding app op is denied
     *       for runtime permissions.</li>
     *   <li>the app ops is ignored for app op permissions.</li>
     * </ul>
     *
     * @hide
     */
    public static final int PERMISSION_SOFT_DENIED =
            PermissionCheckerManager.PERMISSION_SOFT_DENIED;

    /**
     * The permission is denied.
     *
     * <p>Returned when:
     * <ul>
     *   <li>the permission is denied for non app op permissions.</li>
     *   <li>the app op is denied or app op is {@link AppOpsManager#MODE_DEFAULT}
     *   and permission is denied.</li>
     * </ul>
     *
     * @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.
     *
     * <strong>NOTE:</strong> Use this method only for permission checks at the
     * point where you will deliver the permission protected data to clients.
     *
     * <p>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.
     *
     * <p>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,
                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.
     *
     * <strong>NOTE:</strong> Use this method only for permission checks at the
     * point where you will deliver the permission protected data to clients.
     *
     * <p>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.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> Use this method only for permission checks at the
     * point where you will deliver the permission protected data to clients.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> Use this method only for permission checks at the
     * point where you will deliver the permission protected data to clients.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> Use this method only for permission checks at the
     * point where you will deliver the permission protected data to clients.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> Use this method only for permission checks at the
     * point where you will deliver the permission protected data to clients.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> Use this method only for app op checks at the
     * point where you will deliver the protected data to clients.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> 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.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> Use this method only for op checks at the
     * point where you will deliver the permission protected data to clients.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> 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.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> 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.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> Use this method only for permission checks at the
     * point where you will deliver the permission protected data to clients.
     *
     * <p>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.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> 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.
     *
     * <p>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.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> Use this method only for permission checks at the
     * point where you will deliver the permission protected data to clients.
     *
     * <p>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.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> 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.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> Use this method only for permission checks at the
     * point where you will deliver the permission protected data to clients.
     *
     * <p>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.
     *
     * <p>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.
     *
     * <strong>NOTE:</strong> 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.
     *
     * <p>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);
    }
}