Centralize handleAppDied and fix return to home.

The home activity was being returned to when any activity in a task
that was launched from home crashed. If there were still activities
left in the task then the crash should have brought up those
activities next, not home.

This may be a partial fix for crashes where the back stack was showing
up under launcher icons. Bug 10858941.

Change-Id: I840a25bd8395bfce46f4e21b112d78b12884706d
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index a88c3cc..d5059b6 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -334,20 +334,16 @@
         mCurrentUser = service.mCurrentUserId;
     }
 
-    private boolean okToShow(ActivityRecord r) {
+    boolean okToShow(ActivityRecord r) {
         return r.userId == mCurrentUser
                 || (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0;
     }
 
     final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = mTaskHistory.get(taskNdx);
-            final ArrayList<ActivityRecord> activities = task.mActivities;
-            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-                ActivityRecord r = activities.get(activityNdx);
-                if (!r.finishing && r != notTop && okToShow(r)) {
-                    return r;
-                }
+            ActivityRecord r = mTaskHistory.get(taskNdx).topRunningActivityLocked(notTop);
+            if (r != null) {
+                return r;
             }
         }
         return null;
@@ -3401,11 +3397,16 @@
         }
     }
 
-    void handleAppDiedLocked(ProcessRecord app, boolean restarting) {
+    /**
+     * Reset local parameters because an app's activity died.
+     * @param app The app of the activity that died.
+     * @return true if home should be launched next.
+     */
+    boolean handleAppDiedLocked(ProcessRecord app) {
         if (!containsApp(app)) {
-            return;
+            return false;
         }
-        // TODO: handle the case where an app spans multiple stacks.
+
         if (mPausingActivity != null && mPausingActivity.app == app) {
             if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG,
                     "App died while pausing: " + mPausingActivity);
@@ -3415,28 +3416,32 @@
             mLastPausedActivity = null;
             mLastNoHistoryActivity = null;
         }
-        final ActivityRecord top = topRunningActivityLocked(null);
-        final boolean launchHomeTaskNext =
-                top != null && top.app == app && top.task.mOnTopOfHome;
 
-        // Remove this application's activities from active lists.
-        boolean hasVisibleActivities = removeHistoryRecordsForAppLocked(app);
-
-        if (!restarting) {
-            ActivityStack stack = mStackSupervisor.getFocusedStack();
-            if (stack == null || launchHomeTaskNext) {
-                mStackSupervisor.resumeHomeActivity(null);
-            } else if (!mStackSupervisor.resumeTopActivitiesLocked(stack, null, null)) {
-                // If there was nothing to resume, and we are not already
-                // restarting this process, but there is a visible activity that
-                // is hosted by the process...  then make sure all visible
-                // activities are running, taking care of restarting this
-                // process.
-                if (hasVisibleActivities) {
-                    mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
-                }
+        // Determine if the top task is exiting and should return to home. Do this before it gets
+        // removed in removeHistoryRecordsForAppsLocked.
+        boolean launchHomeNext = false;
+        int top = mTaskHistory.size() - 1;
+        while (top >= 0) {
+            final TaskRecord topTask = mTaskHistory.get(top);
+            if (topTask.mActivities.isEmpty()) {
+                // Not possible, but just in case.
+                --top;
+                continue;
             }
+            ActivityRecord r = topTask.topRunningActivityLocked(null);
+            if (r != null) {
+                // r will be launched next.
+                break;
+            }
+            // There is an activity in topTask that is finishing. If topTask belongs to the app
+            // return to home depending on the task flag.
+            launchHomeNext = topTask.mOnTopOfHome;
+            break;
         }
+
+        removeHistoryRecordsForAppLocked(app);
+
+        return launchHomeNext;
     }
 
     void handleAppCrashLocked(ProcessRecord app) {
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 1ee13ec..bf91904 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1932,10 +1932,28 @@
     }
 
     void handleAppDiedLocked(ProcessRecord app, boolean restarting) {
-        // Just in case.
+        boolean launchHomeTaskNext = false;
+        final ActivityStack focusedStack = getFocusedStack();
         final int numStacks = mStacks.size();
         for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            mStacks.get(stackNdx).handleAppDiedLocked(app, restarting);
+            final ActivityStack stack = mStacks.get(stackNdx);
+            // Only update launchHomeTaskNext for the focused stack.
+            launchHomeTaskNext |= (stack == focusedStack && stack.handleAppDiedLocked(app));
+        }
+
+        if (!restarting) {
+            if (launchHomeTaskNext) {
+                resumeHomeActivity(null);
+            } else {
+                if (!resumeTopActivitiesLocked(focusedStack, null, null)) {
+                    // If there was nothing to resume, and we are not already
+                    // restarting this process, but there is a visible activity that
+                    // is hosted by the process...  then make sure all visible
+                    // activities are running, taking care of restarting this
+                    // process.
+                    ensureActivitiesVisibleLocked(null, 0);
+                }
+            }
         }
     }
 
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index f0bba4f..8a9324c 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -139,6 +139,16 @@
         return null;
     }
 
+    ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
+        for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
+            ActivityRecord r = mActivities.get(activityNdx);
+            if (!r.finishing && r != notTop && stack.okToShow(r)) {
+                return r;
+            }
+        }
+        return null;
+    }
+
     /**
      * Reorder the history stack so that the activity at the given index is
      * brought to the front.