1 /* 2 * Copyright (C) 2011 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 android.os; 18 19 import android.annotation.AppIdInt; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.SystemApi; 23 import android.annotation.TestApi; 24 import android.annotation.UserIdInt; 25 import android.compat.annotation.UnsupportedAppUsage; 26 import android.util.SparseArray; 27 28 import com.android.internal.annotations.GuardedBy; 29 import com.android.internal.annotations.VisibleForTesting; 30 31 import java.io.PrintWriter; 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.Random; 35 36 /** 37 * Representation of a user on the device. 38 */ 39 @android.ravenwood.annotation.RavenwoodKeepWholeClass 40 public final class UserHandle implements Parcelable { 41 // NOTE: keep logic in sync with system/core/libcutils/multiuser.c 42 43 /** 44 * @hide Range of uids allocated for a user. 45 */ 46 @UnsupportedAppUsage 47 public static final int PER_USER_RANGE = 100000; 48 49 /** @hide A user id to indicate all users on the device */ 50 @UnsupportedAppUsage 51 @TestApi 52 public static final @UserIdInt int USER_ALL = -1; 53 54 /** @hide A user handle to indicate all users on the device */ 55 @SystemApi 56 public static final @NonNull UserHandle ALL = new UserHandle(USER_ALL); 57 58 /** @hide A user id to indicate the currently active user */ 59 @UnsupportedAppUsage 60 @TestApi 61 public static final @UserIdInt int USER_CURRENT = -2; 62 63 /** @hide A user handle to indicate the current user of the device */ 64 @SystemApi 65 public static final @NonNull UserHandle CURRENT = new UserHandle(USER_CURRENT); 66 67 /** @hide A user id to indicate that we would like to send to the current 68 * user, but if this is calling from a user process then we will send it 69 * to the caller's user instead of failing with a security exception */ 70 @UnsupportedAppUsage 71 public static final @UserIdInt int USER_CURRENT_OR_SELF = -3; 72 73 /** @hide A user handle to indicate that we would like to send to the current 74 * user, but if this is calling from a user process then we will send it 75 * to the caller's user instead of failing with a security exception */ 76 @UnsupportedAppUsage 77 public static final @NonNull UserHandle CURRENT_OR_SELF = new UserHandle(USER_CURRENT_OR_SELF); 78 79 /** @hide An undefined user id */ 80 @UnsupportedAppUsage 81 @TestApi 82 public static final @UserIdInt int USER_NULL = -10000; 83 84 private static final @NonNull UserHandle NULL = new UserHandle(USER_NULL); 85 86 /** 87 * @hide A user id constant to indicate the "owner" user of the device 88 * @deprecated Consider using either {@link UserHandle#USER_SYSTEM} constant or 89 * check the target user's flag {@link android.content.pm.UserInfo#isAdmin}. 90 */ 91 @UnsupportedAppUsage 92 @Deprecated 93 public static final @UserIdInt int USER_OWNER = 0; 94 95 /** 96 * @hide A user handle to indicate the primary/owner user of the device 97 * @deprecated Consider using either {@link UserHandle#SYSTEM} constant or 98 * check the target user's flag {@link android.content.pm.UserInfo#isAdmin}. 99 */ 100 @UnsupportedAppUsage 101 @Deprecated 102 public static final @NonNull UserHandle OWNER = new UserHandle(USER_OWNER); 103 104 /** @hide A user id constant to indicate the "system" user of the device */ 105 @UnsupportedAppUsage 106 @TestApi 107 public static final @UserIdInt int USER_SYSTEM = 0; 108 109 /** @hide A user serial constant to indicate the "system" user of the device */ 110 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 111 public static final int USER_SERIAL_SYSTEM = 0; 112 113 /** @hide A user handle to indicate the "system" user of the device */ 114 @SystemApi 115 public static final @NonNull UserHandle SYSTEM = new UserHandle(USER_SYSTEM); 116 117 /** 118 * @hide Enable multi-user related side effects. Set this to false if 119 * there are problems with single user use-cases. 120 */ 121 @UnsupportedAppUsage 122 public static final boolean MU_ENABLED = true; 123 124 /** @hide */ 125 @TestApi 126 public static final int MIN_SECONDARY_USER_ID = 10; 127 128 /** @hide */ 129 public static final int MAX_SECONDARY_USER_ID = 130 Integer.MAX_VALUE / UserHandle.PER_USER_RANGE - 1; 131 132 /** 133 * (Arbitrary) user handle cache size. 134 * {@link #CACHED_USER_HANDLES} caches user handles in the range of 135 * [{@link #MIN_SECONDARY_USER_ID}, {@link #MIN_SECONDARY_USER_ID} + {@link #NUM_CACHED_USERS}). 136 * 137 * For other users, we cache UserHandles in {link #sExtraUserHandleCache}. 138 * 139 * Normally, {@link #CACHED_USER_HANDLES} should cover all existing users, but use 140 * {link #sExtraUserHandleCache} to ensure {@link UserHandle#of} will not cause too many 141 * object allocations even if the device happens to have a secondary user with a large number 142 * (e.g. the user kept creating and removing the guest user?). 143 */ 144 private static final int NUM_CACHED_USERS = MU_ENABLED ? 8 : 0; 145 146 /** @see #NUM_CACHED_USERS} */ 147 private static final UserHandle[] CACHED_USER_HANDLES = new UserHandle[NUM_CACHED_USERS]; 148 149 /** 150 * Extra cache for users beyond CACHED_USER_HANDLES. 151 * 152 * @see #NUM_CACHED_USERS 153 * @hide 154 */ 155 @GuardedBy("sExtraUserHandleCache") 156 @VisibleForTesting 157 public static final SparseArray<UserHandle> sExtraUserHandleCache = new SparseArray<>(0); 158 159 /** 160 * Max size of {@link #sExtraUserHandleCache}. Once it reaches this size, we select 161 * an element to remove at random. 162 * 163 * @hide 164 */ 165 @VisibleForTesting 166 public static final int MAX_EXTRA_USER_HANDLE_CACHE_SIZE = 32; 167 168 static { 169 // Not lazily initializing the cache, so that we can share them across processes. 170 // (We'll create them in zygote.) 171 for (int i = 0; i < CACHED_USER_HANDLES.length; i++) { 172 CACHED_USER_HANDLES[i] = new UserHandle(MIN_SECONDARY_USER_ID + i); 173 } 174 } 175 176 /** @hide */ 177 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 178 public static final int ERR_GID = -1; 179 /** @hide */ 180 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 181 public static final int AID_ROOT = android.os.Process.ROOT_UID; 182 /** @hide */ 183 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 184 public static final int AID_APP_START = android.os.Process.FIRST_APPLICATION_UID; 185 /** @hide */ 186 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 187 public static final int AID_APP_END = android.os.Process.LAST_APPLICATION_UID; 188 /** @hide */ 189 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 190 public static final int AID_SHARED_GID_START = android.os.Process.FIRST_SHARED_APPLICATION_GID; 191 /** @hide */ 192 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 193 public static final int AID_CACHE_GID_START = android.os.Process.FIRST_APPLICATION_CACHE_GID; 194 195 /** The userId represented by this UserHandle. */ 196 @UnsupportedAppUsage 197 final @UserIdInt int mHandle; 198 199 /** 200 * Checks to see if the user id is the same for the two uids, i.e., they belong to the same 201 * user. 202 * @hide 203 */ isSameUser(int uid1, int uid2)204 public static boolean isSameUser(int uid1, int uid2) { 205 return getUserId(uid1) == getUserId(uid2); 206 } 207 208 /** 209 * Checks to see if both uids are referring to the same app id, ignoring the user id part of the 210 * uids. 211 * @param uid1 uid to compare 212 * @param uid2 other uid to compare 213 * @return whether the appId is the same for both uids 214 * @hide 215 */ 216 @UnsupportedAppUsage isSameApp(int uid1, int uid2)217 public static boolean isSameApp(int uid1, int uid2) { 218 return getAppId(uid1) == getAppId(uid2); 219 } 220 221 /** 222 * Whether a UID is an "isolated" UID. 223 * @hide 224 */ 225 @UnsupportedAppUsage isIsolated(int uid)226 public static boolean isIsolated(int uid) { 227 if (uid > 0) { 228 return Process.isIsolated(uid); 229 } else { 230 return false; 231 } 232 } 233 234 /** 235 * Whether a UID belongs to a regular app. *Note* "Not a regular app" does not mean 236 * "it's system", because of isolated UIDs. Use {@link #isCore} for that. 237 * @hide 238 */ 239 @UnsupportedAppUsage 240 @TestApi isApp(int uid)241 public static boolean isApp(int uid) { 242 if (uid > 0) { 243 final int appId = getAppId(uid); 244 return appId >= Process.FIRST_APPLICATION_UID && appId <= Process.LAST_APPLICATION_UID; 245 } else { 246 return false; 247 } 248 } 249 250 /** 251 * Whether a UID belongs to a system core component or not. 252 * @hide 253 */ isCore(int uid)254 public static boolean isCore(int uid) { 255 if (uid >= 0) { 256 final int appId = getAppId(uid); 257 return appId < Process.FIRST_APPLICATION_UID; 258 } else { 259 return false; 260 } 261 } 262 263 /** 264 * Whether a UID belongs to a shared app gid. 265 * @hide 266 */ isSharedAppGid(int uid)267 public static boolean isSharedAppGid(int uid) { 268 return getAppIdFromSharedAppGid(uid) != -1; 269 } 270 271 /** 272 * Returns the user for a given uid. 273 * @param uid A uid for an application running in a particular user. 274 * @return A {@link UserHandle} for that user. 275 */ getUserHandleForUid(int uid)276 public static UserHandle getUserHandleForUid(int uid) { 277 return of(getUserId(uid)); 278 } 279 280 /** 281 * Returns the user id for a given uid. 282 * @hide 283 */ 284 @UnsupportedAppUsage 285 @TestApi getUserId(int uid)286 public static @UserIdInt int getUserId(int uid) { 287 if (MU_ENABLED) { 288 return uid / PER_USER_RANGE; 289 } else { 290 return UserHandle.USER_SYSTEM; 291 } 292 } 293 294 /** @hide */ 295 @UnsupportedAppUsage getCallingUserId()296 public static @UserIdInt int getCallingUserId() { 297 return getUserId(Binder.getCallingUid()); 298 } 299 300 /** @hide */ getCallingAppId()301 public static @AppIdInt int getCallingAppId() { 302 return getAppId(Binder.getCallingUid()); 303 } 304 305 /** @hide */ 306 @NonNull fromUserHandles(@onNull List<UserHandle> users)307 public static int[] fromUserHandles(@NonNull List<UserHandle> users) { 308 int[] userIds = new int[users.size()]; 309 for (int i = 0; i < userIds.length; ++i) { 310 userIds[i] = users.get(i).getIdentifier(); 311 } 312 return userIds; 313 } 314 315 /** @hide */ 316 @NonNull toUserHandles(@onNull int[] userIds)317 public static List<UserHandle> toUserHandles(@NonNull int[] userIds) { 318 List<UserHandle> users = new ArrayList<>(userIds.length); 319 for (int i = 0; i < userIds.length; ++i) { 320 users.add(UserHandle.of(userIds[i])); 321 } 322 return users; 323 } 324 325 /** @hide */ 326 @SystemApi of(@serIdInt int userId)327 public static UserHandle of(@UserIdInt int userId) { 328 if (userId == USER_SYSTEM) { 329 return SYSTEM; // Most common. 330 } 331 // These are sequential; so use a switch. Maybe they'll be optimized to a table lookup. 332 switch (userId) { 333 case USER_ALL: 334 return ALL; 335 336 case USER_CURRENT: 337 return CURRENT; 338 339 case USER_CURRENT_OR_SELF: 340 return CURRENT_OR_SELF; 341 } 342 if (userId >= MIN_SECONDARY_USER_ID 343 && userId < (MIN_SECONDARY_USER_ID + CACHED_USER_HANDLES.length)) { 344 return CACHED_USER_HANDLES[userId - MIN_SECONDARY_USER_ID]; 345 } 346 if (userId == USER_NULL) { // Not common. 347 return NULL; 348 } 349 return getUserHandleFromExtraCache(userId); 350 } 351 352 /** @hide */ 353 @VisibleForTesting getUserHandleFromExtraCache(@serIdInt int userId)354 public static UserHandle getUserHandleFromExtraCache(@UserIdInt int userId) { 355 synchronized (sExtraUserHandleCache) { 356 final UserHandle extraCached = sExtraUserHandleCache.get(userId); 357 if (extraCached != null) { 358 return extraCached; 359 } 360 if (sExtraUserHandleCache.size() >= MAX_EXTRA_USER_HANDLE_CACHE_SIZE) { 361 sExtraUserHandleCache.removeAt( 362 (new Random()).nextInt(MAX_EXTRA_USER_HANDLE_CACHE_SIZE)); 363 } 364 final UserHandle newHandle = new UserHandle(userId); 365 sExtraUserHandleCache.put(userId, newHandle); 366 return newHandle; 367 } 368 } 369 370 /** 371 * Returns the uid that is composed from the userId and the appId. 372 * @hide 373 */ 374 @UnsupportedAppUsage 375 @TestApi getUid(@serIdInt int userId, @AppIdInt int appId)376 public static int getUid(@UserIdInt int userId, @AppIdInt int appId) { 377 if (MU_ENABLED && appId >= 0) { 378 return userId * PER_USER_RANGE + (appId % PER_USER_RANGE); 379 } else { 380 return appId; 381 } 382 } 383 384 /** 385 * Returns the uid representing the given appId for this UserHandle. 386 * 387 * @param appId the AppId to compose the uid 388 * @return the uid representing the given appId for this UserHandle 389 * @hide 390 */ 391 @SystemApi getUid(@ppIdInt int appId)392 public int getUid(@AppIdInt int appId) { 393 return getUid(getIdentifier(), appId); 394 } 395 396 /** 397 * Returns the app id (or base uid) for a given uid, stripping out the user id from it. 398 * @hide 399 */ 400 @SystemApi getAppId(int uid)401 public static @AppIdInt int getAppId(int uid) { 402 return uid % PER_USER_RANGE; 403 } 404 405 /** 406 * Returns the gid shared between all apps with this userId. 407 * @hide 408 */ getUserGid(@serIdInt int userId)409 public static int getUserGid(@UserIdInt int userId) { 410 return getUid(userId, Process.SHARED_USER_GID); 411 } 412 413 /** 414 * Returns the gid shared between all users with the app that this uid represents, or -1 if the 415 * uid is invalid. 416 * @hide 417 */ 418 @SystemApi getSharedAppGid(int uid)419 public static int getSharedAppGid(int uid) { 420 return getSharedAppGid(getUserId(uid), getAppId(uid)); 421 } 422 423 /** @hide */ getSharedAppGid(@serIdInt int userId, @AppIdInt int appId)424 public static int getSharedAppGid(@UserIdInt int userId, @AppIdInt int appId) { 425 if (appId >= AID_APP_START && appId <= AID_APP_END) { 426 return (appId - AID_APP_START) + AID_SHARED_GID_START; 427 } else if (appId >= AID_ROOT && appId <= AID_APP_START) { 428 return appId; 429 } else { 430 return -1; 431 } 432 } 433 434 /** 435 * Returns the app id for a given shared app gid. Returns -1 if the ID is invalid. 436 * @hide 437 */ 438 @UnsupportedAppUsage getAppIdFromSharedAppGid(int gid)439 public static @AppIdInt int getAppIdFromSharedAppGid(int gid) { 440 final int appId = getAppId(gid) + Process.FIRST_APPLICATION_UID 441 - Process.FIRST_SHARED_APPLICATION_GID; 442 if (appId < 0 || appId >= Process.FIRST_SHARED_APPLICATION_GID) { 443 return -1; 444 } 445 return appId; 446 } 447 448 /** @hide */ getCacheAppGid(int uid)449 public static int getCacheAppGid(int uid) { 450 return getCacheAppGid(getUserId(uid), getAppId(uid)); 451 } 452 453 /** @hide */ getCacheAppGid(@serIdInt int userId, @AppIdInt int appId)454 public static int getCacheAppGid(@UserIdInt int userId, @AppIdInt int appId) { 455 if (appId >= AID_APP_START && appId <= AID_APP_END) { 456 return getUid(userId, (appId - AID_APP_START) + AID_CACHE_GID_START); 457 } else { 458 return -1; 459 } 460 } 461 462 /** 463 * Generate a text representation of the uid, breaking out its individual 464 * components -- user, app, isolated, etc. 465 * @hide 466 */ formatUid(StringBuilder sb, int uid)467 public static void formatUid(StringBuilder sb, int uid) { 468 if (uid < Process.FIRST_APPLICATION_UID) { 469 sb.append(uid); 470 } else { 471 sb.append('u'); 472 sb.append(getUserId(uid)); 473 final int appId = getAppId(uid); 474 if (isIsolated(appId)) { 475 if (appId > Process.FIRST_ISOLATED_UID) { 476 sb.append('i'); 477 sb.append(appId - Process.FIRST_ISOLATED_UID); 478 } else { 479 sb.append("ai"); 480 sb.append(appId - Process.FIRST_APP_ZYGOTE_ISOLATED_UID); 481 } 482 } else if (appId >= Process.FIRST_APPLICATION_UID) { 483 sb.append('a'); 484 sb.append(appId - Process.FIRST_APPLICATION_UID); 485 } else { 486 sb.append('s'); 487 sb.append(appId); 488 } 489 } 490 } 491 492 /** 493 * Generate a text representation of the uid, breaking out its individual 494 * components -- user, app, isolated, etc. 495 * 496 * @param uid The uid to format 497 * @return A string representing the UID with its individual components broken out 498 * @hide 499 */ 500 @SystemApi 501 @NonNull formatUid(int uid)502 public static String formatUid(int uid) { 503 StringBuilder sb = new StringBuilder(); 504 formatUid(sb, uid); 505 return sb.toString(); 506 } 507 508 /** 509 * Generate a text representation of the uid, breaking out its individual 510 * components -- user, app, isolated, etc. 511 * @hide 512 */ 513 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) formatUid(PrintWriter pw, int uid)514 public static void formatUid(PrintWriter pw, int uid) { 515 if (uid < Process.FIRST_APPLICATION_UID) { 516 pw.print(uid); 517 } else { 518 pw.print('u'); 519 pw.print(getUserId(uid)); 520 final int appId = getAppId(uid); 521 if (isIsolated(appId)) { 522 if (appId > Process.FIRST_ISOLATED_UID) { 523 pw.print('i'); 524 pw.print(appId - Process.FIRST_ISOLATED_UID); 525 } else { 526 pw.print("ai"); 527 pw.print(appId - Process.FIRST_APP_ZYGOTE_ISOLATED_UID); 528 } 529 } else if (appId >= Process.FIRST_APPLICATION_UID) { 530 pw.print('a'); 531 pw.print(appId - Process.FIRST_APPLICATION_UID); 532 } else { 533 pw.print('s'); 534 pw.print(appId); 535 } 536 } 537 } 538 539 /** @hide */ parseUserArg(String arg)540 public static @UserIdInt int parseUserArg(String arg) { 541 int userId; 542 if ("all".equals(arg)) { 543 userId = UserHandle.USER_ALL; 544 } else if ("current".equals(arg) || "cur".equals(arg)) { 545 userId = UserHandle.USER_CURRENT; 546 } else { 547 try { 548 userId = Integer.parseInt(arg); 549 } catch (NumberFormatException e) { 550 throw new IllegalArgumentException("Bad user number: " + arg); 551 } 552 } 553 return userId; 554 } 555 556 /** 557 * Returns the user id of the current process 558 * @return user id of the current process 559 * @hide 560 */ 561 @SystemApi myUserId()562 public static @UserIdInt int myUserId() { 563 return getUserId(Process.myUid()); 564 } 565 566 /** 567 * Returns true if this UserHandle refers to the owner user; false otherwise. 568 * @return true if this UserHandle refers to the owner user; false otherwise. 569 * @hide 570 * @deprecated please use {@link #isSystem()} or check for 571 * {@link android.content.pm.UserInfo#isPrimary()} 572 * {@link android.content.pm.UserInfo#isAdmin()} based on your particular use case. 573 */ 574 @Deprecated 575 @SystemApi isOwner()576 public boolean isOwner() { 577 return this.equals(OWNER); 578 } 579 580 /** 581 * @return true if this UserHandle refers to the system user; false otherwise. 582 * @hide 583 */ 584 @SystemApi isSystem()585 public boolean isSystem() { 586 return this.equals(SYSTEM); 587 } 588 589 /** @hide */ 590 @UnsupportedAppUsage UserHandle(@serIdInt int userId)591 public UserHandle(@UserIdInt int userId) { 592 mHandle = userId; 593 } 594 595 /** 596 * Returns the userId stored in this UserHandle. 597 * @hide 598 */ 599 @SystemApi getIdentifier()600 public @UserIdInt int getIdentifier() { 601 return mHandle; 602 } 603 604 @Override toString()605 public String toString() { 606 return "UserHandle{" + mHandle + "}"; 607 } 608 609 @Override equals(@ullable Object obj)610 public boolean equals(@Nullable Object obj) { 611 if (obj instanceof UserHandle) { 612 UserHandle other = (UserHandle) obj; 613 return mHandle == other.mHandle; 614 } 615 return false; 616 } 617 618 @Override hashCode()619 public int hashCode() { 620 return mHandle; 621 } 622 describeContents()623 public int describeContents() { 624 return 0; 625 } 626 writeToParcel(Parcel out, int flags)627 public void writeToParcel(Parcel out, int flags) { 628 out.writeInt(mHandle); 629 } 630 631 /** 632 * Write a UserHandle to a Parcel, handling null pointers. Must be 633 * read with {@link #readFromParcel(Parcel)}. 634 * 635 * @param h The UserHandle to be written. 636 * @param out The Parcel in which the UserHandle will be placed. 637 * 638 * @see #readFromParcel(Parcel) 639 */ writeToParcel(UserHandle h, Parcel out)640 public static void writeToParcel(UserHandle h, Parcel out) { 641 if (h != null) { 642 h.writeToParcel(out, 0); 643 } else { 644 out.writeInt(USER_NULL); 645 } 646 } 647 648 /** 649 * Read a UserHandle from a Parcel that was previously written 650 * with {@link #writeToParcel(UserHandle, Parcel)}, returning either 651 * a null or new object as appropriate. 652 * 653 * @param in The Parcel from which to read the UserHandle 654 * @return Returns a new UserHandle matching the previously written 655 * object, or null if a null had been written. 656 * 657 * @see #writeToParcel(UserHandle, Parcel) 658 */ readFromParcel(Parcel in)659 public static UserHandle readFromParcel(Parcel in) { 660 int h = in.readInt(); 661 return h != USER_NULL ? new UserHandle(h) : null; 662 } 663 664 public static final @android.annotation.NonNull Parcelable.Creator<UserHandle> CREATOR 665 = new Parcelable.Creator<UserHandle>() { 666 public UserHandle createFromParcel(Parcel in) { 667 // Try to avoid allocation; use of() here. Keep this and the constructor below 668 // in sync. 669 return UserHandle.of(in.readInt()); 670 } 671 672 public UserHandle[] newArray(int size) { 673 return new UserHandle[size]; 674 } 675 }; 676 677 /** 678 * Instantiate a new UserHandle from the data in a Parcel that was 679 * previously written with {@link #writeToParcel(Parcel, int)}. Note that you 680 * must not use this with data written by 681 * {@link #writeToParcel(UserHandle, Parcel)} since it is not possible 682 * to handle a null UserHandle here. 683 * 684 * @param in The Parcel containing the previously written UserHandle, 685 * positioned at the location in the buffer where it was written. 686 */ UserHandle(Parcel in)687 public UserHandle(Parcel in) { 688 mHandle = in.readInt(); // Keep this and createFromParcel() in sync. 689 } 690 } 691