Cleanup after ActivityView

- Release Surface and VirtualDisplay when shutting down ActivityView.
- Shut down child stacks when relaunching parent activity.

Change-Id: I60314b2b43bd2da5406cf6ec871293b5baca157c
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 7acca84..c31669d 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -417,11 +417,13 @@
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
-                if (!isFrontStack(stack)) {
+                if (!isFrontStack(stack) || stack.numActivities() == 0) {
                     continue;
                 }
                 final ActivityRecord resumedActivity = stack.mResumedActivity;
                 if (resumedActivity == null || !resumedActivity.idle) {
+                    if (DEBUG_STATES) Slog.d(TAG, "allResumedActivitiesIdle: stack="
+                             + stack.mStackId + " " + resumedActivity + " not idle");
                     return false;
                 }
             }
@@ -2130,6 +2132,28 @@
         return createActivityContainer(parentActivity, getNextStackId(), callback);
     }
 
+    void removeChildActivityContainers(ActivityRecord parentActivity) {
+        for (int ndx = mActivityContainers.size() - 1; ndx >= 0; --ndx) {
+            final ActivityContainer container = mActivityContainers.valueAt(ndx).get();
+            if (container == null) {
+                mActivityContainers.removeAt(ndx);
+                continue;
+            }
+            if (container.mParentActivity != parentActivity) {
+                continue;
+            }
+
+            ActivityStack stack = container.mStack;
+            ActivityRecord top = stack.topRunningNonDelayedActivityLocked(null);
+            if (top != null) {
+                // TODO: Make sure the next activity doesn't start up when top is destroyed.
+                stack.destroyActivityLocked(top, true, true, "stack removal");
+            }
+            mActivityContainers.removeAt(ndx);
+            container.detachLocked();
+        }
+    }
+
     private int createStackOnDisplay(ActivityRecord parentActivity, int stackId, int displayId) {
         ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
         if (activityDisplay == null) {
@@ -2683,7 +2707,9 @@
     }
 
     final void scheduleResumeTopActivities() {
-        mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
+        if (!mHandler.hasMessages(RESUME_TOP_ACTIVITY_MSG)) {
+            mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
+        }
     }
 
     void removeSleepTimeouts() {
@@ -2731,7 +2757,7 @@
             if (activityDisplay != null) {
                 ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
                 for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                    activityDisplay.detachActivitiesLocked(stacks.get(stackNdx));
+                    stacks.get(stackNdx).mActivityContainer.detachLocked();
                 }
                 mActivityDisplays.remove(displayId);
             }
@@ -2872,6 +2898,7 @@
         final IActivityContainerCallback mCallback;
         final ActivityStack mStack;
         final ActivityRecord mParentActivity;
+        final String mIdString;
 
         /** Display this ActivityStack is currently on. Null if not attached to a Display. */
         ActivityDisplay mActivityDisplay;
@@ -2883,10 +2910,14 @@
                 mStack = new ActivityStack(this);
                 mParentActivity = parentActivity;
                 mCallback = callback;
+                mIdString = "ActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}";
+                if (DEBUG_STACK) Slog.d(TAG, "Creating " + this);
             }
         }
 
         void attachToDisplayLocked(ActivityDisplay activityDisplay) {
+            if (DEBUG_STACK) Slog.d(TAG, "attachToDisplayLocked: " + this
+                    + " to display=" + activityDisplay);
             mActivityDisplay = activityDisplay;
             mStack.mDisplayId = activityDisplay.mDisplayId;
             mStack.mStacks = activityDisplay.mStacks;
@@ -2914,7 +2945,9 @@
             return -1;
         }
 
-        void detachLocked() {
+        private void detachLocked() {
+            if (DEBUG_STACK) Slog.d(TAG, "detachLocked: " + this + " from display="
+                    + mActivityDisplay + " Callers=" + Debug.getCallers(2));
             if (mActivityDisplay != null) {
                 mActivityDisplay.detachActivitiesLocked(mStack);
                 mActivityDisplay = null;
@@ -2951,45 +2984,15 @@
         }
 
         @Override
-        public void createActivityView(Surface surface, int width, int height, int density) {
-            DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
-            VirtualDisplay virtualDisplay;
-            long ident = Binder.clearCallingIdentity();
-            try {
-                virtualDisplay = dm.createVirtualDisplay(mService.mContext,
-                        VIRTUAL_DISPLAY_BASE_NAME, width, height, density, surface,
-                        DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
-                        DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-
-            final Display display = virtualDisplay.getDisplay();
-            final int displayId = display.getDisplayId();
-
-            mWindowManager.handleDisplayAdded(displayId);
-
+        public void attachToSurface(Surface surface, int width, int height, int density) {
             synchronized (mService) {
-                ActivityDisplay activityDisplay = new ActivityDisplay(display);
-                mActivityDisplays.put(displayId, activityDisplay);
+                ActivityDisplay activityDisplay =
+                        new ActivityDisplay(surface, width, height, density);
+                mActivityDisplays.put(activityDisplay.mDisplayId, activityDisplay);
                 attachToDisplayLocked(activityDisplay);
-                activityDisplay.mVirtualDisplay = virtualDisplay;
             }
-        }
-
-        @Override
-        public void deleteActivityView() {
-            synchronized (mService) {
-                if (!isAttached()) {
-                    return;
-                }
-                VirtualDisplay virtualDisplay = mActivityDisplay.mVirtualDisplay;
-                if (virtualDisplay != null) {
-                    virtualDisplay.release();
-                    mActivityDisplay.mVirtualDisplay = null;
-                }
-                detachLocked();
-            }
+            if (DEBUG_STACK) Slog.d(TAG, "attachToSurface: " + this + " to display="
+                    + mActivityDisplay);
         }
 
         ActivityStackSupervisor getOuter() {
@@ -3007,15 +3010,21 @@
                 outBounds.set(0, 0);
             }
         }
+
+        @Override
+        public String toString() {
+            return mIdString + (mActivityDisplay == null ? "N" : "A");
+        }
     }
 
     /** Exactly one of these classes per Display in the system. Capable of holding zero or more
      * attached {@link ActivityStack}s */
     final class ActivityDisplay {
         /** Actual Display this object tracks. */
-        final int mDisplayId;
-        final Display mDisplay;
-        final DisplayInfo mDisplayInfo = new DisplayInfo();
+        int mDisplayId;
+        Display mDisplay;
+        DisplayInfo mDisplayInfo = new DisplayInfo();
+        Surface mSurface;
 
         /** All of the stacks on this display. Order matters, topmost stack is in front of all other
          * stacks, bottommost behind. Accessed directly by ActivityManager package classes */
@@ -3026,10 +3035,32 @@
         VirtualDisplay mVirtualDisplay;
 
         ActivityDisplay(int displayId) {
-            this(mDisplayManager.getDisplay(displayId));
+            init(mDisplayManager.getDisplay(displayId));
         }
 
         ActivityDisplay(Display display) {
+            init(display);
+        }
+
+        ActivityDisplay(Surface surface, int width, int height, int density) {
+            DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
+            long ident = Binder.clearCallingIdentity();
+            try {
+                mVirtualDisplay = dm.createVirtualDisplay(mService.mContext,
+                        VIRTUAL_DISPLAY_BASE_NAME, width, height, density, surface,
+                        DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
+                        DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+
+            init(mVirtualDisplay.getDisplay());
+            mSurface = surface;
+
+            mWindowManager.handleDisplayAdded(mDisplayId);
+        }
+
+        private void init(Display display) {
             mDisplay = display;
             mDisplayId = display.getDisplayId();
             mDisplay.getDisplayInfo(mDisplayInfo);
@@ -3042,9 +3073,14 @@
         }
 
         void detachActivitiesLocked(ActivityStack stack) {
-            if (DEBUG_STACK) Slog.v(TAG, "attachActivities: detaching " + stack
+            if (DEBUG_STACK) Slog.v(TAG, "detachActivitiesLocked: detaching " + stack
                     + " from displayId=" + mDisplayId);
             mStacks.remove(stack);
+            if (mStacks.isEmpty() && mVirtualDisplay != null) {
+                mVirtualDisplay.release();
+                mVirtualDisplay = null;
+            }
+            mSurface.release();
         }
 
         void getBounds(Point bounds) {
@@ -3052,5 +3088,11 @@
             bounds.x = mDisplayInfo.appWidth;
             bounds.y = mDisplayInfo.appHeight;
         }
+
+        @Override
+        public String toString() {
+            return "ActivityDisplay={" + mDisplayId + (mVirtualDisplay == null ? "" : "V")
+                    + " numStacks=" + mStacks.size() + "}";
+        }
     }
 }