Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 95ab7849 authored by Amith Yamasani's avatar Amith Yamasani
Browse files

Decouple user limit from guest creation

Allow Guest to be created even if there are N users.
Allow N users to be created even if there are N-1 users
   and a Guest.
Limit number of guests and managed profiles that can
be added.

Added unit tests.

Bug: 15934700
Change-Id: I1a8f0fa38a91d71ef7b2980e05c974244dfc337a
parent 437e61d5
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -695,6 +695,26 @@ public class UserManager {
        }
    }

    /**
     * Checks whether it's possible to add more users. Caller must hold the MANAGE_USERS
     * permission.
     *
     * @return true if more users can be added, false if limit has been reached.
     * @hide
     */
    public boolean canAddMoreUsers() {
        final List<UserInfo> users = getUsers(true);
        final int totalUserCount = users.size();
        int aliveUserCount = 0;
        for (int i = 0; i < totalUserCount; i++) {
            UserInfo user = users.get(i);
            if (!user.isGuest()) {
                aliveUserCount++;
            }
        }
        return aliveUserCount < getMaxSupportedUsers();
    }

    /**
     * Returns list of the profiles of userHandle including
     * userHandle itself.
+2 −1
Original line number Diff line number Diff line
@@ -113,6 +113,7 @@ public class UserSwitcherController {
     *
     * @param forcePictureLoadForId forces the picture of the given user to be reloaded.
     */
    @SuppressWarnings("unchecked")
    private void refreshUsers(int forcePictureLoadForId) {

        SparseArray<Bitmap> bitmaps = new SparseArray<>(mUsers.size());
@@ -170,7 +171,7 @@ public class UserSwitcherController {
                boolean canCreateGuest = (currentUserCanCreateUsers || anyoneCanCreateUsers)
                        && guestRecord == null;
                boolean canCreateUser = (currentUserCanCreateUsers || anyoneCanCreateUsers)
                        && records.size() < UserManager.getMaxSupportedUsers();
                        && mUserManager.canAddMoreUsers();
                boolean createIsRestricted = !addUsersWhenLocked;

                if (!mSimpleUserSwitcher) {
+35 −2
Original line number Diff line number Diff line
@@ -125,6 +125,10 @@ public class UserManagerService extends IUserManager.Stub {
    // Number of attempts before jumping to the next BACKOFF_TIMES slot
    private static final int BACKOFF_INC_INTERVAL = 5;

    // Maximum number of managed profiles permitted is 1. This cannot be increased
    // without first making sure that the rest of the framework is prepared for it.
    private static final int MAX_MANAGED_PROFILES = 1;

    // Amount of time to force the user to wait before entering the PIN again, after failing
    // BACKOFF_INC_INTERVAL times.
    private static final int[] BACKOFF_TIMES = { 0, 30*1000, 60*1000, 5*60*1000, 30*60*1000 };
@@ -510,7 +514,8 @@ public class UserManagerService extends IUserManager.Stub {
        // Skip over users being removed
        for (int i = 0; i < totalUserCount; i++) {
            UserInfo user = mUsers.valueAt(i);
            if (!mRemovingUserIds.get(user.id)) {
            if (!mRemovingUserIds.get(user.id)
                    && !user.isGuest()) {
                aliveUserCount++;
            }
        }
@@ -1093,6 +1098,7 @@ public class UserManagerService extends IUserManager.Stub {
            Log.w(LOG_TAG, "Cannot add user. DISALLOW_ADD_USER is enabled.");
            return null;
        }
        final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0;
        final long ident = Binder.clearCallingIdentity();
        UserInfo userInfo = null;
        try {
@@ -1103,7 +1109,21 @@ public class UserManagerService extends IUserManager.Stub {
                        parent = getUserInfoLocked(parentId);
                        if (parent == null) return null;
                    }
                    if (isUserLimitReachedLocked()) return null;
                    // If we're not adding a guest user and the limit has been reached,
                    // cannot add a user.
                    if (!isGuest && isUserLimitReachedLocked()) {
                        return null;
                    }
                    // If we're adding a guest and there already exists one, bail.
                    if (isGuest && numberOfUsersOfTypeLocked(UserInfo.FLAG_GUEST, true) > 0) {
                        return null;
                    }
                    // Limit number of managed profiles that can be created
                    if ((flags & UserInfo.FLAG_MANAGED_PROFILE) != 0
                            && numberOfUsersOfTypeLocked(UserInfo.FLAG_MANAGED_PROFILE, true)
                                >= MAX_MANAGED_PROFILES) {
                        return null;
                    }
                    int userId = getNextAvailableIdLocked();
                    userInfo = new UserInfo(userId, name, null, flags);
                    File userPath = new File(mBaseUserPath, Integer.toString(userId));
@@ -1142,6 +1162,19 @@ public class UserManagerService extends IUserManager.Stub {
        return userInfo;
    }

    private int numberOfUsersOfTypeLocked(int flags, boolean excludeDying) {
        int count = 0;
        for (int i = mUsers.size() - 1; i >= 0; i--) {
            UserInfo user = mUsers.valueAt(i);
            if (!excludeDying || !mRemovingUserIds.get(user.id)) {
                if ((user.flags & flags) != 0) {
                    count++;
                }
            }
        }
        return count;
    }

    /**
     * Removes a user and all data directories created for that user. This method should be called
     * after the user's processes have been terminated.
+35 −0
Original line number Diff line number Diff line
@@ -47,6 +47,18 @@ public class UserManagerTest extends AndroidTestCase {
                }
            }
        }, filter);

        removeExistingUsers();
    }

    private void removeExistingUsers() {
        List<UserInfo> list = mUserManager.getUsers();
        boolean found = false;
        for (UserInfo user : list) {
            if (user.id != UserHandle.USER_OWNER) {
                removeUser(user.id);
            }
        }
    }

    public void testHasPrimary() throws Exception {
@@ -95,6 +107,29 @@ public class UserManagerTest extends AndroidTestCase {
        assertFalse(findUser(userInfo.id));
    }

    public void testAddGuest() throws Exception {
        UserInfo userInfo1 = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST);
        UserInfo userInfo2 = mUserManager.createUser("Guest 2", UserInfo.FLAG_GUEST);
        assertNotNull(userInfo1);
        assertNull(userInfo2);

        // Cleanup
        removeUser(userInfo1.id);
    }

    // Make sure only one managed profile can be created
    public void testAddManagedProfile() throws Exception {
        UserInfo userInfo1 = mUserManager.createProfileForUser("Managed 1",
                UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER);
        UserInfo userInfo2 = mUserManager.createProfileForUser("Managed 2",
                UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER);
        assertNotNull(userInfo1);
        assertNull(userInfo2);

        // Cleanup
        removeUser(userInfo1.id);
    }

    private boolean findUser(int id) {
        List<UserInfo> list = mUserManager.getUsers();