Prepare ActivityManagerService for multiple stacks.

- Replace mMainStack with mFocusedStack and mStacks.
- Remove stack from ActivityRecord.
- Add stack to TaskRecord.

Change-Id: I22e9ba34b12c2bd90806b14aafe063d5a2fe66ae
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 21fe0e8..fa7a024 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -164,11 +164,6 @@
     private ArrayList<TaskRecord> mTaskHistory = new ArrayList<TaskRecord>();
 
     /**
-     * Mapping from taskId to TaskRecord
-     */
-    private SparseArray<TaskRecord> mTaskIdToTaskRecord = new SparseArray<TaskRecord>();
-
-    /**
      * Used for validating app tokens with window manager.
      */
     final ArrayList<TaskGroup> mValidateAppTokens = new ArrayList<TaskGroup>();
@@ -368,9 +363,9 @@
                             mService.logAppTooSlow(r.app, r.pauseTime,
                                     "pausing " + r);
                         }
-                    }
 
-                    activityPaused(r != null ? r.appToken : null, true);
+                        activityPausedLocked(r != null ? r.appToken : null, true);
+                    }
                 } break;
                 case IDLE_TIMEOUT_MSG: {
                     if (mService.mDidDexOpt) {
@@ -400,7 +395,9 @@
                     // We don't at this point know if the activity is fullscreen,
                     // so we need to be conservative and assume it isn't.
                     Slog.w(TAG, "Activity destroy timeout for " + r);
-                    activityDestroyed(r != null ? r.appToken : null);
+                    synchronized (mService) {
+                        activityDestroyedLocked(r != null ? r.appToken : null);
+                    }
                 } break;
                 case IDLE_NOW_MSG: {
                     ActivityRecord r = (ActivityRecord)msg.obj;
@@ -526,28 +523,27 @@
         return null;
     }
 
-    final ActivityRecord isInStackLocked(IBinder token) {
-        final ActivityRecord r = ActivityRecord.forToken(token);
-        if (r != null) {
-            final TaskRecord task = r.task;
-            if (mTaskHistory.contains(task) && task.mActivities.contains(r)) {
-                return r;
+    TaskRecord taskForIdLocked(int id) {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            if (task.taskId == id) {
+                return task;
             }
         }
         return null;
     }
 
-    int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
+    ActivityRecord isInStackLocked(IBinder token) {
         final ActivityRecord r = ActivityRecord.forToken(token);
-        if (r == null) {
-            return -1;
+        if (r != null) {
+            final TaskRecord task = r.task;
+            if (task.mActivities.contains(r) && mTaskHistory.contains(task)) {
+                if (task.stack != this) Slog.w(TAG,
+                    "Illegal state! task does not point to stack it is in.");
+                return r;
+            }
         }
-        final TaskRecord task = r.task;
-        switch (task.mActivities.indexOf(r)) {
-            case -1: return -1;
-            case 0: return task.taskId;
-            default: return onlyRoot ? -1 : task.taskId;
-        }
+        return null;
     }
 
     private final boolean updateLRUListLocked(ActivityRecord r) {
@@ -819,9 +815,7 @@
             r.stopped = false;
             mResumedActivity = r;
             r.task.touchActiveTime();
-            if (mMainStack) {
-                mService.addRecentTaskLocked(r.task);
-            }
+            mService.addRecentTaskLocked(r.task);
             completeResumeLocked(r);
             checkReadyForSleepLocked();
             if (DEBUG_SAVED_STATE) Slog.i(TAG, "Launch completed; removing icicle of " + r.icicle);
@@ -1092,36 +1086,30 @@
         }
     }
 
-    final void activityResumed(IBinder token) {
-        synchronized (mService) {
-            final ActivityRecord r = isInStackLocked(token);
-            if (r != null) {
-                if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; dropping state of: " + r);
-                r.icicle = null;
-                r.haveState = false;
-            }
-        }
+    final void activityResumedLocked(IBinder token) {
+        final ActivityRecord r = ActivityRecord.forToken(token);
+        if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; dropping state of: " + r);
+        r.icicle = null;
+        r.haveState = false;
     }
 
-    final void activityPaused(IBinder token, boolean timeout) {
+    final void activityPausedLocked(IBinder token, boolean timeout) {
         if (DEBUG_PAUSE) Slog.v(
             TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
 
-        synchronized (mService) {
-            final ActivityRecord r = isInStackLocked(token);
-            if (r != null) {
-                mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
-                if (mPausingActivity == r) {
-                    if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
-                            + (timeout ? " (due to timeout)" : " (pause complete)"));
-                    r.state = ActivityState.PAUSED;
-                    completePauseLocked();
-                } else {
-                    EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
-                            r.userId, System.identityHashCode(r), r.shortComponentName,
-                            mPausingActivity != null
-                                ? mPausingActivity.shortComponentName : "(none)");
-                }
+        final ActivityRecord r = isInStackLocked(token);
+        if (r != null) {
+            mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
+            if (mPausingActivity == r) {
+                if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
+                        + (timeout ? " (due to timeout)" : " (pause complete)"));
+                r.state = ActivityState.PAUSED;
+                completePauseLocked();
+            } else {
+                EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
+                        r.userId, System.identityHashCode(r), r.shortComponentName,
+                        mPausingActivity != null
+                            ? mPausingActivity.shortComponentName : "(none)");
             }
         }
     }
@@ -1706,9 +1694,7 @@
             next.state = ActivityState.RESUMED;
             mResumedActivity = next;
             next.task.touchActiveTime();
-            if (mMainStack) {
-                mService.addRecentTaskLocked(next.task);
-            }
+            mService.addRecentTaskLocked(next.task);
             mService.updateLruProcessLocked(next.app, true);
             updateLRUListLocked(next);
 
@@ -1843,16 +1829,16 @@
     private final void startActivityLocked(ActivityRecord r, boolean newTask,
             boolean doResume, boolean keepCurTransition, Bundle options) {
         TaskRecord task = null;
-        final int taskId = r.task.taskId;
-        if (mTaskIdToTaskRecord.indexOfKey(taskId) < 0 || newTask) {
+        TaskRecord rTask = r.task;
+        final int taskId = rTask.taskId;
+        if (taskForIdLocked(taskId) == null || newTask) {
             // Last activity in task had been removed or ActivityManagerService is reusing task.
             // Insert or replace.
-            mTaskIdToTaskRecord.put(taskId, r.task);
             // Might not even be in.
-            mTaskHistory.remove(r.task);
+            mTaskHistory.remove(rTask);
             // Now put task at top.
-            mTaskHistory.add(r.task);
-            mService.mWindowManager.moveTaskToTop(r.task.taskId);
+            mTaskHistory.add(rTask);
+            mService.mWindowManager.moveTaskToTop(taskId);
         }
         if (!newTask) {
             // If starting in an existing task, find where that is...
@@ -2073,14 +2059,8 @@
                     if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
                             + " out to bottom task " + p.task);
                 } else {
-                    do {
-                        mService.mCurTask++;
-                        if (mService.mCurTask <= 0) {
-                            mService.mCurTask = 1;
-                        }
-                    } while (mTaskIdToTaskRecord.get(mService.mCurTask) != null);
-                    setTask(target, createTaskRecord(mService.mCurTask, target.info, null, false),
-                            null, false);
+                    setTask(target, createTaskRecord(mService.getNextTaskId(), target.info, null,
+                            false), null, false);
                     target.task.affinityIntent = target.intent;
                     if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
                             + " out to new task " + target.task);
@@ -2235,7 +2215,7 @@
                 } else {
                     if (taskInsertionPoint < 0) {
                         taskInsertionPoint = task.mActivities.size();
-                        
+
                     }
 
                     final int start = replyChainEnd >= 0 ? replyChainEnd : i;
@@ -2578,7 +2558,7 @@
                 } catch (RemoteException e) {
                     mService.mController = null;
                 }
-    
+
                 if (abort) {
                     if (resultRecord != null) {
                         sendActivityResultLocked(-1,
@@ -2594,7 +2574,7 @@
             }
         }
 
-        ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid, callingPackage,
+        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                 intent, resolvedType, aInfo, mService.mConfiguration,
                 resultRecord, resultWho, requestCode, componentSpecified);
         if (outActivity != null) {
@@ -2615,7 +2595,7 @@
                     return ActivityManager.START_SWITCHES_CANCELED;
                 }
             }
-        
+
             if (mService.mDidAppSwitch) {
                 // This is the second allowed switch since we stopped switches,
                 // so now just generally allow switches.  Use case: user presses
@@ -2626,10 +2606,10 @@
             } else {
                 mService.mDidAppSwitch = true;
             }
-         
+
             mService.doPendingActivityLaunchesLocked(false);
         }
-        
+
         err = startActivityUncheckedLocked(r, sourceRecord,
                 startFlags, true, options);
         if (mDismissKeyguardOnNextActivity && mPausingActivity == null) {
@@ -2642,7 +2622,7 @@
         }
         return err;
     }
-  
+
     final void moveHomeToFrontFromLaunchLocked(int launchFlags) {
         if ((launchFlags &
                 (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME))
@@ -2660,20 +2640,20 @@
         final int callingUid = r.launchedFromUid;
 
         int launchFlags = intent.getFlags();
-        
+
         // We'll invoke onUserLeaving before onPause only if the launching
         // activity did not explicitly state that this is an automated launch.
         mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
         if (DEBUG_USER_LEAVING) Slog.v(TAG,
                 "startActivity() => mUserLeaving=" + mUserLeaving);
-        
+
         // If the caller has asked not to resume at this point, we make note
         // of this in the record so that we can skip it when trying to find
         // the top running activity.
         if (!doResume) {
             r.delayedResume = true;
         }
-        
+
         ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
                 != 0 ? r : null;
 
@@ -2935,12 +2915,8 @@
         if (r.resultTo == null && !addingToTask
                 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
             if (reuseTask == null) {
-                // todo: should do better management of integers.
-                mService.mCurTask++;
-                if (mService.mCurTask <= 0) {
-                    mService.mCurTask = 1;
-                }
-                setTask(r, createTaskRecord(mService.mCurTask, r.info, intent, true), null, true);
+                setTask(r, createTaskRecord(mService.getNextTaskId(), r.info, intent, true), null,
+                        true);
                 if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                         + " in new task " + r.task);
             } else {
@@ -2950,7 +2926,7 @@
             if (!movedHome) {
                 moveHomeToFrontFromLaunchLocked(launchFlags);
             }
-            
+
         } else if (sourceRecord != null) {
             if (!addingToTask &&
                     (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
@@ -3010,7 +2986,8 @@
             }
             setTask(r, prev != null
                     ? prev.task
-                    : createTaskRecord(mService.mCurTask, r.info, intent, true), null, true);
+                    : createTaskRecord(mService.getNextTaskId(), r.info, intent, true), null,
+                            true);
             if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                     + " in new guessed " + r.task);
         }
@@ -3654,12 +3631,7 @@
         return true;
     }
 
-    final void finishSubActivityLocked(IBinder token, String resultWho, int requestCode) {
-        ActivityRecord self = isInStackLocked(token);
-        if (self == null) {
-            return;
-        }
-
+    final void finishSubActivityLocked(ActivityRecord self, String resultWho, int requestCode) {
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
@@ -3685,8 +3657,7 @@
                     + r.intent.getComponent().flattenToShortString());
             int taskNdx = mTaskHistory.indexOf(r.task);
             int activityNdx = r.task.mActivities.indexOf(r);
-            r.stack.finishActivityLocked(r, Activity.RESULT_CANCELED,
-                    null, "crashed", false);
+            finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed", false);
             // Also terminate any activities below it that aren't yet
             // stopped, to avoid a situation where one will get
             // re-start our crashing activity once it gets resumed again.
@@ -3708,22 +3679,14 @@
                     if (!r.isHomeActivity || mService.mHomeProcess != r.app) {
                         Slog.w(TAG, "  Force finishing activity "
                                 + r.intent.getComponent().flattenToShortString());
-                        r.stack.finishActivityLocked(r, Activity.RESULT_CANCELED,
-                                null, "crashed", false);
+                        finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed", false);
                     }
                 }
             }
         }
     }
 
-    final boolean finishActivityAffinityLocked(IBinder token) {
-        ActivityRecord r = isInStackLocked(token);
-        if (DEBUG_RESULTS) Slog.v(
-                TAG, "Finishing activity affinity token=" + token + " r=" + r);
-        if (r == null) {
-            return false;
-        }
-
+    final boolean finishActivityAffinityLocked(ActivityRecord r) {
         ArrayList<ActivityRecord> activities = r.task.mActivities;
         for (int index = activities.indexOf(r); index >= 0; --index) {
             ActivityRecord cur = activities.get(index);
@@ -3913,8 +3876,9 @@
         return r;
     }
 
-    final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
+    final boolean navigateUpToLocked(IBinder token, Intent destIntent, int resultCode,
             Intent resultData) {
+        final ActivityRecord srec = ActivityRecord.forToken(token);
         final TaskRecord task = srec.task;
         final ArrayList<ActivityRecord> activities = task.mActivities;
         final int start = activities.indexOf(srec);
@@ -4165,10 +4129,7 @@
 
         if (hadApp) {
             if (removeFromApp) {
-                int idx = r.app.activities.indexOf(r);
-                if (idx >= 0) {
-                    r.app.activities.remove(idx);
-                }
+                r.app.activities.remove(r);
                 if (mService.mHeavyWeightProcess == r.app && r.app.activities.size() <= 0) {
                     mService.mHeavyWeightProcess = null;
                     mService.mHandler.sendEmptyMessage(
@@ -4244,25 +4205,23 @@
         return removedFromHistory;
     }
 
-    final void activityDestroyed(IBinder token) {
-        synchronized (mService) {
-            final long origId = Binder.clearCallingIdentity();
-            try {
-                ActivityRecord r = ActivityRecord.forToken(token);
-                if (r != null) {
-                    mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
-                }
-
-                if (isInStackLocked(token) != null) {
-                    if (r.state == ActivityState.DESTROYING) {
-                        cleanUpActivityLocked(r, true, false);
-                        removeActivityFromHistoryLocked(r);
-                    }
-                }
-                resumeTopActivityLocked(null);
-            } finally {
-                Binder.restoreCallingIdentity(origId);
+    final void activityDestroyedLocked(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            ActivityRecord r = ActivityRecord.forToken(token);
+            if (r != null) {
+                mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
             }
+
+            if (isInStackLocked(token) != null) {
+                if (r.state == ActivityState.DESTROYING) {
+                    cleanUpActivityLocked(r, true, false);
+                    removeActivityFromHistoryLocked(r);
+                }
+            }
+            resumeTopActivityLocked(null);
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
     
@@ -4358,7 +4317,7 @@
                         }
                     }
 
-                    r.stack.cleanUpActivityLocked(r, true, true);
+                    cleanUpActivityLocked(r, true, true);
                 }
             }
         }
@@ -4397,8 +4356,8 @@
     }
 
     final boolean findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) {
-        final TaskRecord task = mTaskIdToTaskRecord.get(taskId);
-        if (mTaskHistory.contains(task)) {
+        final TaskRecord task = taskForIdLocked(taskId);
+        if (task != null) {
             if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
                 mUserLeaving = true;
             }
@@ -4496,7 +4455,10 @@
         if (DEBUG_TRANSITION) Slog.v(TAG,
                 "Prepare to back transition: task=" + task);
 
-        final TaskRecord tr = mTaskIdToTaskRecord.get(task);
+        final TaskRecord tr = taskForIdLocked(task);
+        if (tr == null) {
+            return false;
+        }
         mTaskHistory.remove(tr);
         mTaskHistory.add(0, tr);
 
@@ -4525,7 +4487,7 @@
         TaskAccessInfo info = getTaskAccessInfoLocked(tr, true);
         ActivityRecord resumed = mResumedActivity;
         if (resumed != null && resumed.thumbHolder == tr) {
-            info.mainThumbnail = resumed.stack.screenshotActivities(resumed);
+            info.mainThumbnail = screenshotActivities(resumed);
         }
         if (info.mainThumbnail == null) {
             info.mainThumbnail = tr.lastThumbnail;
@@ -4538,7 +4500,7 @@
         if (resumed != null && resumed.task == tr) {
             // This task is the current resumed task, we just need to take
             // a screenshot of it and return that.
-            return resumed.stack.screenshotActivities(resumed);
+            return screenshotActivities(resumed);
         }
         // Return the information about the task, to figure out the top
         // thumbnail to return.
@@ -4551,7 +4513,10 @@
 
     public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex,
             boolean taskRequired) {
-        final TaskRecord task = mTaskIdToTaskRecord.get(taskId);
+        final TaskRecord task = taskForIdLocked(taskId);
+        if (task == null) {
+            return null;
+        }
         TaskAccessInfo info = getTaskAccessInfoLocked(task, false);
         if (info.root == null) {
             if (taskRequired) {
@@ -4633,7 +4598,7 @@
                     TaskAccessInfo.SubTask sub = thumbs.subtasks.get(index);
                     ActivityRecord resumed = mResumedActivity;
                     if (resumed != null && resumed.thumbHolder == sub.holder) {
-                        return resumed.stack.screenshotActivities(resumed);
+                        return screenshotActivities(resumed);
                     }
                     return sub.holder.lastThumbnail;
                 }
@@ -4847,8 +4812,7 @@
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
                 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
-                    r.stack.finishActivityLocked(r, Activity.RESULT_CANCELED,
-                            null, "close-sys", true);
+                    finishActivityLocked(r, Activity.RESULT_CANCELED, null, "close-sys", true);
                 }
             }
         }
@@ -4884,8 +4848,7 @@
                         r.app = null;
                     }
                     lastTask = r.task;
-                    r.stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "force-stop",
-                            true);
+                    finishActivityLocked(r, Activity.RESULT_CANCELED, null, "force-stop", true);
                 }
             }
         }
@@ -4975,8 +4938,7 @@
                 if (r.app == app) {
                     Slog.w(TAG, "  Force finishing activity "
                             + r.intent.getComponent().flattenToShortString());
-                    r.stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed",
-                            false);
+                    finishActivityLocked(r, Activity.RESULT_CANCELED, null, "crashed", false);
                 }
             }
         }
@@ -5048,11 +5010,11 @@
 
     private void removeActivity(ActivityRecord r) {
         final TaskRecord task = r.task;
+        // TODO: use ActivityManagerService.removeTask to do this.
         if (task.removeActivity(r)) {
             if (DEBUG_ADD_REMOVE) Slog.i(TAG, "removeActivity: Removing from history, task="
                     + task);
             mTaskHistory.remove(task);
-            mTaskIdToTaskRecord.delete(task.taskId);
         }
     }
 
@@ -5066,13 +5028,7 @@
 
     private TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
             boolean toTop) {
-        TaskRecord oldTask = mTaskIdToTaskRecord.get(taskId);
-        if (oldTask != null) {
-            Slog.w(TAG, "createTaskRecord: Reusing taskId=" + taskId + " without removing");
-            mTaskHistory.remove(oldTask);
-        }
-        TaskRecord task = new TaskRecord(taskId, info, intent);
-        mTaskIdToTaskRecord.put(taskId, task);
+        TaskRecord task = new TaskRecord(taskId, info, intent, this);
         if (toTop) {
             mTaskHistory.add(task);
         } else {