• 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 com.android.packageinstaller.role.model;
18 
19 import android.Manifest;
20 import android.app.AppOpsManager;
21 import android.content.Context;
22 import android.content.pm.ApplicationInfo;
23 import android.content.pm.PackageInfo;
24 import android.content.pm.PackageManager;
25 import android.content.pm.PermissionGroupInfo;
26 import android.content.pm.PermissionInfo;
27 import android.os.Build;
28 import android.os.Process;
29 import android.os.UserHandle;
30 import android.permission.PermissionManager;
31 import android.util.ArrayMap;
32 import android.util.ArraySet;
33 import android.util.Log;
34 
35 import androidx.annotation.NonNull;
36 import androidx.annotation.Nullable;
37 
38 import com.android.packageinstaller.permission.utils.ArrayUtils;
39 import com.android.packageinstaller.permission.utils.CollectionUtils;
40 import com.android.packageinstaller.permission.utils.Utils;
41 import com.android.packageinstaller.role.utils.PackageUtils;
42 
43 import java.util.ArrayList;
44 import java.util.List;
45 import java.util.Set;
46 
47 /**
48  * Permissions to be granted or revoke by a {@link Role}.
49  */
50 public class Permissions {
51 
52     private static final String LOG_TAG = Permissions.class.getSimpleName();
53 
54     private static final boolean DEBUG = false;
55 
56     private static ArrayMap<String, String> sForegroundToBackgroundPermission;
57     private static ArrayMap<String, List<String>> sBackgroundToForegroundPermissions;
58     private static final Object sForegroundBackgroundPermissionMappingsLock = new Object();
59 
60     /**
61      * Grant permissions and associated app ops to an application.
62      *
63      * @param packageName the package name of the application to be granted permissions to
64      * @param permissions the list of permissions to be granted
65      * @param overrideDisabledSystemPackage whether to ignore the permissions of a disabled system
66      *                                      package (if this package is an updated system package)
67      * @param overrideUserSetAndFixed whether to override user set and fixed flags on the permission
68      * @param setGrantedByRole whether the permissions will be granted as granted-by-role
69      * @param setGrantedByDefault whether the permissions will be granted as granted-by-default
70      * @param setSystemFixed whether the permissions will be granted as system-fixed
71      * @param context the {@code Context} to retrieve system services
72      *
73      * @return whether any permission or app op changed
74      *
75      * @see com.android.server.pm.permission.DefaultPermissionGrantPolicy#grantRuntimePermissions(
76      *      PackageInfo, java.util.Set, boolean, boolean, int)
77      */
grant(@onNull String packageName, @NonNull List<String> permissions, boolean overrideDisabledSystemPackage, boolean overrideUserSetAndFixed, boolean setGrantedByRole, boolean setGrantedByDefault, boolean setSystemFixed, @NonNull Context context)78     public static boolean grant(@NonNull String packageName, @NonNull List<String> permissions,
79             boolean overrideDisabledSystemPackage, boolean overrideUserSetAndFixed,
80             boolean setGrantedByRole, boolean setGrantedByDefault, boolean setSystemFixed,
81             @NonNull Context context) {
82         if (setGrantedByRole == setGrantedByDefault) {
83             throw new IllegalArgumentException("Permission must be either granted by role, or"
84                     + " granted by default, but not both");
85         }
86 
87         PackageInfo packageInfo = getPackageInfo(packageName, context);
88         if (packageInfo == null) {
89             return false;
90         }
91 
92         if (ArrayUtils.isEmpty(packageInfo.requestedPermissions)) {
93             return false;
94         }
95 
96         // Automatically attempt to grant split permissions to older APKs
97         PermissionManager permissionManager = context.getSystemService(PermissionManager.class);
98         List<PermissionManager.SplitPermissionInfo> splitPermissions =
99                 permissionManager.getSplitPermissions();
100         ArraySet<String> permissionsWithoutSplits = new ArraySet<>(permissions);
101         ArraySet<String> permissionsToGrant = new ArraySet<>(permissionsWithoutSplits);
102         int splitPermissionsSize = splitPermissions.size();
103         for (int i = 0; i < splitPermissionsSize; i++) {
104             PermissionManager.SplitPermissionInfo splitPermission = splitPermissions.get(i);
105 
106             if (packageInfo.applicationInfo.targetSdkVersion < splitPermission.getTargetSdk()
107                     && permissionsWithoutSplits.contains(splitPermission.getSplitPermission())) {
108                 permissionsToGrant.addAll(splitPermission.getNewPermissions());
109             }
110         }
111 
112         CollectionUtils.retainAll(permissionsToGrant, packageInfo.requestedPermissions);
113         if (permissionsToGrant.isEmpty()) {
114             return false;
115         }
116 
117         // In some cases, like for the Phone or SMS app, we grant permissions regardless
118         // of if the version on the system image declares the permission as used since
119         // selecting the app as the default for that function the user makes a deliberate
120         // choice to grant this app the permissions needed to function. For all other
121         // apps, (default grants on first boot and user creation) we don't grant default
122         // permissions if the version on the system image does not declare them.
123         if (!overrideDisabledSystemPackage && isUpdatedSystemApp(packageInfo)) {
124             PackageInfo disabledSystemPackageInfo = getFactoryPackageInfo(packageName, context);
125             if (disabledSystemPackageInfo != null) {
126                 if (ArrayUtils.isEmpty(disabledSystemPackageInfo.requestedPermissions)) {
127                     return false;
128                 }
129                 CollectionUtils.retainAll(permissionsToGrant,
130                         disabledSystemPackageInfo.requestedPermissions);
131                 if (permissionsToGrant.isEmpty()) {
132                     return false;
133                 }
134             }
135         }
136 
137         // Sort foreground permissions first so that we can grant a background permission based on
138         // whether any of its foreground permissions are granted.
139         int permissionsToGrantSize = permissionsToGrant.size();
140         String[] sortedPermissionsToGrant = new String[permissionsToGrantSize];
141         int foregroundPermissionCount = 0;
142         int nonForegroundPermissionCount = 0;
143         for (int i = 0; i < permissionsToGrantSize; i++) {
144             String permission = permissionsToGrant.valueAt(i);
145 
146             if (isForegroundPermission(permission, context)) {
147                 sortedPermissionsToGrant[foregroundPermissionCount] = permission;
148                 foregroundPermissionCount++;
149             } else {
150                 int index = permissionsToGrantSize - 1 - nonForegroundPermissionCount;
151                 sortedPermissionsToGrant[index] = permission;
152                 nonForegroundPermissionCount++;
153             }
154         }
155 
156         boolean permissionOrAppOpChanged = false;
157 
158         PackageManager packageManager = context.getPackageManager();
159         Set<String> whitelistedRestrictedPermissions = new ArraySet<>(
160                 packageManager.getWhitelistedRestrictedPermissions(packageName,
161                         PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM));
162         List<String> smsPermissions = Utils.getPlatformPermissionNamesOfGroup(
163                 Manifest.permission_group.SMS);
164         List<String> callLogPermissions = Utils.getPlatformPermissionNamesOfGroup(
165                 Manifest.permission_group.CALL_LOG);
166 
167         int sortedPermissionsToGrantLength = sortedPermissionsToGrant.length;
168         for (int i = 0; i < sortedPermissionsToGrantLength; i++) {
169             String permission = sortedPermissionsToGrant[i];
170 
171             if ((smsPermissions.contains(permission) || callLogPermissions.contains(permission))
172                     && whitelistedRestrictedPermissions.add(permission)) {
173                 packageManager.addWhitelistedRestrictedPermission(packageName, permission,
174                         PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM);
175             }
176 
177             permissionOrAppOpChanged |= grantSingle(packageName, permission,
178                     overrideUserSetAndFixed, setGrantedByRole, setGrantedByDefault, setSystemFixed,
179                     context);
180         }
181 
182         return permissionOrAppOpChanged;
183     }
184 
grantSingle(@onNull String packageName, @NonNull String permission, boolean overrideUserSetAndFixed, boolean setGrantedByRole, boolean setGrantedByDefault, boolean setSystemFixed, @NonNull Context context)185     private static boolean grantSingle(@NonNull String packageName, @NonNull String permission,
186             boolean overrideUserSetAndFixed, boolean setGrantedByRole, boolean setGrantedByDefault,
187             boolean setSystemFixed, @NonNull Context context) {
188         boolean wasPermissionOrAppOpGranted = isPermissionAndAppOpGranted(packageName, permission,
189                 context);
190         if (isPermissionFixed(packageName, permission, false, overrideUserSetAndFixed, context)
191                 && !wasPermissionOrAppOpGranted) {
192             // Stop granting if this permission is fixed to revoked.
193             return false;
194         }
195 
196         if (isBackgroundPermission(permission, context)) {
197             List<String> foregroundPermissions = getForegroundPermissions(permission, context);
198             boolean isAnyForegroundPermissionGranted = false;
199             int foregroundPermissionsSize = foregroundPermissions.size();
200             for (int i = 0; i < foregroundPermissionsSize; i++) {
201                 String foregroundPermission = foregroundPermissions.get(i);
202 
203                 if (isPermissionAndAppOpGranted(packageName, foregroundPermission, context)) {
204                     isAnyForegroundPermissionGranted = true;
205                     break;
206                 }
207             }
208 
209             if (!isAnyForegroundPermissionGranted) {
210                 // Stop granting if this background permission doesn't have a granted foreground
211                 // permission.
212                 return false;
213             }
214         }
215 
216         boolean permissionOrAppOpChanged = grantPermissionAndAppOp(packageName, permission,
217                 context);
218 
219         // Update permission flags.
220         int newFlags = 0;
221         if (!wasPermissionOrAppOpGranted && setGrantedByRole) {
222             newFlags |= PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE;
223         }
224         if (setGrantedByDefault) {
225             newFlags |= PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
226         }
227         if (setSystemFixed) {
228             newFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
229         }
230         int newMask = newFlags;
231         newMask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
232         if (!wasPermissionOrAppOpGranted) {
233             // If we've granted a permission which wasn't granted, it's no longer user set or fixed.
234             newMask |= PackageManager.FLAG_PERMISSION_USER_FIXED
235                     | PackageManager.FLAG_PERMISSION_USER_SET;
236         }
237         // If a component gets a permission for being the default handler A and also default handler
238         // B, we grant the weaker grant form. This only applies to default permission grant.
239         if (setGrantedByDefault && !setSystemFixed) {
240             int oldFlags = getPermissionFlags(packageName, permission, context);
241             if ((oldFlags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0
242                     && (oldFlags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
243                 if (DEBUG) {
244                     Log.i(LOG_TAG, "Granted not fixed " + permission + " to default handler "
245                             + packageName);
246                 }
247                 newMask |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
248             }
249         }
250 
251         setPermissionFlags(packageName, permission, newFlags, newMask, context);
252 
253         return permissionOrAppOpChanged;
254     }
255 
isPermissionAndAppOpGranted(@onNull String packageName, @NonNull String permission, @NonNull Context context)256     private static boolean isPermissionAndAppOpGranted(@NonNull String packageName,
257             @NonNull String permission, @NonNull Context context) {
258         // Check this permission.
259         if (!isPermissionGrantedWithoutCheckingAppOp(packageName, permission, context)) {
260             return false;
261         }
262 
263         // Check if the permission is review required.
264         if (isPermissionReviewRequired(packageName, permission, context)) {
265             return false;
266         }
267 
268         if (!isBackgroundPermission(permission, context)) {
269             // This permission is not a background permission, check its app op.
270             String appOp = getPermissionAppOp(permission);
271             if (appOp == null) {
272                 return true;
273             }
274             Integer appOpMode = getAppOpMode(packageName, appOp, context);
275             if (appOpMode == null) {
276                 return false;
277             }
278             if (!isForegroundPermission(permission, context)) {
279                 // This permission is an ordinary permission, return true if its app op mode is
280                 // MODE_ALLOWED.
281                 return appOpMode == AppOpsManager.MODE_ALLOWED;
282             } else {
283                 // This permission is a foreground permission, return true if its app op mode is
284                 // MODE_FOREGROUND or MODE_ALLOWED.
285                 return appOpMode == AppOpsManager.MODE_FOREGROUND
286                         || appOpMode == AppOpsManager.MODE_ALLOWED;
287             }
288         } else {
289             // This permission is a background permission, return true if any of its foreground
290             // permissions' app op modes are MODE_ALLOWED.
291             List<String> foregroundPermissions = getForegroundPermissions(permission, context);
292             int foregroundPermissionsSize = foregroundPermissions.size();
293             for (int i = 0; i < foregroundPermissionsSize; i++) {
294                 String foregroundPermission = foregroundPermissions.get(i);
295 
296                 String foregroundAppOp = getPermissionAppOp(foregroundPermission);
297                 if (foregroundAppOp == null) {
298                     continue;
299                 }
300                 Integer foregroundAppOpMode = getAppOpMode(packageName, foregroundAppOp, context);
301                 if (foregroundAppOpMode == null) {
302                     continue;
303                 }
304                 if (foregroundAppOpMode == AppOpsManager.MODE_ALLOWED) {
305                     return true;
306                 }
307             }
308             return false;
309         }
310     }
311 
grantPermissionAndAppOp(@onNull String packageName, @NonNull String permission, @NonNull Context context)312     private static boolean grantPermissionAndAppOp(@NonNull String packageName,
313             @NonNull String permission, @NonNull Context context) {
314         // Grant the permission.
315         boolean permissionOrAppOpChanged = grantPermissionWithoutAppOp(packageName, permission,
316                 context);
317 
318         // Grant the app op.
319         if (!isBackgroundPermission(permission, context)) {
320             String appOp = getPermissionAppOp(permission);
321             if (appOp == null) {
322                 return false;
323             }
324 
325             int appOpMode;
326             if (!isForegroundPermission(permission, context)) {
327                 // This permission is an ordinary permission, set its app op mode to MODE_ALLOWED.
328                 appOpMode = AppOpsManager.MODE_ALLOWED;
329             } else {
330                 // This permission is a foreground permission, set its app op mode according to
331                 // whether its background permission is granted.
332                 String backgroundPermission = getBackgroundPermission(permission, context);
333                 if (!isPermissionAndAppOpGranted(packageName, backgroundPermission, context)) {
334                     appOpMode = AppOpsManager.MODE_FOREGROUND;
335                 } else {
336                     appOpMode = AppOpsManager.MODE_ALLOWED;
337                 }
338             }
339             permissionOrAppOpChanged = setAppOpMode(packageName, appOp, appOpMode, context);
340         } else {
341             // This permission is a background permission, set all its foreground permissions' app
342             // op modes to MODE_ALLOWED.
343             List<String> foregroundPermissions = getForegroundPermissions(permission, context);
344             int foregroundPermissionsSize = foregroundPermissions.size();
345             for (int i = 0; i < foregroundPermissionsSize; i++) {
346                 String foregroundPermission = foregroundPermissions.get(i);
347 
348                 String foregroundAppOp = getPermissionAppOp(foregroundPermission);
349                 if (foregroundAppOp == null) {
350                     continue;
351                 }
352                 permissionOrAppOpChanged |= setAppOpMode(packageName, foregroundAppOp,
353                         AppOpsManager.MODE_ALLOWED, context);
354             }
355         }
356 
357         return permissionOrAppOpChanged;
358     }
359 
360     /**
361      * Revoke permissions and associated app ops from an application.
362      *
363      * @param packageName the package name of the application to be revoke permissions from
364      * @param permissions the list of permissions to be revoked
365      * @param onlyIfGrantedByRole revoke the permission only if it is granted by role
366      * @param onlyIfGrantedByDefault revoke the permission only if it is granted by default
367      * @param overrideSystemFixed whether system-fixed permissions can be revoked
368      * @param context the {@code Context} to retrieve system services
369      *
370      * @return whether any permission or app op changed
371      *
372      * @see com.android.server.pm.permission.DefaultPermissionGrantPolicy#revokeRuntimePermissions(
373      *      String, java.util.Set, boolean, int)
374      */
revoke(@onNull String packageName, @NonNull List<String> permissions, boolean onlyIfGrantedByRole, boolean onlyIfGrantedByDefault, boolean overrideSystemFixed, @NonNull Context context)375     public static boolean revoke(@NonNull String packageName, @NonNull List<String> permissions,
376             boolean onlyIfGrantedByRole, boolean onlyIfGrantedByDefault,
377             boolean overrideSystemFixed, @NonNull Context context) {
378         PackageInfo packageInfo = getPackageInfo(packageName, context);
379         if (packageInfo == null) {
380             return false;
381         }
382 
383         if (ArrayUtils.isEmpty(packageInfo.requestedPermissions)) {
384             return false;
385         }
386 
387         ArraySet<String> permissionsToRevoke = new ArraySet<>(permissions);
388         CollectionUtils.retainAll(permissionsToRevoke, packageInfo.requestedPermissions);
389         if (permissionsToRevoke.isEmpty()) {
390             return false;
391         }
392 
393         // Sort background permissions first so that we can revoke a foreground permission based on
394         // whether its background permission is revoked.
395         int permissionsToRevokeSize = permissionsToRevoke.size();
396         String[] sortedPermissionsToRevoke = new String[permissionsToRevokeSize];
397         int backgroundPermissionCount = 0;
398         int nonBackgroundPermissionCount = 0;
399         for (int i = 0; i < permissionsToRevokeSize; i++) {
400             String permission = permissionsToRevoke.valueAt(i);
401 
402             if (isBackgroundPermission(permission, context)) {
403                 sortedPermissionsToRevoke[backgroundPermissionCount] = permission;
404                 backgroundPermissionCount++;
405             } else {
406                 int index = permissionsToRevokeSize - 1 - nonBackgroundPermissionCount;
407                 sortedPermissionsToRevoke[index] = permission;
408                 nonBackgroundPermissionCount++;
409             }
410         }
411 
412         PackageManager packageManager = context.getPackageManager();
413         Set<String> whitelistedRestrictedPermissions =
414                 packageManager.getWhitelistedRestrictedPermissions(packageName,
415                         Utils.FLAGS_PERMISSION_WHITELIST_ALL);
416 
417         boolean permissionOrAppOpChanged = false;
418 
419         int sortedPermissionsToRevokeLength = sortedPermissionsToRevoke.length;
420         for (int i = 0; i < sortedPermissionsToRevokeLength; i++) {
421             String permission = sortedPermissionsToRevoke[i];
422 
423             permissionOrAppOpChanged |= revokeSingle(packageName, permission, onlyIfGrantedByRole,
424                     onlyIfGrantedByDefault, overrideSystemFixed, context);
425 
426             // Remove from the system whitelist only if not granted by default.
427             if (!isPermissionGrantedByDefault(packageName, permission, context)
428                     && whitelistedRestrictedPermissions.remove(permission)) {
429                 packageManager.removeWhitelistedRestrictedPermission(packageName, permission,
430                         PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM);
431             }
432         }
433 
434         return permissionOrAppOpChanged;
435     }
436 
revokeSingle(@onNull String packageName, @NonNull String permission, boolean onlyIfGrantedByRole, boolean onlyIfGrantedByDefault, boolean overrideSystemFixed, @NonNull Context context)437     private static boolean revokeSingle(@NonNull String packageName, @NonNull String permission,
438             boolean onlyIfGrantedByRole, boolean onlyIfGrantedByDefault,
439             boolean overrideSystemFixed, @NonNull Context context) {
440         if (onlyIfGrantedByRole == onlyIfGrantedByDefault) {
441             throw new IllegalArgumentException("Permission can be revoked only if either granted by"
442                     + " role, or granted by default, but not both");
443         }
444 
445         if (onlyIfGrantedByRole) {
446             if (!isPermissionGrantedByRole(packageName, permission, context)) {
447                 return false;
448             }
449             setPermissionFlags(packageName, permission, 0,
450                     PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, context);
451         }
452 
453         if (onlyIfGrantedByDefault) {
454             if (!isPermissionGrantedByDefault(packageName, permission, context)) {
455                 return false;
456             }
457             // Remove the granted-by-default permission flag.
458             setPermissionFlags(packageName, permission, 0,
459                     PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, context);
460             // Note that we do not revoke FLAG_PERMISSION_SYSTEM_FIXED. That bit remains sticky once
461             // set.
462         }
463 
464         if (isPermissionFixed(packageName, permission, overrideSystemFixed, false, context)
465                 && isPermissionAndAppOpGranted(packageName, permission, context)) {
466             // Stop revoking if this permission is fixed to granted.
467             return false;
468         }
469 
470         if (isForegroundPermission(permission, context)) {
471             String backgroundPermission = getBackgroundPermission(permission, context);
472             if (isPermissionAndAppOpGranted(packageName, backgroundPermission, context)) {
473                 // Stop revoking if this foreground permission has a granted background permission.
474                 return false;
475             }
476         }
477 
478         return revokePermissionAndAppOp(packageName, permission, context);
479     }
480 
revokePermissionAndAppOp(@onNull String packageName, @NonNull String permission, @NonNull Context context)481     private static boolean revokePermissionAndAppOp(@NonNull String packageName,
482             @NonNull String permission, @NonNull Context context) {
483         boolean permissionOrAppOpChanged = false;
484 
485         boolean isRuntimePermissionsSupported = isRuntimePermissionsSupported(packageName, context);
486         if (isRuntimePermissionsSupported) {
487             // Revoke the permission.
488             permissionOrAppOpChanged |= revokePermissionWithoutAppOp(packageName, permission,
489                     context);
490         }
491 
492         // Revoke the app op.
493         if (!isBackgroundPermission(permission, context)) {
494             String appOp = getPermissionAppOp(permission);
495             if (appOp == null) {
496                 return false;
497             }
498 
499             // This permission is an ordinary or foreground permission, reset its app op mode to
500             // default.
501             int appOpMode = getDefaultAppOpMode(appOp);
502             boolean appOpModeChanged = setAppOpMode(packageName, appOp, appOpMode, context);
503             permissionOrAppOpChanged |= appOpModeChanged;
504 
505             if (appOpModeChanged) {
506                 if (!isRuntimePermissionsSupported && (appOpMode == AppOpsManager.MODE_FOREGROUND
507                         || appOpMode == AppOpsManager.MODE_ALLOWED)) {
508                     // We've reset this permission's app op mode to be permissive, so we'll need the
509                     // user to review it again.
510                     setPermissionFlags(packageName, permission,
511                             PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED,
512                             PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, context);
513                 }
514             }
515         } else {
516             // This permission is a background permission, set all its granted foreground
517             // permissions' app op modes to MODE_FOREGROUND.
518             List<String> foregroundPermissions = getForegroundPermissions(permission, context);
519             int foregroundPermissionsSize = foregroundPermissions.size();
520             for (int i = 0; i < foregroundPermissionsSize; i++) {
521                 String foregroundPermission = foregroundPermissions.get(i);
522 
523                 if (!isPermissionAndAppOpGranted(packageName, foregroundPermission, context)) {
524                     continue;
525                 }
526 
527                 String foregroundAppOp = getPermissionAppOp(foregroundPermission);
528                 if (foregroundAppOp == null) {
529                     continue;
530                 }
531                 permissionOrAppOpChanged |= setAppOpMode(packageName, foregroundAppOp,
532                         AppOpsManager.MODE_FOREGROUND, context);
533             }
534         }
535 
536         return permissionOrAppOpChanged;
537     }
538 
539     @Nullable
getPackageInfo(@onNull String packageName, @NonNull Context context)540     private static PackageInfo getPackageInfo(@NonNull String packageName,
541             @NonNull Context context) {
542         return getPackageInfo(packageName, 0, context);
543     }
544 
545     @Nullable
getFactoryPackageInfo(@onNull String packageName, @NonNull Context context)546     private static PackageInfo getFactoryPackageInfo(@NonNull String packageName,
547             @NonNull Context context) {
548         return getPackageInfo(packageName, PackageManager.MATCH_FACTORY_ONLY, context);
549     }
550 
551     @Nullable
getPackageInfo(@onNull String packageName, int extraFlags, @NonNull Context context)552     private static PackageInfo getPackageInfo(@NonNull String packageName, int extraFlags,
553             @NonNull Context context) {
554         return PackageUtils.getPackageInfo(packageName, extraFlags
555                 // TODO: Why MATCH_UNINSTALLED_PACKAGES?
556                 | PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS,
557                 context);
558     }
559 
isUpdatedSystemApp(@onNull PackageInfo packageInfo)560     private static boolean isUpdatedSystemApp(@NonNull PackageInfo packageInfo) {
561         return packageInfo.applicationInfo != null && (packageInfo.applicationInfo.flags
562                 & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
563     }
564 
isRuntimePermissionsSupported(@onNull String packageName, @NonNull Context context)565     static boolean isRuntimePermissionsSupported(@NonNull String packageName,
566             @NonNull Context context) {
567         ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, context);
568         if (applicationInfo == null) {
569             return false;
570         }
571         return applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M;
572     }
573 
getPermissionFlags(@onNull String packageName, @NonNull String permission, @NonNull Context context)574     private static int getPermissionFlags(@NonNull String packageName, @NonNull String permission,
575             @NonNull Context context) {
576         PackageManager packageManager = context.getPackageManager();
577         UserHandle user = Process.myUserHandle();
578         return packageManager.getPermissionFlags(permission, packageName, user);
579     }
580 
isPermissionFixed(@onNull String packageName, @NonNull String permission, boolean overrideSystemFixed, boolean overrideUserSetAndFixed, @NonNull Context context)581     private static boolean isPermissionFixed(@NonNull String packageName,
582             @NonNull String permission, boolean overrideSystemFixed,
583             boolean overrideUserSetAndFixed, @NonNull Context context) {
584         int flags = getPermissionFlags(packageName, permission, context);
585         int fixedFlags = PackageManager.FLAG_PERMISSION_POLICY_FIXED;
586         if (!overrideSystemFixed) {
587             fixedFlags |= PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
588         }
589         if (!overrideUserSetAndFixed) {
590             fixedFlags |= PackageManager.FLAG_PERMISSION_USER_FIXED
591                     | PackageManager.FLAG_PERMISSION_USER_SET;
592         }
593         return (flags & fixedFlags) != 0;
594     }
595 
isPermissionGrantedByDefault(@onNull String packageName, @NonNull String permission, @NonNull Context context)596     private static boolean isPermissionGrantedByDefault(@NonNull String packageName,
597             @NonNull String permission, @NonNull Context context) {
598         int flags = getPermissionFlags(packageName, permission, context);
599         return (flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0;
600     }
601 
isPermissionGrantedByRole(@onNull String packageName, @NonNull String permission, @NonNull Context context)602     private static boolean isPermissionGrantedByRole(@NonNull String packageName,
603             @NonNull String permission, @NonNull Context context) {
604         int flags = getPermissionFlags(packageName, permission, context);
605         return (flags & PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE) != 0;
606     }
607 
isPermissionReviewRequired(@onNull String packageName, @NonNull String permission, @NonNull Context context)608     private static boolean isPermissionReviewRequired(@NonNull String packageName,
609             @NonNull String permission, @NonNull Context context) {
610         int flags = getPermissionFlags(packageName, permission, context);
611         return (flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0;
612     }
613 
setPermissionFlags(@onNull String packageName, @NonNull String permission, int flags, int mask, @NonNull Context context)614     private static void setPermissionFlags(@NonNull String packageName, @NonNull String permission,
615             int flags, int mask, @NonNull Context context) {
616         PackageManager packageManager = context.getPackageManager();
617         UserHandle user = Process.myUserHandle();
618         packageManager.updatePermissionFlags(permission, packageName, mask, flags, user);
619     }
620 
621     /**
622      * Most of the time {@link #isPermissionAndAppOpGranted(String, String, Context)} should be used
623      * instead.
624      */
isPermissionGrantedWithoutCheckingAppOp(@onNull String packageName, @NonNull String permission, @NonNull Context context)625     private static boolean isPermissionGrantedWithoutCheckingAppOp(@NonNull String packageName,
626             @NonNull String permission, @NonNull Context context) {
627         PackageManager packageManager = context.getPackageManager();
628         return packageManager.checkPermission(permission, packageName)
629                 == PackageManager.PERMISSION_GRANTED;
630     }
631 
grantPermissionWithoutAppOp(@onNull String packageName, @NonNull String permission, @NonNull Context context)632     private static boolean grantPermissionWithoutAppOp(@NonNull String packageName,
633             @NonNull String permission, @NonNull Context context) {
634         if (isPermissionGrantedWithoutCheckingAppOp(packageName, permission, context)) {
635             return false;
636         }
637         PackageManager packageManager = context.getPackageManager();
638         UserHandle user = Process.myUserHandle();
639         packageManager.grantRuntimePermission(packageName, permission, user);
640         return true;
641     }
642 
revokePermissionWithoutAppOp(@onNull String packageName, @NonNull String permission, @NonNull Context context)643     private static boolean revokePermissionWithoutAppOp(@NonNull String packageName,
644             @NonNull String permission, @NonNull Context context) {
645         if (!isPermissionGrantedWithoutCheckingAppOp(packageName, permission, context)) {
646             return false;
647         }
648         PackageManager packageManager = context.getPackageManager();
649         UserHandle user = Process.myUserHandle();
650         packageManager.revokeRuntimePermission(packageName, permission, user);
651         return true;
652     }
653 
isForegroundPermission(@onNull String permission, @NonNull Context context)654     private static boolean isForegroundPermission(@NonNull String permission,
655             @NonNull Context context) {
656         ensureForegroundBackgroundPermissionMappings(context);
657         return sForegroundToBackgroundPermission.containsKey(permission);
658     }
659 
660     @Nullable
getBackgroundPermission(@onNull String foregroundPermission, @NonNull Context context)661     private static String getBackgroundPermission(@NonNull String foregroundPermission,
662             @NonNull Context context) {
663         ensureForegroundBackgroundPermissionMappings(context);
664         return sForegroundToBackgroundPermission.get(foregroundPermission);
665     }
666 
isBackgroundPermission(@onNull String permission, @NonNull Context context)667     private static boolean isBackgroundPermission(@NonNull String permission,
668             @NonNull Context context) {
669         ensureForegroundBackgroundPermissionMappings(context);
670         return sBackgroundToForegroundPermissions.containsKey(permission);
671     }
672 
673     @Nullable
getForegroundPermissions(@onNull String backgroundPermission, @NonNull Context context)674     private static List<String> getForegroundPermissions(@NonNull String backgroundPermission,
675             @NonNull Context context) {
676         ensureForegroundBackgroundPermissionMappings(context);
677         return sBackgroundToForegroundPermissions.get(backgroundPermission);
678     }
679 
ensureForegroundBackgroundPermissionMappings(@onNull Context context)680     private static void ensureForegroundBackgroundPermissionMappings(@NonNull Context context) {
681         synchronized (sForegroundBackgroundPermissionMappingsLock) {
682             if (sForegroundToBackgroundPermission == null
683                     && sBackgroundToForegroundPermissions == null) {
684                 createForegroundBackgroundPermissionMappings(context);
685             }
686         }
687     }
688 
createForegroundBackgroundPermissionMappings(@onNull Context context)689     private static void createForegroundBackgroundPermissionMappings(@NonNull Context context) {
690         List<String> permissions = new ArrayList<>();
691         sBackgroundToForegroundPermissions = new ArrayMap<>();
692 
693         PackageManager packageManager = context.getPackageManager();
694         List<PermissionGroupInfo> permissionGroupInfos = packageManager.getAllPermissionGroups(0);
695 
696         int permissionGroupInfosSize = permissionGroupInfos.size();
697         for (int permissionGroupInfosIndex = 0;
698                 permissionGroupInfosIndex < permissionGroupInfosSize; permissionGroupInfosIndex++) {
699             PermissionGroupInfo permissionGroupInfo = permissionGroupInfos.get(
700                     permissionGroupInfosIndex);
701 
702             List<PermissionInfo> permissionInfos;
703             try {
704                 permissionInfos = Utils.getPermissionInfosForGroup(packageManager,
705                         permissionGroupInfo.name);
706             } catch (PackageManager.NameNotFoundException e) {
707                 Log.e(LOG_TAG, "Cannot get permissions for group: " + permissionGroupInfo.name);
708                 continue;
709             }
710 
711             int permissionInfosSize = permissionInfos.size();
712             for (int permissionInfosIndex = 0; permissionInfosIndex < permissionInfosSize;
713                     permissionInfosIndex++) {
714                 PermissionInfo permissionInfo = permissionInfos.get(permissionInfosIndex);
715 
716                 String permission = permissionInfo.name;
717                 permissions.add(permission);
718 
719                 String backgroundPermission = permissionInfo.backgroundPermission;
720                 if (backgroundPermission != null) {
721                     List<String> foregroundPermissions = sBackgroundToForegroundPermissions.get(
722                             backgroundPermission);
723                     if (foregroundPermissions == null) {
724                         foregroundPermissions = new ArrayList<>();
725                         sBackgroundToForegroundPermissions.put(backgroundPermission,
726                                 foregroundPermissions);
727                     }
728                     foregroundPermissions.add(permission);
729                 }
730             }
731         }
732 
733         // Remove background permissions declared by foreground permissions but don't actually
734         // exist.
735         sBackgroundToForegroundPermissions.retainAll(permissions);
736 
737         // Collect foreground permissions that have existent background permissions.
738         sForegroundToBackgroundPermission = new ArrayMap<>();
739 
740         int backgroundToForegroundPermissionsSize = sBackgroundToForegroundPermissions.size();
741         for (int backgroundToForegroundPermissionsIndex = 0;
742                 backgroundToForegroundPermissionsIndex < backgroundToForegroundPermissionsSize;
743                 backgroundToForegroundPermissionsIndex++) {
744             String backgroundPerimssion = sBackgroundToForegroundPermissions.keyAt(
745                     backgroundToForegroundPermissionsIndex);
746             List<String> foregroundPermissions = sBackgroundToForegroundPermissions.valueAt(
747                     backgroundToForegroundPermissionsIndex);
748 
749             int foregroundPermissionsSize = foregroundPermissions.size();
750             for (int foregroundPermissionsIndex = 0;
751                     foregroundPermissionsIndex < foregroundPermissionsSize;
752                     foregroundPermissionsIndex++) {
753                 String foregroundPermission = foregroundPermissions.get(foregroundPermissionsIndex);
754 
755                 sForegroundToBackgroundPermission.put(foregroundPermission, backgroundPerimssion);
756             }
757         }
758     }
759 
760     @Nullable
getPermissionAppOp(@onNull String permission)761     private static String getPermissionAppOp(@NonNull String permission) {
762         return AppOpsManager.permissionToOp(permission);
763     }
764 
765     @Nullable
getAppOpMode(@onNull String packageName, @NonNull String appOp, @NonNull Context context)766     private static Integer getAppOpMode(@NonNull String packageName, @NonNull String appOp,
767             @NonNull Context context) {
768         ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, context);
769         if (applicationInfo == null) {
770             return null;
771         }
772         AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
773         return appOpsManager.unsafeCheckOpRaw(appOp, applicationInfo.uid, packageName);
774     }
775 
getDefaultAppOpMode(@onNull String appOp)776     static int getDefaultAppOpMode(@NonNull String appOp) {
777         return AppOpsManager.opToDefaultMode(appOp);
778     }
779 
setAppOpMode(@onNull String packageName, @NonNull String appOp, int mode, @NonNull Context context)780     static boolean setAppOpMode(@NonNull String packageName, @NonNull String appOp, int mode,
781             @NonNull Context context) {
782         Integer currentMode = getAppOpMode(packageName, appOp, context);
783         if (currentMode != null && currentMode == mode) {
784             return false;
785         }
786         ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, context);
787         if (applicationInfo == null) {
788             Log.e(LOG_TAG, "Cannot get ApplicationInfo for package to set app op mode: "
789                     + packageName);
790             return false;
791         }
792         AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
793         appOpsManager.setUidMode(appOp, applicationInfo.uid, mode);
794         return true;
795     }
796 }
797