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

Commit f7e65e58 authored by Felipe Leme's avatar Felipe Leme
Browse files

Changes user start to enforce profiles are assigned to the parent display.

Previously, when ActivityManager.startProfile() was called, it would
trigger starting the profile on DEFAULT_DISPLAY, which would fail if
called by a user running on background in a secondary display (as the
server side part would require the caller to pass the parent's
display id).

This change fixes that behavior by using a special display id
(Display.PARENT_DISPLAY), which is only used when the device supports
multiple users on multiple displays.

Test: atest FrameworksMockingServicesTests:com.android.server.pm.UserManagerServiceTest UserManagerInternalTest UserControllerTest

Bug: 239982558
Bug: 244452695

Change-Id: I92aa2df97b3a6cf71d9386e67111ff8da6eedf56
parent 5a82b5ae
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -16145,8 +16145,7 @@ public class ActivityManagerService extends IActivityManager.Stub
    @Override
    public boolean startUserInBackgroundOnSecondaryDisplay(int userId, int displayId) {
        // Permission check done inside UserController.
        return mUserController.startUserOnSecondaryDisplay(userId, displayId,
                /* unlockListener= */ null);
        return mUserController.startUserOnSecondaryDisplay(userId, displayId);
    }
    /**
+13 −6
Original line number Diff line number Diff line
@@ -1375,8 +1375,9 @@ class UserController implements Handler.Callback {
        }
        final int profilesToStartSize = profilesToStart.size();
        int i = 0;
        // TODO(b/239982558): pass displayId
        for (; i < profilesToStartSize && i < (getMaxRunningUsers() - 1); ++i) {
            // NOTE: this method is setting the profiles of the current user - which is always
            // assigned to the default display - so there's no need to pass PARENT_DISPLAY
            startUser(profilesToStart.get(i).id, /* foreground= */ false);
        }
        if (i < profilesToStartSize) {
@@ -1419,8 +1420,10 @@ class UserController implements Handler.Callback {
            return false;
        }

        // TODO(b/239982558): pass proper displayId
        return startUserNoChecks(userId, Display.DEFAULT_DISPLAY, /* foreground= */ false,
        int displayId = mInjector.isUsersOnSecondaryDisplaysEnabled()
                ? UserManagerInternal.PARENT_DISPLAY
                : Display.DEFAULT_DISPLAY;
        return startUserNoChecks(userId, displayId, /* foreground= */ false,
                /* unlockListener= */ null);
    }

@@ -1472,8 +1475,7 @@ class UserController implements Handler.Callback {

    // TODO(b/239982558): add javadoc (need to wait until the intents / SystemService callbacks are
    // defined
    boolean startUserOnSecondaryDisplay(@UserIdInt int userId, int displayId,
            @Nullable IProgressListener unlockListener) {
    boolean startUserOnSecondaryDisplay(@UserIdInt int userId, int displayId) {
        checkCallingHasOneOfThosePermissions("startUserOnSecondaryDisplay",
                MANAGE_USERS, CREATE_USERS);

@@ -1482,7 +1484,8 @@ class UserController implements Handler.Callback {
                "Cannot use DEFAULT_DISPLAY");

        try {
            return startUserNoChecks(userId, displayId, /* foreground= */ false, unlockListener);
            return startUserNoChecks(userId, displayId, /* foreground= */ false,
                    /* unlockListener= */ null);
        } catch (RuntimeException e) {
            Slogf.w(TAG, "startUserOnSecondaryDisplay(%d, %d) failed: %s", userId, displayId, e);
            return false;
@@ -3484,5 +3487,9 @@ class UserController implements Handler.Callback {
                }
            }, reason);
        }

        boolean isUsersOnSecondaryDisplaysEnabled() {
            return UserManager.isUsersOnSecondaryDisplaysEnabled();
        }
    }
}
+9 −0
Original line number Diff line number Diff line
@@ -46,6 +46,15 @@ public abstract class UserManagerInternal {
    public @interface OwnerType {
    }

    // TODO(b/245963156): move to Display.java (and @hide) if we decide to support profiles on MUMD
    /**
     * Used only when starting a profile (on systems that
     * {@link android.os.UserManager#isUsersOnSecondaryDisplaysSupported() support users running on
     * secondary displays}), to indicate the profile should be started in the same display as its
     * parent user.
     */
    public static final int PARENT_DISPLAY = -2;

    public interface UserRestrictionsListener {
        /**
         * Called when a user restriction changes.
+29 −38
Original line number Diff line number Diff line
@@ -6820,34 +6820,23 @@ public class UserManagerService extends IUserManager.Stub {

            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);
                    "Cannot assign current user (%d) to other displays", currentUserId);

            synchronized (mUsersOnSecondaryDisplays) {
                if (DBG_MUMD) {
                    Slogf.d(LOG_TAG, "Adding %d->%d to mUsersOnSecondaryDisplays",
                            userId, displayId);
                }

                if (isProfile) {
                if (isProfileUnchecked(userId)) {
                    // Profile can only start in the same display as parent
                    Preconditions.checkArgument(displayId == UserManagerInternal.PARENT_DISPLAY,
                            "Profile user can only be started in the same display as parent");
                    int parentUserId = getProfileParentId(userId);
                    int parentDisplayId = mUsersOnSecondaryDisplays.get(parentUserId);
                    if (displayId != parentDisplayId) {
                        throw new IllegalStateException("Cannot assign profile " + userId + " to "
                                + "display " + displayId + " as its parent (user " + parentUserId
                                + ") is assigned to display " + parentDisplayId);
                    if (DBG_MUMD) {
                        Slogf.d(LOG_TAG, "Adding profile user %d -> display %d", userId,
                                parentDisplayId);
                    }
                } else {
                    mUsersOnSecondaryDisplays.put(userId, parentDisplayId);
                    return;
                }

                // Check if display is available
                for (int i = 0; i < mUsersOnSecondaryDisplays.size(); i++) {
                    // Make sure display is not used by other users...
@@ -6865,8 +6854,10 @@ public class UserManagerService extends IUserManager.Stub {
                    // (for example, would need to add a new AM method to start user in bg on
                    // main display), so it's better to test on unit tests
                }
                }

                if (DBG_MUMD) {
                    Slogf.d(LOG_TAG, "Adding full user %d -> display %d", userId, displayId);
                }
                mUsersOnSecondaryDisplays.put(userId, displayId);
            }
        }
+5 −13
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ import static android.os.UserHandle.USER_SYSTEM;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;

import static com.android.server.pm.UserManagerInternal.PARENT_DISPLAY;

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

import static org.junit.Assert.assertThrows;
@@ -119,9 +121,6 @@ public final class UserManagerInternalTest extends UserManagerServiceOrInternalT
                () -> 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();
    }

@@ -136,10 +135,6 @@ public final class UserManagerInternalTest extends UserManagerServiceOrInternalT
                () -> 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();
    }

@@ -173,7 +168,7 @@ public final class UserManagerInternalTest extends UserManagerServiceOrInternalT
        addDefaultProfileAndParent();

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

        assertUsersAssignedToDisplays(PARENT_USER_ID, SECONDARY_DISPLAY_ID,
                pair(PROFILE_USER_ID, SECONDARY_DISPLAY_ID));
@@ -185,13 +180,10 @@ public final class UserManagerInternalTest extends UserManagerServiceOrInternalT
        addDefaultProfileAndParent();

        mUmi.assignUserToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
        IllegalStateException e = assertThrows(IllegalStateException.class,
                () -> mUmi.assignUserToDisplay(PROFILE_USER_ID, OTHER_SECONDARY_DISPLAY_ID));
        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 + ".*" + OTHER_SECONDARY_DISPLAY_ID
                        + ".*parent.*" + PARENT_USER_ID + ".*" + SECONDARY_DISPLAY_ID + ".*");
        assertUserAssignedToDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
    }

Loading