Home | History | Annotate | Download | only in model
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.packageinstaller.permission.model;
     18 
     19 import android.app.ActivityManager;
     20 import android.app.AppOpsManager;
     21 import android.content.Context;
     22 import android.content.pm.PackageInfo;
     23 import android.content.pm.PackageItemInfo;
     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.util.ArrayMap;
     31 
     32 import com.android.packageinstaller.R;
     33 import com.android.packageinstaller.permission.utils.ArrayUtils;
     34 import com.android.packageinstaller.permission.utils.LocationUtils;
     35 
     36 import java.util.ArrayList;
     37 import java.util.List;
     38 
     39 public final class AppPermissionGroup implements Comparable<AppPermissionGroup> {
     40     private static final String PLATFORM_PACKAGE_NAME = "android";
     41 
     42     private static final String KILL_REASON_APP_OP_CHANGE = "Permission related app op changed";
     43 
     44     private final Context mContext;
     45     private final UserHandle mUserHandle;
     46     private final PackageManager mPackageManager;
     47     private final AppOpsManager mAppOps;
     48     private final ActivityManager mActivityManager;
     49 
     50     private final PackageInfo mPackageInfo;
     51     private final String mName;
     52     private final String mDeclaringPackage;
     53     private final CharSequence mLabel;
     54     private final CharSequence mDescription;
     55     private final ArrayMap<String, Permission> mPermissions = new ArrayMap<>();
     56     private final String mIconPkg;
     57     private final int mIconResId;
     58 
     59     private final boolean mAppSupportsRuntimePermissions;
     60     private final boolean mIsEphemeralApp;
     61     private boolean mContainsEphemeralPermission;
     62     private boolean mContainsPreRuntimePermission;
     63 
     64     public static AppPermissionGroup create(Context context, PackageInfo packageInfo,
     65             String permissionName) {
     66         PermissionInfo permissionInfo;
     67         try {
     68             permissionInfo = context.getPackageManager().getPermissionInfo(permissionName, 0);
     69         } catch (PackageManager.NameNotFoundException e) {
     70             return null;
     71         }
     72 
     73         if ((permissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
     74                 != PermissionInfo.PROTECTION_DANGEROUS
     75                 || (permissionInfo.flags & PermissionInfo.FLAG_INSTALLED) == 0
     76                 || (permissionInfo.flags & PermissionInfo.FLAG_REMOVED) != 0) {
     77             return null;
     78         }
     79 
     80         PackageItemInfo groupInfo = permissionInfo;
     81         if (permissionInfo.group != null) {
     82             try {
     83                 groupInfo = context.getPackageManager().getPermissionGroupInfo(
     84                         permissionInfo.group, 0);
     85             } catch (PackageManager.NameNotFoundException e) {
     86                 /* ignore */
     87             }
     88         }
     89 
     90         List<PermissionInfo> permissionInfos = null;
     91         if (groupInfo instanceof PermissionGroupInfo) {
     92             try {
     93                 permissionInfos = context.getPackageManager().queryPermissionsByGroup(
     94                         groupInfo.name, 0);
     95             } catch (PackageManager.NameNotFoundException e) {
     96                 /* ignore */
     97             }
     98         }
     99 
    100         return create(context, packageInfo, groupInfo, permissionInfos,
    101                 Process.myUserHandle());
    102     }
    103 
    104     public static AppPermissionGroup create(Context context, PackageInfo packageInfo,
    105             PackageItemInfo groupInfo, List<PermissionInfo> permissionInfos,
    106             UserHandle userHandle) {
    107 
    108         AppPermissionGroup group = new AppPermissionGroup(context, packageInfo, groupInfo.name,
    109                 groupInfo.packageName, groupInfo.loadLabel(context.getPackageManager()),
    110                 loadGroupDescription(context, groupInfo), groupInfo.packageName, groupInfo.icon,
    111                 userHandle);
    112 
    113         if (groupInfo instanceof PermissionInfo) {
    114             permissionInfos = new ArrayList<>();
    115             permissionInfos.add((PermissionInfo) groupInfo);
    116         }
    117 
    118         if (permissionInfos == null || permissionInfos.isEmpty()) {
    119             return null;
    120         }
    121 
    122         final int permissionCount = packageInfo.requestedPermissions.length;
    123         for (int i = 0; i < permissionCount; i++) {
    124             String requestedPermission = packageInfo.requestedPermissions[i];
    125 
    126             PermissionInfo requestedPermissionInfo = null;
    127 
    128             for (PermissionInfo permissionInfo : permissionInfos) {
    129                 if (requestedPermission.equals(permissionInfo.name)) {
    130                     requestedPermissionInfo = permissionInfo;
    131                     break;
    132                 }
    133             }
    134 
    135             if (requestedPermissionInfo == null) {
    136                 continue;
    137             }
    138 
    139             // Collect only runtime permissions.
    140             if ((requestedPermissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
    141                     != PermissionInfo.PROTECTION_DANGEROUS) {
    142                 continue;
    143             }
    144 
    145             // Don't allow toggling non-platform permission groups for legacy apps via app ops.
    146             if (packageInfo.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1
    147                     && !PLATFORM_PACKAGE_NAME.equals(groupInfo.packageName)) {
    148                 continue;
    149             }
    150 
    151             final boolean granted = (packageInfo.requestedPermissionsFlags[i]
    152                     & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;
    153 
    154             final String appOp = PLATFORM_PACKAGE_NAME.equals(requestedPermissionInfo.packageName)
    155                     ? AppOpsManager.permissionToOp(requestedPermissionInfo.name) : null;
    156 
    157             final boolean appOpAllowed = appOp != null
    158                     && context.getSystemService(AppOpsManager.class).checkOpNoThrow(appOp,
    159                     packageInfo.applicationInfo.uid, packageInfo.packageName)
    160                     == AppOpsManager.MODE_ALLOWED;
    161 
    162             final int flags = context.getPackageManager().getPermissionFlags(
    163                     requestedPermission, packageInfo.packageName, userHandle);
    164 
    165             Permission permission = new Permission(requestedPermission, granted,
    166                     appOp, appOpAllowed, flags, requestedPermissionInfo.protectionLevel);
    167             group.addPermission(permission);
    168         }
    169 
    170         return group;
    171     }
    172 
    173     private static CharSequence loadGroupDescription(Context context, PackageItemInfo group) {
    174         CharSequence description = null;
    175         if (group instanceof PermissionGroupInfo) {
    176             description = ((PermissionGroupInfo) group).loadDescription(
    177                     context.getPackageManager());
    178         } else if (group instanceof PermissionInfo) {
    179             description = ((PermissionInfo) group).loadDescription(
    180                     context.getPackageManager());
    181         }
    182 
    183         if (description == null || description.length() <= 0) {
    184             description = context.getString(R.string.default_permission_description);
    185         }
    186 
    187         return description;
    188     }
    189 
    190     private AppPermissionGroup(Context context, PackageInfo packageInfo, String name,
    191             String declaringPackage, CharSequence label, CharSequence description,
    192             String iconPkg, int iconResId, UserHandle userHandle) {
    193         mContext = context;
    194         mUserHandle = userHandle;
    195         mPackageManager = mContext.getPackageManager();
    196         mPackageInfo = packageInfo;
    197         mAppSupportsRuntimePermissions = packageInfo.applicationInfo
    198                 .targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;
    199         mIsEphemeralApp = packageInfo.applicationInfo.isInstantApp();
    200         mAppOps = context.getSystemService(AppOpsManager.class);
    201         mActivityManager = context.getSystemService(ActivityManager.class);
    202         mDeclaringPackage = declaringPackage;
    203         mName = name;
    204         mLabel = label;
    205         mDescription = description;
    206         if (iconResId != 0) {
    207             mIconPkg = iconPkg;
    208             mIconResId = iconResId;
    209         } else {
    210             mIconPkg = context.getPackageName();
    211             mIconResId = R.drawable.ic_perm_device_info;
    212         }
    213     }
    214 
    215     public boolean doesSupportRuntimePermissions() {
    216         return mAppSupportsRuntimePermissions;
    217     }
    218 
    219     public boolean isGrantingAllowed() {
    220         return (!mIsEphemeralApp || mContainsEphemeralPermission)
    221                 && (mAppSupportsRuntimePermissions || mContainsPreRuntimePermission);
    222     }
    223 
    224     public boolean isReviewRequired() {
    225         if (mAppSupportsRuntimePermissions) {
    226             return false;
    227         }
    228         final int permissionCount = mPermissions.size();
    229         for (int i = 0; i < permissionCount; i++) {
    230             Permission permission = mPermissions.valueAt(i);
    231             if (permission.isReviewRequired()) {
    232                 return true;
    233             }
    234         }
    235         return false;
    236     }
    237 
    238     public void resetReviewRequired() {
    239         final int permissionCount = mPermissions.size();
    240         for (int i = 0; i < permissionCount; i++) {
    241             Permission permission = mPermissions.valueAt(i);
    242             if (permission.isReviewRequired()) {
    243                 permission.resetReviewRequired();
    244                 mPackageManager.updatePermissionFlags(permission.getName(),
    245                         mPackageInfo.packageName,
    246                         PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED,
    247                         0, mUserHandle);
    248             }
    249         }
    250     }
    251 
    252     public boolean hasGrantedByDefaultPermission() {
    253         final int permissionCount = mPermissions.size();
    254         for (int i = 0; i < permissionCount; i++) {
    255             Permission permission = mPermissions.valueAt(i);
    256             if (permission.isGrantedByDefault()) {
    257                 return true;
    258             }
    259         }
    260         return false;
    261     }
    262 
    263     public PackageInfo getApp() {
    264         return mPackageInfo;
    265     }
    266 
    267     public String getName() {
    268         return mName;
    269     }
    270 
    271     public String getDeclaringPackage() {
    272         return mDeclaringPackage;
    273     }
    274 
    275     public String getIconPkg() {
    276         return mIconPkg;
    277     }
    278 
    279     public int getIconResId() {
    280         return mIconResId;
    281     }
    282 
    283     public CharSequence getLabel() {
    284         return mLabel;
    285     }
    286 
    287     public CharSequence getDescription() {
    288         return mDescription;
    289     }
    290 
    291     public int getUserId() {
    292         return mUserHandle.getIdentifier();
    293     }
    294 
    295     public boolean hasPermission(String permission) {
    296         return mPermissions.get(permission) != null;
    297     }
    298 
    299     public boolean areRuntimePermissionsGranted() {
    300         return areRuntimePermissionsGranted(null);
    301     }
    302 
    303     public boolean areRuntimePermissionsGranted(String[] filterPermissions) {
    304         if (LocationUtils.isLocationGroupAndProvider(mName, mPackageInfo.packageName)) {
    305             return LocationUtils.isLocationEnabled(mContext);
    306         }
    307         final int permissionCount = mPermissions.size();
    308         for (int i = 0; i < permissionCount; i++) {
    309             Permission permission = mPermissions.valueAt(i);
    310             if (filterPermissions != null
    311                     && !ArrayUtils.contains(filterPermissions, permission.getName())) {
    312                 continue;
    313             }
    314             if (mAppSupportsRuntimePermissions) {
    315                 if (permission.isGranted()) {
    316                     return true;
    317                 }
    318             } else if (permission.isGranted() && (permission.getAppOp() == null
    319                     || permission.isAppOpAllowed())) {
    320                 return true;
    321             }
    322         }
    323         return false;
    324     }
    325 
    326     public boolean grantRuntimePermissions(boolean fixedByTheUser) {
    327         return grantRuntimePermissions(fixedByTheUser, null);
    328     }
    329 
    330     public boolean grantRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) {
    331         final int uid = mPackageInfo.applicationInfo.uid;
    332 
    333         // We toggle permissions only to apps that support runtime
    334         // permissions, otherwise we toggle the app op corresponding
    335         // to the permission if the permission is granted to the app.
    336         for (Permission permission : mPermissions.values()) {
    337             if (filterPermissions != null
    338                     && !ArrayUtils.contains(filterPermissions, permission.getName())) {
    339                 continue;
    340             }
    341 
    342             if (!permission.isGrantingAllowed(mIsEphemeralApp, mAppSupportsRuntimePermissions)) {
    343                 // Skip unallowed permissions.
    344                 continue;
    345             }
    346 
    347             if (mAppSupportsRuntimePermissions) {
    348                 // Do not touch permissions fixed by the system.
    349                 if (permission.isSystemFixed()) {
    350                     return false;
    351                 }
    352 
    353                 // Ensure the permission app op enabled before the permission grant.
    354                 if (permission.hasAppOp() && !permission.isAppOpAllowed()) {
    355                     permission.setAppOpAllowed(true);
    356                     mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_ALLOWED);
    357                 }
    358 
    359                 // Grant the permission if needed.
    360                 if (!permission.isGranted()) {
    361                     permission.setGranted(true);
    362                     mPackageManager.grantRuntimePermission(mPackageInfo.packageName,
    363                             permission.getName(), mUserHandle);
    364                 }
    365 
    366                 // Update the permission flags.
    367                 if (!fixedByTheUser) {
    368                     // Now the apps can ask for the permission as the user
    369                     // no longer has it fixed in a denied state.
    370                     if (permission.isUserFixed() || permission.isUserSet()) {
    371                         permission.setUserFixed(false);
    372                         permission.setUserSet(false);
    373                         mPackageManager.updatePermissionFlags(permission.getName(),
    374                                 mPackageInfo.packageName,
    375                                 PackageManager.FLAG_PERMISSION_USER_FIXED
    376                                         | PackageManager.FLAG_PERMISSION_USER_SET,
    377                                 0, mUserHandle);
    378                     }
    379                 }
    380             } else {
    381                 // Legacy apps cannot have a not granted permission but just in case.
    382                 if (!permission.isGranted()) {
    383                     continue;
    384                 }
    385 
    386                 int killUid = -1;
    387                 int mask = 0;
    388 
    389                 // If the permissions has no corresponding app op, then it is a
    390                 // third-party one and we do not offer toggling of such permissions.
    391                 if (permission.hasAppOp()) {
    392                     if (!permission.isAppOpAllowed()) {
    393                         permission.setAppOpAllowed(true);
    394                         // Enable the app op.
    395                         mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_ALLOWED);
    396 
    397                         // Legacy apps do not know that they have to retry access to a
    398                         // resource due to changes in runtime permissions (app ops in this
    399                         // case). Therefore, we restart them on app op change, so they
    400                         // can pick up the change.
    401                         killUid = uid;
    402                     }
    403 
    404                     // Mark that the permission should not be be granted on upgrade
    405                     // when the app begins supporting runtime permissions.
    406                     if (permission.shouldRevokeOnUpgrade()) {
    407                         permission.setRevokeOnUpgrade(false);
    408                         mask |= PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
    409                     }
    410                 }
    411 
    412                 if (mask != 0) {
    413                     mPackageManager.updatePermissionFlags(permission.getName(),
    414                             mPackageInfo.packageName, mask, 0, mUserHandle);
    415                 }
    416 
    417                 if (killUid != -1) {
    418                     mActivityManager.killUid(uid, KILL_REASON_APP_OP_CHANGE);
    419                 }
    420             }
    421         }
    422 
    423         return true;
    424     }
    425 
    426     public boolean revokeRuntimePermissions(boolean fixedByTheUser) {
    427         return revokeRuntimePermissions(fixedByTheUser, null);
    428     }
    429 
    430     public boolean revokeRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) {
    431         final int uid = mPackageInfo.applicationInfo.uid;
    432 
    433         // We toggle permissions only to apps that support runtime
    434         // permissions, otherwise we toggle the app op corresponding
    435         // to the permission if the permission is granted to the app.
    436         for (Permission permission : mPermissions.values()) {
    437             if (filterPermissions != null
    438                     && !ArrayUtils.contains(filterPermissions, permission.getName())) {
    439                 continue;
    440             }
    441 
    442             if (mAppSupportsRuntimePermissions) {
    443                 // Do not touch permissions fixed by the system.
    444                 if (permission.isSystemFixed()) {
    445                     return false;
    446                 }
    447 
    448                 // Revoke the permission if needed.
    449                 if (permission.isGranted()) {
    450                     permission.setGranted(false);
    451                     mPackageManager.revokeRuntimePermission(mPackageInfo.packageName,
    452                             permission.getName(), mUserHandle);
    453                 }
    454 
    455                 // Update the permission flags.
    456                 if (fixedByTheUser) {
    457                     // Take a note that the user fixed the permission.
    458                     if (permission.isUserSet() || !permission.isUserFixed()) {
    459                         permission.setUserSet(false);
    460                         permission.setUserFixed(true);
    461                         mPackageManager.updatePermissionFlags(permission.getName(),
    462                                 mPackageInfo.packageName,
    463                                 PackageManager.FLAG_PERMISSION_USER_SET
    464                                         | PackageManager.FLAG_PERMISSION_USER_FIXED,
    465                                 PackageManager.FLAG_PERMISSION_USER_FIXED,
    466                                 mUserHandle);
    467                     }
    468                 } else {
    469                     if (!permission.isUserSet() || permission.isUserFixed()) {
    470                         permission.setUserSet(true);
    471                         permission.setUserFixed(false);
    472                         // Take a note that the user already chose once.
    473                         mPackageManager.updatePermissionFlags(permission.getName(),
    474                                 mPackageInfo.packageName,
    475                                 PackageManager.FLAG_PERMISSION_USER_SET
    476                                         | PackageManager.FLAG_PERMISSION_USER_FIXED,
    477                                 PackageManager.FLAG_PERMISSION_USER_SET,
    478                                 mUserHandle);
    479                     }
    480                 }
    481             } else {
    482                 // Legacy apps cannot have a non-granted permission but just in case.
    483                 if (!permission.isGranted()) {
    484                     continue;
    485                 }
    486 
    487                 int mask = 0;
    488                 int flags = 0;
    489                 int killUid = -1;
    490 
    491                 // If the permission has no corresponding app op, then it is a
    492                 // third-party one and we do not offer toggling of such permissions.
    493                 if (permission.hasAppOp()) {
    494                     if (permission.isAppOpAllowed()) {
    495                         permission.setAppOpAllowed(false);
    496                         // Disable the app op.
    497                         mAppOps.setUidMode(permission.getAppOp(), uid, AppOpsManager.MODE_IGNORED);
    498 
    499                         // Disabling an app op may put the app in a situation in which it
    500                         // has a handle to state it shouldn't have, so we have to kill the
    501                         // app. This matches the revoke runtime permission behavior.
    502                         killUid = uid;
    503                     }
    504 
    505                     // Mark that the permission should not be granted on upgrade
    506                     // when the app begins supporting runtime permissions.
    507                     if (!permission.shouldRevokeOnUpgrade()) {
    508                         permission.setRevokeOnUpgrade(true);
    509                         mask |= PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
    510                         flags |= PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
    511                     }
    512                 }
    513 
    514                 if (mask != 0) {
    515                     mPackageManager.updatePermissionFlags(permission.getName(),
    516                             mPackageInfo.packageName, mask, flags, mUserHandle);
    517                 }
    518 
    519                 if (killUid != -1) {
    520                     mActivityManager.killUid(uid, KILL_REASON_APP_OP_CHANGE);
    521                 }
    522             }
    523         }
    524 
    525         return true;
    526     }
    527 
    528     public void setPolicyFixed() {
    529         final int permissionCount = mPermissions.size();
    530         for (int i = 0; i < permissionCount; i++) {
    531             Permission permission = mPermissions.valueAt(i);
    532             permission.setPolicyFixed(true);
    533             mPackageManager.updatePermissionFlags(permission.getName(),
    534                     mPackageInfo.packageName,
    535                     PackageManager.FLAG_PERMISSION_POLICY_FIXED,
    536                     PackageManager.FLAG_PERMISSION_POLICY_FIXED,
    537                     mUserHandle);
    538         }
    539     }
    540 
    541     public List<Permission> getPermissions() {
    542         return new ArrayList<>(mPermissions.values());
    543     }
    544 
    545     public int getFlags() {
    546         int flags = 0;
    547         final int permissionCount = mPermissions.size();
    548         for (int i = 0; i < permissionCount; i++) {
    549             Permission permission = mPermissions.valueAt(i);
    550             flags |= permission.getFlags();
    551         }
    552         return flags;
    553     }
    554 
    555     public boolean isUserFixed() {
    556         final int permissionCount = mPermissions.size();
    557         for (int i = 0; i < permissionCount; i++) {
    558             Permission permission = mPermissions.valueAt(i);
    559             if (permission.isUserFixed()) {
    560                 return true;
    561             }
    562         }
    563         return false;
    564     }
    565 
    566     public boolean isPolicyFixed() {
    567         final int permissionCount = mPermissions.size();
    568         for (int i = 0; i < permissionCount; i++) {
    569             Permission permission = mPermissions.valueAt(i);
    570             if (permission.isPolicyFixed()) {
    571                 return true;
    572             }
    573         }
    574         return false;
    575     }
    576 
    577     public boolean isUserSet() {
    578         final int permissionCount = mPermissions.size();
    579         for (int i = 0; i < permissionCount; i++) {
    580             Permission permission = mPermissions.valueAt(i);
    581             if (permission.isUserSet()) {
    582                 return true;
    583             }
    584         }
    585         return false;
    586     }
    587 
    588     public boolean isSystemFixed() {
    589         final int permissionCount = mPermissions.size();
    590         for (int i = 0; i < permissionCount; i++) {
    591             Permission permission = mPermissions.valueAt(i);
    592             if (permission.isSystemFixed()) {
    593                 return true;
    594             }
    595         }
    596         return false;
    597     }
    598 
    599     @Override
    600     public int compareTo(AppPermissionGroup another) {
    601         final int result = mLabel.toString().compareTo(another.mLabel.toString());
    602         if (result == 0) {
    603             // Unbadged before badged.
    604             return mPackageInfo.applicationInfo.uid
    605                     - another.mPackageInfo.applicationInfo.uid;
    606         }
    607         return result;
    608     }
    609 
    610     @Override
    611     public boolean equals(Object obj) {
    612         if (this == obj) {
    613             return true;
    614         }
    615 
    616         if (obj == null) {
    617             return false;
    618         }
    619 
    620         if (getClass() != obj.getClass()) {
    621             return false;
    622         }
    623 
    624         AppPermissionGroup other = (AppPermissionGroup) obj;
    625 
    626         if (mName == null) {
    627             if (other.mName != null) {
    628                 return false;
    629             }
    630         } else if (!mName.equals(other.mName)) {
    631             return false;
    632         }
    633 
    634         return true;
    635     }
    636 
    637     @Override
    638     public int hashCode() {
    639         return mName != null ? mName.hashCode() : 0;
    640     }
    641 
    642     @Override
    643     public String toString() {
    644         StringBuilder builder = new StringBuilder();
    645         builder.append(getClass().getSimpleName());
    646         builder.append("{name=").append(mName);
    647         if (!mPermissions.isEmpty()) {
    648             builder.append(", <has permissions>}");
    649         } else {
    650             builder.append('}');
    651         }
    652         return builder.toString();
    653     }
    654 
    655     private void addPermission(Permission permission) {
    656         mPermissions.put(permission.getName(), permission);
    657         if (permission.isEphemeral()) {
    658             mContainsEphemeralPermission = true;
    659         }
    660         if (!permission.isRuntimeOnly()) {
    661             mContainsPreRuntimePermission = true;
    662         }
    663     }
    664 }
    665