• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 com.android.providers.media.util;
18 
19 import static android.Manifest.permission.ACCESS_MEDIA_LOCATION;
20 import static android.Manifest.permission.ACCESS_MTP;
21 import static android.Manifest.permission.BACKUP;
22 import static android.Manifest.permission.INSTALL_PACKAGES;
23 import static android.Manifest.permission.MANAGE_EXTERNAL_STORAGE;
24 import static android.Manifest.permission.MANAGE_MEDIA;
25 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
26 import static android.Manifest.permission.UPDATE_DEVICE_STATS;
27 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
28 import static android.app.AppOpsManager.MODE_ALLOWED;
29 import static android.app.AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES;
30 import static android.app.AppOpsManager.OPSTR_LEGACY_STORAGE;
31 import static android.app.AppOpsManager.OPSTR_NO_ISOLATED_STORAGE;
32 import static android.app.AppOpsManager.OPSTR_READ_MEDIA_AUDIO;
33 import static android.app.AppOpsManager.OPSTR_READ_MEDIA_IMAGES;
34 import static android.app.AppOpsManager.OPSTR_READ_MEDIA_VIDEO;
35 import static android.app.AppOpsManager.OPSTR_WRITE_MEDIA_AUDIO;
36 import static android.app.AppOpsManager.OPSTR_WRITE_MEDIA_IMAGES;
37 import static android.app.AppOpsManager.OPSTR_WRITE_MEDIA_VIDEO;
38 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
39 
40 import android.app.AppOpsManager;
41 import android.app.DownloadManager;
42 import android.content.Context;
43 import android.content.pm.PackageManager;
44 
45 import androidx.annotation.NonNull;
46 import androidx.annotation.Nullable;
47 import androidx.annotation.VisibleForTesting;
48 
49 public class PermissionUtils {
50 
51     // Callers must hold both the old and new permissions, so that we can
52     // handle obscure cases like when an app targets Q but was installed on
53     // a device that was originally running on P before being upgraded to Q.
54 
55     private static ThreadLocal<String> sOpDescription = new ThreadLocal<>();
56 
setOpDescription(@ullable String description)57     public static void setOpDescription(@Nullable String description) {
58         sOpDescription.set(description);
59     }
60 
clearOpDescription()61     public static void clearOpDescription() { sOpDescription.set(null); }
62 
checkPermissionSelf(@onNull Context context, int pid, int uid)63     public static boolean checkPermissionSelf(@NonNull Context context, int pid, int uid) {
64         return android.os.Process.myUid() == uid;
65     }
66 
checkPermissionShell(@onNull Context context, int pid, int uid)67     public static boolean checkPermissionShell(@NonNull Context context, int pid, int uid) {
68         switch (uid) {
69             case android.os.Process.ROOT_UID:
70             case android.os.Process.SHELL_UID:
71                 return true;
72             default:
73                 return false;
74         }
75     }
76 
77     /**
78      * Check if the given package has been granted the "file manager" role on
79      * the device, which should grant them certain broader access.
80      */
checkPermissionManager(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)81     public static boolean checkPermissionManager(@NonNull Context context, int pid,
82             int uid, @NonNull String packageName, @Nullable String attributionTag) {
83         return checkPermissionForDataDelivery(context, MANAGE_EXTERNAL_STORAGE, pid, uid,
84                 packageName, attributionTag,
85                 generateAppOpMessage(packageName,sOpDescription.get()));
86     }
87 
88     /**
89      * Check if the given package has the ability to "delegate" the ownership of
90      * media items that they own to other apps, typically when they've finished
91      * performing operations on behalf of those apps.
92      * <p>
93      * One use-case for this is backup/restore apps, where the app restoring the
94      * content needs to shift the ownership back to the app that originally
95      * owned that media.
96      * <p>
97      * Another use-case is {@link DownloadManager}, which shifts ownership of
98      * finished downloads to the app that originally requested them.
99      */
checkPermissionDelegator(@onNull Context context, int pid, int uid)100     public static boolean checkPermissionDelegator(@NonNull Context context, int pid, int uid) {
101         return (context.checkPermission(BACKUP, pid, uid) == PERMISSION_GRANTED)
102                 || (context.checkPermission(UPDATE_DEVICE_STATS, pid, uid) == PERMISSION_GRANTED);
103     }
104 
checkPermissionWriteStorage(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)105     public static boolean checkPermissionWriteStorage(@NonNull Context context, int pid, int uid,
106             @NonNull String packageName, @Nullable String attributionTag) {
107         return checkPermissionForDataDelivery(context, WRITE_EXTERNAL_STORAGE, pid, uid,
108                 packageName, attributionTag,
109                 generateAppOpMessage(packageName,sOpDescription.get()));
110     }
111 
checkPermissionReadStorage(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)112     public static boolean checkPermissionReadStorage(@NonNull Context context, int pid, int uid,
113             @NonNull String packageName, @Nullable String attributionTag) {
114         return checkPermissionForDataDelivery(context, READ_EXTERNAL_STORAGE, pid, uid,
115                 packageName, attributionTag,
116                 generateAppOpMessage(packageName,sOpDescription.get()));
117     }
118 
119     /**
120      * Check if the given package has been granted the
121      * android.Manifest.permission#ACCESS_MEDIA_LOCATION permission.
122      */
checkPermissionAccessMediaLocation(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)123     public static boolean checkPermissionAccessMediaLocation(@NonNull Context context, int pid,
124             int uid, @NonNull String packageName, @Nullable String attributionTag) {
125         return checkPermissionForDataDelivery(context, ACCESS_MEDIA_LOCATION, pid, uid, packageName,
126                 attributionTag, generateAppOpMessage(packageName, sOpDescription.get()));
127     }
128 
129     /**
130      * Check if the given package has been granted the
131      * android.Manifest.permission#MANAGE_MEDIA permission.
132      */
checkPermissionManageMedia(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)133     public static boolean checkPermissionManageMedia(@NonNull Context context, int pid, int uid,
134             @NonNull String packageName, @Nullable String attributionTag) {
135         return checkPermissionForDataDelivery(context, MANAGE_MEDIA, pid, uid, packageName,
136                 attributionTag, generateAppOpMessage(packageName, sOpDescription.get()));
137     }
138 
checkIsLegacyStorageGranted(@onNull Context context, int uid, String packageName, @Nullable String attributionTag)139     public static boolean checkIsLegacyStorageGranted(@NonNull Context context, int uid,
140             String packageName, @Nullable String attributionTag) {
141         if (context.getSystemService(AppOpsManager.class)
142                 .unsafeCheckOp(OPSTR_LEGACY_STORAGE, uid, packageName) == MODE_ALLOWED) {
143             return true;
144         }
145         // Check OPSTR_NO_ISOLATED_STORAGE app op.
146         return checkNoIsolatedStorageGranted(context, uid, packageName, attributionTag);
147     }
148 
checkPermissionReadAudio(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)149     public static boolean checkPermissionReadAudio(@NonNull Context context, int pid, int uid,
150             @NonNull String packageName, @Nullable String attributionTag) {
151         if (!checkPermissionForPreflight(context, READ_EXTERNAL_STORAGE, pid, uid, packageName)) {
152             return false;
153         }
154         return checkAppOpAllowingLegacy(context, OPSTR_READ_MEDIA_AUDIO, pid,
155                 uid, packageName, attributionTag,
156                 generateAppOpMessage(packageName, sOpDescription.get()));
157     }
158 
checkPermissionWriteAudio(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)159     public static boolean checkPermissionWriteAudio(@NonNull Context context, int pid, int uid,
160             @NonNull String packageName, @Nullable String attributionTag) {
161         if (!checkPermissionAllowingNonLegacy(
162                     context, WRITE_EXTERNAL_STORAGE, pid, uid, packageName)) {
163             return false;
164         }
165         return checkAppOpAllowingLegacy(context, OPSTR_WRITE_MEDIA_AUDIO, pid,
166                 uid, packageName, attributionTag,
167                 generateAppOpMessage(packageName, sOpDescription.get()));
168     }
169 
checkPermissionReadVideo(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)170     public static boolean checkPermissionReadVideo(@NonNull Context context, int pid, int uid,
171             @NonNull String packageName, @Nullable String attributionTag) {
172         if (!checkPermissionForPreflight(context, READ_EXTERNAL_STORAGE, pid, uid, packageName)) {
173             return false;
174         }
175         return checkAppOpAllowingLegacy(context, OPSTR_READ_MEDIA_VIDEO, pid,
176                 uid, packageName, attributionTag,
177                 generateAppOpMessage(packageName, sOpDescription.get()));
178     }
179 
checkPermissionWriteVideo(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)180     public static boolean checkPermissionWriteVideo(@NonNull Context context, int pid, int uid,
181             @NonNull String packageName, @Nullable String attributionTag) {
182         if (!checkPermissionAllowingNonLegacy(
183                 context, WRITE_EXTERNAL_STORAGE, pid, uid, packageName)) {
184             return false;
185         }
186         return checkAppOpAllowingLegacy(context, OPSTR_WRITE_MEDIA_VIDEO, pid,
187                 uid, packageName, attributionTag,
188                 generateAppOpMessage(packageName, sOpDescription.get()));
189     }
190 
checkPermissionReadImages(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)191     public static boolean checkPermissionReadImages(@NonNull Context context, int pid, int uid,
192             @NonNull String packageName, @Nullable String attributionTag) {
193         if (!checkPermissionForPreflight(context, READ_EXTERNAL_STORAGE, pid, uid, packageName)) {
194             return false;
195         }
196         return checkAppOpAllowingLegacy(context, OPSTR_READ_MEDIA_IMAGES, pid,
197                 uid, packageName, attributionTag,
198                 generateAppOpMessage(packageName, sOpDescription.get()));
199     }
200 
checkPermissionWriteImages(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)201     public static boolean checkPermissionWriteImages(@NonNull Context context, int pid, int uid,
202             @NonNull String packageName, @Nullable String attributionTag) {
203         if (!checkPermissionAllowingNonLegacy(
204                 context, WRITE_EXTERNAL_STORAGE, pid, uid, packageName)) {
205             return false;
206         }
207         return checkAppOpAllowingLegacy(context, OPSTR_WRITE_MEDIA_IMAGES, pid,
208                 uid, packageName, attributionTag,
209                 generateAppOpMessage(packageName, sOpDescription.get()));
210     }
211 
checkPermissionInstallPackages(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)212     public static boolean checkPermissionInstallPackages(@NonNull Context context, int pid, int uid,
213         @NonNull String packageName, @Nullable String attributionTag) {
214         return checkPermissionForDataDelivery(context, INSTALL_PACKAGES, pid,
215                 uid, packageName, attributionTag, null);
216     }
217 
checkPermissionAccessMtp(@onNull Context context, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag)218     public static boolean checkPermissionAccessMtp(@NonNull Context context, int pid, int uid,
219         @NonNull String packageName, @Nullable String attributionTag) {
220         return checkPermissionForDataDelivery(context, ACCESS_MTP, pid,
221                 uid, packageName, attributionTag, null);
222     }
223 
224     /**
225      * Returns {@code true} if the given package has write images or write video app op, which
226      * indicates the package is a system gallery.
227      */
checkWriteImagesOrVideoAppOps(@onNull Context context, int uid, @NonNull String packageName, @Nullable String attributionTag)228     public static boolean checkWriteImagesOrVideoAppOps(@NonNull Context context, int uid,
229             @NonNull String packageName, @Nullable String attributionTag) {
230         return checkAppOp(
231                 context, OPSTR_WRITE_MEDIA_IMAGES, uid, packageName, attributionTag,
232                 generateAppOpMessage(packageName, sOpDescription.get()))
233                 || checkAppOp(
234                         context, OPSTR_WRITE_MEDIA_VIDEO, uid, packageName, attributionTag,
235                 generateAppOpMessage(packageName, sOpDescription.get()));
236     }
237 
238     /**
239      * Returns {@code true} if any package for the given uid has request_install_packages app op.
240      */
checkAppOpRequestInstallPackagesForSharedUid(@onNull Context context, int uid, @NonNull String[] sharedPackageNames, @Nullable String attributionTag)241     public static boolean checkAppOpRequestInstallPackagesForSharedUid(@NonNull Context context,
242             int uid, @NonNull String[] sharedPackageNames, @Nullable String attributionTag) {
243         for (String packageName : sharedPackageNames) {
244             if (checkAppOp(context, OPSTR_REQUEST_INSTALL_PACKAGES, uid, packageName,
245                     attributionTag, generateAppOpMessage(packageName, sOpDescription.get()))) {
246                 return true;
247             }
248         }
249         return false;
250     }
251 
252     @VisibleForTesting
checkNoIsolatedStorageGranted(@onNull Context context, int uid, @NonNull String packageName, @Nullable String attributionTag)253     static boolean checkNoIsolatedStorageGranted(@NonNull Context context, int uid,
254             @NonNull String packageName, @Nullable String attributionTag) {
255         final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
256         int ret = appOps.noteOpNoThrow(OPSTR_NO_ISOLATED_STORAGE, uid, packageName, attributionTag,
257                 generateAppOpMessage(packageName, "am instrument --no-isolated-storage"));
258         return ret == AppOpsManager.MODE_ALLOWED;
259     }
260 
261     /**
262      * Generates a message to be used with the different {@link AppOpsManager#noteOp} variations.
263      * If the supplied description is {@code null}, the returned message will be {@code null}.
264      */
generateAppOpMessage( @onNull String packageName, @Nullable String description)265     private static String generateAppOpMessage(
266             @NonNull String packageName, @Nullable String description) {
267         if (description == null) {
268             return null;
269         }
270         return "Package: " + packageName + ". Description: " + description + ".";
271     }
272 
273     /**
274      * Similar to {@link #checkPermissionForPreflight(Context, String, int, int, String)},
275      * but also returns true for non-legacy apps.
276      */
checkPermissionAllowingNonLegacy(@onNull Context context, @NonNull String permission, int pid, int uid, @NonNull String packageName)277     private static boolean checkPermissionAllowingNonLegacy(@NonNull Context context,
278             @NonNull String permission, int pid, int uid, @NonNull String packageName) {
279         final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
280 
281         // Allowing non legacy apps to bypass this check
282         if (appOps.unsafeCheckOpNoThrow(OPSTR_LEGACY_STORAGE, uid,
283                 packageName) != AppOpsManager.MODE_ALLOWED) return true;
284 
285         // Seems like it's a legacy app, so it has to pass the permission check
286         return checkPermissionForPreflight(context, permission, pid, uid, packageName);
287     }
288 
289     /**
290      * Checks *only* App Ops.
291      */
checkAppOp(@onNull Context context, @NonNull String op, int uid, @NonNull String packageName, @Nullable String attributionTag, @Nullable String opMessage)292     private static boolean checkAppOp(@NonNull Context context,
293             @NonNull String op, int uid, @NonNull String packageName,
294             @Nullable String attributionTag, @Nullable String opMessage) {
295         final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
296         final int mode = appOps.noteOpNoThrow(op, uid, packageName, attributionTag, opMessage);
297         switch (mode) {
298             case AppOpsManager.MODE_ALLOWED:
299                 return true;
300             case AppOpsManager.MODE_DEFAULT:
301             case AppOpsManager.MODE_IGNORED:
302             case AppOpsManager.MODE_ERRORED:
303                 return false;
304             default:
305                 throw new IllegalStateException(op + " has unknown mode " + mode);
306         }
307     }
308 
309 
310     /**
311      * Checks *only* App Ops, also returns true for legacy apps.
312      */
checkAppOpAllowingLegacy(@onNull Context context, @NonNull String op, int pid, int uid, @NonNull String packageName, @Nullable String attributionTag, @Nullable String opMessage)313     private static boolean checkAppOpAllowingLegacy(@NonNull Context context,
314             @NonNull String op, int pid, int uid, @NonNull String packageName,
315             @Nullable String attributionTag, @Nullable String opMessage) {
316         final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
317         final int mode = appOps.noteOpNoThrow(op, uid, packageName, attributionTag, opMessage);
318         switch (mode) {
319             case AppOpsManager.MODE_ALLOWED:
320                 return true;
321             case AppOpsManager.MODE_DEFAULT:
322             case AppOpsManager.MODE_IGNORED:
323             case AppOpsManager.MODE_ERRORED:
324                 // Legacy apps technically have the access granted by this op,
325                 // even when the op is denied
326                 if ((appOps.unsafeCheckOpNoThrow(OPSTR_LEGACY_STORAGE, uid,
327                         packageName) == AppOpsManager.MODE_ALLOWED)) return true;
328 
329                 return false;
330             default:
331                 throw new IllegalStateException(op + " has unknown mode " + mode);
332         }
333     }
334 
335     /**
336      * Checks whether a given package in a UID and PID has a given permission
337      * and whether the app op that corresponds to this permission is allowed.
338      *
339      * <strong>NOTE:</strong> Use this method only for permission checks at the
340      * preflight point where you will not deliver the permission protected data
341      * to clients but schedule permission data delivery, apps register listeners,
342      * etc.
343      *
344      * <p>For example, if an app registers a location listener it should have the location
345      * permission but no data is actually sent to the app at the moment of registration
346      * and you should use this method to determine if the app has or may have location
347      * permission (if app has only foreground location the grant state depends on the app's
348      * fg/gb state) and this check will not leave a trace that permission protected data
349      * was delivered. When you are about to deliver the location data to a registered
350      * listener you should use {@link #checkPermissionForDataDelivery(Context, String,
351      * int, int, String, String, String)} which will evaluate the permission access based on the
352      * current fg/bg state of the app and leave a record that the data was accessed.
353      *
354      * @param context Context for accessing resources.
355      * @param permission The permission to check.
356      * @param pid The process id for which to check.
357      * @param uid The uid for which to check.
358      * @param packageName The package name for which to check. If null the
359      *     the first package for the calling UID will be used.
360      * @return boolean if permission is {@link #PERMISSION_GRANTED}
361      *
362      * @see #checkPermissionForDataDelivery(Context, String, int, int, String, String, String)
363      */
checkPermissionForPreflight(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName)364     private static boolean checkPermissionForPreflight(@NonNull Context context,
365             @NonNull String permission, int pid, int uid, @Nullable String packageName) {
366         return checkPermissionCommon(context, permission, pid, uid, packageName,
367                 null /*attributionTag*/, null /*message*/,
368                 false /*forDataDelivery*/);
369     }
370 
371     /**
372      * Checks whether a given package in a UID and PID has a given permission
373      * and whether the app op that corresponds to this permission is allowed.
374      *
375      * <strong>NOTE:</strong> Use this method only for permission checks at the
376      * point where you will deliver the permission protected data to clients.
377      *
378      * <p>For example, if an app registers a location listener it should have the location
379      * permission but no data is actually sent to the app at the moment of registration
380      * and you should use {@link #checkPermissionForPreflight(Context, String, int, int, String)}
381      * to determine if the app has or may have location permission (if app has only foreground
382      * location the grant state depends on the app's fg/gb state) and this check will not
383      * leave a trace that permission protected data was delivered. When you are about to
384      * deliver the location data to a registered listener you should use this method which
385      * will evaluate the permission access based on the current fg/bg state of the app and
386      * leave a record that the data was accessed.
387      *
388      * @param context Context for accessing resources.
389      * @param permission The permission to check.
390      * @param pid The process id for which to check. Use {@link #PID_UNKNOWN} if the PID
391      *    is not known.
392      * @param uid The uid for which to check.
393      * @param packageName The package name for which to check. If null the
394      *     the first package for the calling UID will be used.
395      * @param attributionTag attribution tag
396      * @return boolean true if {@link #PERMISSION_GRANTED}
397      * @param message A message describing the reason the permission was checked
398      *
399      * @see #checkPermissionForPreflight(Context, String, int, int, String)
400      */
checkPermissionForDataDelivery(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message)401     private static boolean checkPermissionForDataDelivery(@NonNull Context context,
402             @NonNull String permission, int pid, int uid, @Nullable String packageName,
403             @Nullable String attributionTag, @Nullable String message) {
404         return checkPermissionCommon(context, permission, pid, uid, packageName, attributionTag,
405                 message, true /*forDataDelivery*/);
406     }
407 
checkPermissionCommon(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery)408     private static boolean checkPermissionCommon(@NonNull Context context,
409             @NonNull String permission, int pid, int uid, @Nullable String packageName,
410             @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery) {
411         if (packageName == null) {
412             String[] packageNames = context.getPackageManager().getPackagesForUid(uid);
413             if (packageNames != null && packageNames.length > 0) {
414                 packageName = packageNames[0];
415             }
416         }
417 
418         if (isAppOpPermission(permission)) {
419             return checkAppOpPermission(context, permission, pid, uid, packageName, attributionTag,
420                     message, forDataDelivery);
421         }
422         if (isRuntimePermission(permission)) {
423             return checkRuntimePermission(context, permission, pid, uid, packageName,
424                     attributionTag, message, forDataDelivery);
425         }
426         return context.checkPermission(permission, pid, uid) == PERMISSION_GRANTED;
427     }
428 
isAppOpPermission(String permission)429     private static boolean isAppOpPermission(String permission) {
430         switch (permission) {
431             case MANAGE_EXTERNAL_STORAGE:
432             case MANAGE_MEDIA:
433                 return true;
434         }
435         return false;
436     }
437 
isRuntimePermission(String permission)438     private static boolean isRuntimePermission(String permission) {
439         switch (permission) {
440             case ACCESS_MEDIA_LOCATION:
441             case READ_EXTERNAL_STORAGE:
442             case WRITE_EXTERNAL_STORAGE:
443                 return true;
444         }
445         return false;
446     }
447 
checkAppOpPermission(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery)448     private static boolean checkAppOpPermission(@NonNull Context context,
449             @NonNull String permission, int pid, int uid, @Nullable String packageName,
450             @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery) {
451         final String op = AppOpsManager.permissionToOp(permission);
452         if (op == null || packageName == null) {
453             return false;
454         }
455 
456         final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
457         final int opMode = (forDataDelivery)
458                 ? appOpsManager.noteOpNoThrow(op, uid, packageName, attributionTag, message)
459                 : appOpsManager.unsafeCheckOpRawNoThrow(op, uid, packageName);
460 
461         switch (opMode) {
462             case AppOpsManager.MODE_ALLOWED:
463             case AppOpsManager.MODE_FOREGROUND:
464                 return true;
465             case AppOpsManager.MODE_DEFAULT:
466                 return context.checkPermission(permission, pid, uid) == PERMISSION_GRANTED;
467             default:
468                 return false;
469         }
470     }
471 
checkRuntimePermission(@onNull Context context, @NonNull String permission, int pid, int uid, @Nullable String packageName, @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery)472     private static boolean checkRuntimePermission(@NonNull Context context,
473             @NonNull String permission, int pid, int uid, @Nullable String packageName,
474             @Nullable String attributionTag, @Nullable String message, boolean forDataDelivery) {
475         if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) {
476             return false;
477         }
478 
479         final String op = AppOpsManager.permissionToOp(permission);
480         if (op == null || packageName == null) {
481             return true;
482         }
483 
484         final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
485         final int opMode = (forDataDelivery)
486                 ? appOpsManager.noteOpNoThrow(op, uid, packageName, attributionTag, message)
487                 : appOpsManager.unsafeCheckOpRawNoThrow(op, uid, packageName);
488 
489         switch (opMode) {
490             case AppOpsManager.MODE_ALLOWED:
491             case AppOpsManager.MODE_FOREGROUND:
492                 return true;
493             default:
494                 return false;
495         }
496     }
497 }
498