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.packageinstaller.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 
26 /**
27  * A permission and it's properties.
28  *
29  * @see AppPermissionGroup
30  */
31 public final class Permission {
32     private final @NonNull PermissionInfo mPermissionInfo;
33     private final String mName;
34     private final String mBackgroundPermissionName;
35     private final String mAppOp;
36 
37     private boolean mGranted;
38     private boolean mAppOpAllowed;
39     private int mFlags;
40     private boolean mIsEphemeral;
41     private boolean mIsRuntimeOnly;
42     private Permission mBackgroundPermission;
43     private ArrayList<Permission> mForegroundPermissions;
44     private boolean mWhitelisted;
45 
Permission(String name, @NonNull PermissionInfo permissionInfo, boolean granted, String appOp, boolean appOpAllowed, int flags)46     public Permission(String name, @NonNull PermissionInfo permissionInfo, boolean granted,
47             String appOp, boolean appOpAllowed, int flags) {
48         mPermissionInfo = permissionInfo;
49         mName = name;
50         mBackgroundPermissionName = permissionInfo.backgroundPermission;
51         mGranted = granted;
52         mAppOp = appOp;
53         mAppOpAllowed = appOpAllowed;
54         mFlags = flags;
55         mIsEphemeral =
56                 (permissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0;
57         mIsRuntimeOnly =
58                 (permissionInfo.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0;
59     }
60 
61     /**
62      * Mark this permission as background permission for {@code foregroundPermissions}.
63      *
64      * @param foregroundPermission The foreground permission
65      */
addForegroundPermissions(Permission foregroundPermission)66     public void addForegroundPermissions(Permission foregroundPermission) {
67         if (mForegroundPermissions == null) {
68             mForegroundPermissions = new ArrayList<>(1);
69         }
70         mForegroundPermissions.add(foregroundPermission);
71     }
72 
73     /**
74      * Mark this permission as foreground permission for {@code backgroundPermission}.
75      *
76      * @param backgroundPermission The background permission
77      */
setBackgroundPermission(Permission backgroundPermission)78     public void setBackgroundPermission(Permission backgroundPermission) {
79         mBackgroundPermission = backgroundPermission;
80     }
81 
getPermissionInfo()82     public PermissionInfo getPermissionInfo() {
83         return mPermissionInfo;
84     }
85 
getName()86     public String getName() {
87         return mName;
88     }
89 
getAppOp()90     public String getAppOp() {
91         return mAppOp;
92     }
93 
getFlags()94     public int getFlags() {
95         return mFlags;
96     }
97 
isHardRestricted()98     boolean isHardRestricted() {
99         return (mPermissionInfo.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
100     }
101 
isSoftRestricted()102     boolean isSoftRestricted() {
103         return (mPermissionInfo.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0;
104     }
105 
106     /**
107      * Does this permission affect app ops.
108      *
109      * <p>I.e. does this permission have a matching app op or is this a background permission. All
110      * background permissions affect the app op of it's assigned foreground permission.
111      *
112      * @return {@code true} if this permission affects app ops
113      */
affectsAppOp()114     public boolean affectsAppOp() {
115         return mAppOp != null || isBackgroundPermission();
116     }
117 
118     /**
119      * Check if the permission is granted.
120      *
121      * <p>This ignores the state of the app-op. I.e. for apps not handling runtime permissions, this
122      * always returns {@code true}.
123      *
124      * @return If the permission is granted
125      */
isGranted()126     public boolean isGranted() {
127         return mGranted;
128     }
129 
130     /**
131      * Check if the permission is granted, also considering the state of the app-op.
132      *
133      * <p>For the UI, check the grant state of the whole group via
134      * {@link AppPermissionGroup#areRuntimePermissionsGranted}.
135      *
136      * @return {@code true} if the permission (and the app-op) is granted.
137      */
isGrantedIncludingAppOp()138     public boolean isGrantedIncludingAppOp() {
139         return mGranted && (!affectsAppOp() || isAppOpAllowed()) && !isReviewRequired();
140     }
141 
isReviewRequired()142     public boolean isReviewRequired() {
143         return (mFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0;
144     }
145 
unsetReviewRequired()146     public void unsetReviewRequired() {
147         mFlags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
148     }
149 
setGranted(boolean mGranted)150     public void setGranted(boolean mGranted) {
151         this.mGranted = mGranted;
152     }
153 
isAppOpAllowed()154     public boolean isAppOpAllowed() {
155         return mAppOpAllowed;
156     }
157 
isUserFixed()158     public boolean isUserFixed() {
159         return (mFlags & PackageManager.FLAG_PERMISSION_USER_FIXED) != 0;
160     }
161 
setUserFixed(boolean userFixed)162     public void setUserFixed(boolean userFixed) {
163         if (userFixed) {
164             mFlags |= PackageManager.FLAG_PERMISSION_USER_FIXED;
165         } else {
166             mFlags &= ~PackageManager.FLAG_PERMISSION_USER_FIXED;
167         }
168     }
169 
isSystemFixed()170     public boolean isSystemFixed() {
171         return (mFlags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0;
172     }
173 
isPolicyFixed()174     public boolean isPolicyFixed() {
175         return (mFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0;
176     }
177 
isUserSet()178     public boolean isUserSet() {
179         return (mFlags & PackageManager.FLAG_PERMISSION_USER_SET) != 0;
180     }
181 
isGrantedByDefault()182     public boolean isGrantedByDefault() {
183         return (mFlags & PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0;
184     }
185 
186     /**
187      * Is the permission user sensitive, i.e. should it always be shown to the user.
188      *
189      * <p>Non-sensitive permission are usually hidden behind a setting in an overflow menu or
190      * some other kind of flag.
191      *
192      * @return {@code true} if the permission is user sensitive.
193      */
isUserSensitive()194     public boolean isUserSensitive() {
195         if (isGrantedIncludingAppOp()) {
196             return (mFlags & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) != 0;
197         } else {
198             return (mFlags & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED) != 0;
199         }
200     }
201 
202     /**
203      * If this permission is split into a foreground and background permission, this is the name
204      * of the background permission.
205      *
206      * @return The name of the background permission or {@code null} if the permission is not split
207      */
getBackgroundPermissionName()208     public String getBackgroundPermissionName() {
209         return mBackgroundPermissionName;
210     }
211 
212     /**
213      * @return If this permission is split into a foreground and background permission,
214      * returns the background permission
215      */
getBackgroundPermission()216     public Permission getBackgroundPermission() {
217         return mBackgroundPermission;
218     }
219 
220     /**
221      * @return If this permission is split into a foreground and background permission,
222      * returns the foreground permission
223      */
getForegroundPermissions()224     public ArrayList<Permission> getForegroundPermissions() {
225         return mForegroundPermissions;
226     }
227 
228     /**
229      * @return {@code true} iff this is the foreground permission of a background-foreground-split
230      * permission
231      */
hasBackgroundPermission()232     public boolean hasBackgroundPermission() {
233         return mBackgroundPermissionName != null;
234     }
235 
236     /**
237      * @return {@code true} iff this is the background permission of a background-foreground-split
238      * permission
239      */
isBackgroundPermission()240     public boolean isBackgroundPermission() {
241         return mForegroundPermissions != null;
242     }
243 
setUserSet(boolean userSet)244     public void setUserSet(boolean userSet) {
245         if (userSet) {
246             mFlags |= PackageManager.FLAG_PERMISSION_USER_SET;
247         } else {
248             mFlags &= ~PackageManager.FLAG_PERMISSION_USER_SET;
249         }
250     }
251 
setPolicyFixed(boolean policyFixed)252     public void setPolicyFixed(boolean policyFixed) {
253         if (policyFixed) {
254             mFlags |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
255         } else {
256             mFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
257         }
258     }
259 
shouldRevokeOnUpgrade()260     public boolean shouldRevokeOnUpgrade() {
261         return (mFlags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0;
262     }
263 
setRevokeOnUpgrade(boolean revokeOnUpgrade)264     public void setRevokeOnUpgrade(boolean revokeOnUpgrade) {
265         if (revokeOnUpgrade) {
266             mFlags |= PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
267         } else {
268             mFlags &= ~PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
269         }
270     }
271 
setAppOpAllowed(boolean mAppOpAllowed)272     public void setAppOpAllowed(boolean mAppOpAllowed) {
273         this.mAppOpAllowed = mAppOpAllowed;
274     }
275 
isEphemeral()276     public boolean isEphemeral() {
277         return mIsEphemeral;
278     }
279 
isRuntimeOnly()280     public boolean isRuntimeOnly() {
281         return mIsRuntimeOnly;
282     }
283 
isGrantingAllowed(boolean isEphemeralApp, boolean supportsRuntimePermissions)284     public boolean isGrantingAllowed(boolean isEphemeralApp, boolean supportsRuntimePermissions) {
285         return (!isEphemeralApp || isEphemeral())
286                 && (supportsRuntimePermissions || !isRuntimeOnly());
287     }
288 }
289