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