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

Commit cbb722ed authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Don't wait for current activity to pause before resuming next.

We can do this now that we ensure processes are not killed until
they have been stopped.  If the two activities are in the same
process, the ordering will still be correct because we schedule
the pause before the resume.

Change-Id: I209ba739b41e832d35db3edd34d1e7af354cc183
parent dc210ade
Loading
Loading
Loading
Loading
+17 −11
Original line number Original line Diff line number Diff line
@@ -138,6 +138,7 @@ import java.io.StringWriter;
import java.lang.IllegalStateException;
import java.lang.IllegalStateException;
import java.lang.ref.WeakReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collection;
import java.util.Collections;
import java.util.Collections;
import java.util.Comparator;
import java.util.Comparator;
@@ -3520,13 +3521,7 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
        }
        // Just in case...
        // Just in case...
        if (mMainStack.mPausingActivity != null && mMainStack.mPausingActivity.app == app) {
        mMainStack.appDiedLocked(app);
            if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " +mMainStack.mPausingActivity);
            mMainStack.mPausingActivity = null;
        }
        if (mMainStack.mLastPausedActivity != null && mMainStack.mLastPausedActivity.app == app) {
            mMainStack.mLastPausedActivity = null;
        }
        // Remove this application's activities from active lists.
        // Remove this application's activities from active lists.
        mMainStack.removeHistoryRecordsForAppLocked(app);
        mMainStack.removeHistoryRecordsForAppLocked(app);
@@ -7231,7 +7226,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                mMainStack.stopIfSleepingLocked();
                mMainStack.stopIfSleepingLocked();
                final long endTime = System.currentTimeMillis() + timeout;
                final long endTime = System.currentTimeMillis() + timeout;
                while (mMainStack.mResumedActivity != null
                while (mMainStack.mResumedActivity != null
                        || mMainStack.mPausingActivity != null) {
                        || mMainStack.mPausingActivities.size() > 0) {
                    long delay = endTime - System.currentTimeMillis();
                    long delay = endTime - System.currentTimeMillis();
                    if (delay <= 0) {
                    if (delay <= 0) {
                        Slog.w(TAG, "Activity manager shutdown timed out");
                        Slog.w(TAG, "Activity manager shutdown timed out");
@@ -9025,8 +9020,13 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
        }
        pw.println(" ");
        pw.println(" ");
        if (mMainStack.mPausingActivity != null) {
        if (mMainStack.mPausingActivities.size() > 0) {
            pw.println("  mPausingActivity: " + mMainStack.mPausingActivity);
            pw.println("  mPausingActivities: " + Arrays.toString(
                    mMainStack.mPausingActivities.toArray()));
        }
        if (mMainStack.mInputPausedActivities.size() > 0) {
            pw.println("  mInputPausedActivities: " + Arrays.toString(
                    mMainStack.mInputPausedActivities.toArray()));
        }
        }
        pw.println("  mResumedActivity: " + mMainStack.mResumedActivity);
        pw.println("  mResumedActivity: " + mMainStack.mResumedActivity);
        pw.println("  mFocusedActivity: " + mFocusedActivity);
        pw.println("  mFocusedActivity: " + mFocusedActivity);
@@ -14759,7 +14759,13 @@ public final class ActivityManagerService extends ActivityManagerNative
    private final ActivityRecord resumedAppLocked() {
    private final ActivityRecord resumedAppLocked() {
        ActivityRecord resumedActivity = mMainStack.mResumedActivity;
        ActivityRecord resumedActivity = mMainStack.mResumedActivity;
        if (resumedActivity == null || resumedActivity.app == null) {
        if (resumedActivity == null || resumedActivity.app == null) {
            resumedActivity = mMainStack.mPausingActivity;
            for (int i=mMainStack.mPausingActivities.size()-1; i>=0; i--) {
                ActivityRecord r = mMainStack.mPausingActivities.get(i);
                if (r.app != null) {
                    resumedActivity = r;
                    break;
                }
            }
            if (resumedActivity == null || resumedActivity.app == null) {
            if (resumedActivity == null || resumedActivity.app == null) {
                resumedActivity = mMainStack.topRunningActivityLocked(null);
                resumedActivity = mMainStack.topRunningActivityLocked(null);
            }
            }
+4 −1
Original line number Original line Diff line number Diff line
@@ -602,6 +602,7 @@ final class ActivityRecord {
    
    
    public void windowsDrawn() {
    public void windowsDrawn() {
        synchronized(service) {
        synchronized(service) {
            stack.reportActivityDrawnLocked(this);
            if (launchTime != 0) {
            if (launchTime != 0) {
                final long curTime = SystemClock.uptimeMillis();
                final long curTime = SystemClock.uptimeMillis();
                final long thisTime = curTime - launchTime;
                final long thisTime = curTime - launchTime;
@@ -690,7 +691,9 @@ final class ActivityRecord {
            // Hmmm, who might we be waiting for?
            // Hmmm, who might we be waiting for?
            r = stack.mResumedActivity;
            r = stack.mResumedActivity;
            if (r == null) {
            if (r == null) {
                r = stack.mPausingActivity;
                if (stack.mPausingActivities.size() > 0) {
                    r = stack.mPausingActivities.get(stack.mPausingActivities.size()-1);
                }
            }
            }
            // Both of those null?  Fall back to 'this' again
            // Both of those null?  Fall back to 'this' again
            if (r == null) {
            if (r == null) {
+118 −76
Original line number Original line Diff line number Diff line
@@ -227,7 +227,13 @@ final class ActivityStack {
     * When we are in the process of pausing an activity, before starting the
     * When we are in the process of pausing an activity, before starting the
     * next one, this variable holds the activity that is currently being paused.
     * next one, this variable holds the activity that is currently being paused.
     */
     */
    ActivityRecord mPausingActivity = null;
    final ArrayList<ActivityRecord> mPausingActivities = new ArrayList<ActivityRecord>();

    /**
     * These activities currently have their input paused, as they want for
     * the next top activity to have its windows visible.
     */
    final ArrayList<ActivityRecord> mInputPausedActivities = new ArrayList<ActivityRecord>();


    /**
    /**
     * This is the last activity that we put into the paused state.  This is
     * This is the last activity that we put into the paused state.  This is
@@ -807,9 +813,9 @@ final class ActivityStack {
                startPausingLocked(false, true);
                startPausingLocked(false, true);
                return;
                return;
            }
            }
            if (mPausingActivity != null) {
            if (mPausingActivities.size() > 0) {
                // Still waiting for something to pause; can't sleep yet.
                // Still waiting for something to pause; can't sleep yet.
                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity);
                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivities);
                return;
                return;
            }
            }


@@ -872,11 +878,6 @@ final class ActivityStack {
    }
    }


    private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
    private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
        if (mPausingActivity != null) {
            RuntimeException e = new RuntimeException();
            Slog.e(TAG, "Trying to pause when pause is already pending for "
                  + mPausingActivity, e);
        }
        ActivityRecord prev = mResumedActivity;
        ActivityRecord prev = mResumedActivity;
        if (prev == null) {
        if (prev == null) {
            RuntimeException e = new RuntimeException();
            RuntimeException e = new RuntimeException();
@@ -884,19 +885,25 @@ final class ActivityStack {
            resumeTopActivityLocked(null);
            resumeTopActivityLocked(null);
            return;
            return;
        }
        }
        if (mPausingActivities.contains(prev)) {
            RuntimeException e = new RuntimeException();
            Slog.e(TAG, "Trying to pause when pause when already pausing " + prev, e);
        }
        if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
        if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
        else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
        else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
        mResumedActivity = null;
        mResumedActivity = null;
        mPausingActivity = prev;
        mPausingActivities.add(prev);
        mLastPausedActivity = prev;
        mLastPausedActivity = prev;
        prev.state = ActivityState.PAUSING;
        prev.state = ActivityState.PAUSING;
        prev.task.touchActiveTime();
        prev.task.touchActiveTime();
        prev.updateThumbnail(screenshotActivities(prev), null);
        prev.updateThumbnail(screenshotActivities(prev), null);


        mService.updateCpuStats();
        mService.updateCpuStats();
        ActivityRecord pausing;
        
        
        if (prev.app != null && prev.app.thread != null) {
        if (prev.app != null && prev.app.thread != null) {
            if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
            if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
            pausing = prev;
            try {
            try {
                EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                        System.identityHashCode(prev),
                        System.identityHashCode(prev),
@@ -909,12 +916,14 @@ final class ActivityStack {
            } catch (Exception e) {
            } catch (Exception e) {
                // Ignore exception, if process died other code will cleanup.
                // Ignore exception, if process died other code will cleanup.
                Slog.w(TAG, "Exception thrown during pause", e);
                Slog.w(TAG, "Exception thrown during pause", e);
                mPausingActivity = null;
                mPausingActivities.remove(prev);
                mLastPausedActivity = null;
                mLastPausedActivity = null;
                pausing = null;
            }
            }
        } else {
        } else {
            mPausingActivity = null;
            mPausingActivities.remove(prev);
            mLastPausedActivity = null;
            mLastPausedActivity = null;
            pausing = null;
        }
        }


        // If we are not going to sleep, we want to ensure the device is
        // If we are not going to sleep, we want to ensure the device is
@@ -928,18 +937,28 @@ final class ActivityStack {
            }
            }
        }
        }



        if (pausing != null) {
        if (mPausingActivity != null) {
            // Have the window manager pause its key dispatching until the new
            // Have the window manager pause its key dispatching until the new
            // activity has started.  If we're pausing the activity just because
            // activity has started.  If we're pausing the activity just because
            // the screen is being turned off and the UI is sleeping, don't interrupt
            // the screen is being turned off and the UI is sleeping, don't interrupt
            // key dispatch; the same activity will pick it up again on wakeup.
            // key dispatch; the same activity will pick it up again on wakeup.
            if (!uiSleeping) {
            if (!uiSleeping) {
                prev.pauseKeyDispatchingLocked();
                pausing.pauseKeyDispatchingLocked();
                mInputPausedActivities.add(prev);
            } else {
            } else {
                if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
                if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
            }
            }


            if (pausing.configDestroy) {
                // The previous is being paused because the configuration
                // is changing, which means it is actually stopping...
                // To juggle the fact that we are also starting a new
                // instance right now, we need to first completely stop
                // the current instance before starting the new one.
                if (DEBUG_PAUSE) Slog.v(TAG, "Destroying at pause: " + prev);
                destroyActivityLocked(pausing, true, false, "pause-config");
            }

            // Schedule a pause timeout in case the app doesn't respond.
            // Schedule a pause timeout in case the app doesn't respond.
            // We don't give it much time because this directly impacts the
            // We don't give it much time because this directly impacts the
            // responsiveness seen by the user.
            // responsiveness seen by the user.
@@ -951,7 +970,10 @@ final class ActivityStack {
            // This activity failed to schedule the
            // This activity failed to schedule the
            // pause, so just treat it as being paused now.
            // pause, so just treat it as being paused now.
            if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
            if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
            resumeTopActivityLocked(null);
        }

        if (!mService.isSleeping()) {
            resumeTopActivityLocked(pausing);
        }
        }
    }
    }
    
    
@@ -966,16 +988,17 @@ final class ActivityStack {
            if (index >= 0) {
            if (index >= 0) {
                r = mHistory.get(index);
                r = mHistory.get(index);
                mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
                mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
                if (mPausingActivity == r) {
                if (mPausingActivities.contains(r)) {
                    if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
                    if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
                            + (timeout ? " (due to timeout)" : " (pause complete)"));
                            + (timeout ? " (due to timeout)" : " (pause complete)"));
                    r.state = ActivityState.PAUSED;
                    r.state = ActivityState.PAUSED;
                    completePauseLocked();
                    completePauseLocked(r);
                } else {
                } else {
                    ActivityRecord old = mPausingActivities.size() > 0
                            ? mPausingActivities.get(0) : null;
                    EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
                    EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
                            System.identityHashCode(r), r.shortComponentName, 
                            System.identityHashCode(r), r.shortComponentName, 
                            mPausingActivity != null
                            old != null ? old.shortComponentName : "(none)");
                                ? mPausingActivity.shortComponentName : "(none)");
                }
                }
            }
            }
        }
        }
@@ -1001,8 +1024,14 @@ final class ActivityStack {
                ProcessRecord fgApp = null;
                ProcessRecord fgApp = null;
                if (mResumedActivity != null) {
                if (mResumedActivity != null) {
                    fgApp = mResumedActivity.app;
                    fgApp = mResumedActivity.app;
                } else if (mPausingActivity != null) {
                } else {
                    fgApp = mPausingActivity.app;
                    for (int i=mPausingActivities.size()-1; i>=0; i--) {
                        ActivityRecord pausing = mPausingActivities.get(i);
                        if (pausing.app == r.app) {
                            fgApp = pausing.app;
                            break;
                        }
                    }
                }
                }
                if (r.app != null && fgApp != null && r.app != fgApp
                if (r.app != null && fgApp != null && r.app != fgApp
                        && r.lastVisibleTime > mService.mPreviousProcessVisibleTime
                        && r.lastVisibleTime > mService.mPreviousProcessVisibleTime
@@ -1014,11 +1043,9 @@ final class ActivityStack {
        }
        }
    }
    }


    private final void completePauseLocked() {
    private final void completePauseLocked(ActivityRecord prev) {
        ActivityRecord prev = mPausingActivity;
        if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
        if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
        
        
        if (prev != null) {
        if (prev.finishing) {
        if (prev.finishing) {
            if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
            if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
            prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
            prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
@@ -1054,19 +1081,12 @@ final class ActivityStack {
            if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
            if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
            prev = null;
            prev = null;
        }
        }
            mPausingActivity = null;
        mPausingActivities.remove(prev);
        }


        if (!mService.isSleeping()) {
        if (mService.isSleeping()) {
            resumeTopActivityLocked(prev);
        } else {
            checkReadyForSleepLocked();
            checkReadyForSleepLocked();
        }
        }


        if (prev != null) {
            prev.resumeKeyDispatchingLocked();
        }

        if (prev.app != null && prev.cpuTimeAtResume > 0
        if (prev.app != null && prev.cpuTimeAtResume > 0
                && mService.mBatteryStatsService.isOnBattery()) {
                && mService.mBatteryStatsService.isOnBattery()) {
            long diff = 0;
            long diff = 0;
@@ -1122,7 +1142,9 @@ final class ActivityStack {
        if (mMainStack) {
        if (mMainStack) {
            mService.setFocusedActivityLocked(next);
            mService.setFocusedActivityLocked(next);
        }
        }
        if (mInputPausedActivities.remove(next)) {
            next.resumeKeyDispatchingLocked();
            next.resumeKeyDispatchingLocked();
        }
        ensureActivitiesVisibleLocked(null, 0);
        ensureActivitiesVisibleLocked(null, 0);
        mService.mWindowManager.executeAppTransition();
        mService.mWindowManager.executeAppTransition();
        mNoAnimActivities.clear();
        mNoAnimActivities.clear();
@@ -1352,13 +1374,6 @@ final class ActivityStack {


        if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
        if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);


        // If we are currently pausing an activity, then don't do anything
        // until that is done.
        if (mPausingActivity != null) {
            if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity);
            return false;
        }

        // Okay we are now going to start a switch, to 'next'.  We may first
        // Okay we are now going to start a switch, to 'next'.  We may first
        // have to pause the current activity, but this is an important point
        // have to pause the current activity, but this is an important point
        // where we have decided to go to 'next' so keep track of that.
        // where we have decided to go to 'next' so keep track of that.
@@ -2440,7 +2455,7 @@ final class ActivityStack {
        
        
        err = startActivityUncheckedLocked(r, sourceRecord,
        err = startActivityUncheckedLocked(r, sourceRecord,
                grantedUriPermissions, grantedMode, onlyIfNeeded, true);
                grantedUriPermissions, grantedMode, onlyIfNeeded, true);
        if (mDismissKeyguardOnNextActivity && mPausingActivity == null) {
        if (mDismissKeyguardOnNextActivity && mPausingActivities.size() == 0) {
            // Someone asked to have the keyguard dismissed on the next
            // Someone asked to have the keyguard dismissed on the next
            // activity start, but we are not actually doing an activity
            // activity start, but we are not actually doing an activity
            // switch...  just dismiss the keyguard now, because we
            // switch...  just dismiss the keyguard now, because we
@@ -3112,6 +3127,17 @@ final class ActivityStack {
        mService.notifyAll();
        mService.notifyAll();
    }
    }


    void reportActivityDrawnLocked(ActivityRecord r) {
        if (mResumedActivity == r) {
            // Once the resumed activity has been drawn, we can stop
            // pausing input on all other activities.
            for (int i=mInputPausedActivities.size()-1; i>=0; i--) {
                mInputPausedActivities.get(i).resumeKeyDispatchingLocked();
            }
            mInputPausedActivities.clear();
        }
    }

    void reportActivityVisibleLocked(ActivityRecord r) {
    void reportActivityVisibleLocked(ActivityRecord r) {
        for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
        for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
            WaitResult w = mWaitingActivityVisible.get(i);
            WaitResult w = mWaitingActivityVisible.get(i);
@@ -3170,7 +3196,9 @@ final class ActivityStack {
                    mService.setFocusedActivityLocked(topRunningActivityLocked(null));
                    mService.setFocusedActivityLocked(topRunningActivityLocked(null));
                }
                }
            }
            }
            if (mInputPausedActivities.remove(r)) {
                r.resumeKeyDispatchingLocked();
                r.resumeKeyDispatchingLocked();
            }
            try {
            try {
                r.stopped = false;
                r.stopped = false;
                if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
                if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
@@ -3496,7 +3524,7 @@ final class ActivityStack {
            // Tell window manager to prepare for this one to be removed.
            // Tell window manager to prepare for this one to be removed.
            mService.mWindowManager.setAppVisibility(r.appToken, false);
            mService.mWindowManager.setAppVisibility(r.appToken, false);
                
                
            if (mPausingActivity == null) {
            if (!mPausingActivities.contains(r)) {
                if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
                if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
                if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
                if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
                startPausingLocked(false, false);
                startPausingLocked(false, false);
@@ -3580,6 +3608,20 @@ final class ActivityStack {
        return r;
        return r;
    }
    }


    final void appDiedLocked(ProcessRecord app) {
        for (int i=mPausingActivities.size()-1; i>=0; i--) {
            ActivityRecord r = mPausingActivities.get(i);
            if (r.app == app) {
                if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " + r);
                mPausingActivities.remove(i);
                mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
            }
        }
        if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
            mLastPausedActivity = null;
        }
    }

    /**
    /**
     * Perform the common clean-up of an activity record.  This is called both
     * Perform the common clean-up of an activity record.  This is called both
     * as part of destroyActivityLocked() (when destroying the client-side
     * as part of destroyActivityLocked() (when destroying the client-side