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;
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 
PermissionsState()71     public PermissionsState() {
72         /* do nothing */
73     }
74 
PermissionsState(PermissionsState prototype)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      */
setGlobalGids(int[] globalGids)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      */
copyFrom(PermissionsState other)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 
isPermissionReviewRequired(int userId)143     public boolean isPermissionReviewRequired(int userId) {
144         return mPermissionReviewRequired != null && mPermissionReviewRequired.get(userId);
145     }
146 
147     /**
148      * Grant an install permission.
149      *
150      * @param permission The permission to grant.
151      * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
152      *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
153      *     #PERMISSION_OPERATION_FAILURE}.
154      */
grantInstallPermission(BasePermission permission)155     public int grantInstallPermission(BasePermission permission) {
156         return grantPermission(permission, UserHandle.USER_ALL);
157     }
158 
159     /**
160      * Revoke an install permission.
161      *
162      * @param permission The permission to revoke.
163      * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
164      *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
165      *     #PERMISSION_OPERATION_FAILURE}.
166      */
revokeInstallPermission(BasePermission permission)167     public int revokeInstallPermission(BasePermission permission) {
168         return revokePermission(permission, UserHandle.USER_ALL);
169     }
170 
171     /**
172      * Grant a runtime permission for a given device user.
173      *
174      * @param permission The permission to grant.
175      * @param userId The device user id.
176      * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
177      *     or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
178      *     #PERMISSION_OPERATION_FAILURE}.
179      */
grantRuntimePermission(BasePermission permission, int userId)180     public int grantRuntimePermission(BasePermission permission, int userId) {
181         enforceValidUserId(userId);
182         if (userId == UserHandle.USER_ALL) {
183             return PERMISSION_OPERATION_FAILURE;
184         }
185         return grantPermission(permission, userId);
186     }
187 
188     /**
189      *  Revoke a runtime permission for a given device user.
190      *
191      * @param permission The permission to revoke.
192      * @param userId The device user id.
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      */
revokeRuntimePermission(BasePermission permission, int userId)197     public int revokeRuntimePermission(BasePermission permission, int userId) {
198         enforceValidUserId(userId);
199         if (userId == UserHandle.USER_ALL) {
200             return PERMISSION_OPERATION_FAILURE;
201         }
202         return revokePermission(permission, userId);
203     }
204 
205     /**
206      * Gets whether this state has a given runtime permission for a
207      * given device user id.
208      *
209      * @param name The permission name.
210      * @param userId The device user id.
211      * @return Whether this state has the permission.
212      */
hasRuntimePermission(String name, int userId)213     public boolean hasRuntimePermission(String name, int userId) {
214         enforceValidUserId(userId);
215         return !hasInstallPermission(name) && hasPermission(name, userId);
216     }
217 
218     /**
219      * Gets whether this state has a given install permission.
220      *
221      * @param name The permission name.
222      * @return Whether this state has the permission.
223      */
hasInstallPermission(String name)224     public boolean hasInstallPermission(String name) {
225         return hasPermission(name, UserHandle.USER_ALL);
226     }
227 
228     /**
229      * Gets whether the state has a given permission for the specified
230      * user, regardless if this is an install or a runtime permission.
231      *
232      * @param name The permission name.
233      * @param userId The device user id.
234      * @return Whether the user has the permission.
235      */
hasPermission(String name, int userId)236     public boolean hasPermission(String name, int userId) {
237         enforceValidUserId(userId);
238 
239         if (mPermissions == null) {
240             return false;
241         }
242 
243         PermissionData permissionData = mPermissions.get(name);
244         return permissionData != null && permissionData.isGranted(userId);
245     }
246 
247     /**
248      * Returns whether the state has any known request for the given permission name,
249      * whether or not it has been granted.
250      */
hasRequestedPermission(ArraySet<String> names)251     public boolean hasRequestedPermission(ArraySet<String> names) {
252         if (mPermissions == null) {
253             return false;
254         }
255         for (int i=names.size()-1; i>=0; i--) {
256             if (mPermissions.get(names.valueAt(i)) != null) {
257                 return true;
258             }
259         }
260         return false;
261     }
262 
263     /**
264      * Gets all permissions for a given device user id regardless if they
265      * are install time or runtime permissions.
266      *
267      * @param userId The device user id.
268      * @return The permissions or an empty set.
269      */
getPermissions(int userId)270     public Set<String> getPermissions(int userId) {
271         enforceValidUserId(userId);
272 
273         if (mPermissions == null) {
274             return Collections.emptySet();
275         }
276 
277         Set<String> permissions = new ArraySet<>();
278 
279         final int permissionCount = mPermissions.size();
280         for (int i = 0; i < permissionCount; i++) {
281             String permission = mPermissions.keyAt(i);
282 
283             if (hasInstallPermission(permission)) {
284                 permissions.add(permission);
285             }
286 
287             if (userId != UserHandle.USER_ALL) {
288                 if (hasRuntimePermission(permission, userId)) {
289                     permissions.add(permission);
290                 }
291             }
292         }
293 
294         return permissions;
295     }
296 
297     /**
298      * Gets the state for an install permission or null if no such.
299      *
300      * @param name The permission name.
301      * @return The permission state.
302      */
getInstallPermissionState(String name)303     public PermissionState getInstallPermissionState(String name) {
304         return getPermissionState(name, UserHandle.USER_ALL);
305     }
306 
307     /**
308      * Gets the state for a runtime permission or null if no such.
309      *
310      * @param name The permission name.
311      * @param userId The device user id.
312      * @return The permission state.
313      */
getRuntimePermissionState(String name, int userId)314     public PermissionState getRuntimePermissionState(String name, int userId) {
315         enforceValidUserId(userId);
316         return getPermissionState(name, userId);
317     }
318 
319     /**
320      * Gets all install permission states.
321      *
322      * @return The permission states or an empty set.
323      */
getInstallPermissionStates()324     public List<PermissionState> getInstallPermissionStates() {
325         return getPermissionStatesInternal(UserHandle.USER_ALL);
326     }
327 
328     /**
329      * Gets all runtime permission states.
330      *
331      * @return The permission states or an empty set.
332      */
getRuntimePermissionStates(int userId)333     public List<PermissionState> getRuntimePermissionStates(int userId) {
334         enforceValidUserId(userId);
335         return getPermissionStatesInternal(userId);
336     }
337 
338     /**
339      * Gets the flags for a permission regardless if it is install or
340      * runtime permission.
341      *
342      * @param name The permission name.
343      * @return The permission state or null if no such.
344      */
getPermissionFlags(String name, int userId)345     public int getPermissionFlags(String name, int userId) {
346         PermissionState installPermState = getInstallPermissionState(name);
347         if (installPermState != null) {
348             return installPermState.getFlags();
349         }
350         PermissionState runtimePermState = getRuntimePermissionState(name, userId);
351         if (runtimePermState != null) {
352             return runtimePermState.getFlags();
353         }
354         return 0;
355     }
356 
357     /**
358      * Update the flags associated with a given permission.
359      * @param permission The permission whose flags to update.
360      * @param userId The user for which to update.
361      * @param flagMask Mask for which flags to change.
362      * @param flagValues New values for the mask flags.
363      * @return Whether the permission flags changed.
364      */
updatePermissionFlags(BasePermission permission, int userId, int flagMask, int flagValues)365     public boolean updatePermissionFlags(BasePermission permission, int userId,
366             int flagMask, int flagValues) {
367         enforceValidUserId(userId);
368 
369         final boolean mayChangeFlags = flagValues != 0 || flagMask != 0;
370 
371         if (mPermissions == null) {
372             if (!mayChangeFlags) {
373                 return false;
374             }
375             ensurePermissionData(permission);
376         }
377 
378         PermissionData permissionData = mPermissions.get(permission.name);
379         if (permissionData == null) {
380             if (!mayChangeFlags) {
381                 return false;
382             }
383             permissionData = ensurePermissionData(permission);
384         }
385 
386         final int oldFlags = permissionData.getFlags(userId);
387 
388         final boolean updated = permissionData.updateFlags(userId, flagMask, flagValues);
389         if (updated) {
390             final int newFlags = permissionData.getFlags(userId);
391             if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0
392                     && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
393                 if (mPermissionReviewRequired == null) {
394                     mPermissionReviewRequired = new SparseBooleanArray();
395                 }
396                 mPermissionReviewRequired.put(userId, true);
397             } else if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0
398                     && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
399                 if (mPermissionReviewRequired != null) {
400                     mPermissionReviewRequired.delete(userId);
401                     if (mPermissionReviewRequired.size() <= 0) {
402                         mPermissionReviewRequired = null;
403                     }
404                 }
405             }
406         }
407         return updated;
408     }
409 
updatePermissionFlagsForAllPermissions( int userId, int flagMask, int flagValues)410     public boolean updatePermissionFlagsForAllPermissions(
411             int userId, int flagMask, int flagValues) {
412         enforceValidUserId(userId);
413 
414         if (mPermissions == null) {
415             return false;
416         }
417         boolean changed = false;
418         final int permissionCount = mPermissions.size();
419         for (int i = 0; i < permissionCount; i++) {
420             PermissionData permissionData = mPermissions.valueAt(i);
421             changed |= permissionData.updateFlags(userId, flagMask, flagValues);
422         }
423         return changed;
424     }
425 
426     /**
427      * Compute the Linux gids for a given device user from the permissions
428      * granted to this user. Note that these are computed to avoid additional
429      * state as they are rarely accessed.
430      *
431      * @param userId The device user id.
432      * @return The gids for the device user.
433      */
computeGids(int userId)434     public int[] computeGids(int userId) {
435         enforceValidUserId(userId);
436 
437         int[] gids = mGlobalGids;
438 
439         if (mPermissions != null) {
440             final int permissionCount = mPermissions.size();
441             for (int i = 0; i < permissionCount; i++) {
442                 String permission = mPermissions.keyAt(i);
443                 if (!hasPermission(permission, userId)) {
444                     continue;
445                 }
446                 PermissionData permissionData = mPermissions.valueAt(i);
447                 final int[] permGids = permissionData.computeGids(userId);
448                 if (permGids != NO_GIDS) {
449                     gids = appendInts(gids, permGids);
450                 }
451             }
452         }
453 
454         return gids;
455     }
456 
457     /**
458      * Compute the Linux gids for all device users from the permissions
459      * granted to these users.
460      *
461      * @return The gids for all device users.
462      */
computeGids(int[] userIds)463     public int[] computeGids(int[] userIds) {
464         int[] gids = mGlobalGids;
465 
466         for (int userId : userIds) {
467             final int[] userGids = computeGids(userId);
468             gids = appendInts(gids, userGids);
469         }
470 
471         return gids;
472     }
473 
474     /**
475      * Resets the internal state of this object.
476      */
reset()477     public void reset() {
478         mGlobalGids = NO_GIDS;
479         mPermissions = null;
480         mPermissionReviewRequired = null;
481     }
482 
getPermissionState(String name, int userId)483     private PermissionState getPermissionState(String name, int userId) {
484         if (mPermissions == null) {
485             return null;
486         }
487         PermissionData permissionData = mPermissions.get(name);
488         if (permissionData == null) {
489             return null;
490         }
491         return permissionData.getPermissionState(userId);
492     }
493 
getPermissionStatesInternal(int userId)494     private List<PermissionState> getPermissionStatesInternal(int userId) {
495         enforceValidUserId(userId);
496 
497         if (mPermissions == null) {
498             return Collections.emptyList();
499         }
500 
501         List<PermissionState> permissionStates = new ArrayList<>();
502 
503         final int permissionCount = mPermissions.size();
504         for (int i = 0; i < permissionCount; i++) {
505             PermissionData permissionData = mPermissions.valueAt(i);
506 
507             PermissionState permissionState = permissionData.getPermissionState(userId);
508             if (permissionState != null) {
509                 permissionStates.add(permissionState);
510             }
511         }
512 
513         return permissionStates;
514     }
515 
grantPermission(BasePermission permission, int userId)516     private int grantPermission(BasePermission permission, int userId) {
517         if (hasPermission(permission.name, userId)) {
518             return PERMISSION_OPERATION_FAILURE;
519         }
520 
521         final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
522         final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
523 
524         PermissionData permissionData = ensurePermissionData(permission);
525 
526         if (!permissionData.grant(userId)) {
527             return PERMISSION_OPERATION_FAILURE;
528         }
529 
530         if (hasGids) {
531             final int[] newGids = computeGids(userId);
532             if (oldGids.length != newGids.length) {
533                 return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
534             }
535         }
536 
537         return PERMISSION_OPERATION_SUCCESS;
538     }
539 
revokePermission(BasePermission permission, int userId)540     private int revokePermission(BasePermission permission, int userId) {
541         if (!hasPermission(permission.name, userId)) {
542             return PERMISSION_OPERATION_FAILURE;
543         }
544 
545         final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
546         final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
547 
548         PermissionData permissionData = mPermissions.get(permission.name);
549 
550         if (!permissionData.revoke(userId)) {
551             return PERMISSION_OPERATION_FAILURE;
552         }
553 
554         if (permissionData.isDefault()) {
555             ensureNoPermissionData(permission.name);
556         }
557 
558         if (hasGids) {
559             final int[] newGids = computeGids(userId);
560             if (oldGids.length != newGids.length) {
561                 return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
562             }
563         }
564 
565         return PERMISSION_OPERATION_SUCCESS;
566     }
567 
appendInts(int[] current, int[] added)568     private static int[] appendInts(int[] current, int[] added) {
569         if (current != null && added != null) {
570             for (int guid : added) {
571                 current = ArrayUtils.appendInt(current, guid);
572             }
573         }
574         return current;
575     }
576 
enforceValidUserId(int userId)577     private static void enforceValidUserId(int userId) {
578         if (userId != UserHandle.USER_ALL && userId < 0) {
579             throw new IllegalArgumentException("Invalid userId:" + userId);
580         }
581     }
582 
ensurePermissionData(BasePermission permission)583     private PermissionData ensurePermissionData(BasePermission permission) {
584         if (mPermissions == null) {
585             mPermissions = new ArrayMap<>();
586         }
587         PermissionData permissionData = mPermissions.get(permission.name);
588         if (permissionData == null) {
589             permissionData = new PermissionData(permission);
590             mPermissions.put(permission.name, permissionData);
591         }
592         return permissionData;
593     }
594 
ensureNoPermissionData(String name)595     private void ensureNoPermissionData(String name) {
596         if (mPermissions == null) {
597             return;
598         }
599         mPermissions.remove(name);
600         if (mPermissions.isEmpty()) {
601             mPermissions = null;
602         }
603     }
604 
605     private static final class PermissionData {
606         private final BasePermission mPerm;
607         private SparseArray<PermissionState> mUserStates = new SparseArray<>();
608 
PermissionData(BasePermission perm)609         public PermissionData(BasePermission perm) {
610             mPerm = perm;
611         }
612 
PermissionData(PermissionData other)613         public PermissionData(PermissionData other) {
614             this(other.mPerm);
615             final int otherStateCount = other.mUserStates.size();
616             for (int i = 0; i < otherStateCount; i++) {
617                 final int otherUserId = other.mUserStates.keyAt(i);
618                 PermissionState otherState = other.mUserStates.valueAt(i);
619                 mUserStates.put(otherUserId, new PermissionState(otherState));
620             }
621         }
622 
computeGids(int userId)623         public int[] computeGids(int userId) {
624             return mPerm.computeGids(userId);
625         }
626 
isGranted(int userId)627         public boolean isGranted(int userId) {
628             if (isInstallPermission()) {
629                 userId = UserHandle.USER_ALL;
630             }
631 
632             PermissionState userState = mUserStates.get(userId);
633             if (userState == null) {
634                 return false;
635             }
636 
637             return userState.mGranted;
638         }
639 
grant(int userId)640         public boolean grant(int userId) {
641             if (!isCompatibleUserId(userId)) {
642                 return false;
643             }
644 
645             if (isGranted(userId)) {
646                 return false;
647             }
648 
649             PermissionState userState = mUserStates.get(userId);
650             if (userState == null) {
651                 userState = new PermissionState(mPerm.name);
652                 mUserStates.put(userId, userState);
653             }
654 
655             userState.mGranted = true;
656 
657             return true;
658         }
659 
revoke(int userId)660         public boolean revoke(int userId) {
661             if (!isCompatibleUserId(userId)) {
662                 return false;
663             }
664 
665             if (!isGranted(userId)) {
666                 return false;
667             }
668 
669             PermissionState userState = mUserStates.get(userId);
670             userState.mGranted = false;
671 
672             if (userState.isDefault()) {
673                 mUserStates.remove(userId);
674             }
675 
676             return true;
677         }
678 
getPermissionState(int userId)679         public PermissionState getPermissionState(int userId) {
680             return mUserStates.get(userId);
681         }
682 
getFlags(int userId)683         public int getFlags(int userId) {
684             PermissionState userState = mUserStates.get(userId);
685             if (userState != null) {
686                 return userState.mFlags;
687             }
688             return 0;
689         }
690 
isDefault()691         public boolean isDefault() {
692             return mUserStates.size() <= 0;
693         }
694 
isInstallPermissionKey(int userId)695         public static boolean isInstallPermissionKey(int userId) {
696             return userId == UserHandle.USER_ALL;
697         }
698 
updateFlags(int userId, int flagMask, int flagValues)699         public boolean updateFlags(int userId, int flagMask, int flagValues) {
700             if (isInstallPermission()) {
701                 userId = UserHandle.USER_ALL;
702             }
703 
704             if (!isCompatibleUserId(userId)) {
705                 return false;
706             }
707 
708             final int newFlags = flagValues & flagMask;
709 
710             PermissionState userState = mUserStates.get(userId);
711             if (userState != null) {
712                 final int oldFlags = userState.mFlags;
713                 userState.mFlags = (userState.mFlags & ~flagMask) | newFlags;
714                 if (userState.isDefault()) {
715                     mUserStates.remove(userId);
716                 }
717                 return userState.mFlags != oldFlags;
718             } else if (newFlags != 0) {
719                 userState = new PermissionState(mPerm.name);
720                 userState.mFlags = newFlags;
721                 mUserStates.put(userId, userState);
722                 return true;
723             }
724 
725             return false;
726         }
727 
isCompatibleUserId(int userId)728         private boolean isCompatibleUserId(int userId) {
729             return isDefault() || !(isInstallPermission() ^ isInstallPermissionKey(userId));
730         }
731 
isInstallPermission()732         private boolean isInstallPermission() {
733             return mUserStates.size() == 1
734                     && mUserStates.get(UserHandle.USER_ALL) != null;
735         }
736     }
737 
738     public static final class PermissionState {
739         private final String mName;
740         private boolean mGranted;
741         private int mFlags;
742 
PermissionState(String name)743         public PermissionState(String name) {
744             mName = name;
745         }
746 
PermissionState(PermissionState other)747         public PermissionState(PermissionState other) {
748             mName = other.mName;
749             mGranted = other.mGranted;
750             mFlags = other.mFlags;
751         }
752 
isDefault()753         public boolean isDefault() {
754             return !mGranted && mFlags == 0;
755         }
756 
getName()757         public String getName() {
758             return mName;
759         }
760 
isGranted()761         public boolean isGranted() {
762             return mGranted;
763         }
764 
getFlags()765         public int getFlags() {
766             return mFlags;
767         }
768     }
769 }
770