Move BroadcastQueue out of the ActivityManager class.

Change-Id: Ib468481588a1aa506ff00f3c4b1a6ecf672c7b99
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4e1e9d9..ad8fea9 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -291,813 +291,12 @@
     final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
             = new ArrayList<PendingActivityLaunch>();
     
-    /**
-     * BROADCASTS
-     *
-     * We keep two broadcast queues and associated bookkeeping, one for those at
-     * foreground priority, and one for normal (background-priority) broadcasts.
-     */
-    public class BroadcastQueue {
-        static final String TAG = "BroadcastQueue";
 
-        static final int MAX_BROADCAST_HISTORY = 25;
-
-        /**
-         * Recognizable moniker for this queue
-         */
-        String mQueueName;
-
-        /**
-         * Timeout period for this queue's broadcasts
-         */
-        long mTimeoutPeriod;
-
-        /**
-         * Lists of all active broadcasts that are to be executed immediately
-         * (without waiting for another broadcast to finish).  Currently this only
-         * contains broadcasts to registered receivers, to avoid spinning up
-         * a bunch of processes to execute IntentReceiver components.  Background-
-         * and foreground-priority broadcasts are queued separately.
-         */
-        final ArrayList<BroadcastRecord> mParallelBroadcasts
-                = new ArrayList<BroadcastRecord>();
-        /**
-         * List of all active broadcasts that are to be executed one at a time.
-         * The object at the top of the list is the currently activity broadcasts;
-         * those after it are waiting for the top to finish.  As with parallel
-         * broadcasts, separate background- and foreground-priority queues are
-         * maintained.
-         */
-        final ArrayList<BroadcastRecord> mOrderedBroadcasts
-                = new ArrayList<BroadcastRecord>();
-
-        /**
-         * Historical data of past broadcasts, for debugging.
-         */
-        final BroadcastRecord[] mBroadcastHistory
-                = new BroadcastRecord[MAX_BROADCAST_HISTORY];
-
-        /**
-         * Set when we current have a BROADCAST_INTENT_MSG in flight.
-         */
-        boolean mBroadcastsScheduled = false;
-
-        /**
-         * True if we have a pending unexpired BROADCAST_TIMEOUT_MSG posted to our handler.
-         */
-        boolean mPendingBroadcastTimeoutMessage;
-
-        /**
-         * Intent broadcasts that we have tried to start, but are
-         * waiting for the application's process to be created.  We only
-         * need one per scheduling class (instead of a list) because we always
-         * process broadcasts one at a time, so no others can be started while
-         * waiting for this one.
-         */
-        BroadcastRecord mPendingBroadcast = null;
-
-        /**
-         * The receiver index that is pending, to restart the broadcast if needed.
-         */
-        int mPendingBroadcastRecvIndex;
-
-        BroadcastQueue(String name, long timeoutPeriod) {
-            mQueueName = name;
-            mTimeoutPeriod = timeoutPeriod;
-        }
-
-        public boolean isPendingBroadcastProcessLocked(int pid) {
-            return mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid;
-        }
-
-        public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
-            mParallelBroadcasts.add(r);
-        }
-
-        public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
-            mOrderedBroadcasts.add(r);
-        }
-
-        public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
-            for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
-                if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
-                    if (DEBUG_BROADCAST) Slog.v(TAG,
-                            "***** DROPPING PARALLEL ["
-                    + mQueueName + "]: " + r.intent);
-                    mParallelBroadcasts.set(i, r);
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) {
-            for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
-                if (r.intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
-                    if (DEBUG_BROADCAST) Slog.v(TAG,
-                            "***** DROPPING ORDERED ["
-                            + mQueueName + "]: " + r.intent);
-                    mOrderedBroadcasts.set(i, r);
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
-            boolean didSomething = false;
-            final BroadcastRecord br = mPendingBroadcast;
-            if (br != null && br.curApp.pid == app.pid) {
-                try {
-                    mPendingBroadcast = null;
-                    processCurBroadcastLocked(br, app);
-                    didSomething = true;
-                } catch (Exception e) {
-                    Slog.w(TAG, "Exception in new application when starting receiver "
-                            + br.curComponent.flattenToShortString(), e);
-                    logBroadcastReceiverDiscardLocked(br);
-                    finishReceiverLocked(br, br.resultCode, br.resultData,
-                            br.resultExtras, br.resultAbort, true);
-                    scheduleBroadcastsLocked();
-                    // We need to reset the state if we fails to start the receiver.
-                    br.state = BroadcastRecord.IDLE;
-                    throw new RuntimeException(e.getMessage());
-                }
-            }
-            return didSomething;
-        }
-
-        public void skipPendingBroadcastLocked(int pid) {
-            final BroadcastRecord br = mPendingBroadcast;
-            if (br != null && br.curApp.pid == pid) {
-                br.state = BroadcastRecord.IDLE;
-                br.nextReceiver = mPendingBroadcastRecvIndex;
-                mPendingBroadcast = null;
-                scheduleBroadcastsLocked();
-            }
-        }
-
-        public void skipCurrentReceiverLocked(ProcessRecord app) {
-            boolean reschedule = false;
-            BroadcastRecord r = app.curReceiver;
-            if (r != null) {
-                // The current broadcast is waiting for this app's receiver
-                // to be finished.  Looks like that's not going to happen, so
-                // let the broadcast continue.
-                logBroadcastReceiverDiscardLocked(r);
-                finishReceiverLocked(r, r.resultCode, r.resultData,
-                        r.resultExtras, r.resultAbort, true);
-                reschedule = true;
-            }
-
-            r = mPendingBroadcast;
-            if (r != null && r.curApp == app) {
-                if (DEBUG_BROADCAST) Slog.v(TAG,
-                        "[" + mQueueName + "] skip & discard pending app " + r);
-                logBroadcastReceiverDiscardLocked(r);
-                finishReceiverLocked(r, r.resultCode, r.resultData,
-                        r.resultExtras, r.resultAbort, true);
-                reschedule = true;
-            }
-            if (reschedule) {
-                scheduleBroadcastsLocked();
-            }
-        }
-
-        public void scheduleBroadcastsLocked() {
-            if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
-                    + mQueueName + "]: current="
-                    + mBroadcastsScheduled);
-
-            if (mBroadcastsScheduled) {
-                return;
-            }
-            mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
-            mBroadcastsScheduled = true;
-        }
-
-        public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
-            if (mOrderedBroadcasts.size() > 0) {
-                final BroadcastRecord r = mOrderedBroadcasts.get(0);
-                if (r != null && r.receiver == receiver) {
-                    return r;
-                }
-            }
-            return null;
-        }
-
-        public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
-                String resultData, Bundle resultExtras, boolean resultAbort,
-                boolean explicit) {
-            int state = r.state;
-            r.state = BroadcastRecord.IDLE;
-            if (state == BroadcastRecord.IDLE) {
-                if (explicit) {
-                    Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
-                }
-            }
-            r.receiver = null;
-            r.intent.setComponent(null);
-            if (r.curApp != null) {
-                r.curApp.curReceiver = null;
-            }
-            if (r.curFilter != null) {
-                r.curFilter.receiverList.curBroadcast = null;
-            }
-            r.curFilter = null;
-            r.curApp = null;
-            r.curComponent = null;
-            r.curReceiver = null;
-            mPendingBroadcast = null;
-
-            r.resultCode = resultCode;
-            r.resultData = resultData;
-            r.resultExtras = resultExtras;
-            r.resultAbort = resultAbort;
-
-            // We will process the next receiver right now if this is finishing
-            // an app receiver (which is always asynchronous) or after we have
-            // come back from calling a receiver.
-            return state == BroadcastRecord.APP_RECEIVE
-                    || state == BroadcastRecord.CALL_DONE_RECEIVE;
-        }
-
-        private final void processNextBroadcast(boolean fromMsg) {
-            synchronized(ActivityManagerService.this) {
-                BroadcastRecord r;
-
-                if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast ["
-                        + mQueueName + "]: "
-                        + mParallelBroadcasts.size() + " broadcasts, "
-                        + mOrderedBroadcasts.size() + " ordered broadcasts");
-
-                updateCpuStats();
-
-                if (fromMsg) {
-                    mBroadcastsScheduled = false;
-                }
-
-                // First, deliver any non-serialized broadcasts right away.
-                while (mParallelBroadcasts.size() > 0) {
-                    r = mParallelBroadcasts.remove(0);
-                    r.dispatchTime = SystemClock.uptimeMillis();
-                    r.dispatchClockTime = System.currentTimeMillis();
-                    final int N = r.receivers.size();
-                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
-                            + mQueueName + "] " + r);
-                    for (int i=0; i<N; i++) {
-                        Object target = r.receivers.get(i);
-                        if (DEBUG_BROADCAST)  Slog.v(TAG,
-                                "Delivering non-ordered on [" + mQueueName + "] to registered "
-                                + target + ": " + r);
-                        deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
-                    }
-                    addBroadcastToHistoryLocked(r);
-                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
-                            + mQueueName + "] " + r);
-                }
-
-                // Now take care of the next serialized one...
-
-                // If we are waiting for a process to come up to handle the next
-                // broadcast, then do nothing at this point.  Just in case, we
-                // check that the process we're waiting for still exists.
-                if (mPendingBroadcast != null) {
-                    if (DEBUG_BROADCAST_LIGHT) {
-                        Slog.v(TAG, "processNextBroadcast ["
-                                + mQueueName + "]: waiting for "
-                                + mPendingBroadcast.curApp);
-                    }
-
-                    boolean isDead;
-                    synchronized (mPidsSelfLocked) {
-                        isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
-                    }
-                    if (!isDead) {
-                        // It's still alive, so keep waiting
-                        return;
-                    } else {
-                        Slog.w(TAG, "pending app  ["
-                                + mQueueName + "]" + mPendingBroadcast.curApp
-                                + " died before responding to broadcast");
-                        mPendingBroadcast.state = BroadcastRecord.IDLE;
-                        mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
-                        mPendingBroadcast = null;
-                    }
-                }
-
-                boolean looped = false;
-                
-                do {
-                    if (mOrderedBroadcasts.size() == 0) {
-                        // No more broadcasts pending, so all done!
-                        scheduleAppGcsLocked();
-                        if (looped) {
-                            // If we had finished the last ordered broadcast, then
-                            // make sure all processes have correct oom and sched
-                            // adjustments.
-                            updateOomAdjLocked();
-                        }
-                        return;
-                    }
-                    r = mOrderedBroadcasts.get(0);
-                    boolean forceReceive = false;
-
-                    // Ensure that even if something goes awry with the timeout
-                    // detection, we catch "hung" broadcasts here, discard them,
-                    // and continue to make progress.
-                    //
-                    // This is only done if the system is ready so that PRE_BOOT_COMPLETED
-                    // receivers don't get executed with timeouts. They're intended for
-                    // one time heavy lifting after system upgrades and can take
-                    // significant amounts of time.
-                    int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
-                    if (mProcessesReady && r.dispatchTime > 0) {
-                        long now = SystemClock.uptimeMillis();
-                        if ((numReceivers > 0) &&
-                                (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
-                            Slog.w(TAG, "Hung broadcast ["
-                                    + mQueueName + "] discarded after timeout failure:"
-                                    + " now=" + now
-                                    + " dispatchTime=" + r.dispatchTime
-                                    + " startTime=" + r.receiverTime
-                                    + " intent=" + r.intent
-                                    + " numReceivers=" + numReceivers
-                                    + " nextReceiver=" + r.nextReceiver
-                                    + " state=" + r.state);
-                            broadcastTimeoutLocked(false); // forcibly finish this broadcast
-                            forceReceive = true;
-                            r.state = BroadcastRecord.IDLE;
-                        }
-                    }
-
-                    if (r.state != BroadcastRecord.IDLE) {
-                        if (DEBUG_BROADCAST) Slog.d(TAG,
-                                "processNextBroadcast("
-                                + mQueueName + ") called when not idle (state="
-                                + r.state + ")");
-                        return;
-                    }
-
-                    if (r.receivers == null || r.nextReceiver >= numReceivers
-                            || r.resultAbort || forceReceive) {
-                        // No more receivers for this broadcast!  Send the final
-                        // result if requested...
-                        if (r.resultTo != null) {
-                            try {
-                                if (DEBUG_BROADCAST) {
-                                    int seq = r.intent.getIntExtra("seq", -1);
-                                    Slog.i(TAG, "Finishing broadcast ["
-                                            + mQueueName + "] " + r.intent.getAction()
-                                            + " seq=" + seq + " app=" + r.callerApp);
-                                }
-                                performReceiveLocked(r.callerApp, r.resultTo,
-                                    new Intent(r.intent), r.resultCode,
-                                    r.resultData, r.resultExtras, false, false);
-                                // Set this to null so that the reference
-                                // (local and remote) isnt kept in the mBroadcastHistory.
-                                r.resultTo = null;
-                            } catch (RemoteException e) {
-                                Slog.w(TAG, "Failure ["
-                                        + mQueueName + "] sending broadcast result of "
-                                        + r.intent, e);
-                            }
-                        }
-
-                        if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
-                        cancelBroadcastTimeoutLocked();
-
-                        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
-                                + r);
-
-                        // ... and on to the next...
-                        addBroadcastToHistoryLocked(r);
-                        mOrderedBroadcasts.remove(0);
-                        r = null;
-                        looped = true;
-                        continue;
-                    }
-                } while (r == null);
-
-                // Get the next receiver...
-                int recIdx = r.nextReceiver++;
-
-                // Keep track of when this receiver started, and make sure there
-                // is a timeout message pending to kill it if need be.
-                r.receiverTime = SystemClock.uptimeMillis();
-                if (recIdx == 0) {
-                    r.dispatchTime = r.receiverTime;
-                    r.dispatchClockTime = System.currentTimeMillis();
-                    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast ["
-                            + mQueueName + "] " + r);
-                }
-                if (! mPendingBroadcastTimeoutMessage) {
-                    long timeoutTime = r.receiverTime + mTimeoutPeriod;
-                    if (DEBUG_BROADCAST) Slog.v(TAG,
-                            "Submitting BROADCAST_TIMEOUT_MSG ["
-                            + mQueueName + "] for " + r + " at " + timeoutTime);
-                    setBroadcastTimeoutLocked(timeoutTime);
-                }
-
-                Object nextReceiver = r.receivers.get(recIdx);
-                if (nextReceiver instanceof BroadcastFilter) {
-                    // Simple case: this is a registered receiver who gets
-                    // a direct call.
-                    BroadcastFilter filter = (BroadcastFilter)nextReceiver;
-                    if (DEBUG_BROADCAST)  Slog.v(TAG,
-                            "Delivering ordered ["
-                            + mQueueName + "] to registered "
-                            + filter + ": " + r);
-                    deliverToRegisteredReceiverLocked(r, filter, r.ordered);
-                    if (r.receiver == null || !r.ordered) {
-                        // The receiver has already finished, so schedule to
-                        // process the next one.
-                        if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing ["
-                                + mQueueName + "]: ordered="
-                                + r.ordered + " receiver=" + r.receiver);
-                        r.state = BroadcastRecord.IDLE;
-                        scheduleBroadcastsLocked();
-                    }
-                    return;
-                }
-
-                // Hard case: need to instantiate the receiver, possibly
-                // starting its application process to host it.
-
-                ResolveInfo info =
-                    (ResolveInfo)nextReceiver;
-
-                boolean skip = false;
-                int perm = checkComponentPermission(info.activityInfo.permission,
-                        r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
-                        info.activityInfo.exported);
-                if (perm != PackageManager.PERMISSION_GRANTED) {
-                    if (!info.activityInfo.exported) {
-                        Slog.w(TAG, "Permission Denial: broadcasting "
-                                + r.intent.toString()
-                                + " from " + r.callerPackage + " (pid=" + r.callingPid
-                                + ", uid=" + r.callingUid + ")"
-                                + " is not exported from uid " + info.activityInfo.applicationInfo.uid
-                                + " due to receiver " + info.activityInfo.packageName
-                                + "/" + info.activityInfo.name);
-                    } else {
-                        Slog.w(TAG, "Permission Denial: broadcasting "
-                                + r.intent.toString()
-                                + " from " + r.callerPackage + " (pid=" + r.callingPid
-                                + ", uid=" + r.callingUid + ")"
-                                + " requires " + info.activityInfo.permission
-                                + " due to receiver " + info.activityInfo.packageName
-                                + "/" + info.activityInfo.name);
-                    }
-                    skip = true;
-                }
-                if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
-                    r.requiredPermission != null) {
-                    try {
-                        perm = AppGlobals.getPackageManager().
-                                checkPermission(r.requiredPermission,
-                                        info.activityInfo.applicationInfo.packageName);
-                    } catch (RemoteException e) {
-                        perm = PackageManager.PERMISSION_DENIED;
-                    }
-                    if (perm != PackageManager.PERMISSION_GRANTED) {
-                        Slog.w(TAG, "Permission Denial: receiving "
-                                + r.intent + " to "
-                                + info.activityInfo.applicationInfo.packageName
-                                + " requires " + r.requiredPermission
-                                + " due to sender " + r.callerPackage
-                                + " (uid " + r.callingUid + ")");
-                        skip = true;
-                    }
-                }
-                if (r.curApp != null && r.curApp.crashing) {
-                    // If the target process is crashing, just skip it.
-                    if (DEBUG_BROADCAST)  Slog.v(TAG,
-                            "Skipping deliver ordered ["
-                            + mQueueName + "] " + r + " to " + r.curApp
-                            + ": process crashing");
-                    skip = true;
-                }
-
-                if (skip) {
-                    if (DEBUG_BROADCAST)  Slog.v(TAG,
-                            "Skipping delivery of ordered ["
-                            + mQueueName + "] " + r + " for whatever reason");
-                    r.receiver = null;
-                    r.curFilter = null;
-                    r.state = BroadcastRecord.IDLE;
-                    scheduleBroadcastsLocked();
-                    return;
-                }
-
-                r.state = BroadcastRecord.APP_RECEIVE;
-                String targetProcess = info.activityInfo.processName;
-                r.curComponent = new ComponentName(
-                        info.activityInfo.applicationInfo.packageName,
-                        info.activityInfo.name);
-                if (r.callingUid != Process.SYSTEM_UID) {
-                    info.activityInfo = getActivityInfoForUser(info.activityInfo, UserId
-                            .getUserId(r.callingUid));
-                }
-                r.curReceiver = info.activityInfo;
-                if (DEBUG_MU && r.callingUid > UserId.PER_USER_RANGE) {
-                    Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
-                            + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
-                            + info.activityInfo.applicationInfo.uid);
-                }
-
-                // Broadcast is being executed, its package can't be stopped.
-                try {
-                    AppGlobals.getPackageManager().setPackageStoppedState(
-                            r.curComponent.getPackageName(), false);
-                } catch (RemoteException e) {
-                } catch (IllegalArgumentException e) {
-                    Slog.w(TAG, "Failed trying to unstop package "
-                            + r.curComponent.getPackageName() + ": " + e);
-                }
-
-                // Is this receiver's application already running?
-                ProcessRecord app = getProcessRecordLocked(targetProcess,
-                        info.activityInfo.applicationInfo.uid);
-                if (app != null && app.thread != null) {
-                    try {
-                        app.addPackage(info.activityInfo.packageName);
-                        processCurBroadcastLocked(r, app);
-                        return;
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "Exception when sending broadcast to "
-                              + r.curComponent, e);
-                    }
-
-                    // If a dead object exception was thrown -- fall through to
-                    // restart the application.
-                }
-
-                // Not running -- get it started, to be executed when the app comes up.
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
-                        "Need to start app ["
-                        + mQueueName + "] " + targetProcess + " for broadcast " + r);
-                if ((r.curApp=startProcessLocked(targetProcess,
-                        info.activityInfo.applicationInfo, true,
-                        r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
-                        "broadcast", r.curComponent,
-                        (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false))
-                                == null) {
-                    // Ah, this recipient is unavailable.  Finish it if necessary,
-                    // and mark the broadcast record as ready for the next.
-                    Slog.w(TAG, "Unable to launch app "
-                            + info.activityInfo.applicationInfo.packageName + "/"
-                            + info.activityInfo.applicationInfo.uid + " for broadcast "
-                            + r.intent + ": process is bad");
-                    logBroadcastReceiverDiscardLocked(r);
-                    finishReceiverLocked(r, r.resultCode, r.resultData,
-                            r.resultExtras, r.resultAbort, true);
-                    scheduleBroadcastsLocked();
-                    r.state = BroadcastRecord.IDLE;
-                    return;
-                }
-
-                mPendingBroadcast = r;
-                mPendingBroadcastRecvIndex = recIdx;
-            }
-        }
-
-        final void setBroadcastTimeoutLocked(long timeoutTime) {
-            if (! mPendingBroadcastTimeoutMessage) {
-                Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
-                mHandler.sendMessageAtTime(msg, timeoutTime);
-                mPendingBroadcastTimeoutMessage = true;
-            }
-        }
-
-        final void cancelBroadcastTimeoutLocked() {
-            if (mPendingBroadcastTimeoutMessage) {
-                mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
-                mPendingBroadcastTimeoutMessage = false;
-            }
-        }
-
-        final void broadcastTimeoutLocked(boolean fromMsg) {
-            if (fromMsg) {
-                mPendingBroadcastTimeoutMessage = false;
-            }
-
-            if (mOrderedBroadcasts.size() == 0) {
-                return;
-            }
-
-            long now = SystemClock.uptimeMillis();
-            BroadcastRecord r = mOrderedBroadcasts.get(0);
-            if (fromMsg) {
-                if (mDidDexOpt) {
-                    // Delay timeouts until dexopt finishes.
-                    mDidDexOpt = false;
-                    long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
-                    setBroadcastTimeoutLocked(timeoutTime);
-                    return;
-                }
-                if (! mProcessesReady) {
-                    // Only process broadcast timeouts if the system is ready. That way
-                    // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
-                    // to do heavy lifting for system up.
-                    return;
-                }
-
-                long timeoutTime = r.receiverTime + mTimeoutPeriod;
-                if (timeoutTime > now) {
-                    // We can observe premature timeouts because we do not cancel and reset the
-                    // broadcast timeout message after each receiver finishes.  Instead, we set up
-                    // an initial timeout then kick it down the road a little further as needed
-                    // when it expires.
-                    if (DEBUG_BROADCAST) Slog.v(TAG,
-                            "Premature timeout ["
-                            + mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
-                            + timeoutTime);
-                    setBroadcastTimeoutLocked(timeoutTime);
-                    return;
-                }
-            }
-
-            Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
-                    + ", started " + (now - r.receiverTime) + "ms ago");
-            r.receiverTime = now;
-            r.anrCount++;
-
-            // Current receiver has passed its expiration date.
-            if (r.nextReceiver <= 0) {
-                Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
-                return;
-            }
-
-            ProcessRecord app = null;
-            String anrMessage = null;
-
-            Object curReceiver = r.receivers.get(r.nextReceiver-1);
-            Slog.w(TAG, "Receiver during timeout: " + curReceiver);
-            logBroadcastReceiverDiscardLocked(r);
-            if (curReceiver instanceof BroadcastFilter) {
-                BroadcastFilter bf = (BroadcastFilter)curReceiver;
-                if (bf.receiverList.pid != 0
-                        && bf.receiverList.pid != MY_PID) {
-                    synchronized (ActivityManagerService.this.mPidsSelfLocked) {
-                        app = ActivityManagerService.this.mPidsSelfLocked.get(
-                                bf.receiverList.pid);
-                    }
-                }
-            } else {
-                app = r.curApp;
-            }
-
-            if (app != null) {
-                anrMessage = "Broadcast of " + r.intent.toString();
-            }
-
-            if (mPendingBroadcast == r) {
-                mPendingBroadcast = null;
-            }
-
-            // Move on to the next receiver.
-            finishReceiverLocked(r, r.resultCode, r.resultData,
-                    r.resultExtras, r.resultAbort, true);
-            scheduleBroadcastsLocked();
-
-            if (anrMessage != null) {
-                // Post the ANR to the handler since we do not want to process ANRs while
-                // potentially holding our lock.
-                mHandler.post(new AppNotResponding(app, anrMessage));
-            }
-        }
-
-        private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
-            if (r.callingUid < 0) {
-                // This was from a registerReceiver() call; ignore it.
-                return;
-            }
-            System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
-                    MAX_BROADCAST_HISTORY-1);
-            r.finishTime = SystemClock.uptimeMillis();
-            mBroadcastHistory[0] = r;
-        }
-
-        final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
-            if (r.nextReceiver > 0) {
-                Object curReceiver = r.receivers.get(r.nextReceiver-1);
-                if (curReceiver instanceof BroadcastFilter) {
-                    BroadcastFilter bf = (BroadcastFilter) curReceiver;
-                    EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
-                            System.identityHashCode(r),
-                            r.intent.getAction(),
-                            r.nextReceiver - 1,
-                            System.identityHashCode(bf));
-                } else {
-                    EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
-                            System.identityHashCode(r),
-                            r.intent.getAction(),
-                            r.nextReceiver - 1,
-                            ((ResolveInfo)curReceiver).toString());
-                }
-            } else {
-                Slog.w(TAG, "Discarding broadcast before first receiver is invoked: "
-                        + r);
-                EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
-                        System.identityHashCode(r),
-                        r.intent.getAction(),
-                        r.nextReceiver,
-                        "NONE");
-            }
-        }
-
-        final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
-                int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
-            if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
-                    || mPendingBroadcast != null) {
-                boolean printed = false;
-                for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
-                    BroadcastRecord br = mParallelBroadcasts.get(i);
-                    if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
-                        continue;
-                    }
-                    if (!printed) {
-                        if (needSep) {
-                            pw.println();
-                            needSep = false;
-                        }
-                        printed = true;
-                        pw.println("  Active broadcasts [" + mQueueName + "]:");
-                    }
-                    pw.println("  Broadcast #" + i + ":");
-                    br.dump(pw, "    ");
-                }
-                printed = false;
-                needSep = true;
-                for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
-                    BroadcastRecord br = mOrderedBroadcasts.get(i);
-                    if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
-                        continue;
-                    }
-                    if (!printed) {
-                        if (needSep) {
-                            pw.println();
-                        }
-                        needSep = true;
-                        pw.println("  Active ordered broadcasts [" + mQueueName + "]:");
-                    }
-                    pw.println("  Ordered Broadcast #" + i + ":");
-                    mOrderedBroadcasts.get(i).dump(pw, "    ");
-                }
-                if (dumpPackage == null || (mPendingBroadcast != null
-                        && dumpPackage.equals(mPendingBroadcast.callerPackage))) {
-                    if (needSep) {
-                        pw.println();
-                    }
-                    pw.println("  Pending broadcast [" + mQueueName + "]:");
-                    if (mPendingBroadcast != null) {
-                        mPendingBroadcast.dump(pw, "    ");
-                    } else {
-                        pw.println("    (null)");
-                    }
-                    needSep = true;
-                }
-            }
-
-            boolean printed = false;
-            for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
-                BroadcastRecord r = mBroadcastHistory[i];
-                if (r == null) {
-                    break;
-                }
-                if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
-                    continue;
-                }
-                if (!printed) {
-                    if (needSep) {
-                        pw.println();
-                    }
-                    needSep = true;
-                    pw.println("  Historical broadcasts [" + mQueueName + "]:");
-                    printed = true;
-                }
-                if (dumpAll) {
-                    pw.print("  Historical Broadcast #"); pw.print(i); pw.println(":");
-                    r.dump(pw, "    ");
-                } else {
-                    if (i >= 50) {
-                        pw.println("  ...");
-                        break;
-                    }
-                    pw.print("  #"); pw.print(i); pw.print(": "); pw.println(r);
-                }
-            }
-
-            return needSep;
-        }
-    }
-
-    final BroadcastQueue mFgBroadcastQueue = new BroadcastQueue("foreground", BROADCAST_FG_TIMEOUT);
-    final BroadcastQueue mBgBroadcastQueue = new BroadcastQueue("background", BROADCAST_BG_TIMEOUT);
+    BroadcastQueue mFgBroadcastQueue;
+    BroadcastQueue mBgBroadcastQueue;
     // Convenient for easy iteration over the queues. Foreground is first
     // so that dispatch of foreground broadcasts gets precedence.
-    final BroadcastQueue[] mBroadcastQueues = { mFgBroadcastQueue, mBgBroadcastQueue };
+    final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];
 
     BroadcastQueue broadcastQueueForIntent(Intent intent) {
         final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
@@ -1642,8 +841,6 @@
     static final int UPDATE_CONFIGURATION_MSG = 4;
     static final int GC_BACKGROUND_PROCESSES_MSG = 5;
     static final int WAIT_FOR_DEBUGGER_MSG = 6;
-    static final int BROADCAST_INTENT_MSG = 7;
-    static final int BROADCAST_TIMEOUT_MSG = 8;
     static final int SERVICE_TIMEOUT_MSG = 12;
     static final int UPDATE_TIME_ZONE = 13;
     static final int SHOW_UID_ERROR_MSG = 14;
@@ -1663,6 +860,10 @@
     static final int DISPATCH_PROCESS_DIED = 32;
     static final int REPORT_MEM_USAGE = 33;
 
+    static final int FIRST_ACTIVITY_STACK_MSG = 100;
+    static final int FIRST_BROADCAST_QUEUE_MSG = 200;
+    static final int FIRST_COMPAT_MODE_MSG = 300;
+
     AlertDialog mUidAlert;
     CompatModeDialog mCompatModeDialog;
     long mLastMemUsageReportTime = 0;
@@ -1782,18 +983,6 @@
                     }
                 }
             } break;
-            case BROADCAST_INTENT_MSG: {
-                if (DEBUG_BROADCAST) Slog.v(
-                        TAG, "Received BROADCAST_INTENT_MSG");
-                BroadcastQueue queue = (BroadcastQueue) msg.obj;
-                queue.processNextBroadcast(true);
-            } break;
-            case BROADCAST_TIMEOUT_MSG: {
-                final BroadcastQueue queue = (BroadcastQueue) msg.obj;
-                synchronized (ActivityManagerService.this) {
-                    queue.broadcastTimeoutLocked(true);
-                }
-            } break;
             case SERVICE_TIMEOUT_MSG: {
                 if (mDidDexOpt) {
                     mDidDexOpt = false;
@@ -2307,6 +1496,11 @@
     private ActivityManagerService() {
         Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
         
+        mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT);
+        mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT);
+        mBroadcastQueues[0] = mFgBroadcastQueue;
+        mBroadcastQueues[1] = mBgBroadcastQueue;
+
         File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
         systemDir.mkdirs();
@@ -3852,21 +3046,6 @@
         }
     }
 
-    private final class AppNotResponding implements Runnable {
-        private final ProcessRecord mApp;
-        private final String mAnnotation;
-
-        public AppNotResponding(ProcessRecord app, String annotation) {
-            mApp = app;
-            mAnnotation = annotation;
-        }
-
-        @Override
-        public void run() {
-            appNotResponding(mApp, null, null, mAnnotation);
-        }
-    }
-
     final void appNotResponding(ProcessRecord app, ActivityRecord activity,
             ActivityRecord parent, final String annotation) {
         ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
@@ -13493,138 +12672,7 @@
             Binder.restoreCallingIdentity(origId);
         }
     }
-
-    private final void processCurBroadcastLocked(BroadcastRecord r,
-            ProcessRecord app) throws RemoteException {
-        if (DEBUG_BROADCAST)  Slog.v(TAG,
-                "Process cur broadcast " + r + " for app " + app);
-        if (app.thread == null) {
-            throw new RemoteException();
-        }
-        r.receiver = app.thread.asBinder();
-        r.curApp = app;
-        app.curReceiver = r;
-        updateLruProcessLocked(app, true, true);
-
-        // Tell the application to launch this receiver.
-        r.intent.setComponent(r.curComponent);
-
-        boolean started = false;
-        try {
-            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG,
-                    "Delivering to component " + r.curComponent
-                    + ": " + r);
-            ensurePackageDexOpt(r.intent.getComponent().getPackageName());
-            app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
-                    compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
-                    r.resultCode, r.resultData, r.resultExtras, r.ordered);
-            if (DEBUG_BROADCAST)  Slog.v(TAG,
-                    "Process cur broadcast " + r + " DELIVERED for app " + app);
-            started = true;
-        } finally {
-            if (!started) {
-                if (DEBUG_BROADCAST)  Slog.v(TAG,
-                        "Process cur broadcast " + r + ": NOT STARTED!");
-                r.receiver = null;
-                r.curApp = null;
-                app.curReceiver = null;
-            }
-        }
-
-    }
-
-    static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
-            Intent intent, int resultCode, String data, Bundle extras,
-            boolean ordered, boolean sticky) throws RemoteException {
-        // Send the intent to the receiver asynchronously using one-way binder calls.
-        if (app != null && app.thread != null) {
-            // If we have an app thread, do the call through that so it is
-            // correctly ordered with other one-way calls.
-            app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
-                    data, extras, ordered, sticky);
-        } else {
-            receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
-        }
-    }
     
-    private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
-            BroadcastFilter filter, boolean ordered) {
-        boolean skip = false;
-        if (filter.requiredPermission != null) {
-            int perm = checkComponentPermission(filter.requiredPermission,
-                    r.callingPid, r.callingUid, -1, true);
-            if (perm != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission Denial: broadcasting "
-                        + r.intent.toString()
-                        + " from " + r.callerPackage + " (pid="
-                        + r.callingPid + ", uid=" + r.callingUid + ")"
-                        + " requires " + filter.requiredPermission
-                        + " due to registered receiver " + filter);
-                skip = true;
-            }
-        }
-        if (r.requiredPermission != null) {
-            int perm = checkComponentPermission(r.requiredPermission,
-                    filter.receiverList.pid, filter.receiverList.uid, -1, true);
-            if (perm != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission Denial: receiving "
-                        + r.intent.toString()
-                        + " to " + filter.receiverList.app
-                        + " (pid=" + filter.receiverList.pid
-                        + ", uid=" + filter.receiverList.uid + ")"
-                        + " requires " + r.requiredPermission
-                        + " due to sender " + r.callerPackage
-                        + " (uid " + r.callingUid + ")");
-                skip = true;
-            }
-        }
-
-        if (!skip) {
-            // If this is not being sent as an ordered broadcast, then we
-            // don't want to touch the fields that keep track of the current
-            // state of ordered broadcasts.
-            if (ordered) {
-                r.receiver = filter.receiverList.receiver.asBinder();
-                r.curFilter = filter;
-                filter.receiverList.curBroadcast = r;
-                r.state = BroadcastRecord.CALL_IN_RECEIVE;
-                if (filter.receiverList.app != null) {
-                    // Bump hosting application to no longer be in background
-                    // scheduling class.  Note that we can't do that if there
-                    // isn't an app...  but we can only be in that case for
-                    // things that directly call the IActivityManager API, which
-                    // are already core system stuff so don't matter for this.
-                    r.curApp = filter.receiverList.app;
-                    filter.receiverList.app.curReceiver = r;
-                    updateOomAdjLocked();
-                }
-            }
-            try {
-                if (DEBUG_BROADCAST_LIGHT) {
-                    int seq = r.intent.getIntExtra("seq", -1);
-                    Slog.i(TAG, "Delivering to " + filter
-                            + " (seq=" + seq + "): " + r);
-                }
-                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
-                    new Intent(r.intent), r.resultCode,
-                    r.resultData, r.resultExtras, r.ordered, r.initialSticky);
-                if (ordered) {
-                    r.state = BroadcastRecord.CALL_DONE_RECEIVE;
-                }
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
-                if (ordered) {
-                    r.receiver = null;
-                    r.curFilter = null;
-                    filter.receiverList.curBroadcast = null;
-                    if (filter.receiverList.app != null) {
-                        filter.receiverList.app.curReceiver = null;
-                    }
-                }
-            }
-        }
-    }
-
     // =========================================================
     // INSTRUMENTATION
     // =========================================================