Convert mHistory to mTaskHistory (7)

- Remove TaskRecord from mTaskHistory and mTaskIdToTaskRecord when
last ActivityRecord is removed from it.
- Convert finishActivityLocked from mHistory to mTaskHistory.
- Convert navigateUpToLocked from mHistory to mTaskHistory.
- Convert removeHistoryRecordsForAppLocked from mHistory to
mTaskHistory.
- Convert moveHomeToFrontLocked from mHistory to mTaskHistory.

Change-Id: Ic632a8213f48dda1126c5e6853325a298b54f25f
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index d2f3277..24ec866 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -982,9 +982,6 @@
 
             // Make sure any stopped but visible activities are now sleeping.
             // This ensures that the activity's onStop() is called.
-            if (VALIDATE_TASK_REPLACE) {
-                verifyActivityRecords(true);
-            }
             for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                 final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
                 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
@@ -1890,7 +1887,9 @@
         final int NH = mHistory.size();
 
         int addPos = -1;
-        
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords(true);
+        }
         if (!newTask) {
             // If starting in an existing task, find where that is...
             boolean startIt = true;
@@ -1914,9 +1913,11 @@
                         mService.mWindowManager.addAppToken(convertAddPos(addPos), r.appToken,
                                 r.task.taskId, r.info.screenOrientation, r.fullscreen,
                                 (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
+                        if (VALIDATE_TASK_REPLACE) {
+                            verifyActivityRecords(true);
+                        }
                         if (VALIDATE_TOKENS) {
                             validateAppTokensLocked();
-                            verifyActivityRecords(true);
                         }
                         ActivityOptions.abort(options);
                         return;
@@ -2079,6 +2080,9 @@
 
         int replyChainEnd = -1;
         boolean canMoveOptions = true;
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords(true);
+        }
 
         // We only do this for activities that are not the root of the task (since if we finish
         // the root, we may no longer have the task!).
@@ -2127,7 +2131,7 @@
                     // then merge it into the same task.
                     if (VALIDATE_TASK_REPLACE) Slog.w(TAG,
                         "resetTaskFoundIntended: would reparenting " + target + " to bottom " + p.task);
-                    target.setTask(p.task, p.thumbHolder, false);
+                    setTask(target, p.task, p.thumbHolder, false);
                     if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
                             + " out to bottom task " + p.task);
                 } else {
@@ -2137,7 +2141,7 @@
                             mService.mCurTask = 1;
                         }
                     } while (mTaskIdToTaskRecord.get(mService.mCurTask) != null);
-                    target.setTask(createTaskRecord(mService.mCurTask, target.info, null, false),
+                    setTask(target, createTaskRecord(mService.mCurTask, target.info, null, false),
                             null, false);
                     target.task.affinityIntent = target.intent;
                     if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
@@ -2171,12 +2175,19 @@
                             new RuntimeException("here").fillInStackTrace());
                     if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
                             + " out to target's task " + target.task);
-                    p.setTask(targetTask, curThumbHolder, false);
+                    setTask(p, targetTask, curThumbHolder, false);
                     targetTask.addActivityAtBottom(p);
-                    mHistory.remove(p);
-                    mHistory.add(0, p);
+
+                    { // TODO: remove when mHistory no longer used.
+                        mHistory.remove(p);
+                        mHistory.add(0, p);
+                    }
+
                     mService.mWindowManager.setAppGroupId(p.appToken, targetTaskId);
                 }
+                if (VALIDATE_TASK_REPLACE) {
+                    verifyActivityRecords(true);
+                }
 
                 mService.mWindowManager.moveTaskToBottom(targetTaskId);
                 if (VALIDATE_TOKENS) {
@@ -2301,11 +2312,13 @@
                     if (DEBUG_TASKS) Slog.v(TAG, "Reparenting task at index " + i + " to " + end);
                     for (int srcPos = i; srcPos <= end; ++srcPos) {
                         final ActivityRecord p = activities.get(srcPos);
-                        p.setTask(task, null, false);
+                        setTask(p, task, null, false);
                         task.addActivityToTop(p);
 
-                        mHistory.remove(p);
-                        mHistory.add(taskTopI, p);
+                        { // TODO: remove when mHistory no longer used.
+                            mHistory.remove(p);
+                            mHistory.add(taskTopI, p);
+                        }
 
                         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + p
                                 + " to stack at " + task,
@@ -2509,6 +2522,9 @@
     private final void moveActivityToFrontLocked(ActivityRecord newTop) {
         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + newTop
             + " to stack at top", new RuntimeException("here").fillInStackTrace());
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords(true);
+        }
 
         final TaskRecord task = newTop.task;
         task.getTopActivity().frontOfTask = false;
@@ -2516,8 +2532,11 @@
         task.mActivities.add(newTop);
         newTop.frontOfTask = true;
 
-        mHistory.remove(newTop);
-        mHistory.add(newTop);
+        { // TODO: remove when mHistory no longer used.
+            mHistory.remove(newTop);
+            mHistory.add(newTop);
+        }
+
         if (VALIDATE_TASK_REPLACE) {
             verifyActivityRecords(true);
         }
@@ -3009,11 +3028,11 @@
                 if (mService.mCurTask <= 0) {
                     mService.mCurTask = 1;
                 }
-                r.setTask(createTaskRecord(mService.mCurTask, r.info, intent, true), null, true);
+                setTask(r, createTaskRecord(mService.mCurTask, r.info, intent, true), null, true);
                 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                         + " in new task " + r.task);
             } else {
-                r.setTask(reuseTask, reuseTask, true);
+                setTask(r, reuseTask, reuseTask, true);
             }
             newTask = true;
             if (!movedHome) {
@@ -3059,7 +3078,7 @@
             // An existing activity is starting this new activity, so we want
             // to keep the new one in the same task as the one that is starting
             // it.
-            r.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);
+            setTask(r, sourceRecord.task, sourceRecord.thumbHolder, false);
             if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                     + " in existing task " + r.task);
 
@@ -3077,7 +3096,7 @@
                     break;
                 }
             }
-            r.setTask(prev != null
+            setTask(r, prev != null
                     ? prev.task
                     : createTaskRecord(mService.mCurTask, r.info, intent, true), null, true);
             if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
@@ -3891,14 +3910,13 @@
         if (immediate) {
             return finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, oomAdj) == null;
         } else if (mResumedActivity == r) {
-            boolean endTask = index <= 0
-                    || (mHistory.get(index-1)).task != r.task;
+            boolean endTask = index <= 0;
             if (DEBUG_TRANSITION) Slog.v(TAG,
                     "Prepare close transition: finishing " + r);
             mService.mWindowManager.prepareAppTransition(endTask
                     ? AppTransition.TRANSIT_TASK_CLOSE
                     : AppTransition.TRANSIT_ACTIVITY_CLOSE, false);
-    
+
             // Tell window manager to prepare for this one to be removed.
             mService.mWindowManager.setAppVisibility(r.appToken, false);
                 
@@ -3985,27 +4003,20 @@
 
     final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
             Intent resultData) {
-        final int start = mHistory.indexOf(srec);
-        if (start < 0) {
-            // Current activity is not in history stack; do nothing.
+        final TaskRecord task = srec.task;
+        final ArrayList<ActivityRecord> activities = task.mActivities;
+        final int start = activities.indexOf(srec);
+        if (!mTaskHistory.contains(task) || (start < 0)) {
             return false;
         }
         int finishTo = start - 1;
-        ActivityRecord parent = null;
+        ActivityRecord parent = finishTo < 0 ? null : activities.get(finishTo);
         boolean foundParentInTask = false;
-        ComponentName dest = destIntent.getComponent();
-        if (dest != null) {
-            TaskRecord tr = srec.task;
-            for (int i = start - 1; i >= 0; i--) {
-                ActivityRecord r = mHistory.get(i);
-                if (tr != r.task) {
-                    // Couldn't find parent in the same task; stop at the one above this.
-                    // (Root of current task; in-app "home" behavior)
-                    // Always at least finish the current activity.
-                    finishTo = Math.min(start - 1, i + 1);
-                    parent = mHistory.get(finishTo);
-                    break;
-                } else if (r.info.packageName.equals(dest.getPackageName()) &&
+        final ComponentName dest = destIntent.getComponent();
+        if (start > 0 && dest != null) {
+            for (int i = finishTo; i >= 0; i--) {
+                ActivityRecord r = activities.get(i);
+                if (r.info.packageName.equals(dest.getPackageName()) &&
                         r.info.name.equals(dest.getClassName())) {
                     finishTo = i;
                     parent = r;
@@ -4034,9 +4045,8 @@
         }
         final long origId = Binder.clearCallingIdentity();
         for (int i = start; i > finishTo; i--) {
-            ActivityRecord r = mHistory.get(i);
-            requestFinishActivityLocked(r.appToken, resultCode, resultData,
-                    "navigate-up", true);
+            ActivityRecord r = activities.get(i);
+            requestFinishActivityLocked(r.appToken, resultCode, resultData, "navigate-up", true);
             // Only return the supplied result for the first activity finished
             resultCode = Activity.RESULT_CANCELED;
             resultData = null;
@@ -4136,6 +4146,9 @@
     }
 
     final void removeActivityFromHistoryLocked(ActivityRecord r) {
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords(true);
+        }
         finishActivityResultsLocked(r, Activity.RESULT_CANCELED, null);
         r.makeFinishing();
         if (DEBUG_ADD_REMOVE) {
@@ -4143,16 +4156,19 @@
             here.fillInStackTrace();
             Slog.i(TAG, "Removing activity " + r + " from stack");
         }
-        final TaskRecord task = r.task;
-        if (task != null) {
-            // TODO: If this is the last ActivityRecord in task, remove from ActivityStack.
-            task.removeActivity(r);
+        if (r.task != null) {
+            removeActivity(r);
         }
-        mHistory.remove(r);
+
+        { // TODO: Remove when mHistory no longer used.
+            mHistory.remove(r);
+        }
         r.takeFromHistory();
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords(true);
+        }
         removeTimeoutsForActivityLocked(r);
-        if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
-                + " (removed from history)");
+        if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (removed from history)");
         r.state = ActivityState.DESTROYED;
         if (DEBUG_APP) Slog.v(TAG, "Clearing app during remove for activity " + r);
         r.app = null;
@@ -4377,108 +4393,93 @@
         boolean hasVisibleActivities = false;
 
         // Clean out the history list.
-        int i = mHistory.size();
+        int i = numActivities();
         if (DEBUG_CLEANUP) Slog.v(
             TAG, "Removing app " + app + " from history with " + i + " entries");
-        while (i > 0) {
-            i--;
-            ActivityRecord r = mHistory.get(i);
-            if (DEBUG_CLEANUP) Slog.v(
-                TAG, "Record #" + i + " " + r + ": app=" + r.app);
-            if (r.app == app) {
-                boolean remove;
-                if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
-                    // Don't currently have state for the activity, or
-                    // it is finishing -- always remove it.
-                    remove = true;
-                } else if (r.launchCount > 2 &&
-                        r.lastLaunchTime > (SystemClock.uptimeMillis()-60000)) {
-                    // We have launched this activity too many times since it was
-                    // able to run, so give up and remove it.
-                    remove = true;
-                } else {
-                    // The process may be gone, but the activity lives on!
-                    remove = false;
-                }
-                if (remove) {
-                    if (ActivityStack.DEBUG_ADD_REMOVE || DEBUG_CLEANUP) {
-                        RuntimeException here = new RuntimeException("here");
-                        here.fillInStackTrace();
-                        Slog.i(TAG, "Removing activity " + r + " from stack at " + i
-                                + ": haveState=" + r.haveState
-                                + " stateNotNeeded=" + r.stateNotNeeded
-                                + " finishing=" + r.finishing
-                                + " state=" + r.state, here);
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                --i;
+                if (DEBUG_CLEANUP) Slog.v(
+                    TAG, "Record #" + i + " " + r + ": app=" + r.app);
+                if (r.app == app) {
+                    boolean remove;
+                    if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
+                        // Don't currently have state for the activity, or
+                        // it is finishing -- always remove it.
+                        remove = true;
+                    } else if (r.launchCount > 2 &&
+                            r.lastLaunchTime > (SystemClock.uptimeMillis()-60000)) {
+                        // We have launched this activity too many times since it was
+                        // able to run, so give up and remove it.
+                        remove = true;
+                    } else {
+                        // The process may be gone, but the activity lives on!
+                        remove = false;
                     }
-                    if (!r.finishing) {
-                        Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
-                        EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
-                                r.userId, System.identityHashCode(r),
-                                r.task.taskId, r.shortComponentName,
-                                "proc died without state saved");
-                    }
-                    removeActivityFromHistoryLocked(r);
+                    if (remove) {
+                        if (ActivityStack.DEBUG_ADD_REMOVE || DEBUG_CLEANUP) {
+                            RuntimeException here = new RuntimeException("here");
+                            here.fillInStackTrace();
+                            Slog.i(TAG, "Removing activity " + r + " from stack at " + i
+                                    + ": haveState=" + r.haveState
+                                    + " stateNotNeeded=" + r.stateNotNeeded
+                                    + " finishing=" + r.finishing
+                                    + " state=" + r.state, here);
+                        }
+                        if (!r.finishing) {
+                            Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
+                            EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
+                                    r.userId, System.identityHashCode(r),
+                                    r.task.taskId, r.shortComponentName,
+                                    "proc died without state saved");
+                        }
+                        removeActivityFromHistoryLocked(r);
 
-                } else {
-                    // We have the current state for this activity, so
-                    // it can be restarted later when needed.
-                    if (localLOGV) Slog.v(
-                        TAG, "Keeping entry, setting app to null");
-                    if (r.visible) {
-                        hasVisibleActivities = true;
+                    } else {
+                        // We have the current state for this activity, so
+                        // it can be restarted later when needed.
+                        if (localLOGV) Slog.v(
+                            TAG, "Keeping entry, setting app to null");
+                        if (r.visible) {
+                            hasVisibleActivities = true;
+                        }
+                        if (DEBUG_APP) Slog.v(TAG, "Clearing app during removeHistory for activity "
+                                + r);
+                        r.app = null;
+                        r.nowVisible = false;
+                        if (!r.haveState) {
+                            if (ActivityStack.DEBUG_SAVED_STATE) Slog.i(TAG,
+                                    "App died, clearing saved state of " + r);
+                            r.icicle = null;
+                        }
                     }
-                    if (DEBUG_APP) Slog.v(TAG, "Clearing app during removeHistory for activity "
-                            + r);
-                    r.app = null;
-                    r.nowVisible = false;
-                    if (!r.haveState) {
-                        if (ActivityStack.DEBUG_SAVED_STATE) Slog.i(TAG,
-                                "App died, clearing saved state of " + r);
-                        r.icicle = null;
-                    }
-                }
 
-                r.stack.cleanUpActivityLocked(r, true, true);
+                    r.stack.cleanUpActivityLocked(r, true, true);
+                }
             }
         }
 
         return hasVisibleActivities;
     }
-    
+
     /**
      * Move the current home activity's task (if one exists) to the front
      * of the stack.
      */
     final void moveHomeToFrontLocked() {
-        newMoveHomeToFrontLocked();
-        TaskRecord homeTask = null;
-        for (int i=mHistory.size()-1; i>=0; i--) {
-            ActivityRecord hr = mHistory.get(i);
-            if (hr.isHomeActivity) {
-                homeTask = hr.task;
-                break;
-            }
-        }
-        if (homeTask != null) {
-//            moveTaskToFrontLocked(homeTask, null, null);
-        }
-    }
-
-    final void newMoveHomeToFrontLocked() {
-        TaskRecord homeTask = null;
-        for (int taskNdx = mTaskHistory.size() - 1; homeTask == null && taskNdx >= 0; --taskNdx) {
-            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+        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) {
                 final ActivityRecord r = activities.get(activityNdx);
                 if (r.isHomeActivity) {
-                    homeTask = r.task;
-                    break;
+                    moveTaskToFrontLocked(task, null, null);
+                    return;
                 }
             }
         }
-        if (homeTask != null) {
-            moveTaskToFrontLocked(homeTask, null, null);
-        }
     }
 
     final void updateTransitLocked(int transit, Bundle options) {
@@ -4513,6 +4514,9 @@
     }
 
     final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason, Bundle options) {
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords(true);
+        }
 
         final int task = tr.taskId;
         int top = mHistory.size()-1;
@@ -4558,6 +4562,9 @@
             } else {
                 updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
             }
+            if (VALIDATE_TASK_REPLACE) {
+                verifyActivityRecords(true);
+            }
             return;
         }
 
@@ -4631,6 +4638,9 @@
                 }
             }
         }
+        if (VALIDATE_TASK_REPLACE) {
+            verifyActivityRecords(true);
+        }
 
         if (DEBUG_TRANSITION) Slog.v(TAG,
                 "Prepare to back transition: task=" + task);
@@ -5265,6 +5275,24 @@
         }
     }
 
+    private void removeActivity(ActivityRecord r) {
+        final TaskRecord task = r.task;
+        if (task.removeActivity(r)) {
+            if (DEBUG_ADD_REMOVE) Slog.i(TAG, "removeActivity: Removing from history, task="
+                    + task);
+            mTaskHistory.remove(task);
+            mTaskIdToTaskRecord.delete(task.taskId);
+        }
+    }
+
+    private void setTask(ActivityRecord r, TaskRecord newTask, ThumbnailHolder newThumbHolder,
+            boolean isRoot) {
+        if (r.task != null) {
+            removeActivity(r);
+        }
+        r.setTask(newTask, newThumbHolder, isRoot);
+    }
+
     private TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
             boolean toTop) {
         TaskRecord oldTask = mTaskIdToTaskRecord.get(taskId);