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

Commit 858d8a65 authored by Craig Mautner's avatar Craig Mautner
Browse files

Fix user switching.

- Save and restore WindowManager stack states.
- Maintain ActivityManager activity states based on the stack
the activity is in.

Fixes bug 8646641.

Change-Id: I16c76c7708ab49121c3884a7e5bf219898b92d3f
parent cf910b0c
Loading
Loading
Loading
Loading
+14 −9
Original line number Original line Diff line number Diff line
@@ -4133,7 +4133,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                }
                }
            }
            }
            if (mBooted) {
            if (mBooted) {
                mStackSupervisor.resumeTopActivityLocked();
                mStackSupervisor.resumeTopActivitiesLocked();
                mStackSupervisor.scheduleIdleLocked();
                mStackSupervisor.scheduleIdleLocked();
            }
            }
        }
        }
@@ -4984,6 +4984,7 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
        }
    }
    }
    @Override
    public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
    public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
        enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
        enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
                "setProcessForeground()");
                "setProcessForeground()");
@@ -5007,6 +5008,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                }
                }
                if (isForeground && token != null) {
                if (isForeground && token != null) {
                    ForegroundToken newToken = new ForegroundToken() {
                    ForegroundToken newToken = new ForegroundToken() {
                        @Override
                        public void binderDied() {
                        public void binderDied() {
                            foregroundTokenDied(this);
                            foregroundTokenDied(this);
                        }
                        }
@@ -5041,6 +5043,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            mActivityManagerService = activityManagerService;
            mActivityManagerService = activityManagerService;
        }
        }
        @Override
        public boolean checkPermission(String permission, int pid, int uid) {
        public boolean checkPermission(String permission, int pid, int uid) {
            return mActivityManagerService.checkPermission(permission, pid,
            return mActivityManagerService.checkPermission(permission, pid,
                    uid) == PackageManager.PERMISSION_GRANTED;
                    uid) == PackageManager.PERMISSION_GRANTED;
@@ -5048,12 +5051,14 @@ public final class ActivityManagerService extends ActivityManagerNative
    }
    }
    class IntentFirewallInterface implements IntentFirewall.AMSInterface {
    class IntentFirewallInterface implements IntentFirewall.AMSInterface {
        @Override
        public int checkComponentPermission(String permission, int pid, int uid,
        public int checkComponentPermission(String permission, int pid, int uid,
                int owningUid, boolean exported) {
                int owningUid, boolean exported) {
            return ActivityManagerService.this.checkComponentPermission(permission, pid, uid,
            return ActivityManagerService.this.checkComponentPermission(permission, pid, uid,
                    owningUid, exported);
                    owningUid, exported);
        }
        }
        @Override
        public Object getAMSLock() {
        public Object getAMSLock() {
            return ActivityManagerService.this;
            return ActivityManagerService.this;
        }
        }
@@ -8281,7 +8286,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            } finally {
            } finally {
                Binder.restoreCallingIdentity(ident);
                Binder.restoreCallingIdentity(ident);
            }
            }
            mStackSupervisor.resumeTopActivityLocked();
            mStackSupervisor.resumeTopActivitiesLocked();
            sendUserSwitchBroadcastsLocked(-1, mCurrentUserId);
            sendUserSwitchBroadcastsLocked(-1, mCurrentUserId);
        }
        }
    }
    }
@@ -8396,10 +8401,10 @@ public final class ActivityManagerService extends ActivityManagerNative
                // annoy the user repeatedly.  Unless it is persistent, since those
                // annoy the user repeatedly.  Unless it is persistent, since those
                // processes run critical code.
                // processes run critical code.
                removeProcessLocked(app, false, false, "crash");
                removeProcessLocked(app, false, false, "crash");
                mStackSupervisor.resumeTopActivityLocked();
                mStackSupervisor.resumeTopActivitiesLocked();
                return false;
                return false;
            }
            }
            mStackSupervisor.resumeTopActivityLocked();
            mStackSupervisor.resumeTopActivitiesLocked();
        } else {
        } else {
            mStackSupervisor.finishTopRunningActivityLocked(app);
            mStackSupervisor.finishTopRunningActivityLocked(app);
        }
        }
+4 −6
Original line number Original line Diff line number Diff line
@@ -234,7 +234,7 @@ final class ActivityStack {
    int mThumbnailWidth = -1;
    int mThumbnailWidth = -1;
    int mThumbnailHeight = -1;
    int mThumbnailHeight = -1;


    private int mCurrentUser;
    int mCurrentUser;


    final int mStackId;
    final int mStackId;


@@ -576,7 +576,8 @@ final class ActivityStack {
    }
    }


    /*
    /*
     * Move the activities around in the stack to bring a user to the foreground.
     * Move the activities around in the stack to bring a user to the foreground. This only
     * matters on the home stack. All other stacks are single user.
     * @return whether there are any activities for the specified user.
     * @return whether there are any activities for the specified user.
     */
     */
    final boolean switchUserLocked(int userId, UserStartedState uss) {
    final boolean switchUserLocked(int userId, UserStartedState uss) {
@@ -602,9 +603,6 @@ final class ActivityStack {
            }
            }
        }
        }


        // task is now the original topmost TaskRecord. Transition from the old top to the new top.
        ActivityRecord top = task != null ? task.getTopActivity() : null;
        resumeTopActivityLocked(top);
        return haveActivities;
        return haveActivities;
    }
    }


@@ -1718,7 +1716,7 @@ final class ActivityStack {
        }
        }


        if (doResume) {
        if (doResume) {
            mStackSupervisor.resumeTopActivityLocked();
            mStackSupervisor.resumeTopActivitiesLocked();
        }
        }
    }
    }


+62 −22
Original line number Original line Diff line number Diff line
@@ -61,6 +61,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserHandle;
import android.util.EventLog;
import android.util.EventLog;
import android.util.Slog;
import android.util.Slog;
import android.util.SparseArray;


import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
@@ -160,6 +161,9 @@ public class ActivityStackSupervisor {
     * is being brought in front of us. */
     * is being brought in front of us. */
    boolean mUserLeaving = false;
    boolean mUserLeaving = false;


    /** Stacks belonging to users other than mCurrentUser. Indexed by userId. */
    final SparseArray<UserState> mUserStates = new SparseArray<UserState>();

    public ActivityStackSupervisor(ActivityManagerService service, Context context,
    public ActivityStackSupervisor(ActivityManagerService service, Context context,
            Looper looper) {
            Looper looper) {
        mService = service;
        mService = service;
@@ -213,6 +217,9 @@ public class ActivityStackSupervisor {
    }
    }


    boolean isFrontStack(ActivityStack stack) {
    boolean isFrontStack(ActivityStack stack) {
        if (stack.mCurrentUser != mCurrentUser) {
            return false;
        }
        return !(stack.isHomeStack() ^ getFocusedStack().isHomeStack());
        return !(stack.isHomeStack() ^ getFocusedStack().isHomeStack());
    }
    }


@@ -319,6 +326,9 @@ public class ActivityStackSupervisor {
        final String processName = app.processName;
        final String processName = app.processName;
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = mStacks.get(stackNdx);
            final ActivityStack stack = mStacks.get(stackNdx);
            if (!isFrontStack(stack)) {
                continue;
            }
            ActivityRecord hr = stack.topRunningActivityLocked(null);
            ActivityRecord hr = stack.topRunningActivityLocked(null);
            if (hr != null) {
            if (hr != null) {
                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
@@ -449,6 +459,9 @@ public class ActivityStackSupervisor {
        }
        }
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = mStacks.get(stackNdx);
            final ActivityStack stack = mStacks.get(stackNdx);
            if (stack.mCurrentUser != mCurrentUser) {
                continue;
            }
            if (stack != mFocusedStack && isFrontStack(stack)) {
            if (stack != mFocusedStack && isFrontStack(stack)) {
                r = stack.topRunningActivityLocked(null);
                r = stack.topRunningActivityLocked(null);
                if (r != null) {
                if (r != null) {
@@ -1145,8 +1158,14 @@ public class ActivityStackSupervisor {


    ActivityStack getCorrectStack(ActivityRecord r) {
    ActivityStack getCorrectStack(ActivityRecord r) {
        if (!r.isHomeActivity) {
        if (!r.isHomeActivity) {
            if (mStacks.size() == 1) {
            int stackNdx;
                // Time to create the first app stack.
            for (stackNdx = mStacks.size() - 1; stackNdx > 0; --stackNdx) {
                if (mStacks.get(stackNdx).mCurrentUser == mCurrentUser) {
                    break;
                }
            }
            if (stackNdx == 0) {
                // Time to create the first app stack for this user.
                int stackId = mService.createStack(-1, HOME_STACK_ID,
                int stackId = mService.createStack(-1, HOME_STACK_ID,
                        StackBox.TASK_STACK_GOES_OVER, 1.0f);
                        StackBox.TASK_STACK_GOES_OVER, 1.0f);
                mFocusedStack = getStack(stackId);
                mFocusedStack = getStack(stackId);
@@ -1776,7 +1795,7 @@ public class ActivityStackSupervisor {
        return didSomething;
        return didSomething;
    }
    }


    void resumeTopActivityLocked() {
    void resumeTopActivitiesLocked() {
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final ActivityStack stack = mStacks.get(stackNdx);
            final ActivityStack stack = mStacks.get(stackNdx);
            if (isFrontStack(stack)) {
            if (isFrontStack(stack)) {
@@ -1816,7 +1835,6 @@ public class ActivityStackSupervisor {
    }
    }


    int createStack() {
    int createStack() {
        synchronized (this) {
        while (true) {
        while (true) {
            if (++mLastStackId <= HOME_STACK_ID) {
            if (++mLastStackId <= HOME_STACK_ID) {
                mLastStackId = HOME_STACK_ID + 1;
                mLastStackId = HOME_STACK_ID + 1;
@@ -1828,7 +1846,6 @@ public class ActivityStackSupervisor {
        mStacks.add(new ActivityStack(mService, mContext, mLooper, mLastStackId));
        mStacks.add(new ActivityStack(mService, mContext, mLooper, mLastStackId));
        return mLastStackId;
        return mLastStackId;
    }
    }
    }


    void moveTaskToStack(int taskId, int stackId, boolean toTop) {
    void moveTaskToStack(int taskId, int stackId, boolean toTop) {
        final ActivityStack stack = getStack(stackId);
        final ActivityStack stack = getStack(stackId);
@@ -1938,16 +1955,22 @@ public class ActivityStackSupervisor {
    }
    }


    boolean switchUserLocked(int userId, UserStartedState uss) {
    boolean switchUserLocked(int userId, UserStartedState uss) {
        mUserStates.put(mCurrentUser, new UserState());
        mCurrentUser = userId;
        mCurrentUser = userId;
        mStartingUsers.add(uss);
        UserState userState = mUserStates.get(userId);
        boolean haveActivities = false;
        if (userState != null) {
        final int numStacks = mStacks.size();
            userState.restore();
        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
            mUserStates.delete(userId);
            final ActivityStack stack = mStacks.get(stackNdx);
        } else {
            if (isFrontStack(stack)) {
            mFocusedStack = null;
                haveActivities |= stack.switchUserLocked(userId, uss);
            mStackState = STACK_STATE_HOME_IN_FRONT;
            }
        }
        }

        mStartingUsers.add(uss);
        boolean haveActivities = mHomeStack.switchUserLocked(userId, uss);

        resumeTopActivitiesLocked();

        return haveActivities;
        return haveActivities;
    }
    }


@@ -2203,4 +2226,21 @@ public class ActivityStackSupervisor {
            }
            }
        }
        }
    }
    }

    private final class UserState {
        final ActivityStack mSavedFocusedStack;
        final int mSavedStackState;

        public UserState() {
            ActivityStackSupervisor supervisor = ActivityStackSupervisor.this;
            mSavedFocusedStack = supervisor.mFocusedStack;
            mSavedStackState = supervisor.mStackState;
        }

        void restore() {
            ActivityStackSupervisor supervisor = ActivityStackSupervisor.this;
            supervisor.mFocusedStack = mSavedFocusedStack;
            supervisor.mStackState = mSavedStackState;
        }
    }
}
}
+91 −0
Original line number Original line Diff line number Diff line
@@ -18,10 +18,12 @@ package com.android.server.wm;


import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerService.TAG;
import static com.android.server.wm.WindowManagerService.TAG;


import android.graphics.Rect;
import android.graphics.Rect;
import android.util.Slog;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.DisplayInfo;
import android.view.InputChannel;
import android.view.InputChannel;
@@ -104,6 +106,8 @@ class DisplayContent {
    /** Detect user tapping outside of current focused stack bounds .*/
    /** Detect user tapping outside of current focused stack bounds .*/
    StackTapDetector mTapDetector;
    StackTapDetector mTapDetector;


    SparseArray<UserStacks> mUserStacks = new SparseArray<UserStacks>();

    /**
    /**
     * @param display May not be null.
     * @param display May not be null.
     */
     */
@@ -145,6 +149,22 @@ class DisplayContent {
     */
     */
    ArrayList<Task> getTasks() {
    ArrayList<Task> getTasks() {
        mTmpTasks.clear();
        mTmpTasks.clear();
        // First do the tasks belonging to other users.
        final int numUserStacks = mUserStacks.size();
        for (int i = 0; i < numUserStacks; ++i) {
            UserStacks userStacks = mUserStacks.valueAt(i);
            ArrayList<TaskStack> stacks = userStacks.mSavedStackHistory;
            final int numStacks = stacks.size();
            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
                TaskStack stack = stacks.get(stackNdx);
                if (stack != mHomeStack) {
                    if (WindowManagerService.DEBUG_LAYERS) Slog.i(TAG, "getTasks: mStackHistory=" +
                            mStackHistory);
                    mTmpTasks.addAll(stack.getTasks());
                }
            }
        }
        // Now do the current user's tasks.
        final int numStacks = mStackHistory.size();
        final int numStacks = mStackHistory.size();
        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
            mTmpTasks.addAll(mStackHistory.get(stackNdx).getTasks());
            mTmpTasks.addAll(mStackHistory.get(stackNdx).getTasks());
@@ -292,6 +312,14 @@ class DisplayContent {
                return bounds;
                return bounds;
            }
            }
        }
        }
        // Not in the visible stacks, try the saved ones.
        for (int userNdx = mUserStacks.size() - 1; userNdx >= 0; --userNdx) {
            UserStacks userStacks = mUserStacks.valueAt(userNdx);
            Rect bounds = userStacks.mSavedStackBox.getStackBounds(stackId);
            if (bounds != null) {
                return bounds;
            }
        }
        return null;
        return null;
    }
    }


@@ -300,6 +328,26 @@ class DisplayContent {
        return topBox.stackIdFromPoint(x, y);
        return topBox.stackIdFromPoint(x, y);
    }
    }


    void switchUserStacks(int oldUserId, int newUserId) {
        final WindowList windows = getWindowList();
        for (int i = 0; i < windows.size(); i++) {
            final WindowState win = windows.get(i);
            if (win.isHiddenFromUserLocked()) {
                if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding "
                        + win + ", attrs=" + win.mAttrs.type + ", belonging to "
                        + win.mOwnerUid);
                win.hideLw(false);
            }
        }
        // Clear the old user's non-home StackBox
        mUserStacks.put(oldUserId, new UserStacks());
        UserStacks userStacks = mUserStacks.get(newUserId);
        if (userStacks != null) {
            userStacks.restore();
            mUserStacks.delete(newUserId);
        }
    }

    public void dump(String prefix, PrintWriter pw) {
    public void dump(String prefix, PrintWriter pw) {
        pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
        pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
        final String subPrefix = "  " + prefix;
        final String subPrefix = "  " + prefix;
@@ -365,6 +413,49 @@ class DisplayContent {
                  token.dump(pw, "    ");
                  token.dump(pw, "    ");
            }
            }
        }
        }
        if (mUserStacks.size() > 0) {
            pw.println();
            pw.println();
            pw.println("  Saved user stacks:");
            for (int i = 0; i < mUserStacks.size(); ++i) {
                UserStacks userStacks = mUserStacks.valueAt(i);
                pw.print("  UserId="); pw.println(Integer.toHexString(mUserStacks.keyAt(i)));
                pw.print("  StackHistory="); pw.println(userStacks.mSavedStackHistory);
                pw.print("  StackBox="); userStacks.mSavedStackBox.dump("    ", pw);
            }
        }
        pw.println();
    }

    private final class UserStacks {
        final ArrayList<TaskStack> mSavedStackHistory;
        StackBox mSavedStackBox;
        int mBoxNdx;

        public UserStacks() {
            mSavedStackHistory = new ArrayList<TaskStack>(mStackHistory);
            for (int stackNdx = mStackHistory.size() - 1; stackNdx >=0; --stackNdx) {
                if (mStackHistory.get(stackNdx) != mHomeStack) {
                    mStackHistory.remove(stackNdx);
                }
            }
            mSavedStackBox = null;
            mBoxNdx = -1;
            for (int boxNdx = mStackBoxes.size() - 1; boxNdx >= 0; --boxNdx) {
                StackBox box = mStackBoxes.get(boxNdx);
                if (box.mStack != mHomeStack) {
                    mSavedStackBox = box;
                    mBoxNdx = boxNdx;
                    mStackBoxes.remove(boxNdx);
                    break;
                }
            }
        }

        void restore() {
            mStackHistory = mSavedStackHistory;
            if (mBoxNdx >= 0) {
                mStackBoxes.add(mBoxNdx, mSavedStackBox);
            }
        }
    }
    }
}
}
+4 −10
Original line number Original line Diff line number Diff line
@@ -5094,22 +5094,16 @@ public class WindowManagerService extends IWindowManager.Stub


    public void setCurrentUser(final int newUserId) {
    public void setCurrentUser(final int newUserId) {
        synchronized (mWindowMap) {
        synchronized (mWindowMap) {
            int oldUserId = mCurrentUserId;
            mCurrentUserId = newUserId;
            mCurrentUserId = newUserId;
            mPolicy.setCurrentUserLw(newUserId);
            mPolicy.setCurrentUserLw(newUserId);


            // Hide windows that should not be seen by the new user.
            // Hide windows that should not be seen by the new user.
            DisplayContentsIterator iterator = new DisplayContentsIterator();
            DisplayContentsIterator iterator = new DisplayContentsIterator();
            while (iterator.hasNext()) {
            while (iterator.hasNext()) {
                final WindowList windows = iterator.next().getWindowList();
                DisplayContent displayContent = iterator.next();
                for (int i = 0; i < windows.size(); i++) {
                displayContent.switchUserStacks(oldUserId, newUserId);
                    final WindowState win = windows.get(i);
                rebuildAppWindowListLocked(displayContent);
                    if (win.isHiddenFromUserLocked()) {
                        Slog.w(TAG, "current user violation " + newUserId + " hiding "
                                + win + ", attrs=" + win.mAttrs.type + ", belonging to "
                                + win.mOwnerUid);
                        win.hideLw(false);
                    }
                }
            }
            }
            performLayoutAndPlaceSurfacesLocked();
            performLayoutAndPlaceSurfacesLocked();
        }
        }