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