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

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

Merge "Delegated user visibility changes from UserController to UserVisibilityMediator."

parents 90e78e90 e4a65094
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -977,12 +977,11 @@ message UserControllerProto {
        optional int32 profile = 2;
    }
    repeated UserProfile user_profile_group_ids = 4;
    repeated int32 visible_users_array = 5;

    // current_user contains the id of the current user, while current_profiles contains the ids of
    // both the current user and its profiles (if any)
    optional int32 current_user = 6;
    repeated int32 current_profiles = 7;
    optional int32 current_user = 5;
    repeated int32 current_profiles = 6;
}

// sync with com.android.server.am.AppTimeTracker.java
+13 −127
Original line number Diff line number Diff line
@@ -100,7 +100,6 @@ import android.util.EventLog;
import android.util.IntArray;
import android.util.Pair;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
@@ -177,7 +176,8 @@ class UserController implements Handler.Callback {
    static final int START_USER_SWITCH_FG_MSG = 120;
    static final int COMPLETE_USER_SWITCH_MSG = 130;
    static final int USER_COMPLETED_EVENT_MSG = 140;
    static final int USER_VISIBILITY_CHANGED_MSG = 150;

    private static final int NO_ARG2 = 0;

    // Message constant to clear {@link UserJourneySession} from {@link mUserIdToUserJourneyMap} if
    // the user journey, defined in the UserLifecycleJourneyReported atom for statsd, is not
@@ -437,20 +437,6 @@ class UserController implements Handler.Callback {
    /** @see #getLastUserUnlockingUptime */
    private volatile long mLastUserUnlockingUptime = 0;

    // TODO(b/244333150) remove this array and let UserVisibilityMediator call the listeners
    // directly, as that class should be responsible for all user visibility logic (for example,
    // when the foreground user is switched out, its profiles also become invisible)
    /**
     * List of visible users (as defined by {@link UserManager#isUserVisible()}).
     *
     * <p>It's only used to call {@link UserManagerInternal} when the visibility is changed upon
     * the user starting or stopping.
     *
     * <p>Note: only the key is used, not the value.
     */
    @GuardedBy("mLock")
    private final SparseBooleanArray mVisibleUsers = new SparseBooleanArray();

    private final UserLifecycleListener mUserLifecycleListener = new UserLifecycleListener() {
        @Override
        public void onUserCreated(UserInfo user, Object token) {
@@ -1092,24 +1078,11 @@ class UserController implements Handler.Callback {
            // instead.
            userManagerInternal.unassignUserFromDisplayOnStop(userId);

            final boolean visibilityChanged;
            boolean visibleBefore;
            synchronized (mLock) {
                visibleBefore = mVisibleUsers.get(userId);
                if (visibleBefore) {
                    deleteVisibleUserLocked(userId);
                    visibilityChanged = true;
                } else {
                    visibilityChanged = false;
                }
            }

            updateStartedUserArrayLU();

            final boolean allowDelayedLockingCopied = allowDelayedLocking;
            Runnable finishUserStoppingAsync = () ->
                    mHandler.post(() -> finishUserStopping(userId, uss, allowDelayedLockingCopied,
                            visibilityChanged));
                    mHandler.post(() -> finishUserStopping(userId, uss, allowDelayedLockingCopied));

            if (mInjector.getUserManager().isPreCreated(userId)) {
                finishUserStoppingAsync.run();
@@ -1146,22 +1119,8 @@ class UserController implements Handler.Callback {
        }
    }

    private void addVisibleUserLocked(@UserIdInt int userId) {
        if (DEBUG_MU) {
            Slogf.d(TAG, "adding %d to mVisibleUsers", userId);
        }
        mVisibleUsers.put(userId, true);
    }

    private void deleteVisibleUserLocked(@UserIdInt int userId) {
        if (DEBUG_MU) {
            Slogf.d(TAG, "deleting %d from mVisibleUsers", userId);
        }
        mVisibleUsers.delete(userId);
    }

    private void finishUserStopping(final int userId, final UserState uss,
            final boolean allowDelayedLocking, final boolean visibilityChanged) {
            final boolean allowDelayedLocking) {
        EventLog.writeEvent(EventLogTags.UC_FINISH_USER_STOPPING, userId);
        synchronized (mLock) {
            if (uss.state != UserState.STATE_STOPPING) {
@@ -1179,9 +1138,6 @@ class UserController implements Handler.Callback {
                BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,
                Integer.toString(userId), userId);
        mInjector.getSystemServiceManager().onUserStopping(userId);
        if (visibilityChanged) {
            mInjector.onUserVisibilityChanged(userId, /* visible= */ false);
        }

        Runnable finishUserStoppedAsync = () ->
                mHandler.post(() -> finishUserStopped(uss, allowDelayedLocking));
@@ -1655,25 +1611,13 @@ class UserController implements Handler.Callback {
                    userInfo.profileGroupId, foreground, displayId);
            t.traceEnd();

            boolean visible;
            switch (result) {
                case UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE:
                    visible = true;
                    break;
                case UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE:
                    visible = false;
                    break;
                default:
                    Slogf.wtf(TAG, "Wrong result from assignUserToDisplayOnStart(): %d", result);
                    // Fall through
                case UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE:
            if (result == UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE) {
                Slogf.e(TAG, "%s user(%d) / display (%d) assignment failed: %s",
                        (foreground ? "fg" : "bg"), userId, displayId,
                        UserManagerInternal.userAssignmentResultToString(result));
                return false;
            }


            // TODO(b/239982558): might need something similar for bg users on secondary display
            if (foreground && isUserSwitchUiEnabled()) {
                t.traceBegin("startFreezingScreen");
@@ -1724,15 +1668,7 @@ class UserController implements Handler.Callback {
                // Make sure the old user is no longer considering the display to be on.
                mInjector.reportGlobalUsageEvent(UsageEvents.Event.SCREEN_NON_INTERACTIVE);
                boolean userSwitchUiEnabled;
                // TODO(b/244333150): temporary state until the callback logic is moved to
                // UserVisibilityManager
                int previousCurrentUserId; boolean notifyPreviousCurrentUserId;
                synchronized (mLock) {
                    previousCurrentUserId = mCurrentUserId;
                    notifyPreviousCurrentUserId = mVisibleUsers.get(previousCurrentUserId);
                    if (notifyPreviousCurrentUserId) {
                        deleteVisibleUserLocked(previousCurrentUserId);
                    }
                    mCurrentUserId = userId;
                    mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
                    userSwitchUiEnabled = mUserSwitchUiEnabled;
@@ -1753,10 +1689,6 @@ class UserController implements Handler.Callback {
                        mInjector.getWindowManager().lockNow(null);
                    }
                }
                if (notifyPreviousCurrentUserId) {
                    mHandler.sendMessage(mHandler.obtainMessage(USER_VISIBILITY_CHANGED_MSG,
                            previousCurrentUserId, 0));
                }

            } else {
                final Integer currentUserIdInt = mCurrentUserId;
@@ -1768,12 +1700,6 @@ class UserController implements Handler.Callback {
            }
            t.traceEnd();

            if (visible) {
                synchronized (mLock) {
                    addVisibleUserLocked(userId);
                }
            }

            // Make sure user is in the started state.  If it is currently
            // stopping, we need to knock that off.
            if (uss.state == UserState.STATE_STOPPING) {
@@ -1810,20 +1736,10 @@ class UserController implements Handler.Callback {
                // Booting up a new user, need to tell system services about it.
                // Note that this is on the same handler as scheduling of broadcasts,
                // which is important because it needs to go first.
                mHandler.sendMessage(mHandler.obtainMessage(USER_START_MSG, userId,
                        visible ? 1 : 0));
                mHandler.sendMessage(mHandler.obtainMessage(USER_START_MSG, userId, NO_ARG2));
                t.traceEnd();
            }

            if (visible) {
                // User was already running and became visible (for example, when switching to a
                // user that was started in the background before), so it's necessary to explicitly
                // notify the services (while when the user starts from BOOTING, USER_START_MSG
                // takes care of that.
                mHandler.sendMessage(
                        mHandler.obtainMessage(USER_VISIBILITY_CHANGED_MSG, userId, 1));
            }

            t.traceBegin("sendMessages");
            if (foreground) {
                mHandler.sendMessage(mHandler.obtainMessage(USER_CURRENT_MSG, userId, oldUserId));
@@ -2248,11 +2164,6 @@ class UserController implements Handler.Callback {
        uss.switching = false;
        stopGuestOrEphemeralUserIfBackground(oldUserId);
        stopUserOnSwitchIfEnforced(oldUserId);
        if (oldUserId == UserHandle.USER_SYSTEM) {
            // System user is never stopped, but its visibility is changed (as it is brought to the
            // background)
            updateSystemUserVisibility(t, /* visible= */ false);
        }

        t.traceEnd(); // end continueUserSwitch
    }
@@ -2614,27 +2525,10 @@ class UserController implements Handler.Callback {
            // Don't need to call on HSUM because it will be called when the system user is
            // restarted on background
            mInjector.onUserStarting(UserHandle.USER_SYSTEM);
            mInjector.onUserVisibilityChanged(UserHandle.USER_SYSTEM, /* visible= */ true);
            mInjector.onSystemUserVisibilityChanged(/* visible= */ true);
        }
    }

    private void updateSystemUserVisibility(TimingsTraceAndSlog t, boolean visible) {
        t.traceBegin("update-system-userVisibility-" + visible);
        if (DEBUG_MU) {
            Slogf.d(TAG, "updateSystemUserVisibility(): visible=%b", visible);
        }
        int userId = UserHandle.USER_SYSTEM;
        synchronized (mLock) {
            if (visible) {
                addVisibleUserLocked(userId);
            } else {
                deleteVisibleUserLocked(userId);
            }
        }
        mInjector.onUserVisibilityChanged(userId, visible);
        t.traceEnd();
    }

    /**
     * Refreshes the internal caches related to user profiles.
     *
@@ -3032,9 +2926,6 @@ class UserController implements Handler.Callback {
                    proto.end(uToken);
                }
            }
            for (int i = 0; i < mVisibleUsers.size(); i++) {
                proto.write(UserControllerProto.VISIBLE_USERS_ARRAY, mVisibleUsers.keyAt(i));
            }
            proto.write(UserControllerProto.CURRENT_USER, mCurrentUserId);
            for (int i = 0; i < mCurrentProfileIds.length; i++) {
                proto.write(UserControllerProto.CURRENT_PROFILES, mCurrentProfileIds[i]);
@@ -3094,7 +2985,6 @@ class UserController implements Handler.Callback {
                pw.println("  mSwitchingToSystemUserMessage: " + mSwitchingToSystemUserMessage);
            }
            pw.println("  mLastUserUnlockingUptime: " + mLastUserUnlockingUptime);
            pw.println("  mVisibleUsers: " + mVisibleUsers);
        }
    }

@@ -3212,10 +3102,6 @@ class UserController implements Handler.Callback {
            case COMPLETE_USER_SWITCH_MSG:
                completeUserSwitch(msg.arg1);
                break;
            case USER_VISIBILITY_CHANGED_MSG:
                mInjector.onUserVisibilityChanged(/* userId= */ msg.arg1,
                        /* visible= */ msg.arg2 == 1);
                break;
        }
        return false;
    }
@@ -3750,8 +3636,8 @@ class UserController implements Handler.Callback {
            getSystemServiceManager().onUserStarting(TimingsTraceAndSlog.newAsyncLog(), userId);
        }

        void onUserVisibilityChanged(@UserIdInt int userId, boolean visible) {
            getUserManagerInternal().onUserVisibilityChanged(userId, visible);
        void onSystemUserVisibilityChanged(boolean visible) {
            getUserManagerInternal().onSystemUserVisibilityChanged(visible);
        }
    }
}
+4 −2
Original line number Diff line number Diff line
@@ -435,8 +435,10 @@ public abstract class UserManagerInternal {
    /** Removes a {@link UserVisibilityListener}. */
    public abstract void removeUserVisibilityListener(UserVisibilityListener listener);

    /** TODO(b/244333150): temporary method until UserVisibilityMediator handles that logic */
    public abstract void onUserVisibilityChanged(@UserIdInt int userId, boolean visible);
    // TODO(b/242195409): remove this method if not needed anymore
    /** Notify {@link UserVisibilityListener listeners} that the visibility of the
     * {@link android.os.UserHandle#USER_SYSTEM} changed. */
    public abstract void onSystemUserVisibilityChanged(boolean visible);

    /** Return the integer types of the given user IDs. Only used for reporting metrics to statsd.
     */
+4 −27
Original line number Diff line number Diff line
@@ -97,7 +97,6 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
import android.util.Slog;
@@ -126,7 +125,6 @@ import com.android.server.BundleUtils;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.SystemService;
import com.android.server.am.EventLogTags;
import com.android.server.am.UserState;
import com.android.server.pm.UserManagerInternal.UserLifecycleListener;
import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
@@ -512,10 +510,6 @@ public class UserManagerService extends IUserManager.Stub {
    @GuardedBy("mUserLifecycleListeners")
    private final ArrayList<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();

    // TODO(b/244333150): temporary array, should belong to UserVisibilityMediator
    @GuardedBy("mUserVisibilityListeners")
    private final ArrayList<UserVisibilityListener> mUserVisibilityListeners = new ArrayList<>();

    private final LockPatternUtils mLockPatternUtils;

    private final String ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK =
@@ -6383,9 +6377,6 @@ public class UserManagerService extends IUserManager.Stub {
        synchronized (mUserLifecycleListeners) {
            pw.println("  user lifecycle events: " + mUserLifecycleListeners.size());
        }
        synchronized (mUserVisibilityListeners) {
            pw.println("  user visibility events: " + mUserVisibilityListeners.size());
        }

        // Dump UserTypes
        pw.println();
@@ -6961,31 +6952,17 @@ public class UserManagerService extends IUserManager.Stub {

        @Override
        public void addUserVisibilityListener(UserVisibilityListener listener) {
            synchronized (mUserVisibilityListeners) {
                mUserVisibilityListeners.add(listener);
            }
            mUserVisibilityMediator.addListener(listener);
        }

        @Override
        public void removeUserVisibilityListener(UserVisibilityListener listener) {
            synchronized (mUserVisibilityListeners) {
                mUserVisibilityListeners.remove(listener);
            }
            mUserVisibilityMediator.removeListener(listener);
        }

        @Override
        public void onUserVisibilityChanged(@UserIdInt int userId, boolean visible) {
            EventLog.writeEvent(EventLogTags.UM_USER_VISIBILITY_CHANGED, userId, visible ? 1 : 0);
            mHandler.post(() -> {
                UserVisibilityListener[] listeners;
                synchronized (mUserVisibilityListeners) {
                    listeners = new UserVisibilityListener[mUserVisibilityListeners.size()];
                    mUserVisibilityListeners.toArray(listeners);
                }
                for (UserVisibilityListener listener : listeners) {
                    listener.onUserVisibilityChanged(userId, visible);
                }
            });
        public void onSystemUserVisibilityChanged(boolean visible) {
            mUserVisibilityMediator.onSystemUserVisibilityChanged(visible);
        }

        @Override
+16 −4
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Dumpable;
import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
import android.util.SparseIntArray;
@@ -40,6 +41,7 @@ import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import com.android.server.am.EventLogTags;
import com.android.server.pm.UserManagerInternal.UserAssignmentResult;
import com.android.server.pm.UserManagerInternal.UserVisibilityListener;
import com.android.server.utils.Slogf;
@@ -68,6 +70,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
public final class UserVisibilityMediator implements Dumpable {

    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();

@@ -381,8 +384,8 @@ public final class UserVisibilityMediator implements Dumpable {
    public boolean isUserVisible(@UserIdInt int userId) {
        // First check current foreground user and their profiles (on main display)
        if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
            if (DBG) {
                Slogf.d(TAG, "isUserVisible(%d): true to current user or profile", userId);
            if (VERBOSE) {
                Slogf.v(TAG, "isUserVisible(%d): true to current user or profile", userId);
            }
            return true;
        }
@@ -517,6 +520,14 @@ public final class UserVisibilityMediator implements Dumpable {
        }
    }

    // TODO(b/242195409): remove this method if not needed anymore
    /**
     * Nofify all listeners that the system user visibility changed.
     */
    void onSystemUserVisibilityChanged(boolean visible) {
        dispatchVisibilityChanged(mListeners, USER_SYSTEM, visible);
    }

    /**
     * Nofify all listeners about the visibility changes from before / after a change of state.
     */
@@ -534,7 +545,7 @@ public final class UserVisibilityMediator implements Dumpable {
            Slogf.d(TAG,
                    "dispatchVisibilityChanged(): visibleUsersBefore=%s, visibleUsersAfter=%s, "
                    + "%d listeners (%s)", visibleUsersBefore, visibleUsersAfter, listeners.size(),
                    mListeners);
                    listeners);
        }
        for (int i = 0; i < visibleUsersBefore.size(); i++) {
            int userId = visibleUsersBefore.get(i);
@@ -552,13 +563,14 @@ public final class UserVisibilityMediator implements Dumpable {

    private void dispatchVisibilityChanged(CopyOnWriteArrayList<UserVisibilityListener> listeners,
            @UserIdInt int userId, boolean visible) {
        EventLog.writeEvent(EventLogTags.UM_USER_VISIBILITY_CHANGED, userId, visible ? 1 : 0);
        if (DBG) {
            Slogf.d(TAG, "dispatchVisibilityChanged(%d -> %b): sending to %d listeners",
                    userId, visible, listeners.size());
        }
        for (int i = 0; i < mListeners.size(); i++) {
            UserVisibilityListener listener =  mListeners.get(i);
            if (DBG) {
            if (VERBOSE) {
                Slogf.v(TAG, "dispatchVisibilityChanged(%d -> %b): sending to %s",
                        userId, visible, listener);
            }
Loading