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