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