Add CarUserManager API

- Car-specific user management APIs are added to CarUserManager.
- ICarUserService binder interface is defined.
- Remove CarUserService's dependency on CarUserManagerHelper.
- Unit tests for the newly added interface are implemented.

Bug: 139743504
Test: Run CarUserServiceTest.
Change-Id: I50f148a920f15a36aad6863d604ada12702f1ebf
diff --git a/service/src/com/android/car/user/CarUserService.java b/service/src/com/android/car/user/CarUserService.java
index 0c3222d4..8436fe7 100644
--- a/service/src/com/android/car/user/CarUserService.java
+++ b/service/src/com/android/car/user/CarUserService.java
@@ -16,16 +16,21 @@
 
 package com.android.car.user;
 
+import static com.android.car.CarLog.TAG_USER;
+
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.IActivityManager;
+import android.car.ICarUserService;
 import android.car.settings.CarSettings;
-import android.car.userlib.CarUserManagerHelper;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
+import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
 import android.location.LocationManager;
+import android.os.Binder;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -35,27 +40,61 @@
 import com.android.car.CarServiceBase;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.UserIcons;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
  * User service for cars. Manages users at boot time. Including:
  *
  * <ol>
+ *   <li> Creates a user used as driver.
+ *   <li> Creates a user used as passenger.
  *   <li> Creates a secondary admin user on first run.
- *   <li> Log in to the last active user.
+ *   <li> Switch drivers.
  * <ol/>
  */
-public class CarUserService extends BroadcastReceiver implements CarServiceBase {
-    private static final String TAG = "CarUserService";
+public final class CarUserService extends ICarUserService.Stub implements CarServiceBase {
     private final Context mContext;
-    private final CarUserManagerHelper mCarUserManagerHelper;
     private final IActivityManager mAm;
     private final UserManager mUserManager;
     private final int mMaxRunningUsers;
 
+    /**
+     * Default restrictions for Non-Admin users.
+     */
+    private static final String[] DEFAULT_NON_ADMIN_RESTRICTIONS = new String[] {
+            UserManager.DISALLOW_FACTORY_RESET
+    };
+
+    /**
+     * Default restrictions for Guest users.
+     */
+    private static final String[] DEFAULT_GUEST_RESTRICTIONS = new String[] {
+            UserManager.DISALLOW_FACTORY_RESET,
+            UserManager.DISALLOW_REMOVE_USER,
+            UserManager.DISALLOW_MODIFY_ACCOUNTS,
+            UserManager.DISALLOW_INSTALL_APPS,
+            UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+            UserManager.DISALLOW_UNINSTALL_APPS
+    };
+
+    /**
+     * List of restrictions relaxed for Non-Admin users.
+     *
+     * <p>Each non-admin has sms and outgoing call restrictions applied by the UserManager on
+     * creation. We want to enable these permissions by default in the car.
+     */
+    private static final String[] RELAXED_RESTRICTIONS_FOR_NON_ADMIN = new String[] {
+            UserManager.DISALLOW_SMS,
+            UserManager.DISALLOW_OUTGOING_CALLS
+    };
+
     private final Object mLock = new Object();
     @GuardedBy("mLock")
     private boolean mUser0Unlocked;
@@ -78,19 +117,17 @@
     /** Interface for callbacks related to user activities. */
     public interface UserCallback {
         /** Gets called when user lock status has been changed. */
-        void onUserLockChanged(int userId, boolean unlocked);
+        void onUserLockChanged(@UserIdInt int userId, boolean unlocked);
         /** Called when new foreground user started to boot. */
-        void onSwitchUser(int userId);
+        void onSwitchUser(@UserIdInt int userId);
     }
 
-    public CarUserService(
-            @Nullable Context context, @Nullable CarUserManagerHelper carUserManagerHelper,
-            UserManager userManager, IActivityManager am, int maxRunningUsers) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "constructed");
+    public CarUserService(@NonNull Context context, @NonNull UserManager userManager,
+            @NonNull IActivityManager am, int maxRunningUsers) {
+        if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+            Log.d(TAG_USER, "constructed");
         }
         mContext = context;
-        mCarUserManagerHelper = carUserManagerHelper;
         mAm = am;
         mMaxRunningUsers = maxRunningUsers;
         mUserManager = userManager;
@@ -98,100 +135,221 @@
 
     @Override
     public void init() {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "init");
+        if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+            Log.d(TAG_USER, "init");
         }
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
-
-        mContext.registerReceiver(this, filter);
     }
 
     @Override
     public void release() {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "release");
+        if (Log.isLoggable(TAG_USER, Log.DEBUG)) {
+            Log.d(TAG_USER, "release");
         }
-        mContext.unregisterReceiver(this);
     }
 
     @Override
-    public void dump(PrintWriter writer) {
-        writer.println(TAG);
-        boolean user0Unlocked;
-        ArrayList<Integer> backgroundUsersToRestart;
-        ArrayList<Integer> backgroundUsersRestarted;
+    public void dump(@NonNull PrintWriter writer) {
+        writer.println("*CarUserService*");
         synchronized (mLock) {
-            user0Unlocked = mUser0Unlocked;
-            backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
-            backgroundUsersRestarted = new ArrayList<>(mBackgroundUsersRestartedHere);
-
+            writer.println("User0Unlocked: " + mUser0Unlocked);
+            writer.println("MaxRunningUsers: " + mMaxRunningUsers);
+            writer.println("BackgroundUsersToRestart: " + mBackgroundUsersToRestart);
+            writer.println("BackgroundUsersRestarted: " + mBackgroundUsersRestartedHere);
+            writer.println("NumberOfDrivers: " + getAllDrivers().size());
         }
-        writer.println("User0Unlocked: " + user0Unlocked);
-        writer.println("maxRunningUsers:" + mMaxRunningUsers);
-        writer.println("BackgroundUsersToRestart:" + backgroundUsersToRestart);
-        writer.println("BackgroundUsersRestarted:" + backgroundUsersRestarted);
+    }
+
+    /**
+     * @see CarUserManager.createDriver
+     */
+    @Override
+    @Nullable
+    public UserInfo createDriver(@NonNull String name, boolean admin) {
+        checkManageUsersPermission("createDriver");
+        Preconditions.checkNotNull(name, "name cannot be null");
+        if (admin) {
+            return createNewAdminUser(name);
+        }
+        return createNewNonAdminUser(name);
+    }
+
+    /**
+     * @see CarUserManager.createPassenger
+     */
+    @Override
+    @Nullable
+    public UserInfo createPassenger(@NonNull String name, @UserIdInt int driverId) {
+        checkManageUsersPermission("createPassenger");
+        Preconditions.checkNotNull(name, "name cannot be null");
+        UserInfo driver = mUserManager.getUserInfo(driverId);
+        if (driver == null) {
+            Log.w(TAG_USER, "the driver is invalid");
+            return null;
+        }
+        if (driver.isGuest()) {
+            Log.w(TAG_USER, "a guest driver cannot create a passenger");
+            return null;
+        }
+        UserInfo user = mUserManager.createProfileForUser(name, UserInfo.FLAG_MANAGED_PROFILE,
+                driverId);
+        if (user == null) {
+            // Couldn't create user, most likely because there are too many.
+            Log.w(TAG_USER, "can't create a profile for user" + driverId);
+            return null;
+        }
+        // Passenger user should be a non-admin user.
+        setDefaultNonAdminRestrictions(user, /* enable= */ true);
+        assignDefaultIcon(user);
+        return user;
+    }
+
+    /**
+     * @see CarUserManager.switchDriver
+     */
+    @Override
+    public boolean switchDriver(@UserIdInt int driverId) {
+        checkManageUsersPermission("switchDriver");
+        if (driverId == UserHandle.USER_SYSTEM && UserManager.isHeadlessSystemUserMode()) {
+            // System user doesn't associate with real person, can not be switched to.
+            Log.w(TAG_USER, "switching to system user in headless system user mode is not allowed");
+            return false;
+        }
+        int userSwitchable = mUserManager.getUserSwitchability();
+        if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
+            Log.w(TAG_USER, "current process is not allowed to switch user");
+            return false;
+        }
+        if (driverId == getCurrentUserId()) {
+            // The current user is already the given user.
+            return true;
+        }
+        try {
+            return mAm.switchUser(driverId);
+        } catch (RemoteException e) {
+            // ignore
+            Log.w(TAG_USER, "error while switching user", e);
+        }
+        return false;
+    }
+
+    /**
+     * @see CarUserManager.getAllDrivers
+     */
+    @Override
+    @NonNull
+    public List<UserInfo> getAllDrivers() {
+        checkManageUsersPermission("getAllDrivers");
+        return getUsers((user) -> {
+            return !isSystemUser(user.id) && user.isEnabled() && !user.isManagedProfile()
+                    && !user.isEphemeral();
+        });
+    }
+
+    /**
+     * @see CarUserManager.getPassengers
+     * @return
+     */
+    @Override
+    @NonNull
+    public List<UserInfo> getPassengers(@UserIdInt int driverId) {
+        checkManageUsersPermission("getPassengers");
+        return getUsers((user) -> {
+            return !isSystemUser(user.id) && user.isEnabled() && user.isManagedProfile()
+                    && user.profileGroupId == driverId;
+        });
+    }
+
+    /**
+     * @see CarUserManager.startPassenger
+     */
+    @Override
+    public boolean startPassenger(@UserIdInt int passengerId, int zoneId) {
+        checkManageUsersPermission("startPassenger");
+        // TODO(b/139190199): this method will be implemented when dynamic profile group is enabled.
+        return false;
+    }
+
+    /**
+     * @see CarUserManager.stopPassenger
+     */
+    @Override
+    public boolean stopPassenger(@UserIdInt int passengerId) {
+        checkManageUsersPermission("stopPassenger");
+        // TODO(b/139190199): this method will be implemented when dynamic profile group is enabled.
+        return false;
+    }
+
+    /** Returns whether the given user is a system user. */
+    private static boolean isSystemUser(@UserIdInt int userId) {
+        return userId == UserHandle.USER_SYSTEM;
+    }
+
+    /** Returns whether the user running the current process has a restriction. */
+    private boolean isCurrentProcessUserHasRestriction(String restriction) {
+        return mUserManager.hasUserRestriction(restriction);
     }
 
     private void updateDefaultUserRestriction() {
         // We want to set restrictions on system and guest users only once. These are persisted
         // onto disk, so it's sufficient to do it once + we minimize the number of disk writes.
         if (Settings.Global.getInt(mContext.getContentResolver(),
-                CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) == 0) {
-            // Only apply the system user restrictions if the system user is headless.
-            if (mCarUserManagerHelper.isHeadlessSystemUser()) {
-                setSystemUserRestrictions();
-            }
-            mCarUserManagerHelper.initDefaultGuestRestrictions();
-            Settings.Global.putInt(mContext.getContentResolver(),
-                    CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
+                CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, /* default= */ 0) != 0) {
+            return;
         }
+        // Only apply the system user restrictions if the system user is headless.
+        if (UserManager.isHeadlessSystemUserMode()) {
+            setSystemUserRestrictions();
+        }
+        initDefaultGuestRestrictions();
+        Settings.Global.putInt(mContext.getContentResolver(),
+                CarSettings.Global.DEFAULT_USER_RESTRICTIONS_SET, 1);
     }
 
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        if (Log.isLoggable(TAG, Log.DEBUG)) {
-            Log.d(TAG, "onReceive " + intent);
+    /**
+     * Sets default guest restrictions that will be applied every time a Guest user is created.
+     *
+     * <p> Restrictions are written to disk and persistent across boots.
+     */
+    private void initDefaultGuestRestrictions() {
+        Bundle defaultGuestRestrictions = new Bundle();
+        for (String restriction : DEFAULT_GUEST_RESTRICTIONS) {
+            defaultGuestRestrictions.putBoolean(restriction, true);
         }
-
-        if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
-            // Update last active user if the switched-to user is a persistent, non-system user.
-            final int currentUser = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
-            if (currentUser > UserHandle.USER_SYSTEM && isPersistentUser(currentUser)) {
-                mCarUserManagerHelper.setLastActiveUser(currentUser);
-            }
-        }
+        mUserManager.setDefaultGuestRestrictions(defaultGuestRestrictions);
     }
 
-    private boolean isPersistentUser(int userId) {
+    private boolean isPersistentUser(@UserIdInt int userId) {
         return !mUserManager.getUserInfo(userId).isEphemeral();
     }
 
-    /** Add callback to listen to user activity events. */
-    public void addUserCallback(UserCallback callback) {
+    /** Adds callback to listen to user activity events. */
+    public void addUserCallback(@NonNull UserCallback callback) {
+        Preconditions.checkNotNull(callback, "callback cannot be null");
         mUserCallbacks.add(callback);
     }
 
     /** Removes previously added callback to listen user events. */
-    public void removeUserCallback(UserCallback callback) {
+    public void removeUserCallback(@NonNull UserCallback callback) {
+        Preconditions.checkNotNull(callback, "callback cannot be null");
         mUserCallbacks.remove(callback);
     }
 
     /**
-     * Set user lock / unlocking status. This is coming from system server through ICar binder call.
-     * @param userHandle Handle of user
-     * @param unlocked unlocked (=true) or locked (=false)
+     * Sets user lock/unlocking status. This is coming from system server through ICar binder call.
+     *
+     * @param userId User id whoes lock status is changed.
+     * @param unlocked Unlocked (={@code true}) or locked (={@code false}).
      */
-    public void setUserLockStatus(int userHandle, boolean unlocked) {
+    public void setUserLockStatus(@UserIdInt int userId, boolean unlocked) {
         for (UserCallback callback : mUserCallbacks) {
-            callback.onUserLockChanged(userHandle, unlocked);
+            callback.onUserLockChanged(userId, unlocked);
         }
         if (!unlocked) { // nothing else to do when it is locked back.
             return;
         }
         ArrayList<Runnable> tasks = null;
         synchronized (mLock) {
-            if (userHandle == UserHandle.USER_SYSTEM) {
+            if (userId == UserHandle.USER_SYSTEM) {
                 if (!mUser0Unlocked) { // user 0, unlocked, do this only once
                     updateDefaultUserRestriction();
                     tasks = new ArrayList<>(mUser0UnlockTasks);
@@ -199,18 +357,18 @@
                     mUser0Unlocked = unlocked;
                 }
             } else { // none user0
-                Integer user = userHandle;
-                if (isPersistentUser(userHandle)) {
+                Integer user = userId;
+                if (isPersistentUser(userId)) {
                     // current foreground user should stay in top priority.
-                    if (userHandle == mCarUserManagerHelper.getCurrentForegroundUserId()) {
+                    if (userId == getCurrentUserId()) {
                         mBackgroundUsersToRestart.remove(user);
                         mBackgroundUsersToRestart.add(0, user);
                     }
                     // -1 for user 0
                     if (mBackgroundUsersToRestart.size() > (mMaxRunningUsers - 1)) {
-                        final int userToDrop = mBackgroundUsersToRestart.get(
+                        int userToDrop = mBackgroundUsersToRestart.get(
                                 mBackgroundUsersToRestart.size() - 1);
-                        Log.i(TAG, "New user unlocked:" + userHandle
+                        Log.i(TAG_USER, "New user unlocked:" + userId
                                 + ", dropping least recently user from restart list:" + userToDrop);
                         // Drop the least recently used user.
                         mBackgroundUsersToRestart.remove(mBackgroundUsersToRestart.size() - 1);
@@ -219,7 +377,7 @@
             }
         }
         if (tasks != null && tasks.size() > 0) {
-            Log.d(TAG, "User0 unlocked, run queued tasks:" + tasks.size());
+            Log.d(TAG_USER, "User0 unlocked, run queued tasks:" + tasks.size());
             for (Runnable r : tasks) {
                 r.run();
             }
@@ -227,9 +385,11 @@
     }
 
     /**
-     * Start all background users that were active in system.
+     * Starts all background users that were active in system.
+     *
      * @return list of background users started successfully.
      */
+    @NonNull
     public ArrayList<Integer> startAllBackgroundUsers() {
         ArrayList<Integer> users;
         synchronized (mLock) {
@@ -239,7 +399,7 @@
         }
         ArrayList<Integer> startedUsers = new ArrayList<>();
         for (Integer user : users) {
-            if (user == mCarUserManagerHelper.getCurrentForegroundUserId()) {
+            if (user == getCurrentUserId()) {
                 continue;
             }
             try {
@@ -250,7 +410,7 @@
                     } else if (mAm.unlockUser(user, null, null, null)) {
                         startedUsers.add(user);
                     } else { // started but cannot unlock
-                        Log.w(TAG, "Background user started but cannot be unlocked:" + user);
+                        Log.w(TAG_USER, "Background user started but cannot be unlocked:" + user);
                         if (mUserManager.isUserRunning(user)) {
                             // add to started list so that it can be stopped later.
                             startedUsers.add(user);
@@ -259,6 +419,7 @@
                 }
             } catch (RemoteException e) {
                 // ignore
+                Log.w(TAG_USER, "error while starting user in background", e);
             }
         }
         // Keep only users that were re-started in mBackgroundUsersRestartedHere
@@ -275,15 +436,16 @@
     }
 
     /**
-     * Stop all background users that were active in system.
-     * @return true if stopping succeeds.
+     * Stops all background users that were active in system.
+     *
+     * @return whether stopping succeeds.
      */
-    public boolean stopBackgroundUser(int userId) {
+    public boolean stopBackgroundUser(@UserIdInt int userId) {
         if (userId == UserHandle.USER_SYSTEM) {
             return false;
         }
-        if (userId == mCarUserManagerHelper.getCurrentForegroundUserId()) {
-            Log.i(TAG, "stopBackgroundUser, already a fg user:" + userId);
+        if (userId == getCurrentUserId()) {
+            Log.i(TAG_USER, "stopBackgroundUser, already a FG user:" + userId);
             return false;
         }
         try {
@@ -296,11 +458,12 @@
             } else if (r == ActivityManager.USER_OP_IS_CURRENT) {
                 return false;
             } else {
-                Log.i(TAG, "stopBackgroundUser failed, user:" + userId + " err:" + r);
+                Log.i(TAG_USER, "stopBackgroundUser failed, user:" + userId + " err:" + r);
                 return false;
             }
         } catch (RemoteException e) {
             // ignore
+            Log.w(TAG_USER, "error while stopping user", e);
         }
         return true;
     }
@@ -308,20 +471,25 @@
     /**
      * Called when new foreground user started to boot.
      *
-     * @param userHandle user handle of new user
+     * @param userId User id of new user.
      */
-    public void onSwitchUser(int userHandle) {
+    public void onSwitchUser(@UserIdInt int userId) {
+        if (!isSystemUser(userId) && isPersistentUser(userId)) {
+            setLastActiveUser(userId);
+        }
         for (UserCallback callback : mUserCallbacks) {
-            callback.onSwitchUser(userHandle);
+            callback.onSwitchUser(userId);
         }
     }
 
     /**
-     * Run give runnable when user 0 is unlocked. If user 0 is already unlocked, it is
+     * Runs the given runnable when user 0 is unlocked. If user 0 is already unlocked, it is
      * run inside this call.
+     *
      * @param r Runnable to run.
      */
-    public void runOnUser0Unlock(Runnable r) {
+    public void runOnUser0Unlock(@NonNull Runnable r) {
+        Preconditions.checkNotNull(r, "runnable cannot be null");
         boolean runNow = false;
         synchronized (mLock) {
             if (mUser0Unlocked) {
@@ -336,8 +504,9 @@
     }
 
     @VisibleForTesting
-    protected ArrayList<Integer> getBackgroundUsersToRestart() {
-        ArrayList<Integer> backgroundUsersToRestart;
+    @NonNull
+    ArrayList<Integer> getBackgroundUsersToRestart() {
+        ArrayList<Integer> backgroundUsersToRestart = null;
         synchronized (mLock) {
             backgroundUsersToRestart = new ArrayList<>(mBackgroundUsersToRestart);
         }
@@ -355,4 +524,147 @@
                 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
         locationManager.setLocationEnabledForUser(/* enabled= */ false, systemUserHandle);
     }
+
+    /**
+     * Creates a new user on the system, the created user would be granted admin role.
+     *
+     * @param name Name to be given to the newly created user.
+     * @return Newly created admin user, {@code null} if it fails to create a user.
+     */
+    @Nullable
+    private UserInfo createNewAdminUser(String name) {
+        if (!(mUserManager.isAdminUser() || mUserManager.isSystemUser())) {
+            // Only admins or system user can create other privileged users.
+            Log.e(TAG_USER, "Only admin users and system user can create other admins.");
+            return null;
+        }
+
+        UserInfo user = mUserManager.createUser(name, UserInfo.FLAG_ADMIN);
+        if (user == null) {
+            // Couldn't create user, most likely because there are too many.
+            Log.w(TAG_USER, "can't create admin user.");
+            return null;
+        }
+        assignDefaultIcon(user);
+
+        return user;
+    }
+
+    /**
+     * Creates a new non-admin user on the system.
+     *
+     * @param name Name to be given to the newly created user.
+     * @return Newly created non-admin user, {@code null} if failed to create a user.
+     */
+    @Nullable
+    private UserInfo createNewNonAdminUser(String name) {
+        UserInfo user = mUserManager.createUser(name, /* flags= */ 0);
+        if (user == null) {
+            // Couldn't create user, most likely because there are too many.
+            Log.w(TAG_USER, "can't create non-admin user.");
+            return null;
+        }
+        setDefaultNonAdminRestrictions(user, /* enable= */ true);
+
+        // Remove restrictions which are allowed for non-admin car users.
+        for (String restriction : RELAXED_RESTRICTIONS_FOR_NON_ADMIN) {
+            mUserManager.setUserRestriction(restriction, /* enable= */ false, user.getUserHandle());
+        }
+
+        assignDefaultIcon(user);
+        return user;
+    }
+
+    private Bitmap getUserDefaultIcon(UserInfo userInfo) {
+        return UserIcons.convertToBitmap(
+                UserIcons.getDefaultUserIcon(mContext.getResources(), userInfo.id, false));
+    }
+
+    private Bitmap getGuestDefaultIcon() {
+        return UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(mContext.getResources(),
+                UserHandle.USER_NULL, false));
+    }
+
+    /** Assigns a default icon to a user according to the user's id. */
+    private void assignDefaultIcon(UserInfo userInfo) {
+        Bitmap bitmap = userInfo.isGuest()
+                ? getGuestDefaultIcon() : getUserDefaultIcon(userInfo);
+        mUserManager.setUserIcon(userInfo.id, bitmap);
+    }
+
+    private void setDefaultNonAdminRestrictions(UserInfo userInfo, boolean enable) {
+        for (String restriction : DEFAULT_NON_ADMIN_RESTRICTIONS) {
+            mUserManager.setUserRestriction(restriction, enable, userInfo.getUserHandle());
+        }
+    }
+
+    /** Gets the current user on the device. */
+    @VisibleForTesting
+    @UserIdInt
+    int getCurrentUserId() {
+        UserInfo user = getCurrentUser();
+        return user != null ? user.id : UserHandle.USER_NULL;
+    }
+
+    @Nullable
+    private UserInfo getCurrentUser() {
+        UserInfo user = null;
+        try {
+            user = mAm.getCurrentUser();
+        } catch (RemoteException e) {
+            // ignore
+            Log.w(TAG_USER, "error while getting current user", e);
+        }
+        return user;
+    }
+
+    private interface UserFilter {
+        boolean isEligibleUser(UserInfo user);
+    }
+
+    /** Returns all users who are matched by the given filter. */
+    private List<UserInfo> getUsers(UserFilter filter) {
+        List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
+
+        for (Iterator<UserInfo> iterator = users.iterator(); iterator.hasNext(); ) {
+            UserInfo user = iterator.next();
+            if (!filter.isEligibleUser(user)) {
+                iterator.remove();
+            }
+        }
+        return users;
+    }
+
+    /**
+     * Sets last active user.
+     *
+     * @param userId Last active user id.
+     */
+    @VisibleForTesting
+    void setLastActiveUser(@UserIdInt int userId) {
+        Settings.Global.putInt(
+                mContext.getContentResolver(), Settings.Global.LAST_ACTIVE_USER_ID, userId);
+    }
+
+    /**
+     * Enforces that apps which have the
+     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
+     * can make certain calls to the CarUserManager.
+     *
+     * @param message used as message if SecurityException is thrown.
+     * @throws SecurityException if the caller is not system or root.
+     */
+    private static void checkManageUsersPermission(String message) {
+        int callingUid = Binder.getCallingUid();
+        if (!hasPermissionGranted(android.Manifest.permission.MANAGE_USERS, callingUid)) {
+            throw new SecurityException(
+                    "You need MANAGE_USERS permission to: " + message);
+        }
+    }
+
+    private static boolean hasPermissionGranted(String permission, int uid) {
+        return ActivityManager.checkComponentPermission(
+                permission, uid, /* owningUid = */-1, /* exported = */ true)
+                == android.content.pm.PackageManager.PERMISSION_GRANTED;
+    }
 }