/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.am; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import android.app.ActivityManager; import android.app.AppGlobals; import android.content.ComponentName; import android.content.IIntentReceiver; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.util.EventLog; import android.util.Slog; /** * 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 String TAG_MU = ActivityManagerService.TAG_MU; static final boolean DEBUG_BROADCAST = ActivityManagerService.DEBUG_BROADCAST; static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT; static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU; static final int MAX_BROADCAST_HISTORY = 25; static final int MAX_BROADCAST_SUMMARY_HISTORY = 100; final ActivityManagerService mService; /** * Recognizable moniker for this queue */ final String mQueueName; /** * Timeout period for this queue's broadcasts */ final 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 mParallelBroadcasts = new ArrayList(); /** * 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 mOrderedBroadcasts = new ArrayList(); /** * Historical data of past broadcasts, for debugging. */ final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY]; /** * Summary of historical data of past broadcasts, for debugging. */ final Intent[] mBroadcastSummaryHistory = new Intent[MAX_BROADCAST_SUMMARY_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; static final int BROADCAST_INTENT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG; static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1; final Handler mHandler = new Handler() { //public Handler() { // if (localLOGV) Slog.v(TAG, "Handler started!"); //} public void handleMessage(Message msg) { switch (msg.what) { case BROADCAST_INTENT_MSG: { if (DEBUG_BROADCAST) Slog.v( TAG, "Received BROADCAST_INTENT_MSG"); processNextBroadcast(true); } break; case BROADCAST_TIMEOUT_MSG: { synchronized (mService) { broadcastTimeoutLocked(true); } } break; } } }; 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() { mService.appNotResponding(mApp, null, null, false, mAnnotation); } } BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod) { mService = service; 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; } 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; mService.updateLruProcessLocked(app, 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); mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName()); app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver, mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo), r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId); 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; } } } 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 failed 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 static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) 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, sendingUser); } else { receiver.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); } } private final void deliverToRegisteredReceiverLocked(BroadcastRecord r, BroadcastFilter filter, boolean ordered) { boolean skip = false; if (filter.requiredPermission != null) { int perm = mService.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 (!skip && r.requiredPermission != null) { int perm = mService.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; mService.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, r.userId); 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; } } } } } final void processNextBroadcast(boolean fromMsg) { synchronized(mService) { BroadcastRecord r; if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast [" + mQueueName + "]: " + mParallelBroadcasts.size() + " broadcasts, " + mOrderedBroadcasts.size() + " ordered broadcasts"); mService.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 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, r.userId); // 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; ComponentName component = new ComponentName( info.activityInfo.applicationInfo.packageName, info.activityInfo.name); boolean skip = false; int perm = mService.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 " + component.flattenToShortString()); } 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 " + component.flattenToShortString()); } 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 " + component.flattenToShortString() + " requires " + r.requiredPermission + " due to sender " + r.callerPackage + " (uid " + r.callingUid + ")"); skip = true; } } boolean isSingleton = false; try { isSingleton = mService.isSingleton(info.activityInfo.processName, info.activityInfo.applicationInfo, info.activityInfo.name, info.activityInfo.flags); } catch (SecurityException e) { Slog.w(TAG, e.getMessage()); skip = true; } if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) { if (ActivityManager.checkUidPermission( android.Manifest.permission.INTERACT_ACROSS_USERS, info.activityInfo.applicationInfo.uid) != PackageManager.PERMISSION_GRANTED) { Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString() + " requests FLAG_SINGLE_USER, but app does not hold " + android.Manifest.permission.INTERACT_ACROSS_USERS); 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 = component; if (r.callingUid != Process.SYSTEM_UID && isSingleton) { info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0); } r.curReceiver = info.activityInfo; if (DEBUG_MU && r.callingUid > UserHandle.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, UserHandle.getUserId(r.callingUid)); } 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 = mService.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=mService.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 (mService.mDidDexOpt) { // Delay timeouts until dexopt finishes. mService.mDidDexOpt = false; long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod; setBroadcastTimeoutLocked(timeoutTime); return; } if (!mService.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 != ActivityManagerService.MY_PID) { synchronized (mService.mPidsSelfLocked) { app = mService.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; System.arraycopy(mBroadcastSummaryHistory, 0, mBroadcastSummaryHistory, 1, MAX_BROADCAST_SUMMARY_HISTORY-1); mBroadcastSummaryHistory[0] = r.intent; } 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, bf.owningUserId, System.identityHashCode(r), r.intent.getAction(), r.nextReceiver - 1, System.identityHashCode(bf)); } else { ResolveInfo ri = (ResolveInfo)curReceiver; EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP, UserHandle.getUserId(ri.activityInfo.applicationInfo.uid), System.identityHashCode(r), r.intent.getAction(), r.nextReceiver - 1, ri.toString()); } } else { Slog.w(TAG, "Discarding broadcast before first receiver is invoked: " + r); EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP, -1, 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 = true; printed = true; pw.println(" Active broadcasts [" + mQueueName + "]:"); } pw.println(" Active Broadcast " + mQueueName + " #" + 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; printed = true; pw.println(" Active ordered broadcasts [" + mQueueName + "]:"); } pw.println(" Active Ordered Broadcast " + mQueueName + " #" + 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; } } int i; boolean printed = false; for (i=0; i= 50) { pw.println(" ..."); break; } pw.print(" #"); pw.print(i); pw.print(": "); pw.println(intent.toShortString(false, true, true, false)); Bundle bundle = intent.getExtras(); if (bundle != null) { pw.print(" extras: "); pw.println(bundle.toString()); } } } return needSep; } }