• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.role.controller.model;
18 
19 import android.content.Context;
20 import android.content.pm.PackageManager;
21 import android.content.pm.PermissionInfo;
22 import android.os.Build;
23 import android.os.UserHandle;
24 
25 import androidx.annotation.NonNull;
26 import androidx.annotation.Nullable;
27 
28 import com.android.modules.utils.build.SdkLevel;
29 import com.android.role.controller.util.UserUtils;
30 
31 import java.util.Objects;
32 import java.util.function.Supplier;
33 
34 /**
35  * A permission to be granted or revoke by a {@link Role}.
36  */
37 public class Permission {
38 
39     /**
40      * The name of the permission.
41      */
42     @NonNull
43     private final String mName;
44 
45     /**
46      * The feature flag for this permission to be granted, or {@code null} if none.
47      */
48     @Nullable
49     private final Supplier<Boolean> mFeatureFlag;
50 
51     /**
52      * The minimum SDK version for this permission to be granted.
53      */
54     private final int mMinSdkVersion;
55 
56     /**
57      * The minimum SDK version for this permission to be optionally granted (when it is grantable).
58      */
59     private final int mOptionalMinSdkVersion;
60 
Permission(@onNull String name, @Nullable Supplier<Boolean> featureFlag, int minSdkVersion, int optionalMinSdkVersion)61     public Permission(@NonNull String name, @Nullable Supplier<Boolean> featureFlag,
62             int minSdkVersion, int optionalMinSdkVersion) {
63         mName = name;
64         mFeatureFlag = featureFlag;
65         mMinSdkVersion = minSdkVersion;
66         mOptionalMinSdkVersion = optionalMinSdkVersion;
67     }
68 
69     @NonNull
getName()70     public String getName() {
71         return mName;
72     }
73 
74     @Nullable
getFeatureFlag()75     public Supplier<Boolean> getFeatureFlag() {
76         return mFeatureFlag;
77     }
78 
getMinSdkVersion()79     public int getMinSdkVersion() {
80         return mMinSdkVersion;
81     }
82 
getOptionalMinSdkVersion()83     public int getOptionalMinSdkVersion() {
84         return mOptionalMinSdkVersion;
85     }
86 
87     /**
88      * Check whether this permission is available.
89      *
90      * @param user the user to check for
91      * @param context the {@code Context} to retrieve system services
92      *
93      * @return whether this permission is available
94      */
isAvailableAsUser(@onNull UserHandle user, @NonNull Context context)95     public boolean isAvailableAsUser(@NonNull UserHandle user, @NonNull Context context) {
96         if (mFeatureFlag != null && !mFeatureFlag.get()) {
97             return false;
98         }
99         if (Build.VERSION.SDK_INT >= mMinSdkVersion
100                 // Workaround to match the value 36 for B in roles.xml before SDK finalization.
101                 || (mMinSdkVersion == 36 && SdkLevel.isAtLeastB())) {
102             return true;
103         }
104         if (Build.VERSION.SDK_INT >= mOptionalMinSdkVersion) {
105             Context userContext = UserUtils.getUserContext(context, user);
106             PackageManager userPackageManager = userContext.getPackageManager();
107             PermissionInfo permissionInfo;
108             try {
109                 permissionInfo = userPackageManager.getPermissionInfo(mName, 0);
110             } catch (PackageManager.NameNotFoundException e) {
111                 return false;
112             }
113             return permissionInfo.getProtection() == PermissionInfo.PROTECTION_DANGEROUS
114                     || (permissionInfo.getProtectionFlags() & PermissionInfo.PROTECTION_FLAG_ROLE)
115                             == PermissionInfo.PROTECTION_FLAG_ROLE
116                     || (permissionInfo.getProtectionFlags() & PermissionInfo.PROTECTION_FLAG_APPOP)
117                             == PermissionInfo.PROTECTION_FLAG_APPOP;
118         }
119         return false;
120     }
121 
122     /**
123      * Return a new permission with the specified SDK versions, or this permission if it already has
124      * the same SDK versions.
125      *
126      * @param minSdkVersion the minimum SDK version
127      * @param optionalMinSdkVersion the optional minimum SDK version
128      * @return a permission with the specified SDK versions
129      */
130     @NonNull
withFeatureFlagAndSdkVersions(@ullable Supplier<Boolean> featureFlag, int minSdkVersion, int optionalMinSdkVersion)131     public Permission withFeatureFlagAndSdkVersions(@Nullable Supplier<Boolean> featureFlag,
132             int minSdkVersion, int optionalMinSdkVersion) {
133         if (mFeatureFlag == featureFlag && mMinSdkVersion == minSdkVersion
134                 && mOptionalMinSdkVersion == optionalMinSdkVersion) {
135             return this;
136         }
137         return new Permission(mName, featureFlag, minSdkVersion, optionalMinSdkVersion);
138     }
139 
140     @Override
toString()141     public String toString() {
142         return "Permission{"
143                 + "mName='" + mName + '\''
144                 + ", mFeatureFlag=" + mFeatureFlag
145                 + ", mMinSdkVersion=" + mMinSdkVersion
146                 + ", mOptionalMinSdkVersion=" + mOptionalMinSdkVersion
147                 + '}';
148     }
149 
150     @Override
equals(Object object)151     public boolean equals(Object object) {
152         if (this == object) {
153             return true;
154         }
155         if (object == null || getClass() != object.getClass()) {
156             return false;
157         }
158         Permission that = (Permission) object;
159         return mMinSdkVersion == that.mMinSdkVersion
160                 && mOptionalMinSdkVersion == that.mOptionalMinSdkVersion
161                 && Objects.equals(mName, that.mName)
162                 && Objects.equals(mFeatureFlag, that.mFeatureFlag);
163     }
164 
165     @Override
hashCode()166     public int hashCode() {
167         return Objects.hash(mName, mFeatureFlag, mMinSdkVersion, mOptionalMinSdkVersion);
168     }
169 }
170