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; 18 19 import android.os.UserHandle; 20 import android.util.ArrayMap; 21 import android.util.ArraySet; 22 23 import android.util.SparseArray; 24 import com.android.internal.util.ArrayUtils; 25 26 import java.util.ArrayList; 27 import java.util.Arrays; 28 import java.util.Collections; 29 import java.util.List; 30 import java.util.Set; 31 32 /** 33 * This class encapsulates the permissions for a package or a shared user. 34 * <p> 35 * There are two types of permissions: install (granted at installation) 36 * and runtime (granted at runtime). Install permissions are granted to 37 * all device users while runtime permissions are granted explicitly to 38 * specific users. 39 * </p> 40 * <p> 41 * The permissions are kept on a per device user basis. For example, an 42 * application may have some runtime permissions granted under the device 43 * owner but not granted under the secondary user. 44 * <p> 45 * This class is also responsible for keeping track of the Linux gids per 46 * user for a package or a shared user. The gids are computed as a set of 47 * the gids for all granted permissions' gids on a per user basis. 48 * </p> 49 */ 50 public final class PermissionsState { 51 52 /** The permission operation failed. */ 53 public static final int PERMISSION_OPERATION_FAILURE = -1; 54 55 /** The permission operation succeeded and no gids changed. */ 56 public static final int PERMISSION_OPERATION_SUCCESS = 0; 57 58 /** The permission operation succeeded and gids changed. */ 59 public static final int PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED = 1; 60 61 private static final int[] NO_GIDS = {}; 62 63 private ArrayMap<String, PermissionData> mPermissions; 64 65 private int[] mGlobalGids = NO_GIDS; 66 PermissionsState()67 public PermissionsState() { 68 /* do nothing */ 69 } 70 PermissionsState(PermissionsState prototype)71 public PermissionsState(PermissionsState prototype) { 72 copyFrom(prototype); 73 } 74 75 /** 76 * Sets the global gids, applicable to all users. 77 * 78 * @param globalGids The global gids. 79 */ setGlobalGids(int[] globalGids)80 public void setGlobalGids(int[] globalGids) { 81 if (!ArrayUtils.isEmpty(globalGids)) { 82 mGlobalGids = Arrays.copyOf(globalGids, globalGids.length); 83 } 84 } 85 86 /** 87 * Initialized this instance from another one. 88 * 89 * @param other The other instance. 90 */ copyFrom(PermissionsState other)91 public void copyFrom(PermissionsState other) { 92 if (other == this) { 93 return; 94 } 95 if (mPermissions != null) { 96 if (other.mPermissions == null) { 97 mPermissions = null; 98 } else { 99 mPermissions.clear(); 100 } 101 } 102 if (other.mPermissions != null) { 103 if (mPermissions == null) { 104 mPermissions = new ArrayMap<>(); 105 } 106 final int permissionCount = other.mPermissions.size(); 107 for (int i = 0; i < permissionCount; i++) { 108 String name = other.mPermissions.keyAt(i); 109 PermissionData permissionData = other.mPermissions.valueAt(i); 110 mPermissions.put(name, new PermissionData(permissionData)); 111 } 112 } 113 114 mGlobalGids = NO_GIDS; 115 if (other.mGlobalGids != NO_GIDS) { 116 mGlobalGids = Arrays.copyOf(other.mGlobalGids, 117 other.mGlobalGids.length); 118 } 119 } 120 121 /** 122 * Grant an install permission. 123 * 124 * @param permission The permission to grant. 125 * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS}, 126 * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link 127 * #PERMISSION_OPERATION_FAILURE}. 128 */ grantInstallPermission(BasePermission permission)129 public int grantInstallPermission(BasePermission permission) { 130 return grantPermission(permission, UserHandle.USER_ALL); 131 } 132 133 /** 134 * Revoke an install permission. 135 * 136 * @param permission The permission to revoke. 137 * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS}, 138 * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link 139 * #PERMISSION_OPERATION_FAILURE}. 140 */ revokeInstallPermission(BasePermission permission)141 public int revokeInstallPermission(BasePermission permission) { 142 return revokePermission(permission, UserHandle.USER_ALL); 143 } 144 145 /** 146 * Grant a runtime permission for a given device user. 147 * 148 * @param permission The permission to grant. 149 * @param userId The device user id. 150 * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS}, 151 * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link 152 * #PERMISSION_OPERATION_FAILURE}. 153 */ grantRuntimePermission(BasePermission permission, int userId)154 public int grantRuntimePermission(BasePermission permission, int userId) { 155 enforceValidUserId(userId); 156 if (userId == UserHandle.USER_ALL) { 157 return PERMISSION_OPERATION_FAILURE; 158 } 159 return grantPermission(permission, userId); 160 } 161 162 /** 163 * Revoke a runtime permission for a given device user. 164 * 165 * @param permission The permission to revoke. 166 * @param userId The device user id. 167 * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS}, 168 * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link 169 * #PERMISSION_OPERATION_FAILURE}. 170 */ revokeRuntimePermission(BasePermission permission, int userId)171 public int revokeRuntimePermission(BasePermission permission, int userId) { 172 enforceValidUserId(userId); 173 if (userId == UserHandle.USER_ALL) { 174 return PERMISSION_OPERATION_FAILURE; 175 } 176 return revokePermission(permission, userId); 177 } 178 179 /** 180 * Gets whether this state has a given runtime permission for a 181 * given device user id. 182 * 183 * @param name The permission name. 184 * @param userId The device user id. 185 * @return Whether this state has the permission. 186 */ hasRuntimePermission(String name, int userId)187 public boolean hasRuntimePermission(String name, int userId) { 188 enforceValidUserId(userId); 189 return !hasInstallPermission(name) && hasPermission(name, userId); 190 } 191 192 /** 193 * Gets whether this state has a given install permission. 194 * 195 * @param name The permission name. 196 * @return Whether this state has the permission. 197 */ hasInstallPermission(String name)198 public boolean hasInstallPermission(String name) { 199 return hasPermission(name, UserHandle.USER_ALL); 200 } 201 202 /** 203 * Gets whether the state has a given permission for the specified 204 * user, regardless if this is an install or a runtime permission. 205 * 206 * @param name The permission name. 207 * @param userId The device user id. 208 * @return Whether the user has the permission. 209 */ hasPermission(String name, int userId)210 public boolean hasPermission(String name, int userId) { 211 enforceValidUserId(userId); 212 213 if (mPermissions == null) { 214 return false; 215 } 216 217 PermissionData permissionData = mPermissions.get(name); 218 return permissionData != null && permissionData.isGranted(userId); 219 } 220 221 /** 222 * Returns whether the state has any known request for the given permission name, 223 * whether or not it has been granted. 224 */ hasRequestedPermission(ArraySet<String> names)225 public boolean hasRequestedPermission(ArraySet<String> names) { 226 if (mPermissions == null) { 227 return false; 228 } 229 for (int i=names.size()-1; i>=0; i--) { 230 if (mPermissions.get(names.valueAt(i)) != null) { 231 return true; 232 } 233 } 234 return false; 235 } 236 237 /** 238 * Gets all permissions for a given device user id regardless if they 239 * are install time or runtime permissions. 240 * 241 * @param userId The device user id. 242 * @return The permissions or an empty set. 243 */ getPermissions(int userId)244 public Set<String> getPermissions(int userId) { 245 enforceValidUserId(userId); 246 247 if (mPermissions == null) { 248 return Collections.emptySet(); 249 } 250 251 Set<String> permissions = new ArraySet<>(); 252 253 final int permissionCount = mPermissions.size(); 254 for (int i = 0; i < permissionCount; i++) { 255 String permission = mPermissions.keyAt(i); 256 257 if (hasInstallPermission(permission)) { 258 permissions.add(permission); 259 } 260 261 if (userId != UserHandle.USER_ALL) { 262 if (hasRuntimePermission(permission, userId)) { 263 permissions.add(permission); 264 } 265 } 266 } 267 268 return permissions; 269 } 270 271 /** 272 * Gets the state for an install permission or null if no such. 273 * 274 * @param name The permission name. 275 * @return The permission state. 276 */ getInstallPermissionState(String name)277 public PermissionState getInstallPermissionState(String name) { 278 return getPermissionState(name, UserHandle.USER_ALL); 279 } 280 281 /** 282 * Gets the state for a runtime permission or null if no such. 283 * 284 * @param name The permission name. 285 * @param userId The device user id. 286 * @return The permission state. 287 */ getRuntimePermissionState(String name, int userId)288 public PermissionState getRuntimePermissionState(String name, int userId) { 289 enforceValidUserId(userId); 290 return getPermissionState(name, userId); 291 } 292 293 /** 294 * Gets all install permission states. 295 * 296 * @return The permission states or an empty set. 297 */ getInstallPermissionStates()298 public List<PermissionState> getInstallPermissionStates() { 299 return getPermissionStatesInternal(UserHandle.USER_ALL); 300 } 301 302 /** 303 * Gets all runtime permission states. 304 * 305 * @return The permission states or an empty set. 306 */ getRuntimePermissionStates(int userId)307 public List<PermissionState> getRuntimePermissionStates(int userId) { 308 enforceValidUserId(userId); 309 return getPermissionStatesInternal(userId); 310 } 311 312 /** 313 * Gets the flags for a permission regardless if it is install or 314 * runtime permission. 315 * 316 * @param name The permission name. 317 * @return The permission state or null if no such. 318 */ getPermissionFlags(String name, int userId)319 public int getPermissionFlags(String name, int userId) { 320 PermissionState installPermState = getInstallPermissionState(name); 321 if (installPermState != null) { 322 return installPermState.getFlags(); 323 } 324 PermissionState runtimePermState = getRuntimePermissionState(name, userId); 325 if (runtimePermState != null) { 326 return runtimePermState.getFlags(); 327 } 328 return 0; 329 } 330 331 /** 332 * Update the flags associated with a given permission. 333 * @param permission The permission whose flags to update. 334 * @param userId The user for which to update. 335 * @param flagMask Mask for which flags to change. 336 * @param flagValues New values for the mask flags. 337 * @return Whether the permission flags changed. 338 */ updatePermissionFlags(BasePermission permission, int userId, int flagMask, int flagValues)339 public boolean updatePermissionFlags(BasePermission permission, int userId, 340 int flagMask, int flagValues) { 341 enforceValidUserId(userId); 342 343 final boolean mayChangeFlags = flagValues != 0 || flagMask != 0; 344 345 if (mPermissions == null) { 346 if (!mayChangeFlags) { 347 return false; 348 } 349 ensurePermissionData(permission); 350 } 351 352 PermissionData permissionData = mPermissions.get(permission.name); 353 if (permissionData == null) { 354 if (!mayChangeFlags) { 355 return false; 356 } 357 permissionData = ensurePermissionData(permission); 358 } 359 360 return permissionData.updateFlags(userId, flagMask, flagValues); 361 } 362 updatePermissionFlagsForAllPermissions( int userId, int flagMask, int flagValues)363 public boolean updatePermissionFlagsForAllPermissions( 364 int userId, int flagMask, int flagValues) { 365 enforceValidUserId(userId); 366 367 if (mPermissions == null) { 368 return false; 369 } 370 boolean changed = false; 371 final int permissionCount = mPermissions.size(); 372 for (int i = 0; i < permissionCount; i++) { 373 PermissionData permissionData = mPermissions.valueAt(i); 374 changed |= permissionData.updateFlags(userId, flagMask, flagValues); 375 } 376 return changed; 377 } 378 379 /** 380 * Compute the Linux gids for a given device user from the permissions 381 * granted to this user. Note that these are computed to avoid additional 382 * state as they are rarely accessed. 383 * 384 * @param userId The device user id. 385 * @return The gids for the device user. 386 */ computeGids(int userId)387 public int[] computeGids(int userId) { 388 enforceValidUserId(userId); 389 390 int[] gids = mGlobalGids; 391 392 if (mPermissions != null) { 393 final int permissionCount = mPermissions.size(); 394 for (int i = 0; i < permissionCount; i++) { 395 String permission = mPermissions.keyAt(i); 396 if (!hasPermission(permission, userId)) { 397 continue; 398 } 399 PermissionData permissionData = mPermissions.valueAt(i); 400 final int[] permGids = permissionData.computeGids(userId); 401 if (permGids != NO_GIDS) { 402 gids = appendInts(gids, permGids); 403 } 404 } 405 } 406 407 return gids; 408 } 409 410 /** 411 * Compute the Linux gids for all device users from the permissions 412 * granted to these users. 413 * 414 * @return The gids for all device users. 415 */ computeGids(int[] userIds)416 public int[] computeGids(int[] userIds) { 417 int[] gids = mGlobalGids; 418 419 for (int userId : userIds) { 420 final int[] userGids = computeGids(userId); 421 gids = appendInts(gids, userGids); 422 } 423 424 return gids; 425 } 426 427 /** 428 * Resets the internal state of this object. 429 */ reset()430 public void reset() { 431 mGlobalGids = NO_GIDS; 432 mPermissions = null; 433 } 434 getPermissionState(String name, int userId)435 private PermissionState getPermissionState(String name, int userId) { 436 if (mPermissions == null) { 437 return null; 438 } 439 PermissionData permissionData = mPermissions.get(name); 440 if (permissionData == null) { 441 return null; 442 } 443 return permissionData.getPermissionState(userId); 444 } 445 getPermissionStatesInternal(int userId)446 private List<PermissionState> getPermissionStatesInternal(int userId) { 447 enforceValidUserId(userId); 448 449 if (mPermissions == null) { 450 return Collections.emptyList(); 451 } 452 453 List<PermissionState> permissionStates = new ArrayList<>(); 454 455 final int permissionCount = mPermissions.size(); 456 for (int i = 0; i < permissionCount; i++) { 457 PermissionData permissionData = mPermissions.valueAt(i); 458 459 PermissionState permissionState = permissionData.getPermissionState(userId); 460 if (permissionState != null) { 461 permissionStates.add(permissionState); 462 } 463 } 464 465 return permissionStates; 466 } 467 grantPermission(BasePermission permission, int userId)468 private int grantPermission(BasePermission permission, int userId) { 469 if (hasPermission(permission.name, userId)) { 470 return PERMISSION_OPERATION_FAILURE; 471 } 472 473 final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId)); 474 final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS; 475 476 PermissionData permissionData = ensurePermissionData(permission); 477 478 if (!permissionData.grant(userId)) { 479 return PERMISSION_OPERATION_FAILURE; 480 } 481 482 if (hasGids) { 483 final int[] newGids = computeGids(userId); 484 if (oldGids.length != newGids.length) { 485 return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED; 486 } 487 } 488 489 return PERMISSION_OPERATION_SUCCESS; 490 } 491 revokePermission(BasePermission permission, int userId)492 private int revokePermission(BasePermission permission, int userId) { 493 if (!hasPermission(permission.name, userId)) { 494 return PERMISSION_OPERATION_FAILURE; 495 } 496 497 final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId)); 498 final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS; 499 500 PermissionData permissionData = mPermissions.get(permission.name); 501 502 if (!permissionData.revoke(userId)) { 503 return PERMISSION_OPERATION_FAILURE; 504 } 505 506 if (permissionData.isDefault()) { 507 ensureNoPermissionData(permission.name); 508 } 509 510 if (hasGids) { 511 final int[] newGids = computeGids(userId); 512 if (oldGids.length != newGids.length) { 513 return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED; 514 } 515 } 516 517 return PERMISSION_OPERATION_SUCCESS; 518 } 519 appendInts(int[] current, int[] added)520 private static int[] appendInts(int[] current, int[] added) { 521 if (current != null && added != null) { 522 for (int guid : added) { 523 current = ArrayUtils.appendInt(current, guid); 524 } 525 } 526 return current; 527 } 528 enforceValidUserId(int userId)529 private static void enforceValidUserId(int userId) { 530 if (userId != UserHandle.USER_ALL && userId < 0) { 531 throw new IllegalArgumentException("Invalid userId:" + userId); 532 } 533 } 534 ensurePermissionData(BasePermission permission)535 private PermissionData ensurePermissionData(BasePermission permission) { 536 if (mPermissions == null) { 537 mPermissions = new ArrayMap<>(); 538 } 539 PermissionData permissionData = mPermissions.get(permission.name); 540 if (permissionData == null) { 541 permissionData = new PermissionData(permission); 542 mPermissions.put(permission.name, permissionData); 543 } 544 return permissionData; 545 } 546 ensureNoPermissionData(String name)547 private void ensureNoPermissionData(String name) { 548 if (mPermissions == null) { 549 return; 550 } 551 mPermissions.remove(name); 552 if (mPermissions.isEmpty()) { 553 mPermissions = null; 554 } 555 } 556 557 private static final class PermissionData { 558 private final BasePermission mPerm; 559 private SparseArray<PermissionState> mUserStates = new SparseArray<>(); 560 PermissionData(BasePermission perm)561 public PermissionData(BasePermission perm) { 562 mPerm = perm; 563 } 564 PermissionData(PermissionData other)565 public PermissionData(PermissionData other) { 566 this(other.mPerm); 567 final int otherStateCount = other.mUserStates.size(); 568 for (int i = 0; i < otherStateCount; i++) { 569 final int otherUserId = other.mUserStates.keyAt(i); 570 PermissionState otherState = other.mUserStates.valueAt(i); 571 mUserStates.put(otherUserId, new PermissionState(otherState)); 572 } 573 } 574 computeGids(int userId)575 public int[] computeGids(int userId) { 576 return mPerm.computeGids(userId); 577 } 578 isGranted(int userId)579 public boolean isGranted(int userId) { 580 if (isInstallPermission()) { 581 userId = UserHandle.USER_ALL; 582 } 583 584 PermissionState userState = mUserStates.get(userId); 585 if (userState == null) { 586 return false; 587 } 588 589 return userState.mGranted; 590 } 591 grant(int userId)592 public boolean grant(int userId) { 593 if (!isCompatibleUserId(userId)) { 594 return false; 595 } 596 597 if (isGranted(userId)) { 598 return false; 599 } 600 601 PermissionState userState = mUserStates.get(userId); 602 if (userState == null) { 603 userState = new PermissionState(mPerm.name); 604 mUserStates.put(userId, userState); 605 } 606 607 userState.mGranted = true; 608 609 return true; 610 } 611 revoke(int userId)612 public boolean revoke(int userId) { 613 if (!isCompatibleUserId(userId)) { 614 return false; 615 } 616 617 if (!isGranted(userId)) { 618 return false; 619 } 620 621 PermissionState userState = mUserStates.get(userId); 622 userState.mGranted = false; 623 624 if (userState.isDefault()) { 625 mUserStates.remove(userId); 626 } 627 628 return true; 629 } 630 getPermissionState(int userId)631 public PermissionState getPermissionState(int userId) { 632 return mUserStates.get(userId); 633 } 634 getFlags(int userId)635 public int getFlags(int userId) { 636 PermissionState userState = mUserStates.get(userId); 637 if (userState != null) { 638 return userState.mFlags; 639 } 640 return 0; 641 } 642 isDefault()643 public boolean isDefault() { 644 return mUserStates.size() <= 0; 645 } 646 isInstallPermissionKey(int userId)647 public static boolean isInstallPermissionKey(int userId) { 648 return userId == UserHandle.USER_ALL; 649 } 650 updateFlags(int userId, int flagMask, int flagValues)651 public boolean updateFlags(int userId, int flagMask, int flagValues) { 652 if (isInstallPermission()) { 653 userId = UserHandle.USER_ALL; 654 } 655 656 if (!isCompatibleUserId(userId)) { 657 return false; 658 } 659 660 final int newFlags = flagValues & flagMask; 661 662 PermissionState userState = mUserStates.get(userId); 663 if (userState != null) { 664 final int oldFlags = userState.mFlags; 665 userState.mFlags = (userState.mFlags & ~flagMask) | newFlags; 666 if (userState.isDefault()) { 667 mUserStates.remove(userId); 668 } 669 return userState.mFlags != oldFlags; 670 } else if (newFlags != 0) { 671 userState = new PermissionState(mPerm.name); 672 userState.mFlags = newFlags; 673 mUserStates.put(userId, userState); 674 return true; 675 } 676 677 return false; 678 } 679 isCompatibleUserId(int userId)680 private boolean isCompatibleUserId(int userId) { 681 return isDefault() || !(isInstallPermission() ^ isInstallPermissionKey(userId)); 682 } 683 isInstallPermission()684 private boolean isInstallPermission() { 685 return mUserStates.size() == 1 686 && mUserStates.get(UserHandle.USER_ALL) != null; 687 } 688 } 689 690 public static final class PermissionState { 691 private final String mName; 692 private boolean mGranted; 693 private int mFlags; 694 PermissionState(String name)695 public PermissionState(String name) { 696 mName = name; 697 } 698 PermissionState(PermissionState other)699 public PermissionState(PermissionState other) { 700 mName = other.mName; 701 mGranted = other.mGranted; 702 mFlags = other.mFlags; 703 } 704 isDefault()705 public boolean isDefault() { 706 return !mGranted && mFlags == 0; 707 } 708 getName()709 public String getName() { 710 return mName; 711 } 712 isGranted()713 public boolean isGranted() { 714 return mGranted; 715 } 716 getFlags()717 public int getFlags() { 718 return mFlags; 719 } 720 } 721 } 722