Cache reference to stack objects we use a lot in AM.

This helps with fast access since we are no longer using stack ids
to look-up stack objects.
Also,
- Made ActivityDisplay.mStacks private so no one out the ActivityDisplay
class changing the stack list order.
- Changed some methods to pass stack objects vs. ids.

Test: Existing tests pass.
Test: go/wm-smoke
Change-Id: I04490cd505c4251e115043fa2ba5134d9a641846
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 333d759..5c91e3c 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -631,15 +631,6 @@
         return stack != null && stack == mFocusedStack;
     }
 
-    /** The top most stack on its display. */
-    boolean isFrontStackOnDisplay(ActivityStack stack) {
-        return isFrontOfStackList(stack, stack.getDisplay().mStacks);
-    }
-
-    private boolean isFrontOfStackList(ActivityStack stack, List<ActivityStack> stackList) {
-        return stack == stackList.get((stackList.size() - 1));
-    }
-
     /** NOTE: Should only be called from {@link ActivityStack#moveToFront} */
     void setFocusStackUnchecked(String reason, ActivityStack focusCandidate) {
         if (!focusCandidate.isFocusable()) {
@@ -735,9 +726,9 @@
 
         int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 final TaskRecord task = stack.taskForIdLocked(id);
                 if (task != null) {
                     return task;
@@ -780,9 +771,10 @@
     ActivityRecord isInAnyStackLocked(IBinder token) {
         int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityRecord r = stacks.get(stackNdx).isInStackLocked(token);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                final ActivityRecord r = stack.isInStackLocked(token);
                 if (r != null) {
                     return r;
                 }
@@ -820,18 +812,21 @@
     void lockAllProfileTasks(@UserIdInt int userId) {
         mWindowManager.deferSurfaceLayout();
         try {
-            final List<ActivityStack> stacks = getStacks();
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; stackNdx--) {
-                final List<TaskRecord> tasks = stacks.get(stackNdx).getAllTasks();
-                for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) {
-                    final TaskRecord task = tasks.get(taskNdx);
+            for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+                final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+                for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                    final ActivityStack stack = display.getChildAt(stackNdx);
+                    final List<TaskRecord> tasks = stack.getAllTasks();
+                    for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) {
+                        final TaskRecord task = tasks.get(taskNdx);
 
-                    // Check the task for a top activity belonging to userId, or returning a result
-                    // to an activity belonging to userId. Example case: a document picker for
-                    // personal files, opened by a work app, should still get locked.
-                    if (taskTopActivityIsUser(task, userId)) {
-                        mService.mTaskChangeNotificationController.notifyTaskProfileLocked(
-                                task.taskId, userId);
+                        // Check the task for a top activity belonging to userId, or returning a
+                        // result to an activity belonging to userId. Example case: a document
+                        // picker for personal files, opened by a work app, should still get locked.
+                        if (taskTopActivityIsUser(task, userId)) {
+                            mService.mTaskChangeNotificationController.notifyTaskProfileLocked(
+                                    task.taskId, userId);
+                        }
                     }
                 }
             }
@@ -897,9 +892,9 @@
         final String processName = app.processName;
         boolean didSomething = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (!isFocusedStack(stack)) {
                     continue;
                 }
@@ -932,9 +927,9 @@
 
     boolean allResumedActivitiesIdle() {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (!isFocusedStack(stack) || stack.numActivities() == 0) {
                     continue;
                 }
@@ -953,9 +948,9 @@
 
     boolean allResumedActivitiesComplete() {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (isFocusedStack(stack)) {
                     final ActivityRecord r = stack.mResumedActivity;
                     if (r != null && r.state != RESUMED) {
@@ -972,12 +967,12 @@
         return true;
     }
 
-    boolean allResumedActivitiesVisible() {
+    private boolean allResumedActivitiesVisible() {
         boolean foundResumed = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 final ActivityRecord r = stack.mResumedActivity;
                 if (r != null) {
                     if (!r.nowVisible || mActivitiesWaitingForVisibleActivity.contains(r)) {
@@ -1001,9 +996,9 @@
     boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming, boolean dontWait) {
         boolean someActivityPaused = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (!isFocusedStack(stack) && stack.mResumedActivity != null) {
                     if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack +
                             " mResumedActivity=" + stack.mResumedActivity);
@@ -1018,9 +1013,9 @@
     boolean allPausedActivitiesComplete() {
         boolean pausing = true;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 final ActivityRecord r = stack.mPausingActivity;
                 if (r != null && r.state != PAUSED && r.state != STOPPED && r.state != STOPPING) {
                     if (DEBUG_STATES) {
@@ -1038,9 +1033,10 @@
 
     void cancelInitializingActivities() {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                stacks.get(stackNdx).cancelInitializingActivities();
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                stack.cancelInitializingActivities();
             }
         }
     }
@@ -1138,13 +1134,10 @@
 
         for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) {
             final int displayId = mTmpOrderedDisplayIds.get(i);
-            final List<ActivityStack> stacks = mActivityDisplays.get(displayId).mStacks;
-            if (stacks == null) {
-                continue;
-            }
-            for (int j = stacks.size() - 1; j >= 0; --j) {
-                final ActivityStack stack = stacks.get(j);
-                if (stack != focusedStack && isFrontStackOnDisplay(stack) && stack.isFocusable()) {
+            final ActivityDisplay display = mActivityDisplays.get(displayId);
+            for (int j = display.getChildCount() - 1; j >= 0; --j) {
+                final ActivityStack stack = display.getChildAt(j);
+                if (stack != focusedStack && stack.isTopStackOnDisplay() && stack.isFocusable()) {
                     r = stack.topRunningActivityLocked();
                     if (r != null) {
                         return r;
@@ -1160,9 +1153,9 @@
         ArrayList<ArrayList<RunningTaskInfo>> runningTaskLists = new ArrayList<>();
         final int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<>();
                 runningTaskLists.add(stackTaskList);
                 stack.getTasksLocked(stackTaskList, callingUid, allowed);
@@ -1942,9 +1935,10 @@
     boolean handleAppDiedLocked(ProcessRecord app) {
         boolean hasVisibleActivities = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                hasVisibleActivities |= stacks.get(stackNdx).handleAppDiedLocked(app);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                hasVisibleActivities |= stack.handleAppDiedLocked(app);
             }
         }
         return hasVisibleActivities;
@@ -1952,9 +1946,10 @@
 
     void closeSystemDialogsLocked() {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                stacks.get(stackNdx).closeSystemDialogsLocked();
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                stack.closeSystemDialogsLocked();
             }
         }
     }
@@ -1980,9 +1975,9 @@
             boolean doit, boolean evenPersistent, int userId) {
         boolean didSomething = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (stack.finishDisabledPackageActivitiesLocked(
                         packageName, filterByClasses, doit, evenPersistent, userId)) {
                     didSomething = true;
@@ -2002,9 +1997,9 @@
         // hosted by the process that is actually still the foreground.
         ProcessRecord fgApp = null;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (isFocusedStack(stack)) {
                     if (stack.mResumedActivity != null) {
                         fgApp = stack.mResumedActivity.app;
@@ -2054,9 +2049,10 @@
 
     void updateActivityApplicationInfoLocked(ApplicationInfo aInfo) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                stacks.get(stackNdx).updateActivityApplicationInfoLocked(aInfo);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                stack.updateActivityApplicationInfoLocked(aInfo);
             }
         }
     }
@@ -2065,10 +2061,10 @@
         TaskRecord finishedTask = null;
         ActivityStack focusedStack = getFocusedStack();
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            final int numStacks = stacks.size();
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            final int numStacks = display.getChildCount();
             for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 TaskRecord t = stack.finishTopRunningActivityLocked(app, reason);
                 if (stack == focusedStack || finishedTask == null) {
                     finishedTask = t;
@@ -2080,10 +2076,10 @@
 
     void finishVoiceTask(IVoiceInteractionSession session) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            final int numStacks = stacks.size();
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            final int numStacks = display.getChildCount();
             for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 stack.finishVoiceTask(session);
             }
         }
@@ -2139,7 +2135,7 @@
                 "findTaskToMoveToFront: moved to front of stack=" + currentStack);
 
         handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY,
-                currentStack.mStackId, forceNonResizeable);
+                currentStack, forceNonResizeable);
     }
 
     boolean canUseActivityOptionsLaunchBounds(ActivityOptions options) {
@@ -2334,8 +2330,8 @@
             }
             final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId);
             if (display != null) {
-                for (int i = display.mStacks.size() - 1; i >= 0; --i) {
-                    stack = (T) display.mStacks.get(i);
+                for (int i = display.getChildCount() - 1; i >= 0; --i) {
+                    stack = (T) display.getChildAt(i);
                     if (stack.isCompatible(windowingMode, activityType)) {
                         return stack;
                     }
@@ -2403,8 +2399,8 @@
         }
 
         // Return the topmost valid stack on the display.
-        for (int i = activityDisplay.mStacks.size() - 1; i >= 0; --i) {
-            final ActivityStack stack = activityDisplay.mStacks.get(i);
+        for (int i = activityDisplay.getChildCount() - 1; i >= 0; --i) {
+            final ActivityStack stack = activityDisplay.getChildAt(i);
             if (isValidLaunchStack(stack, displayId, r)) {
                 return stack;
             }
@@ -2442,18 +2438,6 @@
         return false;
     }
 
-    ArrayList<ActivityStack> getStacks() {
-        ArrayList<ActivityStack> allStacks = new ArrayList<>();
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            allStacks.addAll(mActivityDisplays.valueAt(displayNdx).mStacks);
-        }
-        return allStacks;
-    }
-
-    ArrayList<ActivityStack> getStacksOnDefaultDisplay() {
-        return mActivityDisplays.valueAt(DEFAULT_DISPLAY).mStacks;
-    }
-
     /**
      * Get next focusable stack in the system. This will search across displays and stacks
      * in last-focused order for a focusable and visible stack, different from the target stack.
@@ -2468,10 +2452,9 @@
         for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) {
             final int displayId = mTmpOrderedDisplayIds.get(i);
             // If a display is registered in WM, it must also be available in AM.
-            @SuppressWarnings("ConstantConditions")
-            final List<ActivityStack> stacks = getActivityDisplayOrCreateLocked(displayId).mStacks;
-            for (int j = stacks.size() - 1; j >= 0; --j) {
-                final ActivityStack stack = stacks.get(j);
+            final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId);
+            for (int j = display.getChildCount() - 1; j >= 0; --j) {
+                final ActivityStack stack = display.getChildAt(j);
                 if (stack != currentFocus && stack.isFocusable()
                         && stack.shouldBeVisible(null)) {
                     return stack;
@@ -2539,7 +2522,7 @@
             return;
         }
 
-        final boolean splitScreenActive = getDefaultDisplay().hasSplitScreenStack();
+        final boolean splitScreenActive = getDefaultDisplay().hasSplitScreenPrimaryStack();
         if (!allowResizeInDockedMode
                 && !stack.getWindowConfiguration().tasksAreFloating() && splitScreenActive) {
             // If the docked stack exists, don't resize non-floating stacks independently of the
@@ -2614,9 +2597,8 @@
                 // We are moving all tasks from the docked stack to the fullscreen stack,
                 // which is dismissing the docked stack, so resize all other stacks to
                 // fullscreen here already so we don't end up with resize trashing.
-                final ArrayList<ActivityStack> displayStacks = toDisplay.mStacks;
-                for (int i = displayStacks.size() - 1; i >= 0; --i) {
-                    final ActivityStack otherStack = displayStacks.get(i);
+                for (int i = toDisplay.getChildCount() - 1; i >= 0; --i) {
+                    final ActivityStack otherStack = toDisplay.getChildAt(i);
                     if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
                         continue;
                     }
@@ -2711,8 +2693,7 @@
             return;
         }
 
-        final ActivityStack stack = getDefaultDisplay().getStack(
-                WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
+        final ActivityStack stack = getDefaultDisplay().getSplitScreenPrimaryStack();
         if (stack == null) {
             Slog.w(TAG, "resizeDockedStackLocked: docked stack not found");
             return;
@@ -2741,10 +2722,10 @@
                 // static stacks need to be adjusted so they don't overlap with the docked stack.
                 // We get the bounds to use from window manager which has been adjusted for any
                 // screen controls and is also the same for all stacks.
-                final ArrayList<ActivityStack> stacks = getStacksOnDefaultDisplay();
+                final ActivityDisplay display = getDefaultDisplay();
                 final Rect otherTaskRect = new Rect();
-                for (int i = stacks.size() - 1; i >= 0; --i) {
-                    final ActivityStack current = stacks.get(i);
+                for (int i = display.getChildCount() - 1; i >= 0; --i) {
+                    final ActivityStack current = display.getChildAt(i);
                     if (current.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                         continue;
                     }
@@ -2776,8 +2757,7 @@
 
     void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
         // TODO(multi-display): Pinned stack display should be passed in.
-        final PinnedActivityStack stack = getDefaultDisplay().getStack(
-                WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+        final PinnedActivityStack stack = getDefaultDisplay().getPinnedStack();
         if (stack == null) {
             Slog.w(TAG, "resizePinnedStackLocked: pinned stack not found");
             return;
@@ -2815,12 +2795,7 @@
         }
     }
 
-    private void removeStackInSurfaceTransaction(int stackId) {
-        final ActivityStack stack = getStack(stackId);
-        if (stack == null) {
-            return;
-        }
-
+    private void removeStackInSurfaceTransaction(ActivityStack stack) {
         final ArrayList<TaskRecord> tasks = stack.getAllTasks();
         if (stack.getWindowingMode() == WINDOWING_MODE_PINNED) {
             /**
@@ -2850,12 +2825,12 @@
     }
 
     /**
-     * Removes the stack associated with the given {@param stackId}.  If the {@param stackId} is the
+     * Removes the stack associated with the given {@param stack}. If the {@param stack} is the
      * pinned stack, then its tasks are not explicitly removed when the stack is destroyed, but
      * instead moved back onto the fullscreen stack.
      */
-    void removeStackLocked(int stackId) {
-        mWindowManager.inSurfaceTransaction(() -> removeStackInSurfaceTransaction(stackId));
+    void removeStack(ActivityStack stack) {
+        mWindowManager.inSurfaceTransaction(() -> removeStackInSurfaceTransaction(stack));
     }
 
     /**
@@ -3273,9 +3248,9 @@
         ActivityRecord affinityMatch = null;
         if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (!r.hasCompatibleActivityType(stack)) {
                     if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) "
                             + stack);
@@ -3308,12 +3283,13 @@
     }
 
     ActivityRecord findActivityLocked(Intent intent, ActivityInfo info,
-                                      boolean compareIntentFilters) {
+            boolean compareIntentFilters) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityRecord ar = stacks.get(stackNdx)
-                        .findActivityLocked(intent, info, compareIntentFilters);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                final ActivityRecord ar = stack.findActivityLocked(
+                        intent, info, compareIntentFilters);
                 if (ar != null) {
                     return ar;
                 }
@@ -3407,9 +3383,8 @@
             }
 
             // Set the sleeping state of the stacks on the display.
-            final ArrayList<ActivityStack> stacks = display.mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (displayShouldSleep) {
                     stack.goToSleepIfPossible(false /* shuttingDown */);
                 } else {
@@ -3471,12 +3446,13 @@
     private boolean putStacksToSleepLocked(boolean allowDelay, boolean shuttingDown) {
         boolean allSleep = true;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 if (allowDelay) {
-                    allSleep &= stacks.get(stackNdx).goToSleepIfPossible(shuttingDown);
+                    allSleep &= stack.goToSleepIfPossible(shuttingDown);
                 } else {
-                    stacks.get(stackNdx).goToSleep();
+                    stack.goToSleep();
                 }
             }
         }
@@ -3501,11 +3477,10 @@
 
     void handleAppCrashLocked(ProcessRecord app) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            int stackNdx = stacks.size() - 1;
-            while (stackNdx >= 0) {
-                stacks.get(stackNdx).handleAppCrashLocked(app);
-                stackNdx--;
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                stack.handleAppCrashLocked(app);
             }
         }
     }
@@ -3538,10 +3513,9 @@
         try {
             // First the front stacks. In case any are not fullscreen and are in front of home.
             for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-                final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-                final int topStackNdx = stacks.size() - 1;
-                for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
-                    final ActivityStack stack = stacks.get(stackNdx);
+                final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+                for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                    final ActivityStack stack = display.getChildAt(stackNdx);
                     stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows);
                 }
             }
@@ -3552,10 +3526,9 @@
 
     void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            final int topStackNdx = stacks.size() - 1;
-            for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 stack.addStartingWindowsForVisibleActivities(taskSwitch);
             }
         }
@@ -3571,20 +3544,20 @@
         }
         mTaskLayersChanged = false;
         for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); displayNdx++) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
             int baseLayer = 0;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                baseLayer += stacks.get(stackNdx).rankTaskLayers(baseLayer);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                baseLayer += stack.rankTaskLayers(baseLayer);
             }
         }
     }
 
     void clearOtherAppTimeTrackers(AppTimeTracker except) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            final int topStackNdx = stacks.size() - 1;
-            for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 stack.clearOtherAppTimeTrackers(except);
             }
         }
@@ -3592,10 +3565,9 @@
 
     void scheduleDestroyAllActivities(ProcessRecord app, String reason) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            final int numStacks = stacks.size();
-            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 stack.scheduleDestroyActivities(app, reason);
             }
         }
@@ -3647,10 +3619,11 @@
         // let's iterate through the tasks and release the oldest one.
         final int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            final int stackCount = display.getChildCount();
             // Step through all stacks starting from behind, to hit the oldest things first.
-            for (int stackNdx = 0; stackNdx < stacks.size(); stackNdx++) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            for (int stackNdx = 0; stackNdx < stackCount; stackNdx++) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 // Try to release activities in this stack; if we manage to, we are done.
                 if (stack.releaseSomeActivitiesLocked(app, tasks, reason) > 0) {
                     return;
@@ -3662,7 +3635,7 @@
     boolean switchUserLocked(int userId, UserState uss) {
         final int focusStackId = mFocusedStack.getStackId();
         // We dismiss the docked stack whenever we switch users.
-        final ActivityStack dockedStack = getDefaultDisplay().getSplitScreenStack();
+        final ActivityStack dockedStack = getDefaultDisplay().getSplitScreenPrimaryStack();
         if (dockedStack != null) {
             moveTasksToFullscreenStackLocked(dockedStack, mFocusedStack == dockedStack);
         }
@@ -3677,9 +3650,9 @@
 
         mStartingUsers.add(uss);
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 stack.switchUserLocked(userId);
                 TaskRecord task = stack.topTask();
                 if (task != null) {
@@ -3777,9 +3750,9 @@
 
     void validateTopActivitiesLocked() {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 final ActivityRecord r = stack.topRunningActivityLocked();
                 final ActivityState state = r == null ? DESTROYED : r.state;
                 if (isFocusedStack(stack)) {
@@ -3814,7 +3787,7 @@
         pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront);
         for (int i = mActivityDisplays.size() - 1; i >= 0; --i) {
             final ActivityDisplay display = mActivityDisplays.valueAt(i);
-            pw.println(prefix + "displayId=" + display.mDisplayId + " mStacks=" + display.mStacks);
+            display.dump(pw, prefix);
         }
         if (!mWaitingForActivityVisible.isEmpty()) {
             pw.print(prefix); pw.println("mWaitingForActivityVisible=");
@@ -3871,9 +3844,9 @@
             ArrayList<ActivityRecord> activities = new ArrayList<>();
             int numDisplays = mActivityDisplays.size();
             for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-                for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                    ActivityStack stack = stacks.get(stackNdx);
+                final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+                for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                    final ActivityStack stack = display.getChildAt(stackNdx);
                     if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
                         activities.addAll(stack.getDumpActivitiesLocked(name));
                     }
@@ -3906,9 +3879,9 @@
             ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx);
             pw.print("Display #"); pw.print(activityDisplay.mDisplayId);
                     pw.println(" (activities from top to bottom):");
-            ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
                 pw.println();
                 pw.println("  Stack #" + stack.mStackId
                         + ": type=" + activityTypeToString(stack.getActivityType())
@@ -4156,30 +4129,29 @@
         }
 
         synchronized (mService) {
-            ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
-            if (activityDisplay != null) {
-                final boolean destroyContentOnRemoval
-                        = activityDisplay.shouldDestroyContentOnRemove();
-                final ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
-                while (!stacks.isEmpty()) {
-                    final ActivityStack stack = stacks.get(0);
-                    if (destroyContentOnRemoval) {
-                        moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY,
-                                false /* onTop */);
-                        stack.finishAllActivitiesLocked(true /* immediately */);
-                    } else {
-                        // Moving all tasks to fullscreen stack, because it's guaranteed to be
-                        // a valid launch stack for all activities. This way the task history from
-                        // external display will be preserved on primary after move.
-                        moveTasksToFullscreenStackLocked(stack, true /* onTop */);
-                    }
-                }
-
-                releaseSleepTokens(activityDisplay);
-
-                mActivityDisplays.remove(displayId);
-                mWindowManager.onDisplayRemoved(displayId);
+            final ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
+            if (activityDisplay == null) {
+                return;
             }
+            final boolean destroyContentOnRemoval
+                    = activityDisplay.shouldDestroyContentOnRemove();
+            while (activityDisplay.getChildCount() > 0) {
+                final ActivityStack stack = activityDisplay.getChildAt(0);
+                if (destroyContentOnRemoval) {
+                    moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, false /* onTop */);
+                    stack.finishAllActivitiesLocked(true /* immediately */);
+                } else {
+                    // Moving all tasks to fullscreen stack, because it's guaranteed to be
+                    // a valid launch stack for all activities. This way the task history from
+                    // external display will be preserved on primary after move.
+                    moveTasksToFullscreenStackLocked(stack, true /* onTop */);
+                }
+            }
+
+            releaseSleepTokens(activityDisplay);
+
+            mActivityDisplays.remove(displayId);
+            mWindowManager.onDisplayRemoved(displayId);
         }
     }
 
@@ -4251,7 +4223,7 @@
         info.userId = stack.mCurrentUser;
         info.visible = stack.shouldBeVisible(null);
         // A stack might be not attached to a display.
-        info.position = display != null ? display.mStacks.indexOf(stack) : 0;
+        info.position = display != null ? display.getIndexOf(stack) : 0;
         info.configuration.setTo(stack.getConfiguration());
 
         ArrayList<TaskRecord> tasks = stack.getAllTasks();
@@ -4297,25 +4269,25 @@
     ArrayList<StackInfo> getAllStackInfosLocked() {
         ArrayList<StackInfo> list = new ArrayList<>();
         for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
-            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) {
-                list.add(getStackInfo(stacks.get(ndx)));
+            final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = display.getChildAt(stackNdx);
+                list.add(getStackInfo(stack));
             }
         }
         return list;
     }
 
     void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode,
-            int preferredDisplayId, int actualStackId) {
+            int preferredDisplayId, ActivityStack actualStack) {
         handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredDisplayId,
-                actualStackId, false /* forceNonResizable */);
+                actualStack, false /* forceNonResizable */);
     }
 
     void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode,
-            int preferredDisplayId, int actualStackId, boolean forceNonResizable) {
+            int preferredDisplayId, ActivityStack actualStack, boolean forceNonResizable) {
         final boolean isSecondaryDisplayPreferred =
                 (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY);
-        final ActivityStack actualStack = getStack(actualStackId);
         final boolean inSplitScreenMode = actualStack != null
                 && actualStack.inSplitScreenWindowingMode();
         if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
@@ -4362,10 +4334,9 @@
             // Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
             // we need to move it to top of fullscreen stack, otherwise it will be covered.
 
-            final ActivityStack dockedStack = task.getStack().getDisplay().getSplitScreenStack();
+            final ActivityStack dockedStack = task.getStack().getDisplay().getSplitScreenPrimaryStack();
             if (dockedStack != null) {
-                moveTasksToFullscreenStackLocked(dockedStack,
-                        actualStackId == dockedStack.getStackId());
+                moveTasksToFullscreenStackLocked(dockedStack, actualStack == dockedStack);
             }
         } else if (topActivity != null && topActivity.isNonResizableOrForcedResizable()
                 && !topActivity.noDisplay) {
@@ -4577,14 +4548,13 @@
         if (display == null) {
             return null;
         }
-        final ArrayList<ActivityStack> stacks = display.mStacks;
-        for (int i = stacks.size() - 1; i >= 0; i--) {
-            if (stacks.get(i) == stack && i > 0) {
-                return stacks.get(i - 1);
+        for (int i = display.getChildCount() - 1; i >= 0; i--) {
+            if (display.getChildAt(i) == stack && i > 0) {
+                return display.getChildAt(i - 1);
             }
         }
         throw new IllegalStateException("Failed to find a stack behind stack=" + stack
-                + " in=" + stacks);
+                + " in=" + display);
     }
 
     /**
@@ -4697,8 +4667,8 @@
         for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
             final ActivityDisplay display = mActivityDisplays.valueAt(i);
             // Traverse all stacks on a display.
-            for (int j = display.mStacks.size() - 1; j >= 0; j--) {
-                final ActivityStack stack = display.mStacks.get(j);
+            for (int j = display.getChildCount() - 1; j >= 0; --j) {
+                final ActivityStack stack = display.getChildAt(j);
                 // Get top activity from a visible stack and add it to the list.
                 if (stack.shouldBeVisible(null /* starting */)) {
                     final ActivityRecord top = stack.topActivity();