Move activity timeouts to ActivityRecord (81/n)

Reduces reliance on ActivityStack
Also:
- Removed AS#mWindowManager and use mWmService instead
- Renames AS#mService to mAtmService
- Removed AS#mLruActivities which was only used for logging

Change-Id: I61ade9104b9be65b69f68f3055ad2c226d364202
Test: Existing tests pass.
Bug: 80414790
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b09e19f..cffcfef 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -379,6 +379,27 @@
     @VisibleForTesting static final int Z_BOOST_BASE = 800570000;
     static final int INVALID_PID = -1;
 
+    // How long we wait until giving up on the last activity to pause.  This
+    // is short because it directly impacts the responsiveness of starting the
+    // next activity.
+    private static final int PAUSE_TIMEOUT = 500;
+
+    // Ticks during which we check progress while waiting for an app to launch.
+    private static final int LAUNCH_TICK = 500;
+
+    // How long we wait for the activity to tell us it has stopped before
+    // giving up.  This is a good amount of time because we really need this
+    // from the application in order to get its saved state. Once the stop
+    // is complete we may start destroying client resources triggering
+    // crashes if the UI thread was hung. We put this timeout one second behind
+    // the ANR timeout so these situations will generate ANR instead of
+    // Surface lost or other errors.
+    private static final int STOP_TIMEOUT = 11 * 1000;
+
+    // How long we wait until giving up on an activity telling us it has
+    // finished destroying itself.
+    private static final int DESTROY_TIMEOUT = 10 * 1000;
+
     final ActivityTaskManagerService mAtmService;
     final ActivityInfo info; // activity info provided by developer in AndroidManifest
     // Non-null only for application tokens.
@@ -681,6 +702,55 @@
     // Token for targeting this activity for assist purposes.
     final Binder assistToken = new Binder();
 
+    private final Runnable mPauseTimeoutRunnable = new Runnable() {
+        @Override
+        public void run() {
+            // We don't at this point know if the activity is fullscreen,
+            // so we need to be conservative and assume it isn't.
+            Slog.w(TAG, "Activity pause timeout for " + ActivityRecord.this);
+            synchronized (mAtmService.mGlobalLock) {
+                if (hasProcess()) {
+                    mAtmService.logAppTooSlow(app, pauseTime, "pausing " + ActivityRecord.this);
+                }
+                activityPaused(true);
+            }
+        }
+    };
+
+    private final Runnable mLaunchTickRunnable = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mAtmService.mGlobalLock) {
+                if (continueLaunchTicking()) {
+                    mAtmService.logAppTooSlow(
+                            app, launchTickTime, "launching " + ActivityRecord.this);
+                }
+            }
+        }
+    };
+
+    private final Runnable mDestroyTimeoutRunnable = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mAtmService.mGlobalLock) {
+                Slog.w(TAG, "Activity destroy timeout for " + ActivityRecord.this);
+                destroyed("destroyTimeout");
+            }
+        }
+    };
+
+    private final Runnable mStopTimeoutRunnable = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mAtmService.mGlobalLock) {
+                Slog.w(TAG, "Activity stop timeout for " + ActivityRecord.this);
+                if (isInHistory()) {
+                    activityStopped(null /*icicle*/, null /*persistentState*/, null /*description*/);
+                }
+            }
+        }
+    };
+
     private static String startingWindowStateToString(int state) {
         switch (state) {
             case STARTING_WINDOW_NOT_SHOWN:
@@ -2684,11 +2754,6 @@
         EventLogTags.writeWmDestroyActivity(mUserId, System.identityHashCode(this),
                 task.mTaskId, shortComponentName, reason);
 
-        final ActivityStack stack = getActivityStack();
-        if (hasProcess() && !stack.inLruList(this)) {
-            Slog.w(TAG, "Activity " + this + " being finished, but not in LRU list");
-        }
-
         boolean removedFromHistory = false;
 
         cleanUp(false /* cleanServices */, false /* setState */);
@@ -2735,7 +2800,7 @@
                 }
                 setState(DESTROYING,
                         "destroyActivityLocked. finishing and not skipping destroy");
-                stack.scheduleDestroyTimeoutForActivity(this);
+                mAtmService.mH.postDelayed(mDestroyTimeoutRunnable, DESTROY_TIMEOUT);
             } else {
                 if (DEBUG_STATES) {
                     Slog.v(TAG_STATES, "Moving to DESTROYED: " + this + " (destroy skipped)");
@@ -2785,8 +2850,7 @@
         }
 
         takeFromHistory();
-        final ActivityStack stack = getActivityStack();
-        stack.removeTimeoutsForActivity(this);
+        removeTimeouts();
         if (DEBUG_STATES) {
             Slog.v(TAG_STATES, "Moving to DESTROYED: " + this + " (removed from history)");
         }
@@ -2814,7 +2878,7 @@
      * AND finished.
      */
     void destroyed(String reason) {
-        getActivityStack().removeDestroyTimeoutForActivity(this);
+        removeDestroyTimeout();
 
         if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS, "activityDestroyedLocked: r=" + this);
 
@@ -2872,7 +2936,7 @@
         }
 
         // Get rid of any pending idle timeouts.
-        stack.removeTimeoutsForActivity(this);
+        removeTimeouts();
         // Clean-up activities are no longer relaunching (e.g. app process died). Notify window
         // manager so it can update its bookkeeping.
         clearRelaunching();
@@ -4737,6 +4801,73 @@
         }
     }
 
+    void activityPaused(boolean timeout) {
+        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE,
+                "Activity paused: token=" + appToken + ", timeout=" + timeout);
+
+        final ActivityStack stack = getStack();
+
+        if (stack != null) {
+            removePauseTimeout();
+
+            if (stack.mPausingActivity == this) {
+                if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + this
+                        + (timeout ? " (due to timeout)" : " (pause complete)"));
+                mAtmService.deferWindowLayout();
+                try {
+                    stack.completePauseLocked(true /* resumeNext */, null /* resumingActivity */);
+                } finally {
+                    mAtmService.continueWindowLayout();
+                }
+                return;
+            } else {
+                EventLogTags.writeWmFailedToPause(mUserId, System.identityHashCode(this),
+                        shortComponentName, stack.mPausingActivity != null
+                                ? stack.mPausingActivity.shortComponentName : "(none)");
+                if (isState(PAUSING)) {
+                    setState(PAUSED, "activityPausedLocked");
+                    if (finishing) {
+                        if (DEBUG_PAUSE) Slog.v(TAG,
+                                "Executing finish of failed to pause activity: " + this);
+                        completeFinishing("activityPausedLocked");
+                    }
+                }
+            }
+        }
+
+        mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+    }
+
+    /**
+     * Schedule a pause timeout in case the app doesn't respond. We don't give it much time because
+     * this directly impacts the responsiveness seen by the user.
+     */
+    void schedulePauseTimeout() {
+        pauseTime = SystemClock.uptimeMillis();
+        mAtmService.mH.postDelayed(mPauseTimeoutRunnable, PAUSE_TIMEOUT);
+        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Waiting for pause to complete...");
+    }
+
+    private void removePauseTimeout() {
+        mAtmService.mH.removeCallbacks(mPauseTimeoutRunnable);
+    }
+
+    private void removeDestroyTimeout() {
+        mAtmService.mH.removeCallbacks(mDestroyTimeoutRunnable);
+    }
+
+    private void removeStopTimeout() {
+        mAtmService.mH.removeCallbacks(mStopTimeoutRunnable);
+    }
+
+    void removeTimeouts() {
+        mStackSupervisor.removeIdleTimeoutForActivity(this);
+        removePauseTimeout();
+        removeStopTimeout();
+        removeDestroyTimeout();
+        finishLaunchTickingLocked();
+    }
+
     void stopIfPossible() {
         if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + this);
         final ActivityStack stack = getActivityStack();
@@ -4783,7 +4914,7 @@
             if (stack.shouldSleepOrShutDownActivities()) {
                 setSleeping(true);
             }
-            stack.scheduleStopTimeoutForActivity(this);
+            mAtmService.mH.postDelayed(mStopTimeoutRunnable, STOP_TIMEOUT);
         } catch (Exception e) {
             // Maybe just ignore exceptions here...  if the process has crashed, our death
             // notification will clean things up.
@@ -4798,13 +4929,13 @@
         }
     }
 
-    final void activityStoppedLocked(Bundle newIcicle, PersistableBundle newPersistentState,
+    void activityStopped(Bundle newIcicle, PersistableBundle newPersistentState,
             CharSequence description) {
         final ActivityStack stack = getActivityStack();
         final boolean isStopping = mState == STOPPING;
         if (!isStopping && mState != RESTARTING_PROCESS) {
             Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this);
-            stack.removeStopTimeoutForActivity(this);
+            removeStopTimeout();
             return;
         }
         if (newPersistentState != null) {
@@ -4822,7 +4953,7 @@
         if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + mIcicle);
         if (!stopped) {
             if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + this + " (stop complete)");
-            stack.removeStopTimeoutForActivity(this);
+            removeStopTimeout();
             stopped = true;
             if (isStopping) {
                 setState(STOPPED, "activityStoppedLocked");
@@ -4877,11 +5008,11 @@
         }
         if (launchTickTime == 0) {
             launchTickTime = SystemClock.uptimeMillis();
-            continueLaunchTickingLocked();
+            continueLaunchTicking();
         }
     }
 
-    boolean continueLaunchTickingLocked() {
+    private boolean continueLaunchTicking() {
         if (launchTickTime == 0) {
             return false;
         }
@@ -4892,10 +5023,14 @@
         }
 
         stack.removeLaunchTickMessages();
-        stack.scheduleLaunchTickForActivity(this);
+        mAtmService.mH.postDelayed(mLaunchTickRunnable, LAUNCH_TICK);
         return true;
     }
 
+    void removeLaunchTickRunnable() {
+        mAtmService.mH.removeCallbacks(mLaunchTickRunnable);
+    }
+
     void finishLaunchTickingLocked() {
         launchTickTime = 0;
         final ActivityStack stack = getActivityStack();
@@ -7017,10 +7152,7 @@
             newIntents = null;
             mAtmService.getAppWarningsLocked().onResumeActivity(this);
         } else {
-            final ActivityStack stack = getActivityStack();
-            if (stack != null) {
-                stack.removePauseTimeoutForActivity(this);
-            }
+            removePauseTimeout();
             setState(PAUSED, "relaunchActivityLocked");
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 7935dba..37ceb73 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -192,7 +192,7 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_ATM;
     static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
     private static final String TAG_APP = TAG + POSTFIX_APP;
-    private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
+    static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
     private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
     private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
     private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
@@ -204,27 +204,6 @@
     private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
     static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
 
-    // Ticks during which we check progress while waiting for an app to launch.
-    private static final int LAUNCH_TICK = 500;
-
-    // How long we wait until giving up on the last activity to pause.  This
-    // is short because it directly impacts the responsiveness of starting the
-    // next activity.
-    private static final int PAUSE_TIMEOUT = 500;
-
-    // How long we wait for the activity to tell us it has stopped before
-    // giving up.  This is a good amount of time because we really need this
-    // from the application in order to get its saved state. Once the stop
-    // is complete we may start destroying client resources triggering
-    // crashes if the UI thread was hung. We put this timeout one second behind
-    // the ANR timeout so these situations will generate ANR instead of
-    // Surface lost or other errors.
-    private static final int STOP_TIMEOUT = 11 * 1000;
-
-    // How long we wait until giving up on an activity telling us it has
-    // finished destroying itself.
-    private static final int DESTROY_TIMEOUT = 10 * 1000;
-
     // Set to false to disable the preview that is shown while a new activity
     // is being started.
     private static final boolean SHOW_APP_STARTING_PREVIEW = true;
@@ -270,15 +249,7 @@
         RESTARTING_PROCESS
     }
 
-    final ActivityTaskManagerService mService;
-    final WindowManagerService mWindowManager;
-
-    /**
-     * List of running activities, sorted by recent usage.
-     * The first entry in the list is the least recently used.
-     * It contains HistoryRecord objects.
-     */
-    private final ArrayList<ActivityRecord> mLruActivities = new ArrayList<>();
+    final ActivityTaskManagerService mAtmService;
 
     /**
      * When we are in the process of pausing an activity, before starting the
@@ -418,21 +389,7 @@
     private boolean mTopActivityOccludesKeyguard;
     private ActivityRecord mTopDismissingKeyguardActivity;
 
-    private static final int PAUSE_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 1;
-    private static final int DESTROY_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 2;
-    private static final int LAUNCH_TICK_MSG = FIRST_ACTIVITY_STACK_MSG + 3;
-    private static final int STOP_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 4;
-    private static final int DESTROY_ACTIVITIES_MSG = FIRST_ACTIVITY_STACK_MSG + 5;
-    private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 6;
-
-    private static class ScheduleDestroyArgs {
-        final WindowProcessController mOwner;
-        final String mReason;
-        ScheduleDestroyArgs(WindowProcessController owner, String reason) {
-            mOwner = owner;
-            mReason = reason;
-        }
-    }
+    private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 1;
 
     private final Handler mHandler;
 
@@ -445,57 +402,8 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case PAUSE_TIMEOUT_MSG: {
-                    ActivityRecord r = (ActivityRecord)msg.obj;
-                    // We don't at this point know if the activity is fullscreen,
-                    // so we need to be conservative and assume it isn't.
-                    Slog.w(TAG, "Activity pause timeout for " + r);
-                    synchronized (mService.mGlobalLock) {
-                        if (r.hasProcess()) {
-                            mService.logAppTooSlow(r.app, r.pauseTime, "pausing " + r);
-                        }
-                        activityPausedLocked(r.appToken, true);
-                    }
-                } break;
-                case LAUNCH_TICK_MSG: {
-                    ActivityRecord r = (ActivityRecord)msg.obj;
-                    synchronized (mService.mGlobalLock) {
-                        if (r.continueLaunchTickingLocked()) {
-                            mService.logAppTooSlow(r.app, r.launchTickTime, "launching " + r);
-                        }
-                    }
-                } break;
-                case DESTROY_TIMEOUT_MSG: {
-                    ActivityRecord r = (ActivityRecord)msg.obj;
-                    // We don't at this point know if the activity is fullscreen,
-                    // so we need to be conservative and assume it isn't.
-                    Slog.w(TAG, "Activity destroy timeout for " + r);
-                    synchronized (mService.mGlobalLock) {
-                        if (r != null) {
-                            r.destroyed("destroyTimeout");
-                        }
-                    }
-                } break;
-                case STOP_TIMEOUT_MSG: {
-                    ActivityRecord r = (ActivityRecord)msg.obj;
-                    // We don't at this point know if the activity is fullscreen,
-                    // so we need to be conservative and assume it isn't.
-                    Slog.w(TAG, "Activity stop timeout for " + r);
-                    synchronized (mService.mGlobalLock) {
-                        if (r.isInHistory()) {
-                            r.activityStoppedLocked(null /* icicle */,
-                                    null /* persistentState */, null /* description */);
-                        }
-                    }
-                } break;
-                case DESTROY_ACTIVITIES_MSG: {
-                    ScheduleDestroyArgs args = (ScheduleDestroyArgs)msg.obj;
-                    synchronized (mService.mGlobalLock) {
-                        destroyActivities(args.mOwner, args.mReason);
-                    }
-                } break;
                 case TRANSLUCENT_TIMEOUT_MSG: {
-                    synchronized (mService.mGlobalLock) {
+                    synchronized (mAtmService.mGlobalLock) {
                         notifyActivityDrawnLocked(null);
                     }
                 } break;
@@ -737,12 +645,11 @@
                         com.android.internal.R.dimen.docked_stack_minimize_thickness);
         EventLogTags.writeWmStackCreated(stackId);
         mStackSupervisor = supervisor;
-        mService = supervisor.mService;
-        mRootActivityContainer = mService.mRootActivityContainer;
+        mAtmService = supervisor.mService;
+        mRootActivityContainer = mAtmService.mRootActivityContainer;
         mHandler = new ActivityStackHandler(supervisor.mLooper);
-        mWindowManager = mService.mWindowManager;
         mRemoteToken = new RemoteToken(this);
-        mCurrentUser = mService.mAmInternal.getCurrentUserId();
+        mCurrentUser = mAtmService.mAmInternal.getCurrentUserId();
         // Set display id before setting activity and window type to make sure it won't affect
         // stacks on a wrong display.
         mDisplayId = display.mDisplayId;
@@ -767,7 +674,7 @@
                     + reason);
             setResumedActivity(record, reason + " - onActivityStateChanged");
             if (record == mRootActivityContainer.getTopResumedActivity()) {
-                mService.setResumedActivityUncheckLocked(record, reason);
+                mAtmService.setResumedActivityUncheckLocked(record, reason);
             }
             mStackSupervisor.mRecentTasks.add(record.getTask());
         }
@@ -922,7 +829,7 @@
      */
     void setWindowingMode(int preferredWindowingMode, boolean animate, boolean showRecents,
             boolean enteringSplitScreenMode, boolean deferEnsuringVisibility, boolean creating) {
-        mWindowManager.inSurfaceTransaction(() -> setWindowingModeInSurfaceTransaction(
+        mWmService.inSurfaceTransaction(() -> setWindowingModeInSurfaceTransaction(
                 preferredWindowingMode, animate, showRecents, enteringSplitScreenMode,
                 deferEnsuringVisibility, creating));
     }
@@ -970,7 +877,7 @@
                 // Looks like we can't launch in split screen mode or the stack we are launching
                 // doesn't support split-screen mode, go ahead an dismiss split-screen and display a
                 // warning toast about it.
-                mService.getTaskChangeNotificationController().notifyActivityDismissingDockedStack();
+                mAtmService.getTaskChangeNotificationController().notifyActivityDismissingDockedStack();
                 final ActivityStack primarySplitStack = display.getSplitScreenPrimaryStack();
                 primarySplitStack.setWindowingModeInSurfaceTransaction(WINDOWING_MODE_UNDEFINED,
                         false /* animate */, false /* showRecents */,
@@ -1004,11 +911,11 @@
             // Inform the user that they are starting an app that may not work correctly in
             // multi-window mode.
             final String packageName = topActivity.info.applicationInfo.packageName;
-            mService.getTaskChangeNotificationController().notifyActivityForcedResizable(
+            mAtmService.getTaskChangeNotificationController().notifyActivityForcedResizable(
                     topTask.mTaskId, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN, packageName);
         }
 
-        mService.deferWindowLayout();
+        mAtmService.deferWindowLayout();
         try {
             if (!animate && topActivity != null) {
                 mStackSupervisor.mNoAnimActivities.add(topActivity);
@@ -1063,16 +970,16 @@
                 // task, and from the tests
                 // TODO (b/78247419): Fix the rotation animation from fullscreen to minimized mode
                 final boolean isRecentsComponentHome =
-                        mService.getRecentTasks().isRecentsComponentHomeActivity(mCurrentUser);
+                        mAtmService.getRecentTasks().isRecentsComponentHomeActivity(mCurrentUser);
                 final ActivityStack recentStack = display.getOrCreateStack(
                         WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
                         isRecentsComponentHome ? ACTIVITY_TYPE_HOME : ACTIVITY_TYPE_RECENTS,
                         true /* onTop */);
                 recentStack.moveToFront("setWindowingMode");
                 // If task moved to docked stack - show recents if needed.
-                mService.mWindowManager.showRecentApps();
+                mWmService.showRecentApps();
             }
-            mService.continueWindowLayout();
+            mAtmService.continueWindowLayout();
         }
 
         if (!deferEnsuringVisibility) {
@@ -1240,18 +1147,6 @@
         return display != null && display.isSingleTaskInstance();
     }
 
-    /** @return {@code true} if LRU list contained the specified activity. */
-    final boolean inLruList(ActivityRecord activity) {
-        return mLruActivities.contains(activity);
-    }
-
-    /** @return {@code true} if the given activity was contained in LRU list. */
-    final boolean updateLruList(ActivityRecord r) {
-        final boolean contained = mLruActivities.remove(r);
-        mLruActivities.add(r);
-        return contained;
-    }
-
     final boolean isHomeOrRecentsStack() {
         return isActivityTypeHome() || isActivityTypeRecents();
     }
@@ -1375,7 +1270,7 @@
     private void clearLaunchTime(ActivityRecord r) {
         // Make sure that there is no activity waiting for this to launch.
         if (!mStackSupervisor.mWaitingActivityLaunched.isEmpty()) {
-            mStackSupervisor.removeTimeoutsForActivityLocked(r);
+            mStackSupervisor.removeIdleTimeoutForActivity(r);
             mStackSupervisor.scheduleIdleTimeoutLocked(r);
         }
     }
@@ -1385,7 +1280,7 @@
         forAllActivities((Consumer<ActivityRecord>) (r) -> r.setSleeping(false));
         if (mPausingActivity != null) {
             Slog.d(TAG, "awakeFromSleepingLocked: previously pausing activity didn't pause");
-            activityPausedLocked(mPausingActivity.appToken, true);
+            mPausingActivity.activityPaused(true);
         }
     }
 
@@ -1520,7 +1415,7 @@
         prev.getTask().touchActiveTime();
         clearLaunchTime(prev);
 
-        mService.updateCpuStats();
+        mAtmService.updateCpuStats();
 
         boolean pauseImmediately = false;
         if (resuming != null && (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0) {
@@ -1541,7 +1436,7 @@
                 EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
                         prev.shortComponentName, "userLeaving=" + userLeaving);
 
-                mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
+                mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
                         prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
                                 prev.configChangeFlags, pauseImmediately));
             } catch (Exception e) {
@@ -1559,7 +1454,7 @@
 
         // If we are not going to sleep, we want to ensure the device is
         // awake until the next activity is started.
-        if (!uiSleeping && !mService.isSleepingOrShuttingDownLocked()) {
+        if (!uiSleeping && !mAtmService.isSleepingOrShuttingDownLocked()) {
             mStackSupervisor.acquireLaunchWakelock();
         }
 
@@ -1581,7 +1476,7 @@
                 return false;
 
             } else {
-                schedulePauseTimeoutForActivity(prev);
+                prev.schedulePauseTimeout();
                 return true;
             }
 
@@ -1596,41 +1491,6 @@
         }
     }
 
-    final void activityPausedLocked(IBinder token, boolean timeout) {
-        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE,
-            "Activity paused: token=" + token + ", timeout=" + timeout);
-
-        final ActivityRecord r = isInStackLocked(token);
-
-        if (r != null) {
-            mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
-            if (mPausingActivity == r) {
-                if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + r
-                        + (timeout ? " (due to timeout)" : " (pause complete)"));
-                mService.deferWindowLayout();
-                try {
-                    completePauseLocked(true /* resumeNext */, null /* resumingActivity */);
-                } finally {
-                    mService.continueWindowLayout();
-                }
-                return;
-            } else {
-                EventLogTags.writeWmFailedToPause(r.mUserId, System.identityHashCode(r),
-                        r.shortComponentName, mPausingActivity != null
-                                ? mPausingActivity.shortComponentName : "(none)");
-                if (r.isState(PAUSING)) {
-                    r.setState(PAUSED, "activityPausedLocked");
-                    if (r.finishing) {
-                        if (DEBUG_PAUSE) Slog.v(TAG,
-                                "Executing finish of failed to pause activity: " + r);
-                        r.completeFinishing("activityPausedLocked");
-                    }
-                }
-            }
-        }
-        mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
-    }
-
     @VisibleForTesting
     void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
         ActivityRecord prev = mPausingActivity;
@@ -1702,10 +1562,10 @@
                 if (diff > 0) {
                     final Runnable r = PooledLambda.obtainRunnable(
                             ActivityManagerInternal::updateForegroundTimeIfOnBattery,
-                            mService.mAmInternal, prev.info.packageName,
+                            mAtmService.mAmInternal, prev.info.packageName,
                             prev.info.applicationInfo.uid,
                             diff);
-                    mService.mH.post(r);
+                    mAtmService.mH.post(r);
                 }
             }
             prev.cpuTimeAtResume = 0; // reset it
@@ -1716,7 +1576,7 @@
         // task stack changes, because its positioning may depend on it.
         if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause
                 || (getDisplay() != null && getDisplay().hasPinnedStack())) {
-            mService.getTaskChangeNotificationController().notifyTaskStackChanged();
+            mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
             mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
         }
 
@@ -1839,7 +1699,7 @@
                 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                     if (activityType == ACTIVITY_TYPE_HOME
                             || (activityType == ACTIVITY_TYPE_ASSISTANT
-                                && mWindowManager.getRecentsAnimationController() != null)) {
+                                && mWmService.getRecentsAnimationController() != null)) {
                         break;
                     }
                 }
@@ -2085,7 +1945,7 @@
             mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG);
 
             if (waitingActivity != null) {
-                mWindowManager.setWindowOpaqueLocked(waitingActivity.appToken, false);
+                mWmService.setWindowOpaqueLocked(waitingActivity.appToken, false);
                 if (waitingActivity.attachedToProcess()) {
                     try {
                         waitingActivity.app.getThread().scheduleTranslucentConversionComplete(
@@ -2182,7 +2042,7 @@
 
     @GuardedBy("mService")
     private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
-        if (!mService.isBooting() && !mService.isBooted()) {
+        if (!mAtmService.isBooting() && !mAtmService.isBooted()) {
             // Not ready yet!
             return false;
         }
@@ -2237,7 +2097,7 @@
             // If the current top activity may be able to occlude keyguard but the occluded state
             // has not been set, update visibility and check again if we should continue to resume.
             boolean nothingToResume = true;
-            if (!mService.mShuttingDown) {
+            if (!mAtmService.mShuttingDown) {
                 final boolean canShowWhenLocked = !mTopActivityOccludesKeyguard
                         && next.canShowWhenLocked();
                 final boolean mayDismissKeyguard = mTopDismissingKeyguardActivity != next
@@ -2262,7 +2122,7 @@
         // Make sure that the user who owns this activity is started.  If not,
         // we will just leave it as is because someone should be bringing
         // another user's activities to the top of the stack.
-        if (!mService.mAmInternal.hasStartedUserState(next.mUserId)) {
+        if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) {
             Slog.w(TAG, "Skipping resume of top activity " + next
                     + ": user " + next.mUserId + " is stopped");
             return false;
@@ -2322,7 +2182,7 @@
                 // activity isn't running, we can start the process earlier to save the time to wait
                 // for the current activity to be paused.
                 final boolean isTop = this == display.getFocusedStack();
-                mService.startProcessAsync(next, false /* knownToBeDead */, isTop,
+                mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
                         isTop ? "pre-top-activity" : "pre-activity");
             }
             if (lastResumed != null) {
@@ -2379,7 +2239,7 @@
         // Launching this app's activity, make sure the app is no longer
         // considered stopped.
         try {
-            mService.getPackageManager().setPackageStoppedState(
+            mAtmService.getPackageManager().setPackageStoppedState(
                     next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */
         } catch (RemoteException e1) {
         } catch (IllegalArgumentException e) {
@@ -2465,7 +2325,7 @@
                     lastFocusedStack == null ? null : lastFocusedStack.mResumedActivity;
             final ActivityState lastState = next.getState();
 
-            mService.updateCpuStats();
+            mAtmService.updateCpuStats();
 
             if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next
                     + " (in existing)");
@@ -2474,7 +2334,6 @@
 
             next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
                     true /* activityChange */, true /* updateOomAdj */);
-            updateLruList(next);
 
             // Have the window manager re-evaluate the orientation of
             // the screen based on the new activity order.
@@ -2543,13 +2402,13 @@
                         next.getTask().mTaskId, next.shortComponentName);
 
                 next.sleeping = false;
-                mService.getAppWarningsLocked().onResumeActivity(next);
-                next.app.setPendingUiCleanAndForceProcessStateUpTo(mService.mTopProcessState);
+                mAtmService.getAppWarningsLocked().onResumeActivity(next);
+                next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState);
                 next.clearOptionsLocked();
                 transaction.setLifecycleStateRequest(
                         ResumeActivityItem.obtain(next.app.getReportedProcState(),
                                 dc.isNextTransitionForward()));
-                mService.getLifecycleManager().scheduleTransaction(transaction);
+                mAtmService.getLifecycleManager().scheduleTransaction(transaction);
 
                 if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
                         + next);
@@ -2861,7 +2720,7 @@
             // Set focused app directly because if the next focused activity is already resumed
             // (e.g. the next top activity is on a different display), there won't have activity
             // state change to update it.
-            mService.setResumedActivityUncheckLocked(stack.mResumedActivity, reason);
+            mAtmService.setResumedActivityUncheckLocked(stack.mResumedActivity, reason);
         }
         return stack;
     }
@@ -2892,7 +2751,7 @@
         if (activityBelow != null) {
             if (activityBelow.isState(STARTED, RESUMED, PAUSING, PAUSED)) {
                 if (!activityBelow.isActivityTypeHome()
-                        || mService.mHomeProcess != activityBelow.app) {
+                        || mAtmService.mHomeProcess != activityBelow.app) {
                     Slog.w(TAG, "  Force finishing activity "
                             + activityBelow.intent.getComponent().flattenToShortString());
                     activityBelow.finishIfPossible(reason, false /* oomAdj */);
@@ -3023,7 +2882,7 @@
 
         // TODO: There is a dup. of this block of code in ActivityTaskManagerService.finishActivity
         // We should consolidate.
-        IActivityController controller = mService.mController;
+        IActivityController controller = mAtmService.mController;
         if (controller != null) {
             ActivityRecord next = topRunningActivity(srec.appToken, INVALID_TASK_ID);
             if (next != null) {
@@ -3032,7 +2891,7 @@
                 try {
                     resumeOK = controller.activityResuming(next.packageName);
                 } catch (RemoteException e) {
-                    mService.mController = null;
+                    mAtmService.mController = null;
                     Watchdog.getInstance().setActivityController(null);
                 }
 
@@ -3076,7 +2935,7 @@
                             destIntent.getComponent(), ActivityManagerService.STOCK_PM_FLAGS,
                             srec.mUserId);
                     // TODO(b/64750076): Check if calling pid should really be -1.
-                    final int res = mService.getActivityStartController()
+                    final int res = mAtmService.getActivityStartController()
                             .obtainStarter(destIntent, "navigateUpTo")
                             .setCaller(srec.app.getThread())
                             .setActivityInfo(aInfo)
@@ -3104,10 +2963,9 @@
      * an activity moves away from the stack.
      */
     void onActivityRemovedFromStack(ActivityRecord r) {
-        removeTimeoutsForActivity(r);
+        r.removeTimeouts();
 
         mExitingActivities.remove(r);
-        mLruActivities.remove(r);
 
         if (mResumedActivity != null && mResumedActivity == r) {
             setResumedActivity(null, "onActivityRemovedFromStack");
@@ -3121,120 +2979,10 @@
         if (r.isState(RESUMED)) {
             setResumedActivity(r, "onActivityAddedToStack");
         }
-        if (r.hasProcess()) {
-            updateLruList(r);
-        }
-    }
-
-    void removeTimeoutsForActivity(ActivityRecord r) {
-        mStackSupervisor.removeTimeoutsForActivityLocked(r);
-        removePauseTimeoutForActivity(r);
-        removeStopTimeoutForActivity(r);
-        removeDestroyTimeoutForActivity(r);
-        r.finishLaunchTickingLocked();
-    }
-
-    void scheduleDestroyActivities(WindowProcessController owner, String reason) {
-        final Message msg = mHandler.obtainMessage(DESTROY_ACTIVITIES_MSG);
-        msg.obj = new ScheduleDestroyArgs(owner, reason);
-        mHandler.sendMessage(msg);
-    }
-
-    void scheduleDestroyTimeoutForActivity(ActivityRecord r) {
-        final Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG, r);
-        mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
-    }
-
-    void removeDestroyTimeoutForActivity(ActivityRecord r) {
-        mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
-    }
-
-    void scheduleStopTimeoutForActivity(ActivityRecord r) {
-        final Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
-        mHandler.sendMessageDelayed(msg, STOP_TIMEOUT);
-    }
-
-    void removeStopTimeoutForActivity(ActivityRecord r) {
-        mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
-    }
-
-    /**
-     * Schedule a pause timeout in case the app doesn't respond. We don't give it much time because
-     * this directly impacts the responsiveness seen by the user.
-     */
-    private void schedulePauseTimeoutForActivity(ActivityRecord r) {
-        final Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG, r);
-        r.pauseTime = SystemClock.uptimeMillis();
-        mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
-        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Waiting for pause to complete...");
-    }
-
-    void removePauseTimeoutForActivity(ActivityRecord r) {
-        mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
-    }
-
-    void scheduleLaunchTickForActivity(ActivityRecord r) {
-        final Message msg = mHandler.obtainMessage(LAUNCH_TICK_MSG, r);
-        mHandler.sendMessageDelayed(msg, LAUNCH_TICK);
     }
 
     void removeLaunchTickMessages() {
-        mHandler.removeMessages(LAUNCH_TICK_MSG);
-    }
-    /// HANDLER INTERFACE END
-
-    private void destroyActivities(WindowProcessController owner, String reason) {
-        try {
-            mStackSupervisor.beginDeferResume();
-
-            final PooledConsumer c = PooledLambda.obtainConsumer(ActivityStack::destroyActivity,
-                    PooledLambda.__(ActivityRecord.class), owner, reason);
-            forAllActivities(c);
-            c.recycle();
-        } finally {
-            mStackSupervisor.endDeferResume();
-            mRootActivityContainer.resumeFocusedStacksTopActivities();
-        }
-    }
-
-    private static void destroyActivity(
-            ActivityRecord r, WindowProcessController owner, String reason) {
-        if (r.finishing || (owner != null && r.app != owner) || !r.isDestroyable()) return;
-
-        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r
-                + " in state " + r.getState()
-                + " resumed=" + r.getStack().mResumedActivity
-                + " pausing=" + r.getStack().mPausingActivity + " for reason " + reason);
-
-        r.destroyImmediately(true /* removeFromTask */, reason);
-    }
-
-    private void removeHistoryRecordsForApp(ArrayList<ActivityRecord> list,
-            WindowProcessController app, String listName) {
-        int i = list.size();
-        if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
-            "Removing app " + app + " from list " + listName + " with " + i + " entries");
-        while (i > 0) {
-            i--;
-            ActivityRecord r = list.get(i);
-            if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "Record #" + i + " " + r);
-            if (r.app == app) {
-                if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "---> REMOVING this entry!");
-                list.remove(i);
-                removeTimeoutsForActivity(r);
-            }
-        }
-    }
-
-    private boolean removeHistoryRecordsForApp(WindowProcessController app) {
-        removeHistoryRecordsForApp(mLruActivities, app, "mLruActivities");
-        removeHistoryRecordsForApp(mStackSupervisor.mStoppingActivities, app,
-                "mStoppingActivities");
-        removeHistoryRecordsForApp(mStackSupervisor.mGoingToSleepActivities, app,
-                "mGoingToSleepActivities");
-        removeHistoryRecordsForApp(mStackSupervisor.mFinishingActivities, app,
-                "mFinishingActivities");
-        return mRemoveHistoryRecordsForApp.process(app);
+        forAllActivities(ActivityRecord::removeLaunchTickRunnable);
     }
 
     private void updateTransitLocked(int transit, ActivityOptions options) {
@@ -3324,7 +3072,7 @@
 
             mRootActivityContainer.resumeFocusedStacksTopActivities();
             EventLogTags.writeWmTaskToFront(tr.mUserId, tr.mTaskId);
-            mService.getTaskChangeNotificationController().notifyTaskMovedToFront(tr.getTaskInfo());
+            mAtmService.getTaskChangeNotificationController().notifyTaskMovedToFront(tr.getTaskInfo());
         } finally {
             getDisplay().continueUpdateImeTarget();
         }
@@ -3346,14 +3094,14 @@
 
         // In LockTask mode, moving a locked task to the back of the stack may expose unlocked
         // ones. Therefore we need to check if this operation is allowed.
-        if (!mService.getLockTaskController().canMoveTaskToBack(tr)) {
+        if (!mAtmService.getLockTaskController().canMoveTaskToBack(tr)) {
             return false;
         }
 
         // If we have a watcher, preflight the move before committing to it.  First check
         // for *other* available tasks, but if none are available, then try again allowing the
         // current task to be selected.
-        if (isTopStackOnDisplay() && mService.mController != null) {
+        if (isTopStackOnDisplay() && mAtmService.mController != null) {
             ActivityRecord next = topRunningActivity(null, tr.mTaskId);
             if (next == null) {
                 next = topRunningActivity(null, INVALID_TASK_ID);
@@ -3362,9 +3110,9 @@
                 // ask watcher if this is allowed
                 boolean moveOK = true;
                 try {
-                    moveOK = mService.mController.activityResuming(next.packageName);
+                    moveOK = mAtmService.mController.activityResuming(next.packageName);
                 } catch (RemoteException e) {
-                    mService.mController = null;
+                    mAtmService.mController = null;
                     Watchdog.getInstance().setActivityController(null);
                 }
                 if (!moveOK) {
@@ -3415,7 +3163,7 @@
         }
 
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "stack.resize_" + mStackId);
-        mService.deferWindowLayout();
+        mAtmService.deferWindowLayout();
         try {
             // Update override configurations of all tasks in the stack.
             final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : bounds;
@@ -3431,7 +3179,7 @@
                 ensureVisibleActivitiesConfiguration(topRunningActivity(), preserveWindows);
             }
         } finally {
-            mService.continueWindowLayout();
+            mAtmService.continueWindowLayout();
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
     }
@@ -3514,7 +3262,7 @@
      * @param app The app of the activity that died.
      * @return result from removeHistoryRecordsForAppLocked.
      */
-    boolean handleAppDiedLocked(WindowProcessController app) {
+    boolean handleAppDied(WindowProcessController app) {
         if (mPausingActivity != null && mPausingActivity.app == app) {
             if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE,
                     "App died while pausing: " + mPausingActivity);
@@ -3525,7 +3273,8 @@
             mLastNoHistoryActivity = null;
         }
 
-        return removeHistoryRecordsForApp(app);
+        mStackSupervisor.removeHistoryRecords(app);
+        return mRemoveHistoryRecordsForApp.process(app);
     }
 
     boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient,
@@ -3538,10 +3287,6 @@
 
         boolean printed = dumpActivities(fd, pw, dumpAll, dumpClient, dumpPackage, needSep);
 
-        printed |= dumpHistoryList(fd, pw, mLruActivities, "    ", "Run", false,
-                !dumpAll, false, dumpPackage, true,
-                "    Running activities (most recent first):", null);
-
         needSep = printed;
         boolean pr = printThisActivity(pw, mPausingActivity, dumpPackage, needSep,
                 "    mPausingActivity: ");
@@ -3666,7 +3411,7 @@
         EventLogTags.writeWmRemoveTask(((Task) child).mTaskId, mStackId);
 
         if (display.isSingleTaskInstance()) {
-            mService.notifySingleTaskDisplayEmpty(display.mDisplayId);
+            mAtmService.notifySingleTaskDisplayEmpty(display.mDisplayId);
         }
 
         display.mDisplayContent.setLayoutNeeded();
@@ -3694,11 +3439,11 @@
             boolean toTop, ActivityRecord activity, ActivityRecord source,
             ActivityOptions options) {
         final Task task = Task.create(
-                mService, taskId, info, intent, voiceSession, voiceInteractor, this);
+                mAtmService, taskId, info, intent, voiceSession, voiceInteractor, this);
         // add the task to stack first, mTaskPositioner might need the stack association
         addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
         final int displayId = mDisplayId != INVALID_DISPLAY ? mDisplayId : DEFAULT_DISPLAY;
-        final boolean isLockscreenShown = mService.mStackSupervisor.getKeyguardController()
+        final boolean isLockscreenShown = mAtmService.mStackSupervisor.getKeyguardController()
                 .isKeyguardOrAodShowing(displayId);
         if (!mStackSupervisor.getLaunchParamsController()
                 .layoutTask(task, info.windowLayout, activity, source, options)
@@ -3790,19 +3535,18 @@
         // Apps may depend on onResume()/onPause() being called in pairs.
         if (setResume) {
             r.setState(RESUMED, "moveToFrontAndResumeStateIfNeeded");
-            updateLruList(r);
         }
         // If the activity was previously pausing, then ensure we transfer that as well
         if (setPause) {
             mPausingActivity = r;
-            schedulePauseTimeoutForActivity(r);
+            r.schedulePauseTimeout();
         }
         // Move the stack in which we are placing the activity to the front.
         moveToFront(reason);
         // If the original state is resumed, there is no state change to update focused app.
         // So here makes sure the activity focus is set if it is the top.
         if (origState == RESUMED && r == mRootActivityContainer.getTopResumedActivity()) {
-            mService.setResumedActivityUncheckLocked(r, reason);
+            mAtmService.setResumedActivityUncheckLocked(r, reason);
         }
     }
 
@@ -3902,14 +3646,14 @@
             top.savePinnedStackBounds();
         }
 
-        mWindowManager.inSurfaceTransaction(() -> {
+        mWmService.inSurfaceTransaction(() -> {
             final Task task = getBottomMostTask();
             setWindowingMode(WINDOWING_MODE_UNDEFINED);
 
             getDisplay().positionStackAtTop(this, false /* includingParents */);
 
             mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this);
-            MetricsLoggerWrapper.logPictureInPictureFullScreen(mService.mContext,
+            MetricsLoggerWrapper.logPictureInPictureFullScreen(mAtmService.mContext,
                     task.effectiveUid, task.realActivity.flattenToString());
         });
     }
@@ -5377,11 +5121,11 @@
             return false;
         }
 
-        return display != null ? display.isSleeping() : mService.isSleepingLocked();
+        return display != null ? display.isSleeping() : mAtmService.isSleepingLocked();
     }
 
     boolean shouldSleepOrShutDownActivities() {
-        return shouldSleepActivities() || mService.mShuttingDown;
+        return shouldSleepActivities() || mAtmService.mShuttingDown;
     }
 
     public void dumpDebug(ProtoOutputStream proto, long fieldId,
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 26d9dbc..9203fcb 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -52,7 +52,9 @@
 
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
+import static com.android.server.wm.ActivityStack.TAG_CLEANUP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_IDLE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
@@ -956,9 +958,6 @@
         }
 
         r.launchFailed = false;
-        if (stack.updateLruList(r)) {
-            Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list");
-        }
 
         // TODO(lifecycler): Resume or pause requests are done as part of launch transaction,
         // so updating the state should be done accordingly.
@@ -2162,7 +2161,7 @@
                     if (!processPausingActivities && s.isState(PAUSING)) {
                         // Defer processing pausing activities in this iteration and reschedule
                         // a delayed idle to reprocess it again
-                        removeTimeoutsForActivityLocked(idleActivity);
+                        removeIdleTimeoutForActivity(idleActivity);
                         scheduleIdleTimeoutLocked(idleActivity);
                         continue;
                     }
@@ -2181,6 +2180,29 @@
         return stops;
     }
 
+    void removeHistoryRecords(WindowProcessController app) {
+        removeHistoryRecords(mStoppingActivities, app, "mStoppingActivities");
+        removeHistoryRecords(mGoingToSleepActivities, app, "mGoingToSleepActivities");
+        removeHistoryRecords(mFinishingActivities, app, "mFinishingActivities");
+    }
+
+    private void removeHistoryRecords(ArrayList<ActivityRecord> list, WindowProcessController app,
+            String listName) {
+        int i = list.size();
+        if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
+                "Removing app " + this + " from list " + listName + " with " + i + " entries");
+        while (i > 0) {
+            i--;
+            ActivityRecord r = list.get(i);
+            if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "Record #" + i + " " + r);
+            if (r.app == app) {
+                if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP, "---> REMOVING this entry!");
+                list.remove(i);
+                r.removeTimeouts();
+            }
+        }
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         pw.println();
         pw.println("ActivityStackSupervisor state:");
@@ -2371,7 +2393,7 @@
         scheduleTopResumedActivityStateIfNeeded();
     }
 
-    void removeTimeoutsForActivityLocked(ActivityRecord r) {
+    void removeIdleTimeoutForActivity(ActivityRecord r) {
         if (DEBUG_IDLE) Slog.d(TAG_IDLE, "removeTimeoutsForActivity: Callers="
                 + Debug.getCallers(4));
         mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0864c9c..6f80feb 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -306,7 +306,7 @@
 public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityTaskManagerService" : TAG_ATM;
     private static final String TAG_STACK = TAG + POSTFIX_STACK;
-    private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+    static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
     private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE;
     private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
     private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
@@ -1730,9 +1730,9 @@
         final long origId = Binder.clearCallingIdentity();
         synchronized (mGlobalLock) {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityPaused");
-            ActivityStack stack = ActivityRecord.getStackLocked(token);
-            if (stack != null) {
-                stack.activityPausedLocked(token, false);
+            final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+            if (r != null) {
+                r.activityPaused(false);
             }
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
@@ -1765,7 +1765,7 @@
                     restartingName = r.app.mName;
                     restartingUid = r.app.mUid;
                 }
-                r.activityStoppedLocked(icicle, persistentState, description);
+                r.activityStopped(icicle, persistentState, description);
             }
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
@@ -7304,7 +7304,7 @@
         @Override
         public void scheduleDestroyAllActivities(String reason) {
             synchronized (mGlobalLock) {
-                mRootActivityContainer.scheduleDestroyAllActivities(null, reason);
+                mRootActivityContainer.scheduleDestroyAllActivities(reason);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 4ac918c..c0077e4 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -54,6 +54,7 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
@@ -62,6 +63,7 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
+import static com.android.server.wm.ActivityTaskManagerService.TAG_SWITCH;
 import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
 import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
 
@@ -205,6 +207,28 @@
     private boolean mTmpBoolean;
     private RemoteException mTmpRemoteException;
 
+    private String mDestroyAllActivitiesReason;
+    private final Runnable mDestroyAllActivitiesRunnable = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mService.mGlobalLock) {
+                try {
+                    mStackSupervisor.beginDeferResume();
+
+                    final PooledConsumer c = PooledLambda.obtainConsumer(
+                            RootActivityContainer::destroyActivity, RootActivityContainer.this,
+                            PooledLambda.__(ActivityRecord.class));
+                    forAllActivities(c);
+                    c.recycle();
+                } finally {
+                    mStackSupervisor.endDeferResume();
+                    resumeFocusedStacksTopActivities();
+                }
+            }
+        }
+
+    };
+
     private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
     static class FindTaskResult implements Function<Task, Boolean> {
         ActivityRecord mRecord;
@@ -1653,14 +1677,19 @@
         }
     }
 
-    void scheduleDestroyAllActivities(WindowProcessController app, String reason) {
-        for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
-            final DisplayContent display = getChildAt(displayNdx);
-            for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = display.getStackAt(stackNdx);
-                stack.scheduleDestroyActivities(app, reason);
-            }
-        }
+    void scheduleDestroyAllActivities(String reason) {
+        mDestroyAllActivitiesReason = reason;
+        mService.mH.post(mDestroyAllActivitiesRunnable);
+    }
+
+    private void destroyActivity(ActivityRecord r) {
+        if (r.finishing || !r.isDestroyable()) return;
+
+        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r + " in state " + r.getState()
+                + " resumed=" + r.getStack().mResumedActivity + " pausing="
+                + r.getStack().mPausingActivity + " for reason " + mDestroyAllActivitiesReason);
+
+        r.destroyImmediately(true /* removeFromTask */, mDestroyAllActivitiesReason);
     }
 
     // Tries to put all activity stacks to sleep. Returns true if all stacks were
@@ -2059,7 +2088,7 @@
             final DisplayContent display = getChildAt(displayNdx);
             for (int stackNdx = display.getStackCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getStackAt(stackNdx);
-                hasVisibleActivities |= stack.handleAppDiedLocked(app);
+                hasVisibleActivities |= stack.handleAppDied(app);
             }
         }
         return hasVisibleActivities;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 65704c8..14c0ca1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -601,7 +601,7 @@
 
         // Set state to STOPPING, or ActivityRecord#activityStoppedLocked() call will be ignored.
         mActivity.setState(STOPPING, "test");
-        mActivity.activityStoppedLocked(savedState, persistentSavedState, "desc");
+        mActivity.activityStopped(savedState, persistentSavedState, "desc");
         assertTrue(mActivity.hasSavedState());
         assertEquals(savedState, mActivity.getSavedState());
         assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
@@ -609,7 +609,7 @@
         // Sending 'null' for saved state can only happen due to timeout, so previously stored saved
         // states should not be overridden.
         mActivity.setState(STOPPING, "test");
-        mActivity.activityStoppedLocked(null /* savedState */, null /* persistentSavedState */,
+        mActivity.activityStopped(null /* savedState */, null /* persistentSavedState */,
                 "desc");
         assertTrue(mActivity.hasSavedState());
         assertEquals(savedState, mActivity.getSavedState());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 8a1a10d..4f7f513 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -901,7 +901,7 @@
 
         assertEquals(2, mTask.getChildCount());
 
-        mStack.handleAppDiedLocked(secondActivity.app);
+        mRootActivityContainer.handleAppDied(secondActivity.app);
 
         assertFalse(mTask.hasChild());
         assertFalse(mStack.hasChild());
@@ -915,7 +915,7 @@
         activity.launchCount = 1;
         activity.setSavedState(null /* savedState */);
 
-        mStack.handleAppDiedLocked(activity.app);
+        mRootActivityContainer.handleAppDied(activity.app);
 
         assertEquals(1, mTask.getChildCount());
         assertEquals(1, mStack.getChildCount());
@@ -929,7 +929,7 @@
         activity.launchCount = 3;
         activity.setSavedState(null /* savedState */);
 
-        mStack.handleAppDiedLocked(activity.app);
+        mRootActivityContainer.handleAppDied(activity.app);
 
         assertFalse(mTask.hasChild());
         assertFalse(mStack.hasChild());
@@ -943,7 +943,7 @@
         activity.launchCount = 1;
         activity.setSavedState(null /* savedState */);
 
-        mStack.handleAppDiedLocked(activity.app);
+        mRootActivityContainer.handleAppDied(activity.app);
 
         assertEquals(1, mTask.getChildCount());
         assertEquals(1, mStack.getChildCount());
@@ -957,7 +957,7 @@
         activity.launchCount = 3;
         activity.setSavedState(null /* savedState */);
 
-        mStack.handleAppDiedLocked(activity.app);
+        mRootActivityContainer.handleAppDied(activity.app);
 
         assertFalse(mTask.hasChild());
         assertFalse(mStack.hasChild());
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 5edd725..186f001 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -161,7 +161,7 @@
         assertFalse(recentsActivity.mVisibleRequested);
 
         // Assume it is stopped to test next use case.
-        recentsActivity.activityStoppedLocked(null /* newIcicle */, null /* newPersistentState */,
+        recentsActivity.activityStopped(null /* newIcicle */, null /* newPersistentState */,
                 null /* description */);
         mSupervisor.mStoppingActivities.remove(recentsActivity);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 26743c8..084216a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -52,9 +52,9 @@
     }
 
     static ActivityRecord createTestActivityRecord(ActivityStack stack) {
-        synchronized (stack.mService.mGlobalLock) {
+        synchronized (stack.mAtmService.mGlobalLock) {
             final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(
-                    stack.mService)
+                    stack.mAtmService)
                     .setStack(stack)
                     .setCreateTask(true)
                     .build();