Don't remove all app token windows when window client dies

AppWindowToken can contain windows from multiple clients (Processes)
If one of the client dies we shouldn't remove all windows in the app
token. We should only remove dea windows.

Bug: 28467642
Change-Id: I8be6a98e0acc79719158567114f4902066069c1b
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index b4ead44..805c986 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -109,7 +109,6 @@
     // Set to true when the token has been removed from the window mgr.
     boolean removed;
 
-    boolean appDied;
     // Information about an application starting window if displayed.
     StartingData startingData;
     WindowState startingWindow;
@@ -458,12 +457,12 @@
 
     void removeAllDeadWindows() {
         for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
-                // removeWindowLocked at bottom of loop may remove multiple entries from
-                // allAppWindows if the window to be removed has child windows. It also may
-                // not remove any windows from allAppWindows at all if win is exiting and
-                // currently animating away. This ensures that winNdx is monotonically decreasing
-                // and never beyond allAppWindows bounds.
-                winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
+            // removeWindowLocked at bottom of loop may remove multiple entries from
+            // allAppWindows if the window to be removed has child windows. It also may
+            // not remove any windows from allAppWindows at all if win is exiting and
+            // currently animating away. This ensures that winNdx is monotonically decreasing
+            // and never beyond allAppWindows bounds.
+            winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
             WindowState win = allAppWindows.get(winNdx);
             if (win.mAppDied) {
                 if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
@@ -476,6 +475,15 @@
         }
     }
 
+    boolean hasWindowsAlive() {
+        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+            if (!allAppWindows.get(i).mAppDied) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     void setReplacingWindows(boolean animate) {
         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken
                 + " with replacing windows.");
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 8d41dab..7ee26a0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -125,9 +125,9 @@
         mHomeTask = homeTask;
     }
 
-    private boolean hasAppTokensAlive() {
+    private boolean hasWindowsAlive() {
         for (int i = mAppTokens.size() - 1; i >= 0; i--) {
-            if (!mAppTokens.get(i).appDied) {
+            if (mAppTokens.get(i).hasWindowsAlive()) {
                 return true;
             }
         }
@@ -135,7 +135,7 @@
     }
 
     void removeLocked() {
-        if (hasAppTokensAlive() && mStack.isAnimating()) {
+        if (hasWindowsAlive() && mStack.isAnimating()) {
             if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
             mDeferRemoval = true;
             return;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 57f551c..8d93c35 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2000,11 +2000,6 @@
                 return WindowManagerGlobal.ADD_INVALID_DISPLAY;
             }
 
-            if (atoken != null && atoken.appDied) {
-                Slog.d(TAG_WM, "App is now revived: " + atoken);
-                atoken.appDied = false;
-            }
-
             mPolicy.adjustWindowParamsLw(win.mAttrs);
             win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
 
@@ -2260,6 +2255,10 @@
     }
 
     void removeWindowLocked(WindowState win) {
+        removeWindowLocked(win, false);
+    }
+
+    void removeWindowLocked(WindowState win, boolean keepVisibleDeadWindow) {
         win.mWindowRemovalAllowed = true;
         if (DEBUG_ADD_REMOVE) Slog.v(TAG,
                 "removeWindowLocked: " + win + " callers=" + Debug.getCallers(4));
@@ -2317,7 +2316,7 @@
             // If we are not currently running the exit animation, we need to see about starting one
             wasVisible = win.isWinVisibleLw();
 
-            if (win.shouldKeepVisibleDeadAppWindow()) {
+            if (keepVisibleDeadWindow) {
                 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
                         "Not removing " + win + " because app died while it's visible");
 
@@ -4408,12 +4407,11 @@
             wtoken.waitingToShow = false;
             wtoken.hiddenRequested = !visible;
 
-            if (!visible && wtoken.appDied) {
-                // This app is dead while it was visible, we kept its dead window on screen.
+            if (!visible) {
+                // If the app is dead while it was visible, we kept its dead window on screen.
                 // Now that the app is going invisible, we can remove it. It will be restarted
                 // if made visible again.
-                wtoken.appDied = false;
-                wtoken.removeAllWindows();
+                wtoken.removeAllDeadWindows();
             } else if (visible) {
                 if (!mAppTransition.isTransitionSet() && mAppTransition.isReady()) {
                     // Add the app mOpeningApps if transition is unset but ready. This means
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index dd88bea..6a2a91d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1740,10 +1740,7 @@
                     WindowState win = mService.windowForClientLocked(mSession, mClient, false);
                     Slog.i(TAG, "WIN DEATH: " + win);
                     if (win != null) {
-                        if (win.mAppToken != null && !win.mAppToken.clientHidden) {
-                            win.mAppToken.appDied = true;
-                        }
-                        mService.removeWindowLocked(win);
+                        mService.removeWindowLocked(win, shouldKeepVisibleDeadAppWindow());
                         if (win.mAttrs.type == TYPE_DOCK_DIVIDER) {
                             // The owner of the docked divider died :( We reset the docked stack,
                             // just in case they have the divider at an unstable position. Better
@@ -1761,8 +1758,7 @@
                     }
                 }
             } catch (IllegalArgumentException ex) {
-                // This will happen if the window has already been
-                // removed.
+                // This will happen if the window has already been removed.
             }
         }
     }
@@ -1773,7 +1769,7 @@
      * interacts with it.
      */
     boolean shouldKeepVisibleDeadAppWindow() {
-        if (!isWinVisibleLw() || mAppToken == null || !mAppToken.appDied) {
+        if (!isWinVisibleLw() || mAppToken == null || mAppToken.clientHidden) {
             // Not a visible app window or the app isn't dead.
             return false;
         }