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

Commit b4127253 authored by Nikhil Kumar's avatar Nikhil Kumar Committed by Android (Google) Code Review
Browse files

Merge "Refactored start user flow in case of immediate restart after stop"

parents c76b8474 52af2869
Loading
Loading
Loading
Loading
+75 −11
Original line number Diff line number Diff line
@@ -80,7 +80,6 @@ import android.os.IBinder;
import android.os.IProgressListener;
import android.os.IRemoteCallback;
import android.os.IUserManager;
import android.os.Looper;
import android.os.Message;
import android.os.PowerWhitelistManager;
import android.os.Process;
@@ -437,6 +436,12 @@ class UserController implements Handler.Callback {
    /** @see #getLastUserUnlockingUptime */
    private volatile long mLastUserUnlockingUptime = 0;

    /**
     * Pending user starts waiting for shutdown step to complete.
     */
    @GuardedBy("mLock")
    private final List<PendingUserStart> mPendingUserStarts = new ArrayList<>();

    private final UserLifecycleListener mUserLifecycleListener = new UserLifecycleListener() {
        @Override
        public void onUserCreated(UserInfo user, Object token) {
@@ -1184,9 +1189,13 @@ class UserController implements Handler.Callback {
            } else {
                stopped = true;
                // User can no longer run.
                Slogf.i(TAG, "Removing user state from UserController.mStartedUsers for user #"
                        + userId + " as a result of user being stopped");
                mStartedUsers.remove(userId);

                mUserLru.remove(Integer.valueOf(userId));
                updateStartedUserArrayLU();

                if (allowDelayedLocking && !keyEvictedCallbacks.isEmpty()) {
                    Slogf.wtf(TAG,
                            "Delayed locking enabled while KeyEvictedCallbacks not empty, userId:"
@@ -1200,7 +1209,10 @@ class UserController implements Handler.Callback {
            }
        }
        if (stopped) {
            Slogf.i(TAG, "Removing user state from UserManager.mUserStates for user #" + userId
                    + " as a result of user being stopped");
            mInjector.getUserManagerInternal().removeUserState(userId);

            mInjector.activityManagerOnUserStopped(userId);
            // Clean up all state and processes associated with the user.
            // Kill all the processes for the user.
@@ -1228,10 +1240,13 @@ class UserController implements Handler.Callback {
                    USER_LIFECYCLE_EVENT_STATE_FINISH);
            clearSessionId(userId);

            if (!lockUser) {
                return;
            }
            if (lockUser) {
                dispatchUserLocking(userIdToLock, keyEvictedCallbacks);
            }

            // Resume any existing pending user start,
            // which was paused while the SHUTDOWN flow of the user was in progress.
            resumePendingUserStarts(userId);
        } else {
            logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_STOP_USER,
                    USER_LIFECYCLE_EVENT_STATE_NONE);
@@ -1239,6 +1254,31 @@ class UserController implements Handler.Callback {
        }
    }

    /**
     * Resume any existing pending user start for the specified userId which was paused
     * while the shutdown flow of the user was in progress.
     * Remove all the handled user starts from mPendingUserStarts.
     * @param userId the id of the user
     */
    private void resumePendingUserStarts(@UserIdInt int userId) {
        synchronized (mLock) {
            final List<PendingUserStart> handledUserStarts = new ArrayList<>();

            for (PendingUserStart userStart: mPendingUserStarts) {
                if (userStart.userId == userId) {
                    Slogf.i(TAG, "resumePendingUserStart for" + userStart);
                    mHandler.post(() -> startUser(userStart.userId,
                            userStart.isForeground, userStart.unlockListener));

                    handledUserStarts.add(userStart);
                }
            }
            // remove all the pending user starts which are now handled
            mPendingUserStarts.removeAll(handledUserStarts);
        }
    }


    private void dispatchUserLocking(@UserIdInt int userId,
            @Nullable List<KeyEvictedCallback> keyEvictedCallbacks) {
        // Evict the user's credential encryption key. Performed on FgThread to make it
@@ -1252,6 +1292,7 @@ class UserController implements Handler.Callback {
                }
            }
            try {
                Slogf.i(TAG, "Locking CE storage for user #" + userId);
                mInjector.getStorageManager().lockUserKey(userId);
            } catch (RemoteException re) {
                throw re.rethrowAsRuntimeException();
@@ -1657,10 +1698,11 @@ class UserController implements Handler.Callback {
                    updateStartedUserArrayLU();
                    needStart = true;
                    updateUmState = true;
                } else if (uss.state == UserState.STATE_SHUTDOWN && !isCallingOnHandlerThread()) {
                } else if (uss.state == UserState.STATE_SHUTDOWN) {
                    Slogf.i(TAG, "User #" + userId
                            + " is shutting down - will start after full stop");
                    mHandler.post(() -> startUser(userId, foreground, unlockListener));
                            + " is shutting down - will start after full shutdown");
                    mPendingUserStarts.add(new PendingUserStart(userId,
                            foreground, unlockListener));
                    t.traceEnd(); // updateStartedUserArrayStarting
                    return true;
                }
@@ -1818,10 +1860,6 @@ class UserController implements Handler.Callback {
        return true;
    }

    private boolean isCallingOnHandlerThread() {
        return Looper.myLooper() == mHandler.getLooper();
    }

    /**
     * Start user, if its not already running, and bring it to foreground.
     */
@@ -3390,6 +3428,32 @@ class UserController implements Handler.Callback {
        }
    }

    /**
     * Helper class for keeping track of user starts which are paused while user's
     * shutdown is taking place.
     */
    private static class PendingUserStart {
        public final @UserIdInt int userId;
        public final boolean isForeground;
        public final IProgressListener unlockListener;

        PendingUserStart(int userId, boolean foreground,
                IProgressListener unlockListener) {
            this.userId = userId;
            this.isForeground = foreground;
            this.unlockListener = unlockListener;
        }

        @Override
        public String toString() {
            return "PendingUserStart{"
                    + "userId=" + userId
                    + ", isForeground=" + isForeground
                    + ", unlockListener=" + unlockListener
                    + '}';
        }
    }

    @VisibleForTesting
    static class Injector {
        private final ActivityManagerService mService;