• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.permissioncontroller.permission.model;
18 
19 import android.content.pm.PackageManager;
20 import android.content.pm.PermissionInfo;
21 
22 import androidx.annotation.NonNull;
23 
24 import java.util.ArrayList;
25 import java.util.Objects;
26 
27 /**
28  * A permission and it's properties.
29  *
30  * @see AppPermissionGroup
31  */
32 public final class Permission {
33     private final @NonNull PermissionInfo mPermissionInfo;
34     private final String mName;
35     private final String mBackgroundPermissionName;
36     private final String mAppOp;
37 
38     private boolean mGranted;
39     private boolean mAppOpAllowed;
40     private int mFlags;
41     private boolean mIsEphemeral;
42     private boolean mIsRuntimeOnly;
43     private Permission mBackgroundPermission;
44     private ArrayList<Permission> mForegroundPermissions;
45     private boolean mWhitelisted;
46 
Permission(String name, @NonNull PermissionInfo permissionInfo, boolean granted, String appOp, boolean appOpAllowed, int flags)47     public Permission(String name, @NonNull PermissionInfo permissionInfo, boolean granted,
48             String appOp, boolean appOpAllowed, int flags) {
49         mPermissionInfo = permissionInfo;
50         mName = name;
51         mBackgroundPermissionName = permissionInfo.backgroundPermission;
52         mGranted = granted;
53         mAppOp = appOp;
54         mAppOpAllowed = appOpAllowed;
55         mFlags = flags;
56         mIsEphemeral =
57                 (permissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0;
58         mIsRuntimeOnly =
59                 (permissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0;
60     }
61 
62     /**
63      * Mark this permission as background permission for {@code foregroundPermissions}.
64      *
65      * @param foregroundPermission The foreground permission
66      */
addForegroundPermissions(Permission foregroundPermission)67     public void addForegroundPermissions(Permission foregroundPermission) {
68         if (mForegroundPermissions == null) {
69             mForegroundPermissions = new ArrayList<>(1);
70         }
71         mForegroundPermissions.add(foregroundPermission);
72     }
73 
74     /**
75      * Mark this permission as foreground permission for {@code backgroundPermission}.
76      *
77      * @param backgroundPermission The background permission
78      */
setBackgroundPermission(Permission backgroundPermission)79     public void setBackgroundPermission(Permission backgroundPermission) {
80         mBackgroundPermission = backgroundPermission;
81     }
82 
getPermissionInfo()83     public PermissionInfo getPermissionInfo() {
84         return mPermissionInfo;
85     }
86 
getName()87     public String getName() {
88         return mName;
89     }
90 
getAppOp()91     public String getAppOp() {
92         return mAppOp;
93     }
94 
getFlags()95     public int getFlags() {
96         return mFlags;
97     }
98 
isHardRestricted()99     boolean isHardRestricted() {
100         return (mPermissionInfo.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
101     }
102 
isSoftRestricted()103     boolean isSoftRestricted() {
104         return (mPermissionInfo.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0;
105     }
106 
107     /**
108      * Does this permission affect app ops.
109      *
110      * <p>I.e. does this permission have a matching app op or is this a background permission. All
111      * background permissions affect the app op of it's assigned foreground permission.
112      *
113      * @return {@code true} if this permission affects app ops
114      */
affectsAppOp()115     public boolean affectsAppOp() {
116         return mAppOp != null || isBackgroundPermission();
117     }
118 
119     /**
120      * Check if the permission is granted.
121      *
122      * <p>This ignores the state of the app-op. I.e. for apps not handling runtime permissions, this
123      * always returns {@code true}.
124      *
125      * @return If the permission is granted
126      */
isGranted()127     public boolean isGranted() {
128         return mGranted;
129     }
130 
131     /**
132      * Check if the permission is granted, also considering the state of the app-op.
133      *
134      * <p>For the UI, check the grant state of the whole group via
135      * {@link AppPermissionGroup#areRuntimePermissionsGranted}.
136      *
137      * @return {@code true} if the permission (and the app-op) is granted.
138      */
isGrantedIncludingAppOp()139     public boolean isGrantedIncludingAppOp() {
140         return mGranted && (!affectsAppOp() || isAppOpAllowed()) && !isReviewRequired();
141     }
142 
isReviewRequired()143     public boolean isReviewRequired() {
144         return (mFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0;
145     }
146 
unsetReviewRequired()147     public void unsetReviewRequired() {
148         mFlags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
149     }
150 
setGranted(boolean mGranted)151     public void setGranted(boolean mGranted) {
152         this.mGranted = mGranted;
153     }
154 
isAppOpAllowed()155     public boolean isAppOpAllowed() {
156         return mAppOpAllowed;
157     }
158 
isUserFixed()159     public boolean isUserFixed() {
160         return (mFlags & PackageManager.FLAG_PERMISSION_USER_FIXED) != 0;
161     }
162 
setUserFixed(boolean userFixed)163     public void setUserFixed(boolean userFixed) {
164         if (userFixed) {
165             mFlags |= PackageManager.FLAG_PERMISSION_USER_FIXED;
166         } else {
167             mFlags &= ~PackageManager.FLAG_PERMISSION_USER_FIXED;
168         }
169     }
170 
171     /**
172      * Sets the one-time permission flag
173      * @param oneTime true to set the flag, false to unset it
174      */
setOneTime(boolean oneTime)175     public void setOneTime(boolean oneTime) {
176         if (oneTime) {
177             mFlags |= PackageManager.FLAG_PERMISSION_ONE_TIME;
178         } else {
179             mFlags &= ~PackageManager.FLAG_PERMISSION_ONE_TIME;
180         }
181     }
182 
isSelectedLocationAccuracy()183     public boolean isSelectedLocationAccuracy() {
184         return (mFlags & PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY) != 0;
185     }
186 
187    /**
188      * Sets the selected-location-accuracy permission flag
189      * @param selectedLocationAccuracy true to set the flag, false to unset it
190      */
setSelectedLocationAccuracy(boolean selectedLocationAccuracy)191     public void setSelectedLocationAccuracy(boolean selectedLocationAccuracy) {
192         if (selectedLocationAccuracy) {
193             mFlags |= PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY;
194         } else {
195             mFlags &= ~PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY;
196         }
197     }
198 
isSystemFixed()199     public boolean isSystemFixed() {
200         return (mFlags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0;
201     }
202 
isPolicyFixed()203     public boolean isPolicyFixed() {
204         return (mFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0;
205     }
206 
isUserSet()207     public boolean isUserSet() {
208         return (mFlags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
209     }
210 
isGrantedByDefault()211     public boolean isGrantedByDefault() {
212         return (mFlags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0;
213     }
214 
215     /**
216      * Is the permission user sensitive, i.e. should it always be shown to the user.
217      *
218      * <p>Non-sensitive permission are usually hidden behind a setting in an overflow menu or
219      * some other kind of flag.
220      *
221      * @return {@code true} if the permission is user sensitive.
222      */
isUserSensitive()223     public boolean isUserSensitive() {
224         if (isGrantedIncludingAppOp()) {
225             return (mFlags & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) != 0;
226         } else {
227             return (mFlags & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED) != 0;
228         }
229     }
230 
231     /**
232      * If this permission is split into a foreground and background permission, this is the name
233      * of the background permission.
234      *
235      * @return The name of the background permission or {@code null} if the permission is not split
236      */
getBackgroundPermissionName()237     public String getBackgroundPermissionName() {
238         return mBackgroundPermissionName;
239     }
240 
241     /**
242      * @return If this permission is split into a foreground and background permission,
243      * returns the background permission
244      */
getBackgroundPermission()245     public Permission getBackgroundPermission() {
246         return mBackgroundPermission;
247     }
248 
249     /**
250      * @return If this permission is split into a foreground and background permission,
251      * returns the foreground permission
252      */
getForegroundPermissions()253     public ArrayList<Permission> getForegroundPermissions() {
254         return mForegroundPermissions;
255     }
256 
257     /**
258      * @return {@code true} iff this is the foreground permission of a background-foreground-split
259      * permission
260      */
hasBackgroundPermission()261     public boolean hasBackgroundPermission() {
262         return mBackgroundPermissionName != null;
263     }
264 
265     /**
266      * @return {@code true} iff this is the background permission of a background-foreground-split
267      * permission
268      */
isBackgroundPermission()269     public boolean isBackgroundPermission() {
270         return mForegroundPermissions != null;
271     }
272 
273     /**
274      * @see PackageManager#FLAG_PERMISSION_ONE_TIME
275      */
isOneTime()276     public boolean isOneTime() {
277         return (mFlags & PackageManager.FLAG_PERMISSION_ONE_TIME) != 0;
278     }
279 
setUserSet(boolean userSet)280     public void setUserSet(boolean userSet) {
281         if (userSet) {
282             mFlags |= PackageManager.FLAG_PERMISSION_USER_SET;
283         } else {
284             mFlags &= ~PackageManager.FLAG_PERMISSION_USER_SET;
285         }
286     }
287 
setPolicyFixed(boolean policyFixed)288     public void setPolicyFixed(boolean policyFixed) {
289         if (policyFixed) {
290             mFlags |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
291         } else {
292             mFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
293         }
294     }
295 
isRevokedCompat()296     public boolean isRevokedCompat() {
297         return (mFlags & PackageManager.FLAG_PERMISSION_REVOKED_COMPAT) != 0;
298     }
299 
setRevokedCompat(boolean revokedCompat)300     public void setRevokedCompat(boolean revokedCompat) {
301         if (revokedCompat) {
302             mFlags |= PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
303         } else {
304             mFlags &= ~PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
305         }
306     }
307 
setAppOpAllowed(boolean mAppOpAllowed)308     public void setAppOpAllowed(boolean mAppOpAllowed) {
309         this.mAppOpAllowed = mAppOpAllowed;
310     }
311 
isEphemeral()312     public boolean isEphemeral() {
313         return mIsEphemeral;
314     }
315 
isRuntimeOnly()316     public boolean isRuntimeOnly() {
317         return mIsRuntimeOnly;
318     }
319 
isGrantingAllowed(boolean isEphemeralApp, boolean supportsRuntimePermissions)320     public boolean isGrantingAllowed(boolean isEphemeralApp, boolean supportsRuntimePermissions) {
321         return (!isEphemeralApp || isEphemeral())
322                 && (supportsRuntimePermissions || !isRuntimeOnly());
323     }
324 
325     @Override
equals(Object o)326     public boolean equals(Object o) {
327         if (!(o instanceof Permission)) {
328             return false;
329         }
330 
331         Permission other = (Permission) o;
332 
333         if (!Objects.equals(getName(), other.getName()) || getFlags() != other.getFlags()
334                 || isGranted() != other.isGranted()) {
335             return false;
336         }
337 
338 
339         // Only compare permission names, in order to avoid recursion
340         if (getBackgroundPermission() != null && other.getBackgroundPermission() != null) {
341             if (!Objects.equals(getBackgroundPermissionName(),
342                     other.getBackgroundPermissionName())) {
343                 return false;
344             }
345         } else if (getBackgroundPermission() != other.getBackgroundPermission()) {
346             return false;
347         }
348 
349         if (getForegroundPermissions() != null && other.getForegroundPermissions() != null) {
350             ArrayList<Permission> others = other.getForegroundPermissions();
351             if (getForegroundPermissions().size() != others.size()) {
352                 return false;
353             }
354             for (int i = 0; i < others.size(); i++) {
355                 if (!getForegroundPermissions().get(i).getName().equals(others.get(i).getName())) {
356                     return false;
357                 }
358             }
359         } else if (getForegroundPermissions() != null || other.getForegroundPermissions() != null) {
360             return false;
361         }
362 
363         return Objects.equals(getAppOp(), other.getAppOp())
364                 && isAppOpAllowed() == other.isAppOpAllowed();
365     }
366 
367     @Override
hashCode()368     public int hashCode() {
369         ArrayList<String> linkedPermissionNames = new ArrayList<>();
370         if (mBackgroundPermission != null) {
371             linkedPermissionNames.add(mBackgroundPermission.getName());
372         }
373         if (mForegroundPermissions != null) {
374             for (Permission linkedPermission: mForegroundPermissions) {
375                 if (linkedPermission != null) {
376                     linkedPermissionNames.add(linkedPermission.getName());
377                 }
378             }
379         }
380         return Objects.hash(mName, mFlags, mGranted, mAppOp, mAppOpAllowed, linkedPermissionNames);
381     }
382 }
383