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/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 5c24e67..10db70f 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -439,7 +439,7 @@
 
         ActivityRecord activity = null;
         if (token != null) {
-            activity = mAm.mMainStack.isInStackLocked(token);
+            activity = ActivityRecord.isInStackLocked(token);
             if (activity == null) {
                 Slog.w(TAG, "Binding with unknown activity: " + token);
                 return 0;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index d1b5071..21fbbda 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -272,7 +272,11 @@
     
     static final String[] EMPTY_STRING_ARRAY = new String[0];
 
-    public ActivityStack mMainStack;
+    /** All of the stacks in the system */
+    final public ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
+
+    /** The current stack for manipulating */
+    public ActivityStack mFocusedStack;
 
     private final boolean mHeadless;
 
@@ -749,7 +753,7 @@
      * todo: Replace this with a TokenSpace class that generates non-repeating
      * integers that won't wrap.
      */
-    int mCurTask = 1;
+    private int mCurTask = 0;
 
     /**
      * Current sequence id for oom_adj computation traversal.
@@ -1461,8 +1465,9 @@
         context.setTheme(android.R.style.Theme_Holo);
         m.mContext = context;
         m.mFactoryTest = factoryTest;
-        m.mMainStack = new ActivityStack(m, context, true, thr.mLooper);
-        
+        m.mFocusedStack = new ActivityStack(m, context, true, thr.mLooper);
+        m.mStacks.add(m.mFocusedStack);
+
         m.mBatteryStatsService.publish(context);
         m.mUsageStatsService.publish(context);
         m.mAppOpsService.publish(context);
@@ -2292,7 +2297,7 @@
                     aInfo.applicationInfo.uid);
             if (app == null || app.instrumentationClass == null) {
                 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
-                mMainStack.startActivityLocked(null, intent, null, aInfo,
+                mFocusedStack.startActivityLocked(null, intent, null, aInfo,
                         null, null, 0, 0, 0, null, 0, null, false, null);
             }
         }
@@ -2370,7 +2375,7 @@
                     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                     intent.setComponent(new ComponentName(
                             ri.activityInfo.packageName, ri.activityInfo.name));
-                    mMainStack.startActivityLocked(null, intent, null, ri.activityInfo,
+                    mFocusedStack.startActivityLocked(null, intent, null, ri.activityInfo,
                             null, null, 0, 0, 0, null, 0, null, false, null);
                 }
             }
@@ -2500,7 +2505,7 @@
         }
         for (int i=0; i<N; i++) {
             PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
-            mMainStack.startActivityUncheckedLocked(pal.r, pal.sourceRecord,
+            pal.r.task.stack.startActivityUncheckedLocked(pal.r, pal.sourceRecord,
                     pal.startFlags, doResume && i == (N-1), null);
         }
         mPendingActivityLaunches.clear();
@@ -2515,6 +2520,7 @@
                 startFlags, profileFile, profileFd, options, UserHandle.getCallingUserId());
     }
 
+    @Override
     public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags,
@@ -2522,11 +2528,12 @@
         enforceNotIsolatedCaller("startActivity");
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, true, "startActivity", null);
-        return mMainStack.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
+        return mFocusedStack.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
                 null, null, options, userId);
     }
 
+    @Override
     public final WaitResult startActivityAndWait(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags, String profileFile,
@@ -2535,12 +2542,13 @@
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, true, "startActivityAndWait", null);
         WaitResult res = new WaitResult();
-        mMainStack.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
+        mFocusedStack.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
                 res, null, options, UserHandle.getCallingUserId());
         return res;
     }
 
+    @Override
     public final int startActivityWithConfig(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags, Configuration config,
@@ -2548,8 +2556,8 @@
         enforceNotIsolatedCaller("startActivityWithConfig");
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, true, "startActivityWithConfig", null);
-        int ret = mMainStack.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
-                resultTo, resultWho, requestCode, startFlags,
+        int ret = mFocusedStack.startActivityMayWait(caller, -1, callingPackage, intent,
+                resolvedType, resultTo, resultWho, requestCode, startFlags,
                 null, null, null, config, options, userId);
         return ret;
     }
@@ -2574,8 +2582,8 @@
         synchronized (this) {
             // If this is coming from the currently resumed activity, it is
             // effectively saying that app switches are allowed at this point.
-            if (mMainStack.mResumedActivity != null
-                    && mMainStack.mResumedActivity.info.applicationInfo.uid ==
+            if (mFocusedStack.mResumedActivity != null
+                    && mFocusedStack.mResumedActivity.info.applicationInfo.uid ==
                             Binder.getCallingUid()) {
                 mAppSwitchesAllowedTime = 0;
             }
@@ -2593,7 +2601,7 @@
         }
 
         synchronized (this) {
-            ActivityRecord r = mMainStack.isInStackLocked(callingActivity);
+            final ActivityRecord r = ActivityRecord.isInStackLocked(callingActivity);
             if (r == null) {
                 ActivityOptions.abort(options);
                 return false;
@@ -2667,7 +2675,7 @@
             }
 
             final long origId = Binder.clearCallingIdentity();
-            int res = mMainStack.startActivityLocked(r.app.thread, intent,
+            int res = r.task.stack.startActivityLocked(r.app.thread, intent,
                     r.resolvedType, aInfo, resultTo != null ? resultTo.appToken : null,
                     resultWho, requestCode, -1, r.launchedFromUid, r.launchedFromPackage, 0,
                     options, false, null);
@@ -2688,7 +2696,7 @@
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, true, "startActivityInPackage", null);
 
-        int ret = mMainStack.startActivityMayWait(null, uid, callingPackage, intent, resolvedType,
+        int ret = mFocusedStack.startActivityMayWait(null, uid, callingPackage, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags,
                 null, null, null, null, options, userId);
         return ret;
@@ -2700,7 +2708,7 @@
         enforceNotIsolatedCaller("startActivities");
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, true, "startActivity", null);
-        int ret = mMainStack.startActivities(caller, -1, callingPackage, intents,
+        int ret = mFocusedStack.startActivities(caller, -1, callingPackage, intents,
                 resolvedTypes, resultTo, options, userId);
         return ret;
     }
@@ -2711,7 +2719,7 @@
 
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, true, "startActivityInPackage", null);
-        int ret = mMainStack.startActivities(null, uid, callingPackage, intents, resolvedTypes,
+        int ret = mFocusedStack.startActivities(null, uid, callingPackage, intents, resolvedTypes,
                 resultTo, options, userId);
         return ret;
     }
@@ -2747,7 +2755,7 @@
     public void setRequestedOrientation(IBinder token,
             int requestedOrientation) {
         synchronized (this) {
-            ActivityRecord r = mMainStack.isInStackLocked(token);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
                 return;
             }
@@ -2759,7 +2767,7 @@
             if (config != null) {
                 r.frozenBeforeDestroy = true;
                 if (!updateConfigurationLocked(config, r, false, false)) {
-                    mMainStack.resumeTopActivityLocked(null);
+                    r.task.stack.resumeTopActivityLocked(null);
                 }
             }
             Binder.restoreCallingIdentity(origId);
@@ -2768,7 +2776,7 @@
 
     public int getRequestedOrientation(IBinder token) {
         synchronized (this) {
-            ActivityRecord r = mMainStack.isInStackLocked(token);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
                 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
             }
@@ -2785,6 +2793,7 @@
      * 
      * @return Returns true if the activity successfully finished, or false if it is still running.
      */
+    @Override
     public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
         // Refuse possible leaked file descriptors
         if (resultData != null && resultData.hasFileDescriptors() == true) {
@@ -2792,9 +2801,13 @@
         }
 
         synchronized(this) {
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r == null) {
+                return true;
+            }
             if (mController != null) {
                 // Find the first activity that is not finishing.
-                ActivityRecord next = mMainStack.topRunningActivityLocked(token, 0);
+                ActivityRecord next = r.task.stack.topRunningActivityLocked(token, 0);
                 if (next != null) {
                     // ask watcher if this is allowed
                     boolean resumeOK = true;
@@ -2810,13 +2823,14 @@
                 }
             }
             final long origId = Binder.clearCallingIdentity();
-            boolean res = mMainStack.requestFinishActivityLocked(token, resultCode,
+            boolean res = r.task.stack.requestFinishActivityLocked(token, resultCode,
                     resultData, "app-request", true);
             Binder.restoreCallingIdentity(origId);
             return res;
         }
     }
 
+    @Override
     public final void finishHeavyWeightApp() {
         if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -2838,7 +2852,7 @@
             for (int i=0; i<activities.size(); i++) {
                 ActivityRecord r = activities.get(i);
                 if (!r.finishing) {
-                    mMainStack.finishActivityLocked(r, Activity.RESULT_CANCELED,
+                    r.task.stack.finishActivityLocked(r, Activity.RESULT_CANCELED,
                             null, "finish-heavy", true);
                 }
             }
@@ -2907,19 +2921,28 @@
         }
     }
     
+    @Override
     public final void finishSubActivity(IBinder token, String resultWho,
             int requestCode) {
         synchronized(this) {
             final long origId = Binder.clearCallingIdentity();
-            mMainStack.finishSubActivityLocked(token, resultWho, requestCode);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            if (r != null) {
+                r.task.stack.finishSubActivityLocked(r, resultWho, requestCode);
+            }
             Binder.restoreCallingIdentity(origId);
         }
     }
 
+    @Override
     public boolean finishActivityAffinity(IBinder token) {
         synchronized(this) {
             final long origId = Binder.clearCallingIdentity();
-            boolean res = mMainStack.finishActivityAffinityLocked(token);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            boolean res = false;
+            if (r != null) {
+                res = r.task.stack.finishActivityAffinityLocked(r);
+            }
             Binder.restoreCallingIdentity(origId);
             return res;
         }
@@ -2928,14 +2951,19 @@
     @Override
     public boolean willActivityBeVisible(IBinder token) {
         synchronized(this) {
-            return mMainStack.willActivityBeVisibleLocked(token);
+            ActivityStack stack = ActivityRecord.getStackLocked(token);
+            if (stack != null) {
+                return stack.willActivityBeVisibleLocked(token);
+            }
+            return false;
         }
     }
 
+    @Override
     public void overridePendingTransition(IBinder token, String packageName,
             int enterAnim, int exitAnim) {
         synchronized(this) {
-            ActivityRecord self = mMainStack.isInStackLocked(token);
+            ActivityRecord self = ActivityRecord.isInStackLocked(token);
             if (self == null) {
                 return;
             }
@@ -2969,20 +2997,37 @@
         }
 
         // Just in case...
-        if (mMainStack.mPausingActivity != null && mMainStack.mPausingActivity.app == app) {
-            if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG,
-                    "App died while pausing: " + mMainStack.mPausingActivity);
-            mMainStack.mPausingActivity = null;
-        }
-        if (mMainStack.mLastPausedActivity != null && mMainStack.mLastPausedActivity.app == app) {
-            mMainStack.mLastPausedActivity = null;
-        }
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (stack.mPausingActivity != null && stack.mPausingActivity.app == app) {
+                if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG,
+                        "App died while pausing: " + stack.mPausingActivity);
+                stack.mPausingActivity = null;
+            }
+            if (stack.mLastPausedActivity != null && stack.mLastPausedActivity.app == app) {
+                stack.mLastPausedActivity = null;
+            }
 
-        // Remove this application's activities from active lists.
-        boolean hasVisibleActivities = mMainStack.removeHistoryRecordsForAppLocked(app);
+            // Remove this application's activities from active lists.
+            boolean hasVisibleActivities = stack.removeHistoryRecordsForAppLocked(app);
+
+            if (!restarting) {
+                if (!stack.resumeTopActivityLocked(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) {
+                        stack.ensureActivitiesVisibleLocked(null, 0);
+                    }
+                }
+            }
+        }
 
         app.activities.clear();
-        
+
         if (app.instrumentationClass != null) {
             Slog.w(TAG, "Crash of app " + app.processName
                   + " running instrumentation " + app.instrumentationClass);
@@ -2990,19 +3035,6 @@
             info.putString("shortMsg", "Process crashed.");
             finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
         }
-
-        if (!restarting) {
-            if (!mMainStack.resumeTopActivityLocked(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) {
-                    mMainStack.ensureActivitiesVisibleLocked(null, 0);
-                }
-            }
-        }
     }
 
     private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
@@ -3701,7 +3733,11 @@
         }
         mWindowManager.closeSystemDialogs(reason);
 
-        mMainStack.closeSystemDialogsLocked();
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            stack.closeSystemDialogsLocked();
+        }
 
         broadcastIntentLocked(null, null, intent, null,
                 null, 0, null, null, null, AppOpsManager.OP_NONE, false, false, -1,
@@ -3909,11 +3945,15 @@
                 -100, callerWillRestart, true, doit, evenPersistent,
                 name == null ? ("force stop user " + userId) : ("force stop " + name));
 
-        if (mMainStack.forceStopPackageLocked(name, doit, evenPersistent, userId)) {
-            if (!doit) {
-                return true;
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) {
+                if (!doit) {
+                    return true;
+                }
+                didSomething = true;
             }
-            didSomething = true;
         }
 
         if (mServices.forceStopLocked(name, userId, evenPersistent, doit)) {
@@ -4001,8 +4041,11 @@
                 }
             }
             if (mBooted) {
-                mMainStack.resumeTopActivityLocked(null);
-                mMainStack.scheduleIdleLocked();
+                for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                    final ActivityStack stack = mStacks.get(stackNdx);
+                    stack.resumeTopActivityLocked(null);
+                    stack.scheduleIdleLocked();
+                }
             }
         }
         
@@ -4255,14 +4298,14 @@
         boolean didSomething = false;
 
         // See if the top visible activity is waiting to run in this process...
-        ActivityRecord hr = mMainStack.topRunningActivityLocked(null);
+        ActivityRecord hr = mFocusedStack.topRunningActivityLocked(null);
         if (hr != null && normalMode) {
             if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                     && processName.equals(hr.processName)) {
                 try {
                     if (mHeadless) {
                         Slog.e(TAG, "Starting activities not supported on headless device: " + hr);
-                    } else if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
+                    } else if (mFocusedStack.realStartActivityLocked(hr, app, true, true)) {
                         didSomething = true;
                     }
                 } catch (Exception e) {
@@ -4271,7 +4314,7 @@
                     badApp = true;
                 }
             } else {
-                mMainStack.ensureActivitiesVisibleLocked(hr, null, processName, 0);
+                mFocusedStack.ensureActivitiesVisibleLocked(hr, null, processName, 0);
             }
         }
 
@@ -4331,13 +4374,15 @@
         }
     }
 
+    @Override
     public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
         final long origId = Binder.clearCallingIdentity();
-        ActivityRecord r = mMainStack.activityIdleInternal(token, false, config);
         if (stopProfiling) {
             synchronized (this) {
-                if (mProfileProc == r.app) {
-                    if (mProfileFd != null) {
+                ActivityStack stack = ActivityRecord.getStackLocked(token);
+                if (stack != null) {
+                    ActivityRecord r = stack.activityIdleInternal(token, false, config);
+                    if ((mProfileProc == r.app) && (mProfileFd != null)) {
                         try {
                             mProfileFd.close();
                         } catch (IOException e) {
@@ -4374,7 +4419,7 @@
                     mLockScreenShown = false;
                     comeOutOfSleepIfNeededLocked();
                 }
-                mMainStack.dismissKeyguardOnNextActivityLocked();
+                mFocusedStack.dismissKeyguardOnNextActivityLocked();
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -4460,18 +4505,31 @@
         }
     }
 
+    @Override
     public final void activityResumed(IBinder token) {
         final long origId = Binder.clearCallingIdentity();
-        mMainStack.activityResumed(token);
+        synchronized(this) {
+            ActivityStack stack = ActivityRecord.getStackLocked(token);
+            if (stack != null) {
+                stack.activityResumedLocked(token);
+            }
+        }
         Binder.restoreCallingIdentity(origId);
     }
 
+    @Override
     public final void activityPaused(IBinder token) {
         final long origId = Binder.clearCallingIdentity();
-        mMainStack.activityPaused(token, false);
+        synchronized(this) {
+            ActivityStack stack = ActivityRecord.getStackLocked(token);
+            if (stack != null) {
+                stack.activityPausedLocked(token, false);
+            }
+        }
         Binder.restoreCallingIdentity(origId);
     }
 
+    @Override
     public final void activityStopped(IBinder token, Bundle icicle, Bitmap thumbnail,
             CharSequence description) {
         if (localLOGV) Slog.v(
@@ -4487,9 +4545,9 @@
         final long origId = Binder.clearCallingIdentity();
 
         synchronized (this) {
-            r = mMainStack.isInStackLocked(token);
+            r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
-                r.stack.activityStoppedLocked(r, icicle, thumbnail, description);
+                r.task.stack.activityStoppedLocked(r, icicle, thumbnail, description);
             }
         }
 
@@ -4502,9 +4560,15 @@
         Binder.restoreCallingIdentity(origId);
     }
 
+    @Override
     public final void activityDestroyed(IBinder token) {
         if (DEBUG_SWITCH) Slog.v(TAG, "ACTIVITY DESTROYED: " + token);
-        mMainStack.activityDestroyed(token);
+        synchronized (this) {
+            ActivityStack stack = ActivityRecord.getStackLocked(token);
+            if (stack != null) {
+                stack.activityDestroyedLocked(token);
+            }
+        }
     }
     
     public String getCallingPackage(IBinder token) {
@@ -4522,16 +4586,17 @@
     }
 
     private ActivityRecord getCallingRecordLocked(IBinder token) {
-        ActivityRecord r = mMainStack.isInStackLocked(token);
+        ActivityRecord r = ActivityRecord.isInStackLocked(token);
         if (r == null) {
             return null;
         }
         return r.resultTo;
     }
 
+    @Override
     public ComponentName getActivityClassForToken(IBinder token) {
         synchronized(this) {
-            ActivityRecord r = mMainStack.isInStackLocked(token);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
                 return null;
             }
@@ -4541,7 +4606,7 @@
 
     public String getPackageForToken(IBinder token) {
         synchronized(this) {
-            ActivityRecord r = mMainStack.isInStackLocked(token);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
                 return null;
             }
@@ -4619,7 +4684,7 @@
             }
         }
     }
-    
+
     IIntentSender getIntentSenderLocked(int type, String packageName,
             int callingUid, int userId, IBinder token, String resultWho,
             int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
@@ -4628,7 +4693,7 @@
             Slog.v(TAG_MU, "getIntentSenderLocked(): uid=" + callingUid);
         ActivityRecord activity = null;
         if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) {
-            activity = mMainStack.isInStackLocked(token);
+            activity = ActivityRecord.isInStackLocked(token);
             if (activity == null) {
                 return null;
             }
@@ -5654,7 +5719,8 @@
                 throw new SecurityException(msg);
             }
 
-            topRecord = mMainStack.getTasksLocked(maxNum, receiver, pending, list);
+            // TODO: Improve with MRU list from all ActivityStacks.
+            topRecord = mFocusedStack.getTasksLocked(maxNum, receiver, pending, list);
 
             if (!pending.pendingRecords.isEmpty()) {
                 mPendingThumbnails.add(pending);
@@ -5760,49 +5826,77 @@
         }
     }
 
-    private TaskRecord taskForIdLocked(int id) {
+    private TaskRecord recentTaskForIdLocked(int id) {
         final int N = mRecentTasks.size();
-        for (int i=0; i<N; i++) {
-            TaskRecord tr = mRecentTasks.get(i);
-            if (tr.taskId == id) {
-                return tr;
+            for (int i=0; i<N; i++) {
+                TaskRecord tr = mRecentTasks.get(i);
+                if (tr.taskId == id) {
+                    return tr;
+                }
+            }
+            return null;
+    }
+
+    TaskRecord anyTaskForIdLocked(int id) {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            ActivityStack stack = mStacks.get(stackNdx);
+            TaskRecord task = stack.taskForIdLocked(id);
+            if (task != null) {
+                return task;
             }
         }
         return null;
     }
 
+    int getNextTaskId() {
+        do {
+            mCurTask++;
+            if (mCurTask <= 0) {
+                mCurTask = 1;
+            }
+        } while (anyTaskForIdLocked(mCurTask) != null);
+        return mCurTask;
+    }
+
+    @Override
     public ActivityManager.TaskThumbnails getTaskThumbnails(int id) {
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
                     "getTaskThumbnails()");
-            TaskRecord tr = taskForIdLocked(id);
+            TaskRecord tr = recentTaskForIdLocked(id);
             if (tr != null) {
-                return mMainStack.getTaskThumbnailsLocked(tr);
+                return tr.stack.getTaskThumbnailsLocked(tr);
             }
         }
         return null;
     }
 
+    @Override
     public Bitmap getTaskTopThumbnail(int id) {
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
                     "getTaskTopThumbnail()");
-            TaskRecord tr = taskForIdLocked(id);
+            TaskRecord tr = recentTaskForIdLocked(id);
             if (tr != null) {
-                return mMainStack.getTaskTopThumbnailLocked(tr);
+                return tr.stack.getTaskTopThumbnailLocked(tr);
             }
         }
         return null;
     }
 
+    @Override
     public boolean removeSubTask(int taskId, int subTaskIndex) {
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
                     "removeSubTask()");
             long ident = Binder.clearCallingIdentity();
             try {
-                return mMainStack.removeTaskActivitiesLocked(taskId, subTaskIndex,
-                        true) != null;
+                TaskRecord tr = recentTaskForIdLocked(taskId);
+                if (tr != null) {
+                    return tr.stack.removeTaskActivitiesLocked(taskId, subTaskIndex,
+                            true) != null;
+                }
+                return false;
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -5856,43 +5950,32 @@
         }
     }
 
+    @Override
     public boolean removeTask(int taskId, int flags) {
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
                     "removeTask()");
             long ident = Binder.clearCallingIdentity();
             try {
-                ActivityRecord r = mMainStack.removeTaskActivitiesLocked(taskId, -1,
-                        false);
-                if (r != null) {
-                    mRecentTasks.remove(r.task);
-                    cleanUpRemovedTaskLocked(r.task, flags);
-                    return true;
-                } else {
-                    TaskRecord tr = null;
-                    int i=0;
-                    while (i < mRecentTasks.size()) {
-                        TaskRecord t = mRecentTasks.get(i);
-                        if (t.taskId == taskId) {
-                            tr = t;
-                            break;
-                        }
-                        i++;
+                TaskRecord tr = recentTaskForIdLocked(taskId);
+                if (tr != null) {
+                    ActivityRecord r = tr.stack.removeTaskActivitiesLocked(taskId, -1, false);
+                    if (r != null) {
+                        mRecentTasks.remove(tr);
+                        cleanUpRemovedTaskLocked(tr, flags);
+                        return true;
                     }
-                    if (tr != null) {
-                        if (tr.numActivities <= 0) {
-                            // Caller is just removing a recent task that is
-                            // not actively running.  That is easy!
-                            mRecentTasks.remove(i);
-                            cleanUpRemovedTaskLocked(tr, flags);
-                            return true;
-                        } else {
-                            Slog.w(TAG, "removeTask: task " + taskId
-                                    + " does not have activities to remove, "
-                                    + " but numActivities=" + tr.numActivities
-                                    + ": " + tr);
-                        }
+                    if (tr.mActivities.size() == 0) {
+                        // Caller is just removing a recent task that is
+                        // not actively running.  That is easy!
+                        mRecentTasks.remove(tr);
+                        cleanUpRemovedTaskLocked(tr, flags);
+                        return true;
                     }
+                    Slog.w(TAG, "removeTask: task " + taskId
+                            + " does not have activities to remove, "
+                            + " but numActivities=" + tr.numActivities
+                            + ": " + tr);
                 }
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -5904,6 +5987,7 @@
     /**
      * TODO: Add mController hook
      */
+    @Override
     public void moveTaskToFront(int task, int flags, Bundle options) {
         enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
                 "moveTaskToFront()");
@@ -5916,21 +6000,25 @@
             }
             final long origId = Binder.clearCallingIdentity();
             try {
-                TaskRecord tr = taskForIdLocked(task);
+                TaskRecord tr = recentTaskForIdLocked(task);
                 if (tr != null) {
+                    ActivityStack stack = tr.stack;
                     if ((flags&ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
-                        mMainStack.mUserLeaving = true;
+                        stack.mUserLeaving = true;
                     }
                     if ((flags&ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
                         // Caller wants the home activity moved with it.  To accomplish this,
                         // we'll just move the home task to the top first.
-                        mMainStack.moveHomeToFrontLocked();
+                        stack.moveHomeToFrontLocked();
                     }
-                    mMainStack.moveTaskToFrontLocked(tr, null, options);
+                    stack.moveTaskToFrontLocked(tr, null, options);
                     return;
                 }
-                if (mMainStack.findTaskToMoveToFrontLocked(task, flags, options)) {
-                    return;
+                // Failed to find the task in the recents list. Look in all stacks.
+                for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                    if (mStacks.get(stackNdx).findTaskToMoveToFrontLocked(task, flags, options)) {
+                        return;
+                    }
                 }
             } finally {
                 Binder.restoreCallingIdentity(origId);
@@ -5939,21 +6027,25 @@
         }
     }
 
+    @Override
     public void moveTaskToBack(int task) {
         enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
                 "moveTaskToBack()");
 
         synchronized(this) {
-            if (mMainStack.mResumedActivity != null
-                    && mMainStack.mResumedActivity.task.taskId == task) {
-                if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
-                        Binder.getCallingUid(), "Task to back")) {
-                    return;
+            TaskRecord tr = recentTaskForIdLocked(task);
+            if (tr != null) {
+                ActivityStack stack = tr.stack;
+                if (stack.mResumedActivity != null && stack.mResumedActivity.task == tr) {
+                    if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
+                            Binder.getCallingUid(), "Task to back")) {
+                        return;
+                    }
                 }
+                final long origId = Binder.clearCallingIdentity();
+                stack.moveTaskToBackLocked(task, null);
+                Binder.restoreCallingIdentity(origId);
             }
-            final long origId = Binder.clearCallingIdentity();
-            mMainStack.moveTaskToBackLocked(task, null);
-            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -5966,13 +6058,14 @@
      *                of a task; if true it will work for any activity in a task.
      * @return Returns true if the move completed, false if not.
      */
+    @Override
     public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
         enforceNotIsolatedCaller("moveActivityTaskToBack");
         synchronized(this) {
             final long origId = Binder.clearCallingIdentity();
-            int taskId = mMainStack.getTaskForActivityLocked(token, !nonRoot);
+            int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot);
             if (taskId >= 0) {
-                return mMainStack.moveTaskToBackLocked(taskId, null);
+                return ActivityRecord.getStackLocked(token).moveTaskToBackLocked(taskId, null);
             }
             Binder.restoreCallingIdentity(origId);
         }
@@ -5998,9 +6091,10 @@
         Slog.e(TAG, "moveTaskBackwards not yet implemented!");
     }
 
+    @Override
     public int getTaskForActivity(IBinder token, boolean onlyRoot) {
         synchronized(this) {
-            return mMainStack.getTaskForActivityLocked(token, onlyRoot);
+            return ActivityRecord.getTaskForActivityLocked(token, onlyRoot);
         }
     }
 
@@ -6025,7 +6119,7 @@
 
         synchronized(this) {
             if (r == null) {
-                r = mMainStack.isInStackLocked(token);
+                r = ActivityRecord.isInStackLocked(token);
                 if (r == null) {
                     return;
                 }
@@ -6911,7 +7005,7 @@
         synchronized(this) {
             final long origId = Binder.clearCallingIdentity();
             try {
-                mMainStack.unhandledBackLocked();
+                mFocusedStack.unhandledBackLocked();
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
@@ -6970,7 +7064,11 @@
 
             if (!mSleeping) {
                 mSleeping = true;
-                mMainStack.stopIfSleepingLocked();
+                final int numStacks = mStacks.size();
+                for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                    final ActivityStack stack = mStacks.get(stackNdx);
+                    stack.stopIfSleepingLocked();
+                }
 
                 // Initialize the wake times of all processes.
                 checkExcessivePowerUsageLocked(false);
@@ -6981,33 +7079,38 @@
         }
     }
 
+    @Override
     public boolean shutdown(int timeout) {
         if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires permission "
                     + android.Manifest.permission.SHUTDOWN);
         }
-        
+
         boolean timedout = false;
-        
+
         synchronized(this) {
             mShuttingDown = true;
             updateEventDispatchingLocked();
 
-            if (mMainStack.mResumedActivity != null) {
-                mMainStack.stopIfSleepingLocked();
-                final long endTime = System.currentTimeMillis() + timeout;
-                while (mMainStack.mResumedActivity != null
-                        || mMainStack.mPausingActivity != null) {
-                    long delay = endTime - System.currentTimeMillis();
-                    if (delay <= 0) {
-                        Slog.w(TAG, "Activity manager shutdown timed out");
-                        timedout = true;
-                        break;
-                    }
-                    try {
-                        this.wait();
-                    } catch (InterruptedException e) {
+            final int numStacks = mStacks.size();
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = mStacks.get(stackNdx);
+                if (stack.mResumedActivity != null) {
+                    stack.stopIfSleepingLocked();
+                    final long endTime = System.currentTimeMillis() + timeout;
+                    while (stack.mResumedActivity != null
+                            || stack.mPausingActivity != null) {
+                        long delay = endTime - System.currentTimeMillis();
+                        if (delay <= 0) {
+                            Slog.w(TAG, "Activity manager shutdown timed out");
+                            timedout = true;
+                            break;
+                        }
+                        try {
+                            this.wait();
+                        } catch (InterruptedException e) {
+                        }
                     }
                 }
             }
@@ -7016,7 +7119,7 @@
         mAppOpsService.shutdown();
         mUsageStatsService.shutdown();
         mBatteryStatsService.shutdown();
-        
+
         return timedout;
     }
     
@@ -7029,9 +7132,9 @@
         final long origId = Binder.clearCallingIdentity();
 
         synchronized (this) {
-            r = mMainStack.isInStackLocked(token);
+            r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
-                mMainStack.activitySleptLocked(r);
+                r.task.stack.activitySleptLocked(r);
             }
         }
 
@@ -7042,8 +7145,12 @@
         if (!mWentToSleep && !mLockScreenShown) {
             if (mSleeping) {
                 mSleeping = false;
-                mMainStack.awakeFromSleepingLocked();
-                mMainStack.resumeTopActivityLocked(null);
+                final int numStacks = mStacks.size();
+                for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                    final ActivityStack stack = mStacks.get(stackNdx);
+                    stack.awakeFromSleepingLocked();
+                    stack.resumeTopActivityLocked(null);
+                }
             }
         }
     }
@@ -7318,7 +7425,7 @@
         PendingActivityExtras pae;
         Bundle extras = new Bundle();
         synchronized (this) {
-            ActivityRecord activity = mMainStack.mResumedActivity;
+            ActivityRecord activity = mFocusedStack.mResumedActivity;
             if (activity == null) {
                 Slog.w(TAG, "getTopActivityExtras failed: no resumed activity");
                 return null;
@@ -7385,7 +7492,7 @@
 
     public void setImmersive(IBinder token, boolean immersive) {
         synchronized(this) {
-            final ActivityRecord r = mMainStack.isInStackLocked(token);
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
                 throw new IllegalArgumentException();
             }
@@ -7403,7 +7510,7 @@
 
     public boolean isImmersive(IBinder token) {
         synchronized (this) {
-            ActivityRecord r = mMainStack.isInStackLocked(token);
+            ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r == null) {
                 throw new IllegalArgumentException();
             }
@@ -7414,7 +7521,7 @@
     public boolean isTopActivityImmersive() {
         enforceNotIsolatedCaller("startActivity");
         synchronized (this) {
-            ActivityRecord r = mMainStack.topRunningActivityLocked(null);
+            ActivityRecord r = mFocusedStack.topRunningActivityLocked(null);
             return (r != null) ? r.immersive : false;
         }
     }
@@ -7912,7 +8019,7 @@
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
-            mMainStack.resumeTopActivityLocked(null);
+            mFocusedStack.resumeTopActivityLocked(null);
             sendUserSwitchBroadcastsLocked(-1, mCurrentUserId);
         }
     }
@@ -8001,13 +8108,17 @@
         } else {
             crashTime = null;
         }
+        final int numStacks = mStacks.size();
         if (crashTime != null && now < crashTime+ProcessList.MIN_CRASH_INTERVAL) {
             // This process loses!
             Slog.w(TAG, "Process " + app.info.processName
                     + " has crashed too many times: killing!");
             EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
                     app.userId, app.info.processName, app.uid);
-            mMainStack.handleAppCrashLocked(app);
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = mStacks.get(stackNdx);
+                stack.handleAppCrashLocked(app);
+            }
             if (!app.persistent) {
                 // We don't want to start this process again until the user
                 // explicitly does so...  but for persistent process, we really
@@ -8027,12 +8138,21 @@
                 // annoy the user repeatedly.  Unless it is persistent, since those
                 // processes run critical code.
                 removeProcessLocked(app, false, false, "crash");
-                mMainStack.resumeTopActivityLocked(null);
+                for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                    final ActivityStack stack = mStacks.get(stackNdx);
+                    stack.resumeTopActivityLocked(null);
+                }
                 return false;
             }
-            mMainStack.resumeTopActivityLocked(null);
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = mStacks.get(stackNdx);
+                stack.resumeTopActivityLocked(null);
+            }
         } else {
-            mMainStack.finishTopRunningActivityLocked(app);
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = mStacks.get(stackNdx);
+                stack.finishTopRunningActivityLocked(app);
+            }
         }
 
         // Bump up the crash count of any services currently running in the proc.
@@ -8052,9 +8172,9 @@
         // from blocking the user to manually clear the list.
         if (app == mHomeProcess && mHomeProcess.activities.size() > 0
                     && (mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
-            Iterator it = mHomeProcess.activities.iterator();
+            Iterator<ActivityRecord> it = mHomeProcess.activities.iterator();
             while (it.hasNext()) {
-                ActivityRecord r = (ActivityRecord)it.next();
+                ActivityRecord r = it.next();
                 if (r.isHomeActivity) {
                     Log.i(TAG, "Clearing package preferred activities from " + r.packageName);
                     try {
@@ -9050,48 +9170,57 @@
     boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
         pw.println("ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)");
-        pw.println("  Main stack:");
-        mMainStack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage);
-        pw.println(" ");
-        pw.println("  Running activities (most recent first):");
-        dumpHistoryList(fd, pw, mMainStack.mLRUActivities, "  ", "Run", false, !dumpAll, false,
-                dumpPackage);
-        if (mMainStack.mWaitingVisibleActivities.size() > 0) {
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            pw.print("  Stack #"); pw.print(mStacks.indexOf(stack)); pw.println(":");
+            stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage);
             pw.println(" ");
-            pw.println("  Activities waiting for another to become visible:");
-            dumpHistoryList(fd, pw, mMainStack.mWaitingVisibleActivities, "  ", "Wait", false,
-                    !dumpAll, false, dumpPackage);
-        }
-        if (mMainStack.mStoppingActivities.size() > 0) {
-            pw.println(" ");
-            pw.println("  Activities waiting to stop:");
-            dumpHistoryList(fd, pw, mMainStack.mStoppingActivities, "  ", "Stop", false,
-                    !dumpAll, false, dumpPackage);
-        }
-        if (mMainStack.mGoingToSleepActivities.size() > 0) {
-            pw.println(" ");
-            pw.println("  Activities waiting to sleep:");
-            dumpHistoryList(fd, pw, mMainStack.mGoingToSleepActivities, "  ", "Sleep", false,
-                    !dumpAll, false, dumpPackage);
-        }
-        if (mMainStack.mFinishingActivities.size() > 0) {
-            pw.println(" ");
-            pw.println("  Activities waiting to finish:");
-            dumpHistoryList(fd, pw, mMainStack.mFinishingActivities, "  ", "Fin", false,
-                    !dumpAll, false, dumpPackage);
+            pw.println("  Running activities (most recent first):");
+            dumpHistoryList(fd, pw, stack.mLRUActivities, "  ", "Run", false, !dumpAll, false,
+                    dumpPackage);
+            if (stack.mWaitingVisibleActivities.size() > 0) {
+                pw.println(" ");
+                pw.println("  Activities waiting for another to become visible:");
+                dumpHistoryList(fd, pw, stack.mWaitingVisibleActivities, "  ", "Wait", false,
+                        !dumpAll, false, dumpPackage);
+            }
+            if (stack.mStoppingActivities.size() > 0) {
+                pw.println(" ");
+                pw.println("  Activities waiting to stop:");
+                dumpHistoryList(fd, pw, stack.mStoppingActivities, "  ", "Stop", false,
+                        !dumpAll, false, dumpPackage);
+            }
+            if (stack.mGoingToSleepActivities.size() > 0) {
+                pw.println(" ");
+                pw.println("  Activities waiting to sleep:");
+                dumpHistoryList(fd, pw, stack.mGoingToSleepActivities, "  ", "Sleep", false,
+                        !dumpAll, false, dumpPackage);
+            }
+            if (stack.mFinishingActivities.size() > 0) {
+                pw.println(" ");
+                pw.println("  Activities waiting to finish:");
+                dumpHistoryList(fd, pw, stack.mFinishingActivities, "  ", "Fin", false,
+                        !dumpAll, false, dumpPackage);
+            }
         }
 
         pw.println(" ");
-        if (mMainStack.mPausingActivity != null) {
-            pw.println("  mPausingActivity: " + mMainStack.mPausingActivity);
-        }
-        pw.println("  mResumedActivity: " + mMainStack.mResumedActivity);
         pw.println("  mFocusedActivity: " + mFocusedActivity);
-        if (dumpAll) {
-            pw.println("  mLastPausedActivity: " + mMainStack.mLastPausedActivity);
-            pw.println("  mSleepTimeout: " + mMainStack.mSleepTimeout);
-            pw.println("  mDismissKeyguardOnNextActivity: "
-                    + mMainStack.mDismissKeyguardOnNextActivity);
+        pw.println(" ");
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            pw.print("  Stack #"); pw.println(mStacks.indexOf(stack));
+            if (stack.mPausingActivity != null) {
+                pw.println("  mPausingActivity: " + stack.mPausingActivity);
+            }
+            pw.println("  mResumedActivity: " + stack.mResumedActivity);
+            if (dumpAll) {
+                pw.println("  mLastPausedActivity: " + stack.mLastPausedActivity);
+                pw.println("  mSleepTimeout: " + stack.mSleepTimeout);
+                pw.println("  mDismissKeyguardOnNextActivity: "
+                        + stack.mDismissKeyguardOnNextActivity);
+            }
         }
 
         if (mRecentTasks.size() > 0) {
@@ -9336,7 +9465,7 @@
         }
         pw.println("  mConfiguration: " + mConfiguration);
         if (dumpAll) {
-            pw.println("  mConfigWillChange: " + mMainStack.mConfigWillChange);
+            pw.println("  mConfigWillChange: " + mFocusedStack.mConfigWillChange);
             if (mCompatModePackages.getPackages().size() > 0) {
                 boolean printed = false;
                 for (Map.Entry<String, Integer> entry
@@ -9396,8 +9525,8 @@
             pw.print("  mLastPowerCheckUptime=");
                     TimeUtils.formatDuration(mLastPowerCheckUptime, pw);
                     pw.println("");
-            pw.println("  mGoingToSleep=" + mMainStack.mGoingToSleep);
-            pw.println("  mLaunchingActivity=" + mMainStack.mLaunchingActivity);
+            pw.println("  mGoingToSleep=" + mFocusedStack.mGoingToSleep);
+            pw.println("  mLaunchingActivity=" + mFocusedStack.mLaunchingActivity);
             pw.println("  mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq);
             pw.println("  mNumNonHiddenProcs=" + mNumNonHiddenProcs
                     + " mNumHiddenProcs=" + mNumHiddenProcs
@@ -9584,7 +9713,7 @@
         ArrayList<ActivityRecord> activities;
         
         synchronized (this) {
-            activities = mMainStack.getDumpActivitiesLocked(name);
+            activities = mFocusedStack.getDumpActivitiesLocked(name);
         }
 
         if (activities.size() <= 0) {
@@ -12314,21 +12443,25 @@
                 }
             }
         }
-        
-        if (changes != 0 && starting == null) {
-            // If the configuration changed, and the caller is not already
-            // in the process of starting an activity, then find the top
-            // activity to check if its configuration needs to change.
-            starting = mMainStack.topRunningActivityLocked(null);
+
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (changes != 0 && starting == null) {
+                // If the configuration changed, and the caller is not already
+                // in the process of starting an activity, then find the top
+                // activity to check if its configuration needs to change.
+                starting = stack.topRunningActivityLocked(null);
+            }
+
+            if (starting != null) {
+                kept = stack.ensureActivityConfigurationLocked(starting, changes);
+                // And we need to make sure at this point that all other activities
+                // are made visible with the correct configuration.
+                stack.ensureActivitiesVisibleLocked(starting, changes);
+            }
         }
-        
-        if (starting != null) {
-            kept = mMainStack.ensureActivityConfigurationLocked(starting, changes);
-            // And we need to make sure at this point that all other activities
-            // are made visible with the correct configuration.
-            mMainStack.ensureActivitiesVisibleLocked(starting, changes);
-        }
-        
+
         if (values != null && mWindowManager != null) {
             mWindowManager.setNewConfiguration(mConfiguration);
         }
@@ -12376,12 +12509,11 @@
             Intent resultData) {
 
         synchronized (this) {
-            ActivityRecord srec = ActivityRecord.forToken(token);
-            if (srec == null) {
-                return false;
+            final ActivityStack stack = ActivityRecord.getStackLocked(token);
+            if (stack != null) {
+                return stack.navigateUpToLocked(token, destIntent, resultCode, resultData);
             }
-            ActivityStack stack = srec.stack;
-            return stack.navigateUpToLocked(srec, destIntent, resultCode, resultData);
+            return false;
         }
     }
 
@@ -13122,8 +13254,8 @@
             }
         }
         return !processingBroadcasts
-                && (mSleeping || (mMainStack.mResumedActivity != null &&
-                        mMainStack.mResumedActivity.idle));
+                && (mSleeping || (mFocusedStack.mResumedActivity != null &&
+                        mFocusedStack.mResumedActivity.idle));
     }
     
     /**
@@ -13407,11 +13539,11 @@
     }
 
     private final ActivityRecord resumedAppLocked() {
-        ActivityRecord resumedActivity = mMainStack.mResumedActivity;
+        ActivityRecord resumedActivity = mFocusedStack.mResumedActivity;
         if (resumedActivity == null || resumedActivity.app == null) {
-            resumedActivity = mMainStack.mPausingActivity;
+            resumedActivity = mFocusedStack.mPausingActivity;
             if (resumedActivity == null || resumedActivity.app == null) {
-                resumedActivity = mMainStack.topRunningActivityLocked(null);
+                resumedActivity = mFocusedStack.topRunningActivityLocked(null);
             }
         }
         return resumedActivity;
@@ -13657,7 +13789,11 @@
                                 // be in a consistent state at this point.
                                 // For these apps we will also finish their activities
                                 // to help them free memory.
-                                mMainStack.scheduleDestroyActivities(app, false, "trim");
+                                final int numStacks = mStacks.size();
+                                for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                                    final ActivityStack stack = mStacks.get(stackNdx);
+                                    stack.scheduleDestroyActivities(app, false, "trim");
+                                }
                             }
                         }
                     }
@@ -13731,7 +13867,11 @@
         if (mAlwaysFinishActivities) {
             // Need to do this on its own message because the stack may not
             // be in a consistent state at this point.
-            mMainStack.scheduleDestroyActivities(null, false, "always-finish");
+            final int numStacks = mStacks.size();
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = mStacks.get(stackNdx);
+                stack.scheduleDestroyActivities(null, false, "always-finish");
+            }
         }
     }
 
@@ -14097,7 +14237,12 @@
                     }
                 }
 
-                boolean haveActivities = mMainStack.switchUserLocked(userId, uss);
+                boolean haveActivities = false;
+                final int numStacks = mStacks.size();
+                for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                    final ActivityStack stack = mStacks.get(stackNdx);
+                    haveActivities |= stack.switchUserLocked(userId, uss);
+                }
                 if (!haveActivities) {
                     startHomeActivityLocked(userId);
                 }
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index d134c13..2075af7 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -20,7 +20,6 @@
 import com.android.server.AttributeCache;
 import com.android.server.am.ActivityStack.ActivityState;
 
-import android.app.Activity;
 import android.app.ActivityOptions;
 import android.app.ResultInfo;
 import android.content.ComponentName;
@@ -56,7 +55,6 @@
  */
 final class ActivityRecord {
     final ActivityManagerService service; // owner
-    final ActivityStack stack; // owner
     final IApplicationToken.Stub appToken; // window manager token
     final ActivityInfo info; // all about me
     final int launchedFromUid; // always the uid who started the activity.
@@ -183,7 +181,7 @@
         if (newIntents != null && newIntents.size() > 0) {
             pw.print(prefix); pw.println("Pending New Intents:");
             for (int i=0; i<newIntents.size(); i++) {
-                Intent intent = (Intent)newIntents.get(i);
+                Intent intent = newIntents.get(i);
                 pw.print(prefix); pw.print("  - ");
                 if (intent == null) {
                     pw.println("null");
@@ -327,13 +325,12 @@
         }
     }
 
-    ActivityRecord(ActivityManagerService _service, ActivityStack _stack, ProcessRecord _caller,
+    ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
             int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
             ActivityInfo aInfo, Configuration _configuration,
             ActivityRecord _resultTo, String _resultWho, int _reqCode,
             boolean _componentSpecified) {
         service = _service;
-        stack = _stack;
         appToken = new Token(this);
         info = aInfo;
         launchedFromUid = _launchedFromUid;
@@ -565,7 +562,7 @@
 
     void addNewIntentLocked(Intent intent) {
         if (newIntents == null) {
-            newIntents = new ArrayList();
+            newIntents = new ArrayList<Intent>();
         }
         newIntents.add(intent);
     }
@@ -585,7 +582,7 @@
         // case we will deliver it if this is the current top activity on its
         // stack.
         if ((state == ActivityState.RESUMED || (service.mSleeping
-                        && stack.topRunningActivityLocked(null) == this))
+                        && task.stack.topRunningActivityLocked(null) == this))
                 && app != null && app.thread != null) {
             try {
                 ArrayList<Intent> ar = new ArrayList<Intent>();
@@ -729,6 +726,7 @@
 
     boolean continueLaunchTickingLocked() {
         if (launchTickTime != 0) {
+            final ActivityStack stack = task.stack;
             Message msg = stack.mHandler.obtainMessage(ActivityStack.LAUNCH_TICK_MSG);
             msg.obj = this;
             stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
@@ -740,7 +738,7 @@
 
     void finishLaunchTickingLocked() {
         launchTickTime = 0;
-        stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
+        task.stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
     }
 
     // IApplicationToken
@@ -769,6 +767,7 @@
     public void windowsDrawn() {
         synchronized(service) {
             if (launchTime != 0) {
+                final ActivityStack stack = task.stack;
                 final long curTime = SystemClock.uptimeMillis();
                 final long thisTime = curTime - launchTime;
                 final long totalTime = stack.mInitialStartTime != 0
@@ -804,6 +803,7 @@
 
     public void windowsVisible() {
         synchronized(service) {
+            final ActivityStack stack = task.stack;
             stack.reportActivityVisibleLocked(this);
             if (ActivityManagerService.DEBUG_SWITCH) Log.v(
                     ActivityManagerService.TAG, "windowsVisible(): " + this);
@@ -824,8 +824,7 @@
                     final int N = stack.mWaitingVisibleActivities.size();
                     if (N > 0) {
                         for (int i=0; i<N; i++) {
-                            ActivityRecord r = (ActivityRecord)
-                                stack.mWaitingVisibleActivities.get(i);
+                            ActivityRecord r = stack.mWaitingVisibleActivities.get(i);
                             r.waitingVisible = false;
                             if (ActivityManagerService.DEBUG_SWITCH) Log.v(
                                     ActivityManagerService.TAG,
@@ -853,6 +852,7 @@
         // for another app to start, then we have paused dispatching
         // for this activity.
         ActivityRecord r = this;
+        final ActivityStack stack = task.stack;
         if (r.waitingVisible) {
             // Hmmm, who might we be waiting for?
             r = stack.mResumedActivity;
@@ -902,6 +902,7 @@
         if (app != null && app.thread != null) {
             try {
                 app.thread.scheduleSleeping(appToken, _sleeping);
+                final ActivityStack stack = task.stack;
                 if (sleeping && !stack.mGoingToSleepActivities.contains(this)) {
                     stack.mGoingToSleepActivities.add(this);
                 }
@@ -913,6 +914,35 @@
         }
     }
 
+    static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
+        final ActivityRecord r = ActivityRecord.forToken(token);
+        if (r == null) {
+            return -1;
+        }
+        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;
+        }
+    }
+
+    static ActivityRecord isInStackLocked(IBinder token) {
+        final ActivityRecord r = ActivityRecord.forToken(token);
+        if (r != null) {
+            return r.task.stack.isInStackLocked(token);
+        }
+        return null;
+    }
+
+    static final ActivityStack getStackLocked(IBinder token) {
+        final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+        if (r != null) {
+            return r.task.stack;
+        }
+        return null;
+    }
+
     @Override
     public String toString() {
         if (stringName != null) {
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 {
diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java
index 863bdad..c56fdff 100644
--- a/services/java/com/android/server/am/CompatModePackages.java
+++ b/services/java/com/android/server/am/CompatModePackages.java
@@ -166,7 +166,7 @@
     }
 
     public boolean getFrontActivityAskCompatModeLocked() {
-        ActivityRecord r = mService.mMainStack.topRunningActivityLocked(null);
+        ActivityRecord r = mService.mFocusedStack.topRunningActivityLocked(null);
         if (r == null) {
             return false;
         }
@@ -178,7 +178,7 @@
     }
 
     public void setFrontActivityAskCompatModeLocked(boolean ask) {
-        ActivityRecord r = mService.mMainStack.topRunningActivityLocked(null);
+        ActivityRecord r = mService.mFocusedStack.topRunningActivityLocked(null);
         if (r != null) {
             setPackageAskCompatModeLocked(r.packageName, ask);
         }
@@ -200,7 +200,7 @@
     }
 
     public int getFrontActivityScreenCompatModeLocked() {
-        ActivityRecord r = mService.mMainStack.topRunningActivityLocked(null);
+        ActivityRecord r = mService.mFocusedStack.topRunningActivityLocked(null);
         if (r == null) {
             return ActivityManager.COMPAT_MODE_UNKNOWN;
         }
@@ -208,7 +208,7 @@
     }
 
     public void setFrontActivityScreenCompatModeLocked(int mode) {
-        ActivityRecord r = mService.mMainStack.topRunningActivityLocked(null);
+        ActivityRecord r = mService.mFocusedStack.topRunningActivityLocked(null);
         if (r == null) {
             Slog.w(TAG, "setFrontActivityScreenCompatMode failed: no top activity");
             return;
@@ -296,7 +296,7 @@
             mHandler.sendMessageDelayed(msg, 10000);
 
             
-            ActivityRecord starting = mService.mMainStack.restartPackage(packageName);
+            ActivityRecord starting = mService.mFocusedStack.restartPackage(packageName);
 
             // Tell all processes that loaded this package about the change.
             for (int i=mService.mLruProcesses.size()-1; i>=0; i--) {
@@ -315,10 +315,10 @@
             }
 
             if (starting != null) {
-                mService.mMainStack.ensureActivityConfigurationLocked(starting, 0);
+                mService.mFocusedStack.ensureActivityConfigurationLocked(starting, 0);
                 // And we need to make sure at this point that all other activities
                 // are made visible with the correct configuration.
-                mService.mMainStack.ensureActivitiesVisibleLocked(starting, 0);
+                mService.mFocusedStack.ensureActivitiesVisibleLocked(starting, 0);
             }
         }
     }
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index 8ab71dd..28593fe 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -259,7 +259,7 @@
                         }
                         break;
                     case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
-                        key.activity.stack.sendActivityResultLocked(-1, key.activity,
+                        key.activity.task.stack.sendActivityResultLocked(-1, key.activity,
                                 key.who, key.requestCode, code, finalIntent);
                         break;
                     case ActivityManager.INTENT_SENDER_BROADCAST:
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 4c3b590..9833d31 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -43,12 +43,17 @@
 
     int numFullscreen;      // Number of fullscreen activities.
 
+    /** List of all activities in the task arranged in history order */
     final ArrayList<ActivityRecord> mActivities = new ArrayList<ActivityRecord>();
 
-    TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
+    /** Current stack */
+    ActivityStack stack;
+
+    TaskRecord(int _taskId, ActivityInfo info, Intent _intent, ActivityStack _stack) {
         taskId = _taskId;
         affinity = info.taskAffinity;
         setIntent(_intent, info);
+        stack = _stack;
     }
 
     void touchActiveTime() {