OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / services / core / java / com / android / server / pm / PermissionsState.java
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
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     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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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<>(mPermissions.size());
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                 continue;
286             }
287
288             if (userId != UserHandle.USER_ALL) {
289                 if (hasRuntimePermission(permission, userId)) {
290                     permissions.add(permission);
291                 }
292             }
293         }
294
295         return permissions;
296     }
297
298     /**
299      * Gets the state for an install permission or null if no such.
300      *
301      * @param name The permission name.
302      * @return The permission state.
303      */
304     public PermissionState getInstallPermissionState(String name) {
305         return getPermissionState(name, UserHandle.USER_ALL);
306     }
307
308     /**
309      * Gets the state for a runtime permission or null if no such.
310      *
311      * @param name The permission name.
312      * @param userId The device user id.
313      * @return The permission state.
314      */
315     public PermissionState getRuntimePermissionState(String name, int userId) {
316         enforceValidUserId(userId);
317         return getPermissionState(name, userId);
318     }
319
320     /**
321      * Gets all install permission states.
322      *
323      * @return The permission states or an empty set.
324      */
325     public List<PermissionState> getInstallPermissionStates() {
326         return getPermissionStatesInternal(UserHandle.USER_ALL);
327     }
328
329     /**
330      * Gets all runtime permission states.
331      *
332      * @return The permission states or an empty set.
333      */
334     public List<PermissionState> getRuntimePermissionStates(int userId) {
335         enforceValidUserId(userId);
336         return getPermissionStatesInternal(userId);
337     }
338
339     /**
340      * Gets the flags for a permission regardless if it is install or
341      * runtime permission.
342      *
343      * @param name The permission name.
344      * @return The permission state or null if no such.
345      */
346     public int getPermissionFlags(String name, int userId) {
347         PermissionState installPermState = getInstallPermissionState(name);
348         if (installPermState != null) {
349             return installPermState.getFlags();
350         }
351         PermissionState runtimePermState = getRuntimePermissionState(name, userId);
352         if (runtimePermState != null) {
353             return runtimePermState.getFlags();
354         }
355         return 0;
356     }
357
358     /**
359      * Update the flags associated with a given permission.
360      * @param permission The permission whose flags to update.
361      * @param userId The user for which to update.
362      * @param flagMask Mask for which flags to change.
363      * @param flagValues New values for the mask flags.
364      * @return Whether the permission flags changed.
365      */
366     public boolean updatePermissionFlags(BasePermission permission, int userId,
367             int flagMask, int flagValues) {
368         enforceValidUserId(userId);
369
370         final boolean mayChangeFlags = flagValues != 0 || flagMask != 0;
371
372         if (mPermissions == null) {
373             if (!mayChangeFlags) {
374                 return false;
375             }
376             ensurePermissionData(permission);
377         }
378
379         PermissionData permissionData = mPermissions.get(permission.name);
380         if (permissionData == null) {
381             if (!mayChangeFlags) {
382                 return false;
383             }
384             permissionData = ensurePermissionData(permission);
385         }
386
387         final int oldFlags = permissionData.getFlags(userId);
388
389         final boolean updated = permissionData.updateFlags(userId, flagMask, flagValues);
390         if (updated) {
391             final int newFlags = permissionData.getFlags(userId);
392             if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0
393                     && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
394                 if (mPermissionReviewRequired == null) {
395                     mPermissionReviewRequired = new SparseBooleanArray();
396                 }
397                 mPermissionReviewRequired.put(userId, true);
398             } else if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0
399                     && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
400                 if (mPermissionReviewRequired != null) {
401                     mPermissionReviewRequired.delete(userId);
402                     if (mPermissionReviewRequired.size() <= 0) {
403                         mPermissionReviewRequired = null;
404                     }
405                 }
406             }
407         }
408         return updated;
409     }
410
411     public boolean updatePermissionFlagsForAllPermissions(
412             int userId, int flagMask, int flagValues) {
413         enforceValidUserId(userId);
414
415         if (mPermissions == null) {
416             return false;
417         }
418         boolean changed = false;
419         final int permissionCount = mPermissions.size();
420         for (int i = 0; i < permissionCount; i++) {
421             PermissionData permissionData = mPermissions.valueAt(i);
422             changed |= permissionData.updateFlags(userId, flagMask, flagValues);
423         }
424         return changed;
425     }
426
427     /**
428      * Compute the Linux gids for a given device user from the permissions
429      * granted to this user. Note that these are computed to avoid additional
430      * state as they are rarely accessed.
431      *
432      * @param userId The device user id.
433      * @return The gids for the device user.
434      */
435     public int[] computeGids(int userId) {
436         enforceValidUserId(userId);
437
438         int[] gids = mGlobalGids;
439
440         if (mPermissions != null) {
441             final int permissionCount = mPermissions.size();
442             for (int i = 0; i < permissionCount; i++) {
443                 String permission = mPermissions.keyAt(i);
444                 if (!hasPermission(permission, userId)) {
445                     continue;
446                 }
447                 PermissionData permissionData = mPermissions.valueAt(i);
448                 final int[] permGids = permissionData.computeGids(userId);
449                 if (permGids != NO_GIDS) {
450                     gids = appendInts(gids, permGids);
451                 }
452             }
453         }
454
455         return gids;
456     }
457
458     /**
459      * Compute the Linux gids for all device users from the permissions
460      * granted to these users.
461      *
462      * @return The gids for all device users.
463      */
464     public int[] computeGids(int[] userIds) {
465         int[] gids = mGlobalGids;
466
467         for (int userId : userIds) {
468             final int[] userGids = computeGids(userId);
469             gids = appendInts(gids, userGids);
470         }
471
472         return gids;
473     }
474
475     /**
476      * Resets the internal state of this object.
477      */
478     public void reset() {
479         mGlobalGids = NO_GIDS;
480         mPermissions = null;
481         mPermissionReviewRequired = null;
482     }
483
484     private PermissionState getPermissionState(String name, int userId) {
485         if (mPermissions == null) {
486             return null;
487         }
488         PermissionData permissionData = mPermissions.get(name);
489         if (permissionData == null) {
490             return null;
491         }
492         return permissionData.getPermissionState(userId);
493     }
494
495     private List<PermissionState> getPermissionStatesInternal(int userId) {
496         enforceValidUserId(userId);
497
498         if (mPermissions == null) {
499             return Collections.emptyList();
500         }
501
502         List<PermissionState> permissionStates = new ArrayList<>();
503
504         final int permissionCount = mPermissions.size();
505         for (int i = 0; i < permissionCount; i++) {
506             PermissionData permissionData = mPermissions.valueAt(i);
507
508             PermissionState permissionState = permissionData.getPermissionState(userId);
509             if (permissionState != null) {
510                 permissionStates.add(permissionState);
511             }
512         }
513
514         return permissionStates;
515     }
516
517     private int grantPermission(BasePermission permission, int userId) {
518         if (hasPermission(permission.name, userId)) {
519             return PERMISSION_OPERATION_FAILURE;
520         }
521
522         final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
523         final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
524
525         PermissionData permissionData = ensurePermissionData(permission);
526
527         if (!permissionData.grant(userId)) {
528             return PERMISSION_OPERATION_FAILURE;
529         }
530
531         if (hasGids) {
532             final int[] newGids = computeGids(userId);
533             if (oldGids.length != newGids.length) {
534                 return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
535             }
536         }
537
538         return PERMISSION_OPERATION_SUCCESS;
539     }
540
541     private int revokePermission(BasePermission permission, int userId) {
542         if (!hasPermission(permission.name, userId)) {
543             return PERMISSION_OPERATION_FAILURE;
544         }
545
546         final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
547         final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
548
549         PermissionData permissionData = mPermissions.get(permission.name);
550
551         if (!permissionData.revoke(userId)) {
552             return PERMISSION_OPERATION_FAILURE;
553         }
554
555         if (permissionData.isDefault()) {
556             ensureNoPermissionData(permission.name);
557         }
558
559         if (hasGids) {
560             final int[] newGids = computeGids(userId);
561             if (oldGids.length != newGids.length) {
562                 return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
563             }
564         }
565
566         return PERMISSION_OPERATION_SUCCESS;
567     }
568
569     private static int[] appendInts(int[] current, int[] added) {
570         if (current != null && added != null) {
571             for (int guid : added) {
572                 current = ArrayUtils.appendInt(current, guid);
573             }
574         }
575         return current;
576     }
577
578     private static void enforceValidUserId(int userId) {
579         if (userId != UserHandle.USER_ALL && userId < 0) {
580             throw new IllegalArgumentException("Invalid userId:" + userId);
581         }
582     }
583
584     private PermissionData ensurePermissionData(BasePermission permission) {
585         if (mPermissions == null) {
586             mPermissions = new ArrayMap<>();
587         }
588         PermissionData permissionData = mPermissions.get(permission.name);
589         if (permissionData == null) {
590             permissionData = new PermissionData(permission);
591             mPermissions.put(permission.name, permissionData);
592         }
593         return permissionData;
594     }
595
596     private void ensureNoPermissionData(String name) {
597         if (mPermissions == null) {
598             return;
599         }
600         mPermissions.remove(name);
601         if (mPermissions.isEmpty()) {
602             mPermissions = null;
603         }
604     }
605
606     private static final class PermissionData {
607         private final BasePermission mPerm;
608         private SparseArray<PermissionState> mUserStates = new SparseArray<>();
609
610         public PermissionData(BasePermission perm) {
611             mPerm = perm;
612         }
613
614         public PermissionData(PermissionData other) {
615             this(other.mPerm);
616             final int otherStateCount = other.mUserStates.size();
617             for (int i = 0; i < otherStateCount; i++) {
618                 final int otherUserId = other.mUserStates.keyAt(i);
619                 PermissionState otherState = other.mUserStates.valueAt(i);
620                 mUserStates.put(otherUserId, new PermissionState(otherState));
621             }
622         }
623
624         public int[] computeGids(int userId) {
625             return mPerm.computeGids(userId);
626         }
627
628         public boolean isGranted(int userId) {
629             if (isInstallPermission()) {
630                 userId = UserHandle.USER_ALL;
631             }
632
633             PermissionState userState = mUserStates.get(userId);
634             if (userState == null) {
635                 return false;
636             }
637
638             return userState.mGranted;
639         }
640
641         public boolean grant(int userId) {
642             if (!isCompatibleUserId(userId)) {
643                 return false;
644             }
645
646             if (isGranted(userId)) {
647                 return false;
648             }
649
650             PermissionState userState = mUserStates.get(userId);
651             if (userState == null) {
652                 userState = new PermissionState(mPerm.name);
653                 mUserStates.put(userId, userState);
654             }
655
656             userState.mGranted = true;
657
658             return true;
659         }
660
661         public boolean revoke(int userId) {
662             if (!isCompatibleUserId(userId)) {
663                 return false;
664             }
665
666             if (!isGranted(userId)) {
667                 return false;
668             }
669
670             PermissionState userState = mUserStates.get(userId);
671             userState.mGranted = false;
672
673             if (userState.isDefault()) {
674                 mUserStates.remove(userId);
675             }
676
677             return true;
678         }
679
680         public PermissionState getPermissionState(int userId) {
681             return mUserStates.get(userId);
682         }
683
684         public int getFlags(int userId) {
685             PermissionState userState = mUserStates.get(userId);
686             if (userState != null) {
687                 return userState.mFlags;
688             }
689             return 0;
690         }
691
692         public boolean isDefault() {
693             return mUserStates.size() <= 0;
694         }
695
696         public static boolean isInstallPermissionKey(int userId) {
697             return userId == UserHandle.USER_ALL;
698         }
699
700         public boolean updateFlags(int userId, int flagMask, int flagValues) {
701             if (isInstallPermission()) {
702                 userId = UserHandle.USER_ALL;
703             }
704
705             if (!isCompatibleUserId(userId)) {
706                 return false;
707             }
708
709             final int newFlags = flagValues & flagMask;
710
711             PermissionState userState = mUserStates.get(userId);
712             if (userState != null) {
713                 final int oldFlags = userState.mFlags;
714                 userState.mFlags = (userState.mFlags & ~flagMask) | newFlags;
715                 if (userState.isDefault()) {
716                     mUserStates.remove(userId);
717                 }
718                 return userState.mFlags != oldFlags;
719             } else if (newFlags != 0) {
720                 userState = new PermissionState(mPerm.name);
721                 userState.mFlags = newFlags;
722                 mUserStates.put(userId, userState);
723                 return true;
724             }
725
726             return false;
727         }
728
729         private boolean isCompatibleUserId(int userId) {
730             return isDefault() || !(isInstallPermission() ^ isInstallPermissionKey(userId));
731         }
732
733         private boolean isInstallPermission() {
734             return mUserStates.size() == 1
735                     && mUserStates.get(UserHandle.USER_ALL) != null;
736         }
737     }
738
739     public static final class PermissionState {
740         private final String mName;
741         private boolean mGranted;
742         private int mFlags;
743
744         public PermissionState(String name) {
745             mName = name;
746         }
747
748         public PermissionState(PermissionState other) {
749             mName = other.mName;
750             mGranted = other.mGranted;
751             mFlags = other.mFlags;
752         }
753
754         public boolean isDefault() {
755             return !mGranted && mFlags == 0;
756         }
757
758         public String getName() {
759             return mName;
760         }
761
762         public boolean isGranted() {
763             return mGranted;
764         }
765
766         public int getFlags() {
767             return mFlags;
768         }
769     }
770 }