Home | History | Annotate | Download | only in permission
      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.server.pm.permission;
     18 
     19 import android.content.pm.PackageManager;
     20 import android.os.UserHandle;
     21 import android.util.ArrayMap;
     22 import android.util.ArraySet;
     23 
     24 import android.util.SparseArray;
     25 import android.util.SparseBooleanArray;
     26 import com.android.internal.util.ArrayUtils;
     27 
     28 import java.util.ArrayList;
     29 import java.util.Arrays;
     30 import java.util.Collections;
     31 import java.util.List;
     32 import java.util.Set;
     33 
     34 /**
     35  * This class encapsulates the permissions for a package or a shared user.
     36  * <p>
     37  * There are two types of permissions: install (granted at installation)
     38  * and runtime (granted at runtime). Install permissions are granted to
     39  * all device users while runtime permissions are granted explicitly to
     40  * specific users.
     41  * </p>
     42  * <p>
     43  * The permissions are kept on a per device user basis. For example, an
     44  * application may have some runtime permissions granted under the device
     45  * owner but not granted under the secondary user.
     46  * <p>
     47  * This class is also responsible for keeping track of the Linux gids per
     48  * user for a package or a shared user. The gids are computed as a set of
     49  * the gids for all granted permissions' gids on a per user basis.
     50  * </p>
     51  */
     52 public final class PermissionsState {
     53 
     54     /** The permission operation failed. */
     55     public static final int PERMISSION_OPERATION_FAILURE = -1;
     56 
     57     /** The permission operation succeeded and no gids changed. */
     58     public static final int PERMISSION_OPERATION_SUCCESS = 0;
     59 
     60     /** The permission operation succeeded and gids changed. */
     61     public static final int PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED = 1;
     62 
     63     private static final int[] NO_GIDS = {};
     64 
     65     private ArrayMap<String, PermissionData> mPermissions;
     66 
     67     private int[] mGlobalGids = NO_GIDS;
     68 
     69     private SparseBooleanArray mPermissionReviewRequired;
     70 
     71     public PermissionsState() {
     72         /* do nothing */
     73     }
     74 
     75     public PermissionsState(PermissionsState prototype) {
     76         copyFrom(prototype);
     77     }
     78 
     79     /**
     80      * Sets the global gids, applicable to all users.
     81      *
     82      * @param globalGids The global gids.
     83      */
     84     public void setGlobalGids(int[] globalGids) {
     85         if (!ArrayUtils.isEmpty(globalGids)) {
     86             mGlobalGids = Arrays.copyOf(globalGids, globalGids.length);
     87         }
     88     }
     89 
     90     /**
     91      * Initialized this instance from another one.
     92      *
     93      * @param other The other instance.
     94      */
     95     public void copyFrom(PermissionsState other) {
     96         if (other == this) {
     97             return;
     98         }
     99         if (mPermissions != null) {
    100             if (other.mPermissions == null) {
    101                 mPermissions = null;
    102             } else {
    103                 mPermissions.clear();
    104             }
    105         }
    106         if (other.mPermissions != null) {
    107             if (mPermissions == null) {
    108                 mPermissions = new ArrayMap<>();
    109             }
    110             final int permissionCount = other.mPermissions.size();
    111             for (int i = 0; i < permissionCount; i++) {
    112                 String name = other.mPermissions.keyAt(i);
    113                 PermissionData permissionData = other.mPermissions.valueAt(i);
    114                 mPermissions.put(name, new PermissionData(permissionData));
    115             }
    116         }
    117 
    118         mGlobalGids = NO_GIDS;
    119         if (other.mGlobalGids != NO_GIDS) {
    120             mGlobalGids = Arrays.copyOf(other.mGlobalGids,
    121                     other.mGlobalGids.length);
    122         }
    123 
    124         if (mPermissionReviewRequired != null) {
    125             if (other.mPermissionReviewRequired == null) {
    126                 mPermissionReviewRequired = null;
    127             } else {
    128                 mPermissionReviewRequired.clear();
    129             }
    130         }
    131         if (other.mPermissionReviewRequired != null) {
    132             if (mPermissionReviewRequired == null) {
    133                 mPermissionReviewRequired = new SparseBooleanArray();
    134             }
    135             final int userCount = other.mPermissionReviewRequired.size();
    136             for (int i = 0; i < userCount; i++) {
    137                 final boolean reviewRequired = other.mPermissionReviewRequired.valueAt(i);
    138                 mPermissionReviewRequired.put(i, reviewRequired);
    139             }
    140         }
    141     }
    142 
    143     @Override
    144     public boolean equals(Object obj) {
    145         if (this == obj) {
    146             return true;
    147         }
    148         if (obj == null) {
    149             return false;
    150         }
    151         if (getClass() != obj.getClass()) {
    152             return false;
    153         }
    154         final PermissionsState other = (PermissionsState) obj;
    155 
    156         if (mPermissions == null) {
    157             if (other.mPermissions != null) {
    158                 return false;
    159             }
    160         } else if (!mPermissions.equals(other.mPermissions)) {
    161             return false;
    162         }
    163         if (mPermissionReviewRequired == null) {
    164             if (other.mPermissionReviewRequired != null) {
    165                 return false;
    166             }
    167         } else if (!mPermissionReviewRequired.equals(other.mPermissionReviewRequired)) {
    168             return false;
    169         }
    170         return Arrays.equals(mGlobalGids, other.mGlobalGids);
    171     }
    172 
    173     public boolean isPermissionReviewRequired(int userId) {
    174         return mPermissionReviewRequired != null && mPermissionReviewRequired.get(userId);
    175     }
    176 
    177     /**
    178      * Grant an install permission.
    179      *
    180      * @param permission The permission to grant.
    181      * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
    182      *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
    183      *     #PERMISSION_OPERATION_FAILURE}.
    184      */
    185     public int grantInstallPermission(BasePermission permission) {
    186         return grantPermission(permission, UserHandle.USER_ALL);
    187     }
    188 
    189     /**
    190      * Revoke an install permission.
    191      *
    192      * @param permission The permission to revoke.
    193      * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
    194      *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
    195      *     #PERMISSION_OPERATION_FAILURE}.
    196      */
    197     public int revokeInstallPermission(BasePermission permission) {
    198         return revokePermission(permission, UserHandle.USER_ALL);
    199     }
    200 
    201     /**
    202      * Grant a runtime permission for a given device user.
    203      *
    204      * @param permission The permission to grant.
    205      * @param userId The device user id.
    206      * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
    207      *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
    208      *     #PERMISSION_OPERATION_FAILURE}.
    209      */
    210     public int grantRuntimePermission(BasePermission permission, int userId) {
    211         enforceValidUserId(userId);
    212         if (userId == UserHandle.USER_ALL) {
    213             return PERMISSION_OPERATION_FAILURE;
    214         }
    215         return grantPermission(permission, userId);
    216     }
    217 
    218     /**
    219      *  Revoke a runtime permission for a given device user.
    220      *
    221      * @param permission The permission to revoke.
    222      * @param userId The device user id.
    223      * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
    224      *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
    225      *     #PERMISSION_OPERATION_FAILURE}.
    226      */
    227     public int revokeRuntimePermission(BasePermission permission, int userId) {
    228         enforceValidUserId(userId);
    229         if (userId == UserHandle.USER_ALL) {
    230             return PERMISSION_OPERATION_FAILURE;
    231         }
    232         return revokePermission(permission, userId);
    233     }
    234 
    235     /**
    236      * Gets whether this state has a given runtime permission for a
    237      * given device user id.
    238      *
    239      * @param name The permission name.
    240      * @param userId The device user id.
    241      * @return Whether this state has the permission.
    242      */
    243     public boolean hasRuntimePermission(String name, int userId) {
    244         enforceValidUserId(userId);
    245         return !hasInstallPermission(name) && hasPermission(name, userId);
    246     }
    247 
    248     /**
    249      * Gets whether this state has a given install permission.
    250      *
    251      * @param name The permission name.
    252      * @return Whether this state has the permission.
    253      */
    254     public boolean hasInstallPermission(String name) {
    255         return hasPermission(name, UserHandle.USER_ALL);
    256     }
    257 
    258     /**
    259      * Gets whether the state has a given permission for the specified
    260      * user, regardless if this is an install or a runtime permission.
    261      *
    262      * @param name The permission name.
    263      * @param userId The device user id.
    264      * @return Whether the user has the permission.
    265      */
    266     public boolean hasPermission(String name, int userId) {
    267         enforceValidUserId(userId);
    268 
    269         if (mPermissions == null) {
    270             return false;
    271         }
    272 
    273         PermissionData permissionData = mPermissions.get(name);
    274         return permissionData != null && permissionData.isGranted(userId);
    275     }
    276 
    277     /**
    278      * Returns whether the state has any known request for the given permission name,
    279      * whether or not it has been granted.
    280      */
    281     public boolean hasRequestedPermission(ArraySet<String> names) {
    282         if (mPermissions == null) {
    283             return false;
    284         }
    285         for (int i=names.size()-1; i>=0; i--) {
    286             if (mPermissions.get(names.valueAt(i)) != null) {
    287                 return true;
    288             }
    289         }
    290         return false;
    291     }
    292 
    293     /**
    294      * Gets all permissions for a given device user id regardless if they
    295      * are install time or runtime permissions.
    296      *
    297      * @param userId The device user id.
    298      * @return The permissions or an empty set.
    299      */
    300     public Set<String> getPermissions(int userId) {
    301         enforceValidUserId(userId);
    302 
    303         if (mPermissions == null) {
    304             return Collections.emptySet();
    305         }
    306 
    307         Set<String> permissions = new ArraySet<>(mPermissions.size());
    308 
    309         final int permissionCount = mPermissions.size();
    310         for (int i = 0; i < permissionCount; i++) {
    311             String permission = mPermissions.keyAt(i);
    312 
    313             if (hasInstallPermission(permission)) {
    314                 permissions.add(permission);
    315                 continue;
    316             }
    317 
    318             if (userId != UserHandle.USER_ALL) {
    319                 if (hasRuntimePermission(permission, userId)) {
    320                     permissions.add(permission);
    321                 }
    322             }
    323         }
    324 
    325         return permissions;
    326     }
    327 
    328     /**
    329      * Gets the state for an install permission or null if no such.
    330      *
    331      * @param name The permission name.
    332      * @return The permission state.
    333      */
    334     public PermissionState getInstallPermissionState(String name) {
    335         return getPermissionState(name, UserHandle.USER_ALL);
    336     }
    337 
    338     /**
    339      * Gets the state for a runtime permission or null if no such.
    340      *
    341      * @param name The permission name.
    342      * @param userId The device user id.
    343      * @return The permission state.
    344      */
    345     public PermissionState getRuntimePermissionState(String name, int userId) {
    346         enforceValidUserId(userId);
    347         return getPermissionState(name, userId);
    348     }
    349 
    350     /**
    351      * Gets all install permission states.
    352      *
    353      * @return The permission states or an empty set.
    354      */
    355     public List<PermissionState> getInstallPermissionStates() {
    356         return getPermissionStatesInternal(UserHandle.USER_ALL);
    357     }
    358 
    359     /**
    360      * Gets all runtime permission states.
    361      *
    362      * @return The permission states or an empty set.
    363      */
    364     public List<PermissionState> getRuntimePermissionStates(int userId) {
    365         enforceValidUserId(userId);
    366         return getPermissionStatesInternal(userId);
    367     }
    368 
    369     /**
    370      * Gets the flags for a permission regardless if it is install or
    371      * runtime permission.
    372      *
    373      * @param name The permission name.
    374      * @return The permission state or null if no such.
    375      */
    376     public int getPermissionFlags(String name, int userId) {
    377         PermissionState installPermState = getInstallPermissionState(name);
    378         if (installPermState != null) {
    379             return installPermState.getFlags();
    380         }
    381         PermissionState runtimePermState = getRuntimePermissionState(name, userId);
    382         if (runtimePermState != null) {
    383             return runtimePermState.getFlags();
    384         }
    385         return 0;
    386     }
    387 
    388     /**
    389      * Update the flags associated with a given permission.
    390      * @param permission The permission whose flags to update.
    391      * @param userId The user for which to update.
    392      * @param flagMask Mask for which flags to change.
    393      * @param flagValues New values for the mask flags.
    394      * @return Whether the permission flags changed.
    395      */
    396     public boolean updatePermissionFlags(BasePermission permission, int userId,
    397             int flagMask, int flagValues) {
    398         enforceValidUserId(userId);
    399 
    400         final boolean mayChangeFlags = flagValues != 0 || flagMask != 0;
    401 
    402         if (mPermissions == null) {
    403             if (!mayChangeFlags) {
    404                 return false;
    405             }
    406             ensurePermissionData(permission);
    407         }
    408 
    409         PermissionData permissionData = mPermissions.get(permission.getName());
    410         if (permissionData == null) {
    411             if (!mayChangeFlags) {
    412                 return false;
    413             }
    414             permissionData = ensurePermissionData(permission);
    415         }
    416 
    417         final int oldFlags = permissionData.getFlags(userId);
    418 
    419         final boolean updated = permissionData.updateFlags(userId, flagMask, flagValues);
    420         if (updated) {
    421             final int newFlags = permissionData.getFlags(userId);
    422             if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0
    423                     && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
    424                 if (mPermissionReviewRequired == null) {
    425                     mPermissionReviewRequired = new SparseBooleanArray();
    426                 }
    427                 mPermissionReviewRequired.put(userId, true);
    428             } else if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0
    429                     && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
    430                 if (mPermissionReviewRequired != null && !hasPermissionRequiringReview(userId)) {
    431                     mPermissionReviewRequired.delete(userId);
    432                     if (mPermissionReviewRequired.size() <= 0) {
    433                         mPermissionReviewRequired = null;
    434                     }
    435                 }
    436             }
    437         }
    438         return updated;
    439     }
    440 
    441     private boolean hasPermissionRequiringReview(int userId) {
    442         final int permissionCount = mPermissions.size();
    443         for (int i = 0; i < permissionCount; i++) {
    444             final PermissionData permission = mPermissions.valueAt(i);
    445             if ((permission.getFlags(userId)
    446                     & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
    447                 return true;
    448             }
    449         }
    450         return false;
    451     }
    452 
    453     public boolean updatePermissionFlagsForAllPermissions(
    454             int userId, int flagMask, int flagValues) {
    455         enforceValidUserId(userId);
    456 
    457         if (mPermissions == null) {
    458             return false;
    459         }
    460         boolean changed = false;
    461         final int permissionCount = mPermissions.size();
    462         for (int i = 0; i < permissionCount; i++) {
    463             PermissionData permissionData = mPermissions.valueAt(i);
    464             changed |= permissionData.updateFlags(userId, flagMask, flagValues);
    465         }
    466         return changed;
    467     }
    468 
    469     /**
    470      * Compute the Linux gids for a given device user from the permissions
    471      * granted to this user. Note that these are computed to avoid additional
    472      * state as they are rarely accessed.
    473      *
    474      * @param userId The device user id.
    475      * @return The gids for the device user.
    476      */
    477     public int[] computeGids(int userId) {
    478         enforceValidUserId(userId);
    479 
    480         int[] gids = mGlobalGids;
    481 
    482         if (mPermissions != null) {
    483             final int permissionCount = mPermissions.size();
    484             for (int i = 0; i < permissionCount; i++) {
    485                 String permission = mPermissions.keyAt(i);
    486                 if (!hasPermission(permission, userId)) {
    487                     continue;
    488                 }
    489                 PermissionData permissionData = mPermissions.valueAt(i);
    490                 final int[] permGids = permissionData.computeGids(userId);
    491                 if (permGids != NO_GIDS) {
    492                     gids = appendInts(gids, permGids);
    493                 }
    494             }
    495         }
    496 
    497         return gids;
    498     }
    499 
    500     /**
    501      * Compute the Linux gids for all device users from the permissions
    502      * granted to these users.
    503      *
    504      * @return The gids for all device users.
    505      */
    506     public int[] computeGids(int[] userIds) {
    507         int[] gids = mGlobalGids;
    508 
    509         for (int userId : userIds) {
    510             final int[] userGids = computeGids(userId);
    511             gids = appendInts(gids, userGids);
    512         }
    513 
    514         return gids;
    515     }
    516 
    517     /**
    518      * Resets the internal state of this object.
    519      */
    520     public void reset() {
    521         mGlobalGids = NO_GIDS;
    522         mPermissions = null;
    523         mPermissionReviewRequired = null;
    524     }
    525 
    526     private PermissionState getPermissionState(String name, int userId) {
    527         if (mPermissions == null) {
    528             return null;
    529         }
    530         PermissionData permissionData = mPermissions.get(name);
    531         if (permissionData == null) {
    532             return null;
    533         }
    534         return permissionData.getPermissionState(userId);
    535     }
    536 
    537     private List<PermissionState> getPermissionStatesInternal(int userId) {
    538         enforceValidUserId(userId);
    539 
    540         if (mPermissions == null) {
    541             return Collections.emptyList();
    542         }
    543 
    544         List<PermissionState> permissionStates = new ArrayList<>();
    545 
    546         final int permissionCount = mPermissions.size();
    547         for (int i = 0; i < permissionCount; i++) {
    548             PermissionData permissionData = mPermissions.valueAt(i);
    549 
    550             PermissionState permissionState = permissionData.getPermissionState(userId);
    551             if (permissionState != null) {
    552                 permissionStates.add(permissionState);
    553             }
    554         }
    555 
    556         return permissionStates;
    557     }
    558 
    559     private int grantPermission(BasePermission permission, int userId) {
    560         if (hasPermission(permission.getName(), userId)) {
    561             return PERMISSION_OPERATION_FAILURE;
    562         }
    563 
    564         final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
    565         final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
    566 
    567         PermissionData permissionData = ensurePermissionData(permission);
    568 
    569         if (!permissionData.grant(userId)) {
    570             return PERMISSION_OPERATION_FAILURE;
    571         }
    572 
    573         if (hasGids) {
    574             final int[] newGids = computeGids(userId);
    575             if (oldGids.length != newGids.length) {
    576                 return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
    577             }
    578         }
    579 
    580         return PERMISSION_OPERATION_SUCCESS;
    581     }
    582 
    583     private int revokePermission(BasePermission permission, int userId) {
    584         final String permName = permission.getName();
    585         if (!hasPermission(permName, userId)) {
    586             return PERMISSION_OPERATION_FAILURE;
    587         }
    588 
    589         final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
    590         final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
    591 
    592         PermissionData permissionData = mPermissions.get(permName);
    593 
    594         if (!permissionData.revoke(userId)) {
    595             return PERMISSION_OPERATION_FAILURE;
    596         }
    597 
    598         if (permissionData.isDefault()) {
    599             ensureNoPermissionData(permName);
    600         }
    601 
    602         if (hasGids) {
    603             final int[] newGids = computeGids(userId);
    604             if (oldGids.length != newGids.length) {
    605                 return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
    606             }
    607         }
    608 
    609         return PERMISSION_OPERATION_SUCCESS;
    610     }
    611 
    612     // TODO: fix this to use arraycopy and append all ints in one go
    613     private static int[] appendInts(int[] current, int[] added) {
    614         if (current != null && added != null) {
    615             for (int guid : added) {
    616                 current = ArrayUtils.appendInt(current, guid);
    617             }
    618         }
    619         return current;
    620     }
    621 
    622     private static void enforceValidUserId(int userId) {
    623         if (userId != UserHandle.USER_ALL && userId < 0) {
    624             throw new IllegalArgumentException("Invalid userId:" + userId);
    625         }
    626     }
    627 
    628     private PermissionData ensurePermissionData(BasePermission permission) {
    629         final String permName = permission.getName();
    630         if (mPermissions == null) {
    631             mPermissions = new ArrayMap<>();
    632         }
    633         PermissionData permissionData = mPermissions.get(permName);
    634         if (permissionData == null) {
    635             permissionData = new PermissionData(permission);
    636             mPermissions.put(permName, permissionData);
    637         }
    638         return permissionData;
    639     }
    640 
    641     private void ensureNoPermissionData(String name) {
    642         if (mPermissions == null) {
    643             return;
    644         }
    645         mPermissions.remove(name);
    646         if (mPermissions.isEmpty()) {
    647             mPermissions = null;
    648         }
    649     }
    650 
    651     private static final class PermissionData {
    652         private final BasePermission mPerm;
    653         private SparseArray<PermissionState> mUserStates = new SparseArray<>();
    654 
    655         public PermissionData(BasePermission perm) {
    656             mPerm = perm;
    657         }
    658 
    659         public PermissionData(PermissionData other) {
    660             this(other.mPerm);
    661             final int otherStateCount = other.mUserStates.size();
    662             for (int i = 0; i < otherStateCount; i++) {
    663                 final int otherUserId = other.mUserStates.keyAt(i);
    664                 PermissionState otherState = other.mUserStates.valueAt(i);
    665                 mUserStates.put(otherUserId, new PermissionState(otherState));
    666             }
    667         }
    668 
    669         public int[] computeGids(int userId) {
    670             return mPerm.computeGids(userId);
    671         }
    672 
    673         public boolean isGranted(int userId) {
    674             if (isInstallPermission()) {
    675                 userId = UserHandle.USER_ALL;
    676             }
    677 
    678             PermissionState userState = mUserStates.get(userId);
    679             if (userState == null) {
    680                 return false;
    681             }
    682 
    683             return userState.mGranted;
    684         }
    685 
    686         public boolean grant(int userId) {
    687             if (!isCompatibleUserId(userId)) {
    688                 return false;
    689             }
    690 
    691             if (isGranted(userId)) {
    692                 return false;
    693             }
    694 
    695             PermissionState userState = mUserStates.get(userId);
    696             if (userState == null) {
    697                 userState = new PermissionState(mPerm.getName());
    698                 mUserStates.put(userId, userState);
    699             }
    700 
    701             userState.mGranted = true;
    702 
    703             return true;
    704         }
    705 
    706         public boolean revoke(int userId) {
    707             if (!isCompatibleUserId(userId)) {
    708                 return false;
    709             }
    710 
    711             if (!isGranted(userId)) {
    712                 return false;
    713             }
    714 
    715             PermissionState userState = mUserStates.get(userId);
    716             userState.mGranted = false;
    717 
    718             if (userState.isDefault()) {
    719                 mUserStates.remove(userId);
    720             }
    721 
    722             return true;
    723         }
    724 
    725         public PermissionState getPermissionState(int userId) {
    726             return mUserStates.get(userId);
    727         }
    728 
    729         public int getFlags(int userId) {
    730             PermissionState userState = mUserStates.get(userId);
    731             if (userState != null) {
    732                 return userState.mFlags;
    733             }
    734             return 0;
    735         }
    736 
    737         public boolean isDefault() {
    738             return mUserStates.size() <= 0;
    739         }
    740 
    741         public static boolean isInstallPermissionKey(int userId) {
    742             return userId == UserHandle.USER_ALL;
    743         }
    744 
    745         public boolean updateFlags(int userId, int flagMask, int flagValues) {
    746             if (isInstallPermission()) {
    747                 userId = UserHandle.USER_ALL;
    748             }
    749 
    750             if (!isCompatibleUserId(userId)) {
    751                 return false;
    752             }
    753 
    754             final int newFlags = flagValues & flagMask;
    755 
    756             PermissionState userState = mUserStates.get(userId);
    757             if (userState != null) {
    758                 final int oldFlags = userState.mFlags;
    759                 userState.mFlags = (userState.mFlags & ~flagMask) | newFlags;
    760                 if (userState.isDefault()) {
    761                     mUserStates.remove(userId);
    762                 }
    763                 return userState.mFlags != oldFlags;
    764             } else if (newFlags != 0) {
    765                 userState = new PermissionState(mPerm.getName());
    766                 userState.mFlags = newFlags;
    767                 mUserStates.put(userId, userState);
    768                 return true;
    769             }
    770 
    771             return false;
    772         }
    773 
    774         private boolean isCompatibleUserId(int userId) {
    775             return isDefault() || !(isInstallPermission() ^ isInstallPermissionKey(userId));
    776         }
    777 
    778         private boolean isInstallPermission() {
    779             return mUserStates.size() == 1
    780                     && mUserStates.get(UserHandle.USER_ALL) != null;
    781         }
    782     }
    783 
    784     public static final class PermissionState {
    785         private final String mName;
    786         private boolean mGranted;
    787         private int mFlags;
    788 
    789         public PermissionState(String name) {
    790             mName = name;
    791         }
    792 
    793         public PermissionState(PermissionState other) {
    794             mName = other.mName;
    795             mGranted = other.mGranted;
    796             mFlags = other.mFlags;
    797         }
    798 
    799         public boolean isDefault() {
    800             return !mGranted && mFlags == 0;
    801         }
    802 
    803         public String getName() {
    804             return mName;
    805         }
    806 
    807         public boolean isGranted() {
    808             return mGranted;
    809         }
    810 
    811         public int getFlags() {
    812             return mFlags;
    813         }
    814     }
    815 }
    816