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

Commit 90ce83a6 authored by Felipe Leme's avatar Felipe Leme Committed by Android (Google) Code Review
Browse files

Merge "Revert "Fixed UserVisibilityMediator profile scenario.""

parents ceaf4865 8b9cd557
Loading
Loading
Loading
Loading
+5 −30
Original line number Diff line number Diff line
@@ -64,11 +64,12 @@ public abstract class UserManagerInternal {
    })
    public @interface UserAssignmentResult {}

    private static final String PREFIX_USER_START_MODE = "USER_START_MODE_";
    // TODO(b/248408342): Move keep annotation to the method referencing these fields reflectively.
    @Keep public static final int USER_START_MODE_FOREGROUND = 1;
    @Keep public static final int USER_START_MODE_BACKGROUND = 2;
    @Keep public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3;

    /**
     * Type used to indicate how a user started.
     */
    private static final String PREFIX_USER_START_MODE = "USER_START_MODE_";
    @IntDef(flag = false, prefix = {PREFIX_USER_START_MODE}, value = {
            USER_START_MODE_FOREGROUND,
            USER_START_MODE_BACKGROUND,
@@ -76,32 +77,6 @@ public abstract class UserManagerInternal {
    })
    public @interface UserStartMode {}

    // TODO(b/248408342): Move keep annotations below to the method referencing these fields
    // reflectively.

    /** (Full) user started on foreground (a.k.a. "current user"). */
    @Keep public static final int USER_START_MODE_FOREGROUND = 1;

    /**
     * User (full or profile) started on background and is
     * {@link UserManager#isUserVisible() invisible}.
     *
     * <p>This is the "traditional" way of starting a background user, and can be used to start
     * profiles as well, although starting an invisible profile is not common from the System UI
     * (it could be done through APIs or adb, though).
     */
    @Keep public static final int USER_START_MODE_BACKGROUND = 2;

    /**
     * User (full or profile) started on background and is
     * {@link UserManager#isUserVisible() visible}.
     *
     * <p>This is the "traditional" way of starting a profile (i.e., when the profile of the current
     * user is the current foreground user), but it can also be used to start a full user associated
     * with a display (which is the case on automotives with passenger displays).
     */
    @Keep public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3;

    public interface UserRestrictionsListener {
        /**
         * Called when a user restriction changes.
+68 −154
Original line number Diff line number Diff line
@@ -42,7 +42,6 @@ import android.util.Dumpable;
import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.Display;

@@ -56,8 +55,6 @@ import com.android.server.pm.UserManagerInternal.UserVisibilityListener;
import com.android.server.utils.Slogf;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
@@ -80,11 +77,11 @@ import java.util.concurrent.CopyOnWriteArrayList;
 */
public final class UserVisibilityMediator implements Dumpable {

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

    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
    private static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
    private static final boolean VERBOSE = false; // DO NOT SUBMIT WITH TRUE

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

    private static final String PREFIX_SECONDARY_DISPLAY_MAPPING = "SECONDARY_DISPLAY_MAPPING_";
    public static final int SECONDARY_DISPLAY_MAPPING_NEEDED = 1;
    public static final int SECONDARY_DISPLAY_MAPPING_NOT_NEEDED = 2;
@@ -101,7 +98,7 @@ public final class UserVisibilityMediator implements Dumpable {
    })
    public @interface SecondaryDisplayMappingStatus {}

    // TODO(b/266158156): might need to change this if boot logic is refactored for HSUM devices
    // TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices
    @VisibleForTesting
    static final int INITIAL_CURRENT_USER_ID = USER_SYSTEM;

@@ -135,23 +132,10 @@ public final class UserVisibilityMediator implements Dumpable {
    private final SparseIntArray mExtraDisplaysAssignedToUsers;

    /**
     * Mapping of each user that started visible (key) to its profile group id (value).
     *
     * <p>It's used to determine not just if the user is visible, but also
     * {@link #isProfile(int, int) if it's a profile}.
     */
    @GuardedBy("mLock")
    private final SparseIntArray mStartedVisibleProfileGroupIds = new SparseIntArray();

    /**
     * List of profiles that have explicitly started invisible.
     *
     * <p>Only used for debugging purposes (and set when {@link #DBG} is {@code true}), hence we
     * don't care about autoboxing.
     * Mapping from each started user to its profile group.
     */
    @GuardedBy("mLock")
    @Nullable
    private final List<Integer> mStartedInvisibleProfileUserIds;
    private final SparseIntArray mStartedProfileGroupIds = new SparseIntArray();

    /**
     * Handler user to call listeners
@@ -180,14 +164,9 @@ public final class UserVisibilityMediator implements Dumpable {
            mUsersAssignedToDisplayOnStart = null;
            mExtraDisplaysAssignedToUsers = null;
        }
        mStartedInvisibleProfileUserIds = DBG ? new ArrayList<>(4) : null;
        mHandler = handler;
        // TODO(b/266158156): might need to change this if boot logic is refactored for HSUM devices
        mStartedVisibleProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID);

        if (DBG) {
            Slogf.i(TAG, "UserVisibilityMediator created with DBG on");
        }
        // TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices
        mStartedProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID);
    }

    /**
@@ -198,8 +177,6 @@ public final class UserVisibilityMediator implements Dumpable {
            int displayId) {
        Preconditions.checkArgument(!isSpecialUserId(userId), "user id cannot be generic: %d",
                userId);
        validateUserStartMode(userStartMode);

        // This method needs to perform 4 actions:
        //
        // 1. Check if the user can be started given the provided arguments
@@ -247,29 +224,14 @@ public final class UserVisibilityMediator implements Dumpable {

            visibleUsersBefore = getVisibleUsers();

            // Set current user / started users state
            switch (userStartMode) {
                case USER_START_MODE_FOREGROUND:
            // Set current user / profiles state
            if (userStartMode == USER_START_MODE_FOREGROUND) {
                mCurrentUserId = userId;
                    // Fallthrough
                case USER_START_MODE_BACKGROUND_VISIBLE:
                    if (DBG) {
                        Slogf.d(TAG, "adding visible user / profile group id mapping (%d -> %d)",
                                userId, profileGroupId);
            }
                    mStartedVisibleProfileGroupIds.put(userId, profileGroupId);
                    break;
                case USER_START_MODE_BACKGROUND:
                    if (mStartedInvisibleProfileUserIds != null
                            && isProfile(userId, profileGroupId)) {
                        Slogf.d(TAG, "adding user %d to list of invisible profiles", userId);
                        mStartedInvisibleProfileUserIds.add(userId);
                    }
                    break;
                default:
                    Slogf.wtf(TAG,  "invalid userStartMode passed to assignUserToDisplayOnStart: "
                            + "%d", userStartMode);
            if (DBG) {
                Slogf.d(TAG, "adding user / profile mapping (%d -> %d)", userId, profileGroupId);
            }
            mStartedProfileGroupIds.put(userId, profileGroupId);

            //  Set user / display state
            switch (mappingResult) {
@@ -335,46 +297,39 @@ public final class UserVisibilityMediator implements Dumpable {
        boolean foreground = userStartMode == USER_START_MODE_FOREGROUND;
        if (displayId != DEFAULT_DISPLAY) {
            if (foreground) {
                Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: cannot start "
                Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %b, %d) failed: cannot start "
                        + "foreground user on secondary display", userId, profileGroupId,
                        userStartModeToString(userStartMode), displayId);
                        foreground, displayId);
                return USER_ASSIGNMENT_RESULT_FAILURE;
            }
            if (!mVisibleBackgroundUsersEnabled) {
                Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: called on "
                Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %b, %d) failed: called on "
                        + "device that doesn't support multiple users on multiple displays",
                        userId, profileGroupId, userStartModeToString(userStartMode), displayId);
                        userId, profileGroupId, foreground, displayId);
                return USER_ASSIGNMENT_RESULT_FAILURE;
            }
        }

        if (isProfile(userId, profileGroupId)) {
            if (displayId != DEFAULT_DISPLAY) {
                Slogf.w(TAG, "canStartUserLocked(%d, %d, %s, %d) failed: cannot start profile user "
                        + "on secondary display", userId, profileGroupId,
                        userStartModeToString(userStartMode), displayId);
                Slogf.w(TAG, "canStartUserLocked(%d, %d, %b, %d) failed: cannot start profile user "
                        + "on secondary display", userId, profileGroupId, foreground,
                        displayId);
                return USER_ASSIGNMENT_RESULT_FAILURE;
            }
            switch (userStartMode) {
                case USER_START_MODE_FOREGROUND:
                    Slogf.w(TAG, "startUser(%d, %d, %s, %d) failed: cannot start profile user in "
                            + "foreground", userId, profileGroupId,
                            userStartModeToString(userStartMode), displayId);
            if (foreground) {
                Slogf.w(TAG, "startUser(%d, %d, %b, %d) failed: cannot start profile user in "
                        + "foreground", userId, profileGroupId, foreground, displayId);
                return USER_ASSIGNMENT_RESULT_FAILURE;
                case USER_START_MODE_BACKGROUND_VISIBLE:
            } else {
                boolean isParentVisibleOnDisplay = isUserVisible(profileGroupId, displayId);
                    if (!isParentVisibleOnDisplay) {
                        Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: cannot"
                                + " start profile user visible when its parent is not visible in "
                                + "that display", userId, profileGroupId,
                                userStartModeToString(userStartMode), displayId);
                        return USER_ASSIGNMENT_RESULT_FAILURE;
                if (DBG) {
                    Slogf.d(TAG, "parent visible on display: %b", isParentVisibleOnDisplay);
                }
                    return USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE;
                case USER_START_MODE_BACKGROUND:
                    return USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
                return isParentVisibleOnDisplay
                        ? USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE
                        : USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
            }

        }

        return foreground || displayId != DEFAULT_DISPLAY
@@ -392,9 +347,8 @@ public final class UserVisibilityMediator implements Dumpable {
            if (mVisibleBackgroundUserOnDefaultDisplayAllowed
                    && userStartMode == USER_START_MODE_BACKGROUND_VISIBLE) {
                int userStartedOnDefaultDisplay = getUserStartedOnDisplay(DEFAULT_DISPLAY);
                if (userStartedOnDefaultDisplay != USER_NULL
                        && userStartedOnDefaultDisplay != profileGroupId) {
                    Slogf.w(TAG, "canAssignUserToDisplayLocked(): cannot start user %d visible on"
                if (userStartedOnDefaultDisplay != USER_NULL) {
                    Slogf.w(TAG, "getUserVisibilityOnStartLocked(): cannot start user %d visible on"
                            + " default display because user %d already did so", userId,
                            userStartedOnDefaultDisplay);
                    return SECONDARY_DISPLAY_MAPPING_FAILED;
@@ -500,7 +454,7 @@ public final class UserVisibilityMediator implements Dumpable {
                        userId, displayId);
                return false;
            }
            if (isStartedVisibleProfileLocked(userId)) {
            if (isStartedProfile(userId)) {
                Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is a profile",
                        userId, displayId);
                return false;
@@ -588,14 +542,10 @@ public final class UserVisibilityMediator implements Dumpable {
    @GuardedBy("mLock")
    private void unassignUserFromAllDisplaysOnStopLocked(@UserIdInt int userId) {
        if (DBG) {
            Slogf.d(TAG, "Removing %d from mStartedVisibleProfileGroupIds (%s)", userId,
                    mStartedVisibleProfileGroupIds);
        }
        mStartedVisibleProfileGroupIds.delete(userId);
        if (mStartedInvisibleProfileUserIds != null) {
            Slogf.d(TAG, "Removing %d from list of invisible profiles", userId);
            mStartedInvisibleProfileUserIds.remove(Integer.valueOf(userId));
            Slogf.d(TAG, "Removing %d from mStartedProfileGroupIds (%s)", userId,
                    mStartedProfileGroupIds);
        }
        mStartedProfileGroupIds.delete(userId);

        if (!mVisibleBackgroundUsersEnabled) {
            // Don't need to update mUsersAssignedToDisplayOnStart because methods (such as
@@ -625,8 +575,7 @@ public final class UserVisibilityMediator implements Dumpable {
     * See {@link UserManagerInternal#isUserVisible(int)}.
     */
    public boolean isUserVisible(@UserIdInt int userId) {
        // For optimization (as most devices don't support visible background users), check for
        // current foreground user and their profiles first
        // First check current foreground user and their profiles (on main display)
        if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
            if (VERBOSE) {
                Slogf.v(TAG, "isUserVisible(%d): true to current user or profile", userId);
@@ -635,31 +584,19 @@ public final class UserVisibilityMediator implements Dumpable {
        }

        if (!mVisibleBackgroundUsersEnabled) {
            if (VERBOSE) {
                Slogf.v(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when"
            if (DBG) {
                Slogf.d(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when"
                        + " device doesn't support visible background users", userId);
            }
            return false;
        }


        synchronized (mLock) {
            int profileGroupId;
        boolean visible;
        synchronized (mLock) {
                profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
            }
            if (isProfile(userId, profileGroupId)) {
                return isUserAssignedToDisplayOnStartLocked(profileGroupId);
            }
            return isUserAssignedToDisplayOnStartLocked(userId);
            visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0;
        }
    }

    @GuardedBy("mLock")
    private boolean isUserAssignedToDisplayOnStartLocked(@UserIdInt int userId) {
        boolean visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0;
        if (VERBOSE) {
            Slogf.v(TAG, "isUserAssignedToDisplayOnStartLocked(%d): %b", userId, visible);
        if (DBG) {
            Slogf.d(TAG, "isUserVisible(%d): %b from mapping", userId, visible);
        }
        return visible;
    }
@@ -672,8 +609,7 @@ public final class UserVisibilityMediator implements Dumpable {
            return false;
        }

        // For optimization (as most devices don't support visible background users), check for
        // current user and profile first. Current user is always visible on:
        // Current user is always visible on:
        // - Default display
        // - Secondary displays when device doesn't support visible bg users
        //   - Or when explicitly added (which is checked below)
@@ -695,27 +631,15 @@ public final class UserVisibilityMediator implements Dumpable {
        }

        synchronized (mLock) {
            int profileGroupId;
            synchronized (mLock) {
                profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
            }
            if (isProfile(userId, profileGroupId)) {
                return isFullUserVisibleOnBackgroundLocked(profileGroupId, displayId);
            }
            return isFullUserVisibleOnBackgroundLocked(userId, displayId);
        }
    }

    // NOTE: it doesn't check if the userId is a full user, it's up to the caller to check that
    @GuardedBy("mLock")
    private boolean isFullUserVisibleOnBackgroundLocked(@UserIdInt int userId, int displayId) {
            if (mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY) == displayId) {
                // User assigned to display on start
                return true;
            }

            // Check for extra display assignment
            return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId;
        }
    }

    /**
     * See {@link UserManagerInternal#getDisplayAssignedToUser(int)}.
@@ -782,7 +706,7 @@ public final class UserVisibilityMediator implements Dumpable {
                    continue;
                }
                int userId = mUsersAssignedToDisplayOnStart.keyAt(i);
                if (!isStartedVisibleProfileLocked(userId)) {
                if (!isStartedProfile(userId)) {
                    return userId;
                } else if (DBG) {
                    Slogf.d(TAG, "getUserAssignedToDisplay(%d): skipping user %d because it's "
@@ -815,8 +739,8 @@ public final class UserVisibilityMediator implements Dumpable {
        // number of users is too small, the gain is probably not worth the increase on complexity.
        IntArray visibleUsers = new IntArray();
        synchronized (mLock) {
            for (int i = 0; i < mStartedVisibleProfileGroupIds.size(); i++) {
                int userId = mStartedVisibleProfileGroupIds.keyAt(i);
            for (int i = 0; i < mStartedProfileGroupIds.size(); i++) {
                int userId = mStartedProfileGroupIds.keyAt(i);
                if (isUserVisible(userId)) {
                    visibleUsers.add(userId);
                }
@@ -849,7 +773,7 @@ public final class UserVisibilityMediator implements Dumpable {
        }
    }

    // TODO(b/266158156): remove this method if not needed anymore
    // TODO(b/242195409): remove this method if not needed anymore
    /**
     * Nofify all listeners that the system user visibility changed.
     */
@@ -911,9 +835,6 @@ public final class UserVisibilityMediator implements Dumpable {
        ipw.println("UserVisibilityMediator");
        ipw.increaseIndent();

        ipw.print("DBG: ");
        ipw.println(DBG);

        synchronized (mLock) {
            ipw.print("Current user id: ");
            ipw.println(mCurrentUserId);
@@ -921,12 +842,8 @@ public final class UserVisibilityMediator implements Dumpable {
            ipw.print("Visible users: ");
            ipw.println(getVisibleUsers());

            dumpSparseIntArray(ipw, mStartedVisibleProfileGroupIds,
                    "started visible user / profile group", "u", "pg");
            if (mStartedInvisibleProfileUserIds != null) {
                ipw.print("Profiles started invisible: ");
                ipw.println(mStartedInvisibleProfileUserIds);
            }
            dumpSparseIntArray(ipw, mStartedProfileGroupIds, "started user / profile group",
                    "u", "pg");

            ipw.print("Supports visible background users on displays: ");
            ipw.println(mVisibleBackgroundUsersEnabled);
@@ -1034,25 +951,22 @@ public final class UserVisibilityMediator implements Dumpable {
            if (mCurrentUserId == userId) {
                return true;
            }
            return mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID)
                    == mCurrentUserId;
            return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID) == mCurrentUserId;
        }
    }

    @GuardedBy("mLock")
    private boolean isStartedVisibleProfileLocked(@UserIdInt int userId) {
        int profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
    private boolean isStartedProfile(@UserIdInt int userId) {
        int profileGroupId;
        synchronized (mLock) {
            profileGroupId = mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
        }
        return isProfile(userId, profileGroupId);
    }

    private void validateUserStartMode(@UserStartMode int userStartMode) {
        switch (userStartMode) {
            case USER_START_MODE_FOREGROUND:
            case USER_START_MODE_BACKGROUND:
            case USER_START_MODE_BACKGROUND_VISIBLE:
                return;
    private @UserIdInt int getStartedProfileGroupId(@UserIdInt int userId) {
        synchronized (mLock) {
            return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
        }
        throw new IllegalArgumentException("Invalid user start mode: " + userStartMode);
    }

    private static String secondaryDisplayMappingStatusToString(
+6 −4
Original line number Diff line number Diff line
@@ -75,8 +75,8 @@ public final class UserVisibilityMediatorMUPANDTest
        assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID);

        // Make sure another user cannot be started on default display
        int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, otherUserId, BG_VISIBLE,
                DEFAULT_DISPLAY);
        int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, visibleBgUserId,
                BG_VISIBLE, DEFAULT_DISPLAY);
        assertStartUserResult(result2, USER_ASSIGNMENT_RESULT_FAILURE,
                "when user (%d) is starting on default display after it was started by user %d",
                otherUserId, visibleBgUserId);
@@ -119,8 +119,8 @@ public final class UserVisibilityMediatorMUPANDTest
        assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID);

        // Make sure another user cannot be started on default display
        int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, otherUserId, BG_VISIBLE,
                DEFAULT_DISPLAY);
        int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, visibleBgUserId,
                BG_VISIBLE, DEFAULT_DISPLAY);
        assertStartUserResult(result2, USER_ASSIGNMENT_RESULT_FAILURE,
                "when user (%d) is starting on default display after it was started by user %d",
                otherUserId, visibleBgUserId);
@@ -128,6 +128,7 @@ public final class UserVisibilityMediatorMUPANDTest

        listener.verify();
    }
  /* TODO: re-add

    @Test
    public void
@@ -226,4 +227,5 @@ public final class UserVisibilityMediatorMUPANDTest

        listener.verify();
    }
  */
}
+6 −44

File changed.

Preview size limit exceeded, changes collapsed.

+30 −71

File changed.

Preview size limit exceeded, changes collapsed.