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