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.util.ArrayMap; 23 import android.util.SparseArray; 24 import android.util.SparseBooleanArray; 25 26 import java.util.Collection; 27 import java.util.Collections; 28 import java.util.Objects; 29 30 /** 31 * Legacy permission state that was associated with packages or shared users. 32 */ 33 //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER) 34 public final class LegacyPermissionState { 35 // Maps from user IDs to user states. 36 @NonNull 37 private final SparseArray<UserState> mUserStates = new SparseArray<>(); 38 39 // Keyed by user IDs. 40 @NonNull 41 private final SparseBooleanArray mMissing = new SparseBooleanArray(); 42 43 /** 44 * Copy from another permission state. 45 * 46 * @param other the other permission state. 47 * 48 * @hide 49 */ copyFrom(@onNull LegacyPermissionState other)50 public void copyFrom(@NonNull LegacyPermissionState other) { 51 if (other == this) { 52 return; 53 } 54 55 mUserStates.clear(); 56 final int userStatesSize = other.mUserStates.size(); 57 for (int i = 0; i < userStatesSize; i++) { 58 mUserStates.put(other.mUserStates.keyAt(i), 59 new UserState(other.mUserStates.valueAt(i))); 60 } 61 62 mMissing.clear(); 63 final int missingSize = other.mMissing.size(); 64 for (int i = 0; i < missingSize; i++) { 65 mMissing.put(other.mMissing.keyAt(i), other.mMissing.valueAt(i)); 66 } 67 } 68 69 /** 70 * Reset this permission state. 71 * 72 * @hide 73 */ reset()74 public void reset() { 75 mUserStates.clear(); 76 mMissing.clear(); 77 } 78 79 @Override equals(@ullable Object object)80 public boolean equals(@Nullable Object object) { 81 if (this == object) { 82 return true; 83 } 84 if (object == null) { 85 return false; 86 } 87 if (getClass() != object.getClass()) { 88 return false; 89 } 90 final LegacyPermissionState other = (LegacyPermissionState) object; 91 // Hand-code equals() for mUserStates, since SparseArray only has the 92 // default equals() method. 93 final int userStatesSize = mUserStates.size(); 94 if (userStatesSize != other.mUserStates.size()) { 95 return false; 96 } 97 for (int i = 0; i < userStatesSize; i++) { 98 final int userId = mUserStates.keyAt(i); 99 if (!Objects.equals(mUserStates.get(userId), other.mUserStates.get(userId))) { 100 return false; 101 } 102 } 103 return Objects.equals(mMissing, other.mMissing); 104 } 105 106 /** 107 * Get the permission state for a permission and a user. 108 * 109 * @param permissionName the permission name 110 * @param userId the user ID 111 * @return the permission state 112 * 113 * @hide 114 */ 115 @Nullable getPermissionState(@onNull String permissionName, @UserIdInt int userId)116 public PermissionState getPermissionState(@NonNull String permissionName, 117 @UserIdInt int userId) { 118 checkUserId(userId); 119 UserState userState = mUserStates.get(userId); 120 if (userState == null) { 121 return null; 122 } 123 return userState.getPermissionState(permissionName); 124 } 125 126 /** 127 * Put a permission state for a user. 128 * 129 * @param permissionState the permission state 130 * @param userId the user ID 131 */ putPermissionState(@onNull PermissionState permissionState, @UserIdInt int userId)132 public void putPermissionState(@NonNull PermissionState permissionState, 133 @UserIdInt int userId) { 134 checkUserId(userId); 135 UserState userState = mUserStates.get(userId); 136 if (userState == null) { 137 userState = new UserState(); 138 mUserStates.put(userId, userState); 139 } 140 userState.putPermissionState(permissionState); 141 } 142 143 /** 144 * Check whether there are any permission states for the given permissions. 145 * 146 * @param permissionNames the permission names 147 * @return whether there are any permission states 148 * 149 * @hide 150 */ hasPermissionState(@onNull Collection<String> permissionNames)151 public boolean hasPermissionState(@NonNull Collection<String> permissionNames) { 152 final int userStatesSize = mUserStates.size(); 153 for (int i = 0; i < userStatesSize; i++) { 154 final UserState userState = mUserStates.valueAt(i); 155 for (final String permissionName : permissionNames) { 156 if (userState.getPermissionState(permissionName) != null) { 157 return true; 158 } 159 } 160 } 161 return false; 162 } 163 164 /** 165 * Get all the permission states for a user. 166 * 167 * @param userId the user ID 168 * @return the permission states 169 */ 170 @NonNull getPermissionStates(@serIdInt int userId)171 public Collection<PermissionState> getPermissionStates(@UserIdInt int userId) { 172 checkUserId(userId); 173 final UserState userState = mUserStates.get(userId); 174 if (userState == null) { 175 return Collections.emptyList(); 176 } 177 return userState.getPermissionStates(); 178 } 179 180 /** 181 * Check whether the permission state is missing for a user. 182 * <p> 183 * This can happen if permission state is rolled back and we'll need to generate a reasonable 184 * default state to keep the app usable. 185 * 186 * @param userId the user ID 187 * @return whether the permission state is missing 188 */ isMissing(@serIdInt int userId)189 public boolean isMissing(@UserIdInt int userId) { 190 checkUserId(userId); 191 return mMissing.get(userId); 192 } 193 194 /** 195 * Set whether the permission state is missing for a user. 196 * <p> 197 * This can happen if permission state is rolled back and we'll need to generate a reasonable 198 * default state to keep the app usable. 199 * 200 * @param missing whether the permission state is missing 201 * @param userId the user ID 202 */ setMissing(boolean missing, @UserIdInt int userId)203 public void setMissing(boolean missing, @UserIdInt int userId) { 204 checkUserId(userId); 205 if (missing) { 206 mMissing.put(userId, true); 207 } else { 208 mMissing.delete(userId); 209 } 210 } 211 checkUserId(@serIdInt int userId)212 private static void checkUserId(@UserIdInt int userId) { 213 if (userId < 0) { 214 throw new IllegalArgumentException("Invalid user ID " + userId); 215 } 216 } 217 218 /** 219 * Legacy state for permissions for a user. 220 */ 221 private static final class UserState { 222 // Maps from permission names to permission states. 223 @NonNull 224 private final ArrayMap<String, PermissionState> mPermissionStates = new ArrayMap<>(); 225 UserState()226 public UserState() {} 227 UserState(@onNull UserState other)228 public UserState(@NonNull UserState other) { 229 final int permissionStatesSize = other.mPermissionStates.size(); 230 for (int i = 0; i < permissionStatesSize; i++) { 231 mPermissionStates.put(other.mPermissionStates.keyAt(i), 232 new PermissionState(other.mPermissionStates.valueAt(i))); 233 } 234 } 235 236 @Nullable getPermissionState(@onNull String permissionName)237 public PermissionState getPermissionState(@NonNull String permissionName) { 238 return mPermissionStates.get(permissionName); 239 } 240 putPermissionState(@onNull PermissionState permissionState)241 public void putPermissionState(@NonNull PermissionState permissionState) { 242 mPermissionStates.put(permissionState.getName(), permissionState); 243 } 244 245 @NonNull getPermissionStates()246 public Collection<PermissionState> getPermissionStates() { 247 return Collections.unmodifiableCollection(mPermissionStates.values()); 248 } 249 } 250 251 /** 252 * Legacy state for a single permission. 253 */ 254 public static final class PermissionState { 255 @NonNull 256 private final String mName; 257 258 private final boolean mRuntime; 259 260 private final boolean mGranted; 261 262 private final int mFlags; 263 264 /** 265 * Create a new instance of this class. 266 * 267 * @param name the name of the permission 268 * @param runtime whether the permission is runtime 269 * @param granted whether the permission is granted 270 * @param flags the permission flags 271 */ PermissionState(@onNull String name, boolean runtime, boolean granted, int flags)272 public PermissionState(@NonNull String name, boolean runtime, boolean granted, int flags) { 273 mName = name; 274 mRuntime = runtime; 275 mGranted = granted; 276 mFlags = flags; 277 } 278 PermissionState(@onNull PermissionState other)279 private PermissionState(@NonNull PermissionState other) { 280 mName = other.mName; 281 mRuntime = other.mRuntime; 282 mGranted = other.mGranted; 283 mFlags = other.mFlags; 284 } 285 286 /** 287 * Get the permission name. 288 * 289 * @return the permission name 290 */ 291 @NonNull getName()292 public String getName() { 293 return mName; 294 } 295 296 /** 297 * Get whether the permission is a runtime permission. 298 * 299 * @return whether the permission is a runtime permission. 300 */ isRuntime()301 public boolean isRuntime() { 302 return mRuntime; 303 } 304 305 /** 306 * Get whether the permission is granted. 307 * 308 * @return whether the permission is granted 309 */ 310 @NonNull isGranted()311 public boolean isGranted() { 312 return mGranted; 313 } 314 315 /** 316 * Get the permission flags. 317 * 318 * @return the permission flags 319 */ 320 @NonNull getFlags()321 public int getFlags() { 322 return mFlags; 323 } 324 325 @Override equals(@ullable Object object)326 public boolean equals(@Nullable Object object) { 327 if (this == object) { 328 return true; 329 } 330 if (object == null || getClass() != object.getClass()) { 331 return false; 332 } 333 PermissionState that = (PermissionState) object; 334 return mRuntime == that.mRuntime 335 && mGranted == that.mGranted 336 && mFlags == that.mFlags 337 && Objects.equals(mName, that.mName); 338 } 339 340 @Override hashCode()341 public int hashCode() { 342 return Objects.hash(mName, mRuntime, mGranted, mFlags); 343 } 344 } 345 } 346