1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; 4 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; 5 import static android.os.Build.VERSION_CODES.LOLLIPOP; 6 import static android.os.Build.VERSION_CODES.M; 7 import static android.os.Build.VERSION_CODES.N; 8 import static android.os.Build.VERSION_CODES.N_MR1; 9 import static android.os.Build.VERSION_CODES.R; 10 11 import static org.robolectric.shadow.api.Shadow.directlyOn; 12 13 import android.Manifest.permission; 14 import android.annotation.NonNull; 15 import android.annotation.UserIdInt; 16 import android.content.Context; 17 import android.content.pm.PackageManager; 18 import android.content.pm.UserInfo; 19 import android.os.Bundle; 20 import android.os.IUserManager; 21 import android.os.Process; 22 import android.os.UserHandle; 23 import android.os.UserManager; 24 25 import com.google.common.collect.BiMap; 26 import com.google.common.collect.HashBiMap; 27 import com.google.common.collect.ImmutableList; 28 29 import org.robolectric.annotation.Implementation; 30 import org.robolectric.annotation.Implements; 31 import org.robolectric.annotation.RealObject; 32 import org.robolectric.annotation.Resetter; 33 import org.robolectric.util.ReflectionHelpers.ClassParameter; 34 35 import java.util.ArrayList; 36 import java.util.Collections; 37 import java.util.HashMap; 38 import java.util.List; 39 import java.util.Map; 40 import java.util.stream.Collectors; 41 42 /** 43 * Robolectric implementation of {@link android.os.UserManager}. 44 */ 45 @Implements(value = UserManager.class, minSdk = JELLY_BEAN_MR1) 46 public class ShadowUserManager { 47 48 /** 49 * The default user ID user for secondary user testing, when the ID is not otherwise specified. 50 */ 51 public static final int DEFAULT_SECONDARY_USER_ID = 10; 52 53 public static final int FLAG_PRIMARY = UserInfo.FLAG_PRIMARY; 54 public static final int FLAG_ADMIN = UserInfo.FLAG_ADMIN; 55 public static final int FLAG_GUEST = UserInfo.FLAG_GUEST; 56 public static final int FLAG_RESTRICTED = UserInfo.FLAG_RESTRICTED; 57 public static final int FLAG_MANAGED_PROFILE = UserInfo.FLAG_MANAGED_PROFILE; 58 59 private static Map<Integer, Integer> userPidMap = new HashMap<>(); 60 61 @RealObject private UserManager realObject; 62 63 private boolean userUnlocked = true; 64 private boolean managedProfile = false; 65 private boolean isSystemUser = true; 66 private Map<Integer, Bundle> userRestrictions = new HashMap<>(); 67 private BiMap<UserHandle, Long> userProfiles = HashBiMap.create(); 68 private Map<String, Bundle> applicationRestrictions = new HashMap<>(); 69 private long nextUserSerial = 0; 70 private Map<Integer, UserState> userState = new HashMap<>(); 71 private Map<Integer, UserInfo> userInfoMap = new HashMap<>(); 72 private Map<Integer, List<UserInfo>> profiles = new HashMap<>(); 73 private Map<Integer, Integer> profileToParent = new HashMap<>(); 74 75 private Context context; 76 private boolean enforcePermissions; 77 private boolean canSwitchUser = false; 78 79 @Implementation __constructor__(Context context, IUserManager service)80 protected void __constructor__(Context context, IUserManager service) { 81 this.context = context; 82 addUser(UserHandle.USER_SYSTEM, "system_user", UserInfo.FLAG_PRIMARY | UserInfo.FLAG_ADMIN); 83 } 84 85 /** 86 * Compared to real Android, there is no check that the package name matches the application 87 * package name and the method returns instantly. 88 * 89 * @see #setApplicationRestrictions(String, Bundle) 90 */ 91 @Implementation(minSdk = JELLY_BEAN_MR2) getApplicationRestrictions(String packageName)92 protected Bundle getApplicationRestrictions(String packageName) { 93 Bundle bundle = applicationRestrictions.get(packageName); 94 return bundle != null ? bundle : new Bundle(); 95 } 96 97 /** 98 * Sets the value returned by {@link UserManager#getApplicationRestrictions(String)}. 99 */ setApplicationRestrictions(String packageName, Bundle restrictions)100 public void setApplicationRestrictions(String packageName, Bundle restrictions) { 101 applicationRestrictions.put(packageName, restrictions); 102 } 103 104 /** 105 * Adds a profile associated for the user that the calling process is running on. 106 * 107 * The user is assigned an arbitrary unique serial number. 108 * 109 * @return the user's serial number 110 */ addUserProfile(UserHandle userHandle)111 public long addUserProfile(UserHandle userHandle) { 112 long serialNumber = nextUserSerial++; 113 userProfiles.put(userHandle, serialNumber); 114 return serialNumber; 115 } 116 117 @Implementation(minSdk = LOLLIPOP) getUserProfiles()118 protected List<UserHandle> getUserProfiles() { 119 return ImmutableList.copyOf(userProfiles.keySet()); 120 } 121 122 @Implementation getAllProfiles()123 public List<UserHandle> getAllProfiles() { 124 return getUserProfiles(); 125 } 126 127 /** 128 * If any profiles have been added using {@link #addProfile}, return those profiles. 129 * 130 * Otherwise follow real android behaviour. 131 */ 132 @Implementation(minSdk = LOLLIPOP) getProfiles(int userHandle)133 protected List<UserInfo> getProfiles(int userHandle) { 134 if (profiles.containsKey(userHandle)) { 135 return ImmutableList.copyOf(profiles.get(userHandle)); 136 } 137 138 if (profileToParent.containsKey(userHandle) 139 && profiles.containsKey(profileToParent.get(userHandle))) { 140 return ImmutableList.copyOf(profiles.get(profileToParent.get(userHandle))); 141 } 142 143 return directlyOn( 144 realObject, UserManager.class, "getProfiles", ClassParameter.from(int.class, userHandle)); 145 } 146 147 /** Add a profile to be returned by {@link #getProfiles(int)}.**/ addProfile( int userHandle, int profileUserHandle, String profileName, int profileFlags)148 public void addProfile( 149 int userHandle, int profileUserHandle, String profileName, int profileFlags) { 150 UserInfo userInfo = new UserInfo(profileUserHandle, profileName, profileFlags); 151 profiles.putIfAbsent(userHandle, new ArrayList<>()); 152 profiles.get(userHandle).add(userInfo); 153 userInfoMap.put(profileUserHandle, userInfo); 154 profileToParent.put(profileUserHandle, userHandle); 155 } 156 157 /** 158 * If this profile has been added using {@link #addProfile}, return its parent. 159 */ 160 @Implementation(minSdk = LOLLIPOP) getProfileParent(int userHandle)161 protected UserInfo getProfileParent(int userHandle) { 162 if (!profileToParent.containsKey(userHandle)) { 163 return null; 164 } 165 return userInfoMap.get(profileToParent.get(userHandle)); 166 } 167 168 @Implementation(minSdk = N) isUserUnlocked()169 protected boolean isUserUnlocked() { 170 return userUnlocked; 171 } 172 173 /** 174 * Setter for {@link UserManager#isUserUnlocked()} 175 */ setUserUnlocked(boolean userUnlocked)176 public void setUserUnlocked(boolean userUnlocked) { 177 this.userUnlocked = userUnlocked; 178 } 179 180 /** 181 * If permissions are enforced (see {@link #enforcePermissionChecks(boolean)}) and the application 182 * doesn't have the {@link android.Manifest.permission#MANAGE_USERS} permission, throws a 183 * {@link SecurityManager} exception. 184 * 185 * @return `false` by default, or the value specified via {@link #setManagedProfile(boolean)} 186 * @see #enforcePermissionChecks(boolean) 187 * @see #setManagedProfile(boolean) 188 */ 189 @Implementation(minSdk = LOLLIPOP) isManagedProfile()190 protected boolean isManagedProfile() { 191 if (enforcePermissions && !hasManageUsersPermission()) { 192 throw new SecurityException( 193 "You need MANAGE_USERS permission to: check if specified user a " + 194 "managed profile outside your profile group"); 195 } 196 return managedProfile; 197 } 198 199 /** 200 * If permissions are enforced (see {@link #enforcePermissionChecks(boolean)}) and the application 201 * doesn't have the {@link android.Manifest.permission#MANAGE_USERS} permission, throws a {@link 202 * SecurityManager} exception. 203 * 204 * @return true if the profile added has FLAG_MANAGED_PROFILE 205 * @see #enforcePermissionChecks(boolean) 206 * @see #addProfile(int, int, String, int) 207 * @see #addUser(int, String, int) 208 */ 209 @Implementation(minSdk = N) isManagedProfile(int userHandle)210 protected boolean isManagedProfile(int userHandle) { 211 if (enforcePermissions && !hasManageUsersPermission()) { 212 throw new SecurityException( 213 "You need MANAGE_USERS permission to: check if specified user a " 214 + "managed profile outside your profile group"); 215 } 216 UserInfo info = getUserInfo(userHandle); 217 return info != null && ((info.flags & FLAG_MANAGED_PROFILE) == FLAG_MANAGED_PROFILE); 218 } 219 220 // BEGIN-INTERNAL 221 @Implementation(minSdk = R) isProfile()222 protected boolean isProfile() { 223 return isManagedProfile(); 224 } 225 226 /** 227 * Compared to real Android, userId is not used, instead 228 * managedProfile determines if user has badge. 229 * 230 * @param userId ignored, uses managedProfile field 231 * @return true if managedProfile field is true 232 */ 233 @Implementation(minSdk = R) hasBadge(int userId)234 protected boolean hasBadge(int userId) { 235 return isProfile(); 236 } 237 // END-INTERNAL 238 enforcePermissionChecks(boolean enforcePermissions)239 public void enforcePermissionChecks(boolean enforcePermissions) { 240 this.enforcePermissions = enforcePermissions; 241 } 242 243 /** 244 * Setter for {@link UserManager#isManagedProfile()}. 245 */ setManagedProfile(boolean managedProfile)246 public void setManagedProfile(boolean managedProfile) { 247 this.managedProfile = managedProfile; 248 } 249 250 @Implementation(minSdk = LOLLIPOP) hasUserRestriction(String restrictionKey, UserHandle userHandle)251 protected boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) { 252 Bundle bundle = userRestrictions.get(userHandle.getIdentifier()); 253 return bundle != null && bundle.getBoolean(restrictionKey); 254 } 255 256 // BEGIN-INTERNAL 257 @Implementation(minSdk = R) hasUserRestrictionForUser(String restrictionKey, UserHandle userHandle)258 protected boolean hasUserRestrictionForUser(String restrictionKey, UserHandle userHandle) { 259 return hasUserRestriction(restrictionKey, userHandle); 260 } 261 // END-INTERNAL 262 setUserRestriction(UserHandle userHandle, String restrictionKey, boolean value)263 public void setUserRestriction(UserHandle userHandle, String restrictionKey, boolean value) { 264 Bundle bundle = getUserRestrictionsForUser(userHandle); 265 bundle.putBoolean(restrictionKey, value); 266 } 267 268 @Implementation(minSdk = JELLY_BEAN_MR2) setUserRestriction(String key, boolean value)269 protected void setUserRestriction(String key, boolean value) { 270 Bundle bundle = getUserRestrictionsForUser(Process.myUserHandle()); 271 bundle.putBoolean(key, value); 272 } 273 274 /** 275 * Removes all user restrictions set of a user identified by {@code userHandle}. 276 */ clearUserRestrictions(UserHandle userHandle)277 public void clearUserRestrictions(UserHandle userHandle) { 278 userRestrictions.remove(userHandle.getIdentifier()); 279 } 280 281 @Implementation(minSdk = JELLY_BEAN_MR2) getUserRestrictions(UserHandle userHandle)282 protected Bundle getUserRestrictions(UserHandle userHandle) { 283 return new Bundle(getUserRestrictionsForUser(userHandle)); 284 } 285 getUserRestrictionsForUser(UserHandle userHandle)286 private Bundle getUserRestrictionsForUser(UserHandle userHandle) { 287 Bundle bundle = userRestrictions.get(userHandle.getIdentifier()); 288 if (bundle == null) { 289 bundle = new Bundle(); 290 userRestrictions.put(userHandle.getIdentifier(), bundle); 291 } 292 return bundle; 293 } 294 295 /** 296 * @see #addUserProfile(UserHandle) 297 */ 298 @Implementation getSerialNumberForUser(UserHandle userHandle)299 protected long getSerialNumberForUser(UserHandle userHandle) { 300 Long result = userProfiles.get(userHandle); 301 return result == null ? -1L : result; 302 } 303 304 /** 305 * @deprecated prefer {@link #addUserProfile(UserHandle)} to ensure consistency of profiles known 306 * to the {@link UserManager}. Furthermore, calling this method for the current user, i.e: {@link 307 * Process#myUserHandle()} is no longer necessary as this user is always known to UserManager and 308 * has a preassigned serial number. 309 */ 310 @Deprecated setSerialNumberForUser(UserHandle userHandle, long serialNumber)311 public void setSerialNumberForUser(UserHandle userHandle, long serialNumber) { 312 userProfiles.put(userHandle, serialNumber); 313 } 314 315 /** 316 * @see #addUserProfile(UserHandle) 317 */ 318 @Implementation getUserForSerialNumber(long serialNumber)319 protected UserHandle getUserForSerialNumber(long serialNumber) { 320 return userProfiles.inverse().get(serialNumber); 321 } 322 323 /** 324 * @see #addProfile(int, int, String, int) 325 * @see #addUser(int, String, int) 326 */ 327 @Implementation getUserSerialNumber(@serIdInt int userHandle)328 protected int getUserSerialNumber(@UserIdInt int userHandle) { 329 Long result = userProfiles.get(UserHandle.of(userHandle)); 330 return result != null ? result.intValue() : -1; 331 } 332 hasManageUsersPermission()333 private boolean hasManageUsersPermission() { 334 return context.getPackageManager().checkPermission(permission.MANAGE_USERS, context.getPackageName()) == PackageManager.PERMISSION_GRANTED; 335 } 336 checkPermissions()337 private void checkPermissions() { 338 // TODO Ensure permisions 339 // throw new SecurityException("You need INTERACT_ACROSS_USERS or MANAGE_USERS 340 // permission " 341 // + "to: check " + name);throw new SecurityException(); 342 } 343 344 /** 345 * @return `false` by default, or the value specified via {@link #setIsDemoUser(boolean)} 346 */ 347 @Implementation(minSdk = N_MR1) isDemoUser()348 protected boolean isDemoUser() { 349 return getUserInfo(UserHandle.myUserId()).isDemo(); 350 } 351 352 /** 353 * Sets that the current user is a demo user; controls the return value of {@link 354 * UserManager#isDemoUser()}. 355 * 356 * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a demo user 357 * instead of changing default user flags. 358 */ 359 @Deprecated setIsDemoUser(boolean isDemoUser)360 public void setIsDemoUser(boolean isDemoUser) { 361 UserInfo userInfo = getUserInfo(UserHandle.myUserId()); 362 if (isDemoUser) { 363 userInfo.flags |= UserInfo.FLAG_DEMO; 364 } else { 365 userInfo.flags &= ~UserInfo.FLAG_DEMO; 366 } 367 } 368 369 /** 370 * @return {@code false} by default, or the value specified via {@link #setIsAdminUser(boolean)} 371 */ 372 @Implementation(minSdk = N_MR1) isAdminUser()373 public boolean isAdminUser() { 374 return getUserInfo(UserHandle.myUserId()).isAdmin(); 375 } 376 377 /** 378 * Sets that the current user is an admin user; controls the return value of 379 * {@link UserManager#isAdminUser}. 380 */ setIsAdminUser(boolean isAdminUser)381 public void setIsAdminUser(boolean isAdminUser) { 382 UserInfo userInfo = getUserInfo(UserHandle.myUserId()); 383 if (isAdminUser) { 384 userInfo.flags |= UserInfo.FLAG_ADMIN; 385 } else { 386 userInfo.flags &= ~UserInfo.FLAG_ADMIN; 387 } 388 } 389 390 /** 391 * @return 'true' by default, or the value specified via {@link #setIsSystemUser(boolean)} 392 */ 393 @Implementation(minSdk = M) isSystemUser()394 protected boolean isSystemUser() { 395 if (isSystemUser == false) { 396 return false; 397 } else { 398 return directlyOn(realObject, UserManager.class, "isSystemUser"); 399 } 400 } 401 402 /** 403 * Sets that the current user is the system user; controls the return value of {@link 404 * UserManager#isSystemUser()}. 405 * 406 * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a system user 407 * instead of changing default user flags. 408 */ 409 @Deprecated setIsSystemUser(boolean isSystemUser)410 public void setIsSystemUser(boolean isSystemUser) { 411 this.isSystemUser = isSystemUser; 412 } 413 414 /** 415 * Sets that the current user is the primary user; controls the return value of {@link 416 * UserManager#isPrimaryUser()}. 417 * 418 * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a primary user 419 * instead of changing default user flags. 420 */ 421 @Deprecated setIsPrimaryUser(boolean isPrimaryUser)422 public void setIsPrimaryUser(boolean isPrimaryUser) { 423 UserInfo userInfo = getUserInfo(UserHandle.myUserId()); 424 if (isPrimaryUser) { 425 userInfo.flags |= UserInfo.FLAG_PRIMARY; 426 } else { 427 userInfo.flags &= ~UserInfo.FLAG_PRIMARY; 428 } 429 } 430 431 /** 432 * @return 'false' by default, or the value specified via {@link #setIsLinkedUser(boolean)} 433 */ 434 @Implementation(minSdk = JELLY_BEAN_MR2) isLinkedUser()435 protected boolean isLinkedUser() { 436 return getUserInfo(UserHandle.myUserId()).isRestricted(); 437 } 438 439 /** 440 * Sets that the current user is the linked user; controls the return value of {@link 441 * UserManager#isLinkedUser()}. 442 * 443 * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a linked user 444 * instead of changing default user flags. 445 */ 446 @Deprecated setIsLinkedUser(boolean isLinkedUser)447 public void setIsLinkedUser(boolean isLinkedUser) { 448 UserInfo userInfo = getUserInfo(UserHandle.myUserId()); 449 if (isLinkedUser) { 450 userInfo.flags |= UserInfo.FLAG_RESTRICTED; 451 } else { 452 userInfo.flags &= ~UserInfo.FLAG_RESTRICTED; 453 } 454 } 455 456 /** 457 * Sets that the current user is the guest user; controls the return value of {@link 458 * UserManager#isGuestUser()}. 459 * 460 * @deprecated Use {@link ShadowUserManager#addUser(int, String, int)} to create a guest user 461 * instead of changing default user flags. 462 */ 463 @Deprecated setIsGuestUser(boolean isGuestUser)464 public void setIsGuestUser(boolean isGuestUser) { 465 UserInfo userInfo = getUserInfo(UserHandle.myUserId()); 466 if (isGuestUser) { 467 userInfo.flags |= UserInfo.FLAG_GUEST; 468 } else { 469 userInfo.flags &= ~UserInfo.FLAG_GUEST; 470 } 471 } 472 473 /** 474 * @see #setUserState(UserHandle, UserState) 475 */ 476 @Implementation isUserRunning(UserHandle handle)477 protected boolean isUserRunning(UserHandle handle) { 478 checkPermissions(); 479 UserState state = userState.get(handle.getIdentifier()); 480 481 if (state == UserState.STATE_RUNNING_LOCKED 482 || state == UserState.STATE_RUNNING_UNLOCKED 483 || state == UserState.STATE_RUNNING_UNLOCKING) { 484 return true; 485 } else { 486 return false; 487 } 488 } 489 490 /** 491 * @see #setUserState(UserHandle, UserState) 492 */ 493 @Implementation isUserRunningOrStopping(UserHandle handle)494 protected boolean isUserRunningOrStopping(UserHandle handle) { 495 checkPermissions(); 496 UserState state = userState.get(handle.getIdentifier()); 497 498 if (state == UserState.STATE_RUNNING_LOCKED 499 || state == UserState.STATE_RUNNING_UNLOCKED 500 || state == UserState.STATE_RUNNING_UNLOCKING 501 || state == UserState.STATE_STOPPING) { 502 return true; 503 } else { 504 return false; 505 } 506 } 507 508 /** 509 * Describes the current state of the user. State can be set using 510 * {@link #setUserState(UserHandle, UserState)}. 511 */ 512 public enum UserState { 513 // User is first coming up. 514 STATE_BOOTING, 515 // User is in the locked state. 516 STATE_RUNNING_LOCKED, 517 // User is in the unlocking state. 518 STATE_RUNNING_UNLOCKING, 519 // User is in the running state. 520 STATE_RUNNING_UNLOCKED, 521 // User is in the initial process of being stopped. 522 STATE_STOPPING, 523 // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN. 524 STATE_SHUTDOWN 525 } 526 527 /** 528 * Sets the current state for a given user, see {@link UserManager#isUserRunning(UserHandle)} 529 * and {@link UserManager#isUserRunningOrStopping(UserHandle)} 530 */ setUserState(UserHandle handle, UserState state)531 public void setUserState(UserHandle handle, UserState state) { 532 userState.put(handle.getIdentifier(), state); 533 } 534 535 @Implementation getUsers()536 protected List<UserInfo> getUsers() { 537 return new ArrayList<UserInfo>(userInfoMap.values()); 538 } 539 540 @Implementation getUserInfo(int userHandle)541 protected UserInfo getUserInfo(int userHandle) { 542 return userInfoMap.get(userHandle); 543 } 544 545 /** 546 * Returns {@code true} by default, or the value specified via {@link #setCanSwitchUser(boolean)}. 547 */ 548 @Implementation(minSdk = N) canSwitchUsers()549 protected boolean canSwitchUsers() { 550 return canSwitchUser; 551 } 552 553 /** 554 * Sets whether switching users is allowed or not; controls the return value of {@link 555 * UserManager#canSwitchUser()} 556 */ setCanSwitchUser(boolean canSwitchUser)557 public void setCanSwitchUser(boolean canSwitchUser) { 558 this.canSwitchUser = canSwitchUser; 559 } 560 561 @Implementation(minSdk = JELLY_BEAN_MR1) removeUser(int userHandle)562 protected boolean removeUser(int userHandle) { 563 userInfoMap.remove(userHandle); 564 return true; 565 } 566 567 // BEGIN-INTERNAL 568 @Implementation(minSdk = R) createProfileForUserEvenWhenDisallowed(String name, @NonNull String userType, @UserInfo.UserInfoFlag int flags, @UserIdInt int userId, String[] disallowedPackages)569 protected UserInfo createProfileForUserEvenWhenDisallowed(String name, 570 @NonNull String userType, @UserInfo.UserInfoFlag int flags, @UserIdInt int userId, 571 String[] disallowedPackages) throws UserManager.UserOperationException { 572 List<UserInfo> userIdProfiles = profiles.computeIfAbsent(userId, ignored -> new ArrayList<>()); 573 int profileUserId = userIdProfiles.isEmpty() ? 10 : findMaxProfileId(userIdProfiles) + 1; 574 UserInfo profileUserInfo = new UserInfo(profileUserId, name, flags); 575 userIdProfiles.add(profileUserInfo); 576 profileToParent.put(profileUserId, userId); 577 addUserProfile(UserHandle.of(profileUserId)); 578 return profileUserInfo; 579 } 580 581 /** Assumes the given list of profile infos is non-empty. */ findMaxProfileId(List<UserInfo> userIdProfiles)582 private int findMaxProfileId(List<UserInfo> userIdProfiles) { 583 return Collections.max( 584 userIdProfiles.stream() 585 .map(userInfo -> userInfo.id) 586 .collect(Collectors.toList())); 587 } 588 // END-INTERNAL 589 590 /** 591 * Switches the current user to {@code userHandle}. 592 * 593 * @param userId the integer handle of the user, where 0 is the primary user. 594 */ switchUser(int userId)595 public void switchUser(int userId) { 596 if (!userInfoMap.containsKey(userId)) { 597 throw new UnsupportedOperationException("Must add user before switching to it"); 598 } 599 600 ShadowProcess.setUid(userPidMap.get(userId)); 601 } 602 603 /** 604 * Creates a user with the specified name, userId and flags. 605 * 606 * @param id the unique id of user 607 * @param name name of the user 608 * @param flags 16 bits for user type. See {@link UserInfo#flags} 609 */ addUser(int id, String name, int flags)610 public void addUser(int id, String name, int flags) { 611 UserHandle userHandle = 612 id == UserHandle.USER_SYSTEM ? Process.myUserHandle() : new UserHandle(id); 613 addUserProfile(userHandle); 614 setSerialNumberForUser(userHandle, (long) id); 615 profiles.putIfAbsent(id, new ArrayList<>()); 616 userInfoMap.put(id, new UserInfo(id, name, flags)); 617 userPidMap.put( 618 id, 619 id == UserHandle.USER_SYSTEM 620 ? Process.myUid() 621 : id * UserHandle.PER_USER_RANGE + ShadowProcess.getRandomApplicationUid()); 622 } 623 624 @Resetter reset()625 public static void reset() { 626 if (userPidMap != null && userPidMap.isEmpty() == false) { 627 ShadowProcess.setUid(userPidMap.get(UserHandle.USER_SYSTEM)); 628 629 userPidMap.clear(); 630 userPidMap.put(UserHandle.USER_SYSTEM, Process.myUid()); 631 } 632 } 633 } 634