Additional cleanup after stack deletion.

- Remove activity from PendingActivityLaunch list when it is removed
from stack. This prevents the delayed launch causing
IllegalArgumentException in b/16045752.
- Move PendingActivityLaunch from ActivityManagerService to
ActivityStackSupervisor.
- Immediately call onTaskListEmptyLocked() in cases where no
activities are found in stack.

Fixes bug 16045752.

Change-Id: Ia69a449e7f5e08ab6e36157d0fd793c4d2fdaca4
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b68089c..a6deed5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -340,28 +340,6 @@
     // devices.
     private boolean mShowDialogs = true;
 
-    /**
-     * Description of a request to start a new activity, which has been held
-     * due to app switches being disabled.
-     */
-    static class PendingActivityLaunch {
-        final ActivityRecord r;
-        final ActivityRecord sourceRecord;
-        final int startFlags;
-        final ActivityStack stack;
-
-        PendingActivityLaunch(ActivityRecord _r, ActivityRecord _sourceRecord,
-                int _startFlags, ActivityStack _stack) {
-            r = _r;
-            sourceRecord = _sourceRecord;
-            startFlags = _startFlags;
-            stack = _stack;
-        }
-    }
-
-    final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
-            = new ArrayList<PendingActivityLaunch>();
-
     BroadcastQueue mFgBroadcastQueue;
     BroadcastQueue mBgBroadcastQueue;
     // Convenient for easy iteration over the queues. Foreground is first
@@ -1323,7 +1301,7 @@
             } break;
             case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
                 synchronized (ActivityManagerService.this) {
-                    doPendingActivityLaunchesLocked(true);
+                    mStackSupervisor.doPendingActivityLaunchesLocked(true);
                 }
             } break;
             case KILL_APPLICATION_MSG: {
@@ -3034,19 +3012,6 @@
         mProcessObservers.finishBroadcast();
     }
 
-    final void doPendingActivityLaunchesLocked(boolean doResume) {
-        final int N = mPendingActivityLaunches.size();
-        if (N <= 0) {
-            return;
-        }
-        for (int i=0; i<N; i++) {
-            PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
-            mStackSupervisor.startActivityUncheckedLocked(pal.r, pal.sourceRecord, pal.startFlags,
-                    doResume && i == (N-1), null);
-        }
-        mPendingActivityLaunches.clear();
-    }
-
     @Override
     public final int startActivity(IApplicationThread caller, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo,
@@ -8280,6 +8245,7 @@
         }
     }
 
+    @Override
     public void stopAppSwitches() {
         if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
                 != PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 1038ac0..224946c 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2558,18 +2558,23 @@
         return r;
     }
 
-    void finishAllActivitiesLocked() {
+    void finishAllActivitiesLocked(boolean immediately) {
+        boolean noActivitiesInStack = true;
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
-                if (r.finishing) {
+                noActivitiesInStack = false;
+                if (r.finishing && !immediately) {
                     continue;
                 }
-                Slog.d(TAG, "finishAllActivitiesLocked: finishing " + r);
+                Slog.d(TAG, "finishAllActivitiesLocked: finishing " + r + " immediately");
                 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
             }
         }
+        if (noActivitiesInStack) {
+            mActivityContainer.onTaskListEmptyLocked();
+        }
     }
 
     final boolean navigateUpToLocked(IBinder token, Intent destIntent, int resultCode,
@@ -2683,6 +2688,7 @@
         // down to the max limit while they are still waiting to finish.
         mStackSupervisor.mFinishingActivities.remove(r);
         mStackSupervisor.mWaitingVisibleActivities.remove(r);
+        mStackSupervisor.removePendingActivityLaunchesLocked(r);
 
         // Remove any pending results.
         if (r.finishing && r.pendingResults != null) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index bca215d..cdccccc 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -88,7 +88,6 @@
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.os.TransferPipe;
 import com.android.server.LocalServices;
-import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
 import com.android.server.am.ActivityStack.ActivityState;
 import com.android.server.wm.WindowManagerService;
 
@@ -234,6 +233,28 @@
 
     InputManagerInternal mInputManagerInternal;
 
+    final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
+            = new ArrayList<PendingActivityLaunch>();
+
+    /**
+     * Description of a request to start a new activity, which has been held
+     * due to app switches being disabled.
+     */
+    static class PendingActivityLaunch {
+        final ActivityRecord r;
+        final ActivityRecord sourceRecord;
+        final int startFlags;
+        final ActivityStack stack;
+
+        PendingActivityLaunch(ActivityRecord _r, ActivityRecord _sourceRecord,
+                int _startFlags, ActivityStack _stack) {
+            r = _r;
+            sourceRecord = _sourceRecord;
+            startFlags = _startFlags;
+            stack = _stack;
+        }
+    }
+
     public ActivityStackSupervisor(ActivityManagerService service) {
         mService = service;
         PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE);
@@ -1304,7 +1325,7 @@
             if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
                 PendingActivityLaunch pal =
                         new PendingActivityLaunch(r, sourceRecord, startFlags, stack);
-                mService.mPendingActivityLaunches.add(pal);
+                mPendingActivityLaunches.add(pal);
                 setDismissKeyguard(false);
                 ActivityOptions.abort(options);
                 return ActivityManager.START_SWITCHES_CANCELED;
@@ -1322,7 +1343,7 @@
             mService.mDidAppSwitch = true;
         }
 
-        mService.doPendingActivityLaunchesLocked(false);
+        doPendingActivityLaunchesLocked(false);
 
         err = startActivityUncheckedLocked(r, sourceRecord, startFlags, true, options);
 
@@ -1830,6 +1851,23 @@
         return ActivityManager.START_SUCCESS;
     }
 
+    final void doPendingActivityLaunchesLocked(boolean doResume) {
+        while (!mPendingActivityLaunches.isEmpty()) {
+            PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
+            startActivityUncheckedLocked(pal.r, pal.sourceRecord, pal.startFlags,
+                    doResume && mPendingActivityLaunches.isEmpty(), null);
+        }
+    }
+
+    void removePendingActivityLaunchesLocked(ActivityRecord r) {
+        for (int palNdx = mPendingActivityLaunches.size() - 1; palNdx >= 0; --palNdx) {
+            PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx);
+            if (pal.r == r) {
+                mPendingActivityLaunches.remove(palNdx);
+            }
+        }
+    }
+
     void acquireLaunchWakelock() {
         if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
             throw new IllegalStateException("Calling must be system uid");
@@ -2960,7 +2998,9 @@
                     synchronized (mService) {
                         Slog.w(TAG, "Timeout waiting for all activities in task to finish. " +
                                 msg.obj);
-                        ((ActivityContainer) msg.obj).onTaskListEmptyLocked();
+                        final ActivityContainer container = (ActivityContainer) msg.obj;
+                        container.mStack.finishAllActivitiesLocked(true);
+                        container.onTaskListEmptyLocked();
                     }
                 } break;
             }
@@ -3054,11 +3094,11 @@
 
                 final Message msg =
                         mHandler.obtainMessage(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
-                mHandler.sendMessageDelayed(msg, 1000);
+                mHandler.sendMessageDelayed(msg, 2000);
 
                 long origId = Binder.clearCallingIdentity();
                 try {
-                    mStack.finishAllActivitiesLocked();
+                    mStack.finishAllActivitiesLocked(false);
                 } finally {
                     Binder.restoreCallingIdentity(origId);
                 }