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