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.permission; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.UserIdInt; 22 import android.content.pm.PackageManager; 23 import android.util.ArrayMap; 24 import android.util.ArraySet; 25 import android.util.IntArray; 26 27 import java.util.ArrayList; 28 import java.util.Collections; 29 import java.util.List; 30 import java.util.Set; 31 32 /** 33 * Permission state for a UID. 34 */ 35 public final class UidPermissionState { 36 private boolean mMissing; 37 38 @Nullable 39 private ArrayMap<String, PermissionState> mPermissions; 40 UidPermissionState()41 public UidPermissionState() {} 42 UidPermissionState(@onNull UidPermissionState other)43 public UidPermissionState(@NonNull UidPermissionState other) { 44 mMissing = other.mMissing; 45 46 if (other.mPermissions != null) { 47 mPermissions = new ArrayMap<>(); 48 final int permissionsSize = other.mPermissions.size(); 49 for (int i = 0; i < permissionsSize; i++) { 50 final String name = other.mPermissions.keyAt(i); 51 final PermissionState permissionState = other.mPermissions.valueAt(i); 52 mPermissions.put(name, new PermissionState(permissionState)); 53 } 54 } 55 } 56 57 /** 58 * Reset the internal state of this object. 59 */ reset()60 public void reset() { 61 mMissing = false; 62 mPermissions = null; 63 invalidateCache(); 64 } 65 66 /** 67 * Check whether the permissions state is missing for a user. This can happen if permission 68 * state is rolled back and we'll need to generate a reasonable default state to keep the app 69 * usable. 70 */ isMissing()71 public boolean isMissing() { 72 return mMissing; 73 } 74 75 /** 76 * Set whether the permissions state is missing for a user. This can happen if permission state 77 * is rolled back and we'll need to generate a reasonable default state to keep the app usable. 78 */ setMissing(boolean missing)79 public void setMissing(boolean missing) { 80 mMissing = missing; 81 } 82 83 /** 84 * Get whether there is a permission state for a permission. 85 * 86 * @deprecated This used to be named hasRequestedPermission() and its usage is confusing 87 */ 88 @Deprecated hasPermissionState(@onNull String name)89 public boolean hasPermissionState(@NonNull String name) { 90 return mPermissions != null && mPermissions.containsKey(name); 91 } 92 93 /** 94 * Get whether there is a permission state for any of the permissions. 95 * 96 * @deprecated This used to be named hasRequestedPermission() and its usage is confusing 97 */ 98 @Deprecated hasPermissionState(@onNull ArraySet<String> names)99 public boolean hasPermissionState(@NonNull ArraySet<String> names) { 100 if (mPermissions == null) { 101 return false; 102 } 103 final int namesSize = names.size(); 104 for (int i = 0; i < namesSize; i++) { 105 final String name = names.valueAt(i); 106 if (mPermissions.containsKey(name)) { 107 return true; 108 } 109 } 110 return false; 111 } 112 113 /** 114 * Gets the state for a permission or null if none. 115 * 116 * @param name the permission name 117 * @return the permission state 118 */ 119 @Nullable getPermissionState(@onNull String name)120 public PermissionState getPermissionState(@NonNull String name) { 121 if (mPermissions == null) { 122 return null; 123 } 124 return mPermissions.get(name); 125 } 126 127 @NonNull getOrCreatePermissionState(@onNull Permission permission)128 private PermissionState getOrCreatePermissionState(@NonNull Permission permission) { 129 if (mPermissions == null) { 130 mPermissions = new ArrayMap<>(); 131 } 132 final String name = permission.getName(); 133 PermissionState permissionState = mPermissions.get(name); 134 if (permissionState == null) { 135 permissionState = new PermissionState(permission); 136 mPermissions.put(name, permissionState); 137 } 138 return permissionState; 139 } 140 141 /** 142 * Get all permission states. 143 * 144 * @return the permission states 145 */ 146 @NonNull getPermissionStates()147 public List<PermissionState> getPermissionStates() { 148 if (mPermissions == null) { 149 return Collections.emptyList(); 150 } 151 return new ArrayList<>(mPermissions.values()); 152 } 153 154 /** 155 * Put a permission state. 156 * 157 * @param permission the permission 158 * @param granted whether the permission is granted 159 * @param flags the permission flags 160 */ putPermissionState(@onNull Permission permission, boolean granted, int flags)161 public void putPermissionState(@NonNull Permission permission, boolean granted, int flags) { 162 final String name = permission.getName(); 163 if (mPermissions == null) { 164 mPermissions = new ArrayMap<>(); 165 } else { 166 mPermissions.remove(name); 167 } 168 final PermissionState permissionState = new PermissionState(permission); 169 if (granted) { 170 permissionState.grant(); 171 } 172 permissionState.updateFlags(flags, flags); 173 mPermissions.put(name, permissionState); 174 } 175 176 /** 177 * Remove a permission state. 178 * 179 * @param name the permission name 180 * @return whether the permission state changed 181 */ removePermissionState(@onNull String name)182 public boolean removePermissionState(@NonNull String name) { 183 if (mPermissions == null) { 184 return false; 185 } 186 final boolean changed = mPermissions.remove(name) != null; 187 if (changed && mPermissions.isEmpty()) { 188 mPermissions = null; 189 } 190 return changed; 191 } 192 193 /** 194 * Get whether a permission is granted. 195 * 196 * @param name the permission name 197 * @return whether the permission is granted 198 */ isPermissionGranted(@onNull String name)199 public boolean isPermissionGranted(@NonNull String name) { 200 final PermissionState permissionState = getPermissionState(name); 201 return permissionState != null && permissionState.isGranted(); 202 } 203 204 /** 205 * Get all the granted permissions. 206 * 207 * @return the granted permissions 208 */ 209 @NonNull getGrantedPermissions()210 public Set<String> getGrantedPermissions() { 211 if (mPermissions == null) { 212 return Collections.emptySet(); 213 } 214 215 final Set<String> permissions = new ArraySet<>(mPermissions.size()); 216 final int permissionsSize = mPermissions.size(); 217 for (int i = 0; i < permissionsSize; i++) { 218 final PermissionState permissionState = mPermissions.valueAt(i); 219 220 if (permissionState.isGranted()) { 221 permissions.add(permissionState.getName()); 222 } 223 } 224 return permissions; 225 } 226 227 /** 228 * Grant a permission. 229 * 230 * @param permission the permission to grant 231 * @return whether the permission grant state changed 232 */ grantPermission(@onNull Permission permission)233 public boolean grantPermission(@NonNull Permission permission) { 234 final PermissionState permissionState = getOrCreatePermissionState(permission); 235 return permissionState.grant(); 236 } 237 238 /** 239 * Revoke a permission. 240 * 241 * @param permission the permission to revoke 242 * @return whether the permission grant state changed 243 */ revokePermission(@onNull Permission permission)244 public boolean revokePermission(@NonNull Permission permission) { 245 final String name = permission.getName(); 246 final PermissionState permissionState = getPermissionState(name); 247 if (permissionState == null) { 248 return false; 249 } 250 final boolean changed = permissionState.revoke(); 251 if (changed && permissionState.isDefault()) { 252 removePermissionState(name); 253 } 254 return changed; 255 } 256 257 /** 258 * Get the flags for a permission. 259 * 260 * @param name the permission name 261 * @return the permission flags 262 */ getPermissionFlags(@onNull String name)263 public int getPermissionFlags(@NonNull String name) { 264 final PermissionState permissionState = getPermissionState(name); 265 if (permissionState == null) { 266 return 0; 267 } 268 return permissionState.getFlags(); 269 } 270 271 /** 272 * Update the flags for a permission. 273 * 274 * @param permission the permission name 275 * @param flagMask the mask for the flags 276 * @param flagValues the new values for the masked flags 277 * @return whether the permission flags changed 278 */ updatePermissionFlags(@onNull Permission permission, int flagMask, int flagValues)279 public boolean updatePermissionFlags(@NonNull Permission permission, int flagMask, 280 int flagValues) { 281 if (flagMask == 0) { 282 return false; 283 } 284 final PermissionState permissionState = getOrCreatePermissionState(permission); 285 final boolean changed = permissionState.updateFlags(flagMask, flagValues); 286 if (changed && permissionState.isDefault()) { 287 removePermissionState(permission.getName()); 288 } 289 return changed; 290 } 291 updatePermissionFlagsForAllPermissions(int flagMask, int flagValues)292 public boolean updatePermissionFlagsForAllPermissions(int flagMask, int flagValues) { 293 if (flagMask == 0) { 294 return false; 295 } 296 if (mPermissions == null) { 297 return false; 298 } 299 boolean anyChanged = false; 300 for (int i = mPermissions.size() - 1; i >= 0; i--) { 301 final PermissionState permissionState = mPermissions.valueAt(i); 302 final boolean changed = permissionState.updateFlags(flagMask, flagValues); 303 if (changed && permissionState.isDefault()) { 304 mPermissions.removeAt(i); 305 } 306 anyChanged |= changed; 307 } 308 return anyChanged; 309 } 310 isPermissionsReviewRequired()311 public boolean isPermissionsReviewRequired() { 312 if (mPermissions == null) { 313 return false; 314 } 315 final int permissionsSize = mPermissions.size(); 316 for (int i = 0; i < permissionsSize; i++) { 317 final PermissionState permission = mPermissions.valueAt(i); 318 if ((permission.getFlags() & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { 319 return true; 320 } 321 } 322 return false; 323 } 324 325 /** 326 * Compute the Linux GIDs from the permissions granted to a user. 327 * 328 * @param userId the user ID 329 * @return the GIDs for the user 330 */ 331 @NonNull computeGids(@onNull int[] globalGids, @UserIdInt int userId)332 public int[] computeGids(@NonNull int[] globalGids, @UserIdInt int userId) { 333 IntArray gids = IntArray.wrap(globalGids); 334 if (mPermissions == null) { 335 return gids.toArray(); 336 } 337 final int permissionsSize = mPermissions.size(); 338 for (int i = 0; i < permissionsSize; i++) { 339 PermissionState permissionState = mPermissions.valueAt(i); 340 if (!permissionState.isGranted()) { 341 continue; 342 } 343 final int[] permissionGids = permissionState.computeGids(userId); 344 if (permissionGids.length != 0) { 345 gids.addAll(permissionGids); 346 } 347 } 348 return gids.toArray(); 349 } 350 invalidateCache()351 static void invalidateCache() { 352 PackageManager.invalidatePackageInfoCache(); 353 } 354 } 355