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