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

Commit 224a8874 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Added more unit tests for UserManagerInternal."

parents 50afc5e7 9e932ddd
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -318,6 +318,10 @@ public abstract class UserManagerInternal {
     *
     * <p>On most devices this call will be a no-op, but it will be used on devices that support
     * multiple users on multiple displays (like automotives with passenger displays).
     *
     * <p><b>NOTE: </b>this method is meant to be used only by {@code UserController} when a user is
     * started and it doesn't validate if the display exists.
     *
     */
    public abstract void assignUserToDisplay(@UserIdInt int userId, int displayId);

@@ -326,6 +330,9 @@ public abstract class UserManagerInternal {
     *
     * <p>On most devices this call will be a no-op, but it will be used on devices that support
     * multiple users on multiple displays (like automotives with passenger displays).
     *
     * <p><b>NOTE: </b>this method is meant to be used only by {@code UserController} when a user is
     * stopped.
     */
    public abstract void unassignUserFromDisplay(@UserIdInt int userId);

+20 −6
Original line number Diff line number Diff line
@@ -6732,10 +6732,24 @@ public class UserManagerService extends IUserManager.Stub {
                        + "users on multiple displays");
            }

            Preconditions.checkArgument(userId != UserHandle.USER_SYSTEM, "Cannot start system user"
                    + " on secondary display (%d)", displayId);
            // TODO(b/239982558): call DisplayManagerInternal to check if display is valid instead
            Preconditions.checkArgument(displayId > 0, "Invalid display id (%d)", displayId);
            Preconditions.checkArgument(userId != UserHandle.USER_SYSTEM, "Cannot assign system "
                    + "user to secondary display (%d)", displayId);
            Preconditions.checkArgument(displayId != Display.INVALID_DISPLAY,
                    "Cannot assign to INVALID_DISPLAY (%d)", displayId);

            int currentUserId = getCurrentUserId();
            Preconditions.checkArgument(userId != currentUserId,
                    "Cannot assign current user to other displays");

            boolean isProfile = isProfileUnchecked(userId);

            Preconditions.checkArgument(userId != currentUserId,
                    "Cannot assign current user to other displays");

            Preconditions.checkArgument(
                    !isProfile || getProfileParentIdUnchecked(userId) != currentUserId,
                    "Cannot assign profile user %d to display %d when its parent is the current "
                    + "user (%d)", userId, displayId, currentUserId);

            synchronized (mUsersOnSecondaryDisplays) {
                if (DBG_MUMD) {
@@ -6743,7 +6757,7 @@ public class UserManagerService extends IUserManager.Stub {
                            userId, displayId);
                }

                if (isProfileUnchecked(userId)) {
                if (isProfile) {
                    // Profile can only start in the same display as parent
                    int parentUserId = getProfileParentId(userId);
                    int parentDisplayId = mUsersOnSecondaryDisplays.get(parentUserId);
+195 −0
Original line number Diff line number Diff line
@@ -15,11 +15,206 @@
 */
package com.android.server.pm;

import static android.os.UserHandle.USER_SYSTEM;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;

import static com.google.common.truth.Truth.assertWithMessage;

import static org.junit.Assert.assertThrows;

import android.util.Log;

import org.junit.Test;

/**
 * Run as {@code atest FrameworksMockingServicesTests:com.android.server.pm.UserManagerInternalTest}
 */
public final class UserManagerInternalTest extends UserManagerServiceOrInternalTestCase {

    private static final String TAG = UserManagerInternalTest.class.getSimpleName();

    // NOTE: most the tests below only apply to MUMD configurations, so we're not adding _mumd_
    // in the test names, but _nonMumd_ instead

    @Test
    public void testAssignUserToDisplay_nonMumd_defaultDisplayIgnored() {
        mUmi.assignUserToDisplay(USER_ID, DEFAULT_DISPLAY);

        assertNoUserAssignedToDisplay();
    }

    @Test
    public void testAssignUserToDisplay_nonMumd_otherDisplay_currentUser() {
        mockCurrentUser(USER_ID);

        assertThrows(UnsupportedOperationException.class,
                () -> mUmi.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID));
    }

    @Test
    public void testAssignUserToDisplay_nonMumd_otherDisplay_startProfileOfcurrentUser() {
        mockCurrentUser(PARENT_USER_ID);
        addDefaultProfileAndParent();
        startDefaultProfile();

        assertThrows(UnsupportedOperationException.class,
                () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
    }

    @Test
    public void testAssignUserToDisplay_nonMumd_otherDisplay_stoppedProfileOfcurrentUser() {
        mockCurrentUser(PARENT_USER_ID);
        addDefaultProfileAndParent();
        stopDefaultProfile();

        assertThrows(UnsupportedOperationException.class,
                () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
    }

    @Test
    public void testAssignUserToDisplay_defaultDisplayIgnored() {
        enableUsersOnSecondaryDisplays();

        mUmi.assignUserToDisplay(USER_ID, DEFAULT_DISPLAY);

        assertNoUserAssignedToDisplay();
    }

    @Test
    public void testAssignUserToDisplay_systemUser() {
        enableUsersOnSecondaryDisplays();

        assertThrows(IllegalArgumentException.class,
                () -> mUmi.assignUserToDisplay(USER_SYSTEM, SECONDARY_DISPLAY_ID));
    }

    @Test
    public void testAssignUserToDisplay_invalidDisplay() {
        enableUsersOnSecondaryDisplays();

        assertThrows(IllegalArgumentException.class,
                () -> mUmi.assignUserToDisplay(USER_ID, INVALID_DISPLAY));
    }

    @Test
    public void testAssignUserToDisplay_currentUser() {
        enableUsersOnSecondaryDisplays();
        mockCurrentUser(USER_ID);

        assertThrows(IllegalArgumentException.class,
                () -> mUmi.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID));

        assertNoUserAssignedToDisplay();
    }

    @Test
    public void testAssignUserToDisplay_startedProfileOfCurrentUser() {
        enableUsersOnSecondaryDisplays();
        mockCurrentUser(PARENT_USER_ID);
        addDefaultProfileAndParent();
        startDefaultProfile();

        IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
                () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));

        Log.v(TAG, "Exception: " + e);
        assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
                .matches("Cannot.*" + PROFILE_USER_ID + ".*" + SECONDARY_DISPLAY_ID
                        + ".*parent.*current.*" + PARENT_USER_ID + ".*");
        assertNoUserAssignedToDisplay();
    }

    @Test
    public void testAssignUserToDisplay_stoppedProfileOfCurrentUser() {
        enableUsersOnSecondaryDisplays();
        mockCurrentUser(PARENT_USER_ID);
        addDefaultProfileAndParent();
        stopDefaultProfile();

        IllegalArgumentException e = assertThrows(IllegalArgumentException.class,
                () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));

        Log.v(TAG, "Exception: " + e);
        assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
                .matches("Cannot.*" + PROFILE_USER_ID + ".*" + SECONDARY_DISPLAY_ID
                        + ".*parent.*current.*" + PARENT_USER_ID + ".*");

        assertNoUserAssignedToDisplay();
    }

    @Test
    public void testAssignUserToDisplay_displayAvailable() {
        enableUsersOnSecondaryDisplays();

        mUmi.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);

        assertUserAssignedToDisplay(USER_ID, SECONDARY_DISPLAY_ID);
    }

    @Test
    public void testAssignUserToDisplay_displayAlreadyAssigned() {
        enableUsersOnSecondaryDisplays();

        mUmi.assignUserToDisplay(USER_ID, SECONDARY_DISPLAY_ID);

        IllegalStateException e = assertThrows(IllegalStateException.class,
                () -> mUmi.assignUserToDisplay(OTHER_USER_ID, SECONDARY_DISPLAY_ID));

        Log.v(TAG, "Exception: " + e);
        assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
                .matches("Cannot.*" + OTHER_USER_ID + ".*" + SECONDARY_DISPLAY_ID + ".*already.*"
                        + USER_ID + ".*");
    }

    @Test
    public void testAssignUserToDisplay_profileOnSameDisplayAsParent() {
        enableUsersOnSecondaryDisplays();
        addDefaultProfileAndParent();

        mUmi.assignUserToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
        mUmi.assignUserToDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);

        assertUsersAssignedToDisplays(PARENT_USER_ID, SECONDARY_DISPLAY_ID,
                pair(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
    }

    @Test
    public void testAssignUserToDisplay_profileOnDifferentDisplayAsParent() {
        enableUsersOnSecondaryDisplays();
        addDefaultProfileAndParent();

        mUmi.assignUserToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
        IllegalStateException e = assertThrows(IllegalStateException.class,
                () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, OTHER_SECONDARY_DISPLAY_ID));

        Log.v(TAG, "Exception: " + e);
        assertWithMessage("exception (%s) message", e).that(e).hasMessageThat()
                .matches("Cannot.*" + PROFILE_USER_ID + ".*" + OTHER_SECONDARY_DISPLAY_ID
                        + ".*parent.*" + PARENT_USER_ID + ".*" + SECONDARY_DISPLAY_ID + ".*");
        assertUserAssignedToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
    }

    @Test
    public void testUnassignUserFromDisplay_nonMumd_ignored() {
        mockCurrentUser(USER_ID);

        mUmi.unassignUserFromDisplay(USER_SYSTEM);
        mUmi.unassignUserFromDisplay(USER_ID);
        mUmi.unassignUserFromDisplay(OTHER_USER_ID);

        assertNoUserAssignedToDisplay();
    }

    @Test
    public void testUnassignUserFromDisplay() {
        testAssignUserToDisplay_displayAvailable();

        mUmi.unassignUserFromDisplay(USER_ID);

        assertNoUserAssignedToDisplay();
    }

    @Override
    protected boolean isUserVisible(int userId) {
        return mUmi.isUserVisible(userId);
+56 −10
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.content.Context;
import android.content.pm.UserInfo;
import android.os.UserManager;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
import android.util.SparseIntArray;

@@ -49,6 +50,9 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Base class for {@link UserManagerInternalTest} and {@link UserManagerInternalTest}.
 *
@@ -90,7 +94,12 @@ abstract class UserManagerServiceOrInternalTestCase extends ExtendedMockitoTestC
    /**
     * Id of a secondary display (i.e, not {@link android.view.Display.DEFAULT_DISPLAY}).
     */
    private static final int SECONDARY_DISPLAY_ID = 42;
    protected static final int SECONDARY_DISPLAY_ID = 42;

    /**
     * Id of another secondary display (i.e, not {@link android.view.Display.DEFAULT_DISPLAY}).
     */
    protected static final int OTHER_SECONDARY_DISPLAY_ID = 108;

    private final Object mPackagesLock = new Object();
    private final Context mRealContext = androidx.test.InstrumentationRegistry.getInstrumentation()
@@ -426,26 +435,26 @@ abstract class UserManagerServiceOrInternalTestCase extends ExtendedMockitoTestC
     * Change test fixtures to use a version that supports {@code MUMD} (Multiple Users on Multiple
     * Displays).
     */
    protected void enableUsersOnSecondaryDisplays() {
    protected final void enableUsersOnSecondaryDisplays() {
        setServiceFixtures(/* usersOnSecondaryDisplaysEnabled= */ true);
    }

    protected void mockCurrentUser(@UserIdInt int userId) {
    protected final void mockCurrentUser(@UserIdInt int userId) {
        mockGetLocalService(ActivityManagerInternal.class, mActivityManagerInternal);

        when(mActivityManagerInternal.getCurrentUserId()).thenReturn(userId);
    }

    protected <T> void mockGetLocalService(Class<T> serviceClass, T service) {
    protected final <T> void mockGetLocalService(Class<T> serviceClass, T service) {
        doReturn(service).when(() -> LocalServices.getService(serviceClass));
    }

    protected void addDefaultProfileAndParent() {
    protected final void addDefaultProfileAndParent() {
        addUser(PARENT_USER_ID);
        addProfile(PROFILE_USER_ID, PARENT_USER_ID);
    }

    protected void addProfile(@UserIdInt int profileId, @UserIdInt int parentId) {
    protected final void addProfile(@UserIdInt int profileId, @UserIdInt int parentId) {
        TestUserData profileData = new TestUserData(profileId);
        profileData.info.flags = UserInfo.FLAG_PROFILE;
        profileData.info.profileGroupId = parentId;
@@ -453,27 +462,55 @@ abstract class UserManagerServiceOrInternalTestCase extends ExtendedMockitoTestC
        addUserData(profileData);
    }

    protected void addUser(@UserIdInt int userId) {
    protected final void addUser(@UserIdInt int userId) {
        TestUserData userData = new TestUserData(userId);

        addUserData(userData);
    }

    protected void startDefaultProfile() {
    protected final void startDefaultProfile() {
        setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
    }

    protected void stopDefaultProfile() {
    protected final void stopDefaultProfile() {
        // TODO(b/244798930): should set it to STATE_STOPPING or STATE_SHUTDOWN instead
        removeUserState(PROFILE_USER_ID);
    }

    // NOTE: should only called by tests that indirectly needs to check user assignments (like
    // isUserVisible), not by tests for the user assignment methods per se.
    protected void assignUserToDisplay(@UserIdInt int userId, int displayId) {
    protected final void assignUserToDisplay(@UserIdInt int userId, int displayId) {
        mUsersOnSecondaryDisplays.put(userId, displayId);
    }

    protected final void assertNoUserAssignedToDisplay() {
        assertWithMessage("mUsersOnSecondaryDisplays()").that(usersOnSecondaryDisplaysAsMap())
                .isEmpty();
    }

    protected final void assertUserAssignedToDisplay(@UserIdInt int userId, int displayId) {
        assertWithMessage("mUsersOnSecondaryDisplays()").that(usersOnSecondaryDisplaysAsMap())
                .containsExactly(userId, displayId);
    }

    @SafeVarargs
    protected final void assertUsersAssignedToDisplays(@UserIdInt int userId, int displayId,
            @SuppressWarnings("unchecked") Pair<Integer, Integer>... others) {
        Object[] otherObjects = new Object[others.length * 2];
        for (int i = 0; i < others.length; i++) {
            Pair<Integer, Integer> other = others[i];
            otherObjects[i * 2] = other.first;
            otherObjects[i * 2 + 1] = other.second;

        }
        assertWithMessage("mUsersOnSecondaryDisplays()").that(usersOnSecondaryDisplaysAsMap())
                .containsExactly(userId, displayId, otherObjects);
    }

    protected static Pair<Integer, Integer> pair(@UserIdInt int userId, int secondaryDisplayId) {
        return new Pair<>(userId, secondaryDisplayId);
    }

    ///////////////////
    // Private infra //
    ///////////////////
@@ -508,6 +545,15 @@ abstract class UserManagerServiceOrInternalTestCase extends ExtendedMockitoTestC
        mUmi.removeUserState(userId);
    }

    private Map<Integer, Integer> usersOnSecondaryDisplaysAsMap() {
        int size = mUsersOnSecondaryDisplays.size();
        Map<Integer, Integer> map = new LinkedHashMap<>(size);
        for (int i = 0; i < size; i++) {
            map.put(mUsersOnSecondaryDisplays.keyAt(i), mUsersOnSecondaryDisplays.valueAt(i));
        }
        return map;
    }

    private static final class TestUserData extends UserData {

        @SuppressWarnings("deprecation")