am 4d94a766: Fixed some timeout and lock reentrance issues with broadcasts.
Merge commit '4d94a766c3f7cf32dd3f5d543048fa801ad22813' into gingerbread-plus-aosp * commit '4d94a766c3f7cf32dd3f5d543048fa801ad22813': Fixed some timeout and lock reentrance issues with broadcasts.
This commit is contained in:
@@ -565,6 +565,11 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
*/
|
||||
private final StringBuilder mStrictModeBuffer = new StringBuilder();
|
||||
|
||||
/**
|
||||
* True if we have a pending unexpired BROADCAST_TIMEOUT_MSG posted to our handler.
|
||||
*/
|
||||
private boolean mPendingBroadcastTimeoutMessage;
|
||||
|
||||
/**
|
||||
* Intent broadcast that we have tried to start, but are
|
||||
* waiting for its application's process to be created. We only
|
||||
@@ -1071,17 +1076,8 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
processNextBroadcast(true);
|
||||
} break;
|
||||
case BROADCAST_TIMEOUT_MSG: {
|
||||
if (mDidDexOpt) {
|
||||
mDidDexOpt = false;
|
||||
Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
|
||||
mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
// 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
|
||||
if (mProcessesReady) {
|
||||
broadcastTimeout();
|
||||
synchronized (ActivityManagerService.this) {
|
||||
broadcastTimeoutLocked(true);
|
||||
}
|
||||
} break;
|
||||
case SERVICE_TIMEOUT_MSG: {
|
||||
@@ -2806,6 +2802,21 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -3674,7 +3685,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
Slog.w(TAG, "Exception in new application when starting receiver "
|
||||
+ br.curComponent.flattenToShortString(), e);
|
||||
badApp = true;
|
||||
logBroadcastReceiverDiscard(br);
|
||||
logBroadcastReceiverDiscardLocked(br);
|
||||
finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
|
||||
br.resultExtras, br.resultAbort, true);
|
||||
scheduleBroadcastsLocked();
|
||||
@@ -6373,7 +6384,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
// 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.
|
||||
logBroadcastReceiverDiscard(r);
|
||||
logBroadcastReceiverDiscardLocked(r);
|
||||
finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
|
||||
r.resultExtras, r.resultAbort, true);
|
||||
reschedule = true;
|
||||
@@ -6382,7 +6393,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
if (r != null && r.curApp == app) {
|
||||
if (DEBUG_BROADCAST) Slog.v(TAG,
|
||||
"skip & discard pending app " + r);
|
||||
logBroadcastReceiverDiscard(r);
|
||||
logBroadcastReceiverDiscardLocked(r);
|
||||
finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
|
||||
r.resultExtras, r.resultAbort, true);
|
||||
reschedule = true;
|
||||
@@ -10518,7 +10529,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
Binder.restoreCallingIdentity(origId);
|
||||
}
|
||||
|
||||
private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
|
||||
private final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
|
||||
if (r.nextReceiver > 0) {
|
||||
Object curReceiver = r.receivers.get(r.nextReceiver-1);
|
||||
if (curReceiver instanceof BroadcastFilter) {
|
||||
@@ -10546,67 +10557,108 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
}
|
||||
|
||||
private final void broadcastTimeout() {
|
||||
private final void setBroadcastTimeoutLocked(long timeoutTime) {
|
||||
if (! mPendingBroadcastTimeoutMessage) {
|
||||
Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
|
||||
mHandler.sendMessageAtTime(msg, timeoutTime);
|
||||
mPendingBroadcastTimeoutMessage = true;
|
||||
}
|
||||
}
|
||||
|
||||
private final void cancelBroadcastTimeoutLocked() {
|
||||
if (mPendingBroadcastTimeoutMessage) {
|
||||
mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
|
||||
mPendingBroadcastTimeoutMessage = false;
|
||||
}
|
||||
}
|
||||
|
||||
private 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() + BROADCAST_TIMEOUT;
|
||||
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 + BROADCAST_TIMEOUT;
|
||||
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 @ " + 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;
|
||||
|
||||
synchronized (this) {
|
||||
if (mOrderedBroadcasts.size() == 0) {
|
||||
return;
|
||||
}
|
||||
long now = SystemClock.uptimeMillis();
|
||||
BroadcastRecord r = mOrderedBroadcasts.get(0);
|
||||
if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
|
||||
if (DEBUG_BROADCAST) Slog.v(TAG,
|
||||
"Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
|
||||
+ (r.receiverTime + BROADCAST_TIMEOUT));
|
||||
Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
|
||||
mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
|
||||
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;
|
||||
}
|
||||
|
||||
Object curReceiver = r.receivers.get(r.nextReceiver-1);
|
||||
Slog.w(TAG, "Receiver during timeout: " + curReceiver);
|
||||
logBroadcastReceiverDiscard(r);
|
||||
if (curReceiver instanceof BroadcastFilter) {
|
||||
BroadcastFilter bf = (BroadcastFilter)curReceiver;
|
||||
if (bf.receiverList.pid != 0
|
||||
&& bf.receiverList.pid != MY_PID) {
|
||||
synchronized (this.mPidsSelfLocked) {
|
||||
app = this.mPidsSelfLocked.get(
|
||||
bf.receiverList.pid);
|
||||
}
|
||||
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 (this.mPidsSelfLocked) {
|
||||
app = 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.receiver, r.resultCode, r.resultData,
|
||||
r.resultExtras, r.resultAbort, true);
|
||||
scheduleBroadcastsLocked();
|
||||
} 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.receiver, r.resultCode, r.resultData,
|
||||
r.resultExtras, r.resultAbort, true);
|
||||
scheduleBroadcastsLocked();
|
||||
|
||||
if (anrMessage != null) {
|
||||
appNotResponding(app, null, null, anrMessage);
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10648,9 +10700,10 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
|
||||
}
|
||||
|
||||
static void performReceive(ProcessRecord app, IIntentReceiver receiver,
|
||||
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.
|
||||
@@ -10661,7 +10714,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
}
|
||||
|
||||
private final void deliverToRegisteredReceiver(BroadcastRecord r,
|
||||
private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
|
||||
BroadcastFilter filter, boolean ordered) {
|
||||
boolean skip = false;
|
||||
if (filter.requiredPermission != null) {
|
||||
@@ -10719,7 +10772,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
Slog.i(TAG, "Delivering to " + filter
|
||||
+ " (seq=" + seq + "): " + r);
|
||||
}
|
||||
performReceive(filter.receiverList.app, filter.receiverList.receiver,
|
||||
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
|
||||
new Intent(r.intent), r.resultCode,
|
||||
r.resultData, r.resultExtras, r.ordered, r.initialSticky);
|
||||
if (ordered) {
|
||||
@@ -10776,7 +10829,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
if (DEBUG_BROADCAST) Slog.v(TAG,
|
||||
"Delivering non-ordered to registered "
|
||||
+ target + ": " + r);
|
||||
deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
|
||||
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
|
||||
}
|
||||
addBroadcastToHistoryLocked(r);
|
||||
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast "
|
||||
@@ -10832,7 +10885,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
// 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 with timeouts. They're intended for
|
||||
// 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;
|
||||
@@ -10848,7 +10901,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
+ " numReceivers=" + numReceivers
|
||||
+ " nextReceiver=" + r.nextReceiver
|
||||
+ " state=" + r.state);
|
||||
broadcastTimeout(); // forcibly finish this broadcast
|
||||
broadcastTimeoutLocked(false); // forcibly finish this broadcast
|
||||
forceReceive = true;
|
||||
r.state = BroadcastRecord.IDLE;
|
||||
}
|
||||
@@ -10872,7 +10925,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
Slog.i(TAG, "Finishing broadcast " + r.intent.getAction()
|
||||
+ " seq=" + seq + " app=" + r.callerApp);
|
||||
}
|
||||
performReceive(r.callerApp, r.resultTo,
|
||||
performReceiveLocked(r.callerApp, r.resultTo,
|
||||
new Intent(r.intent), r.resultCode,
|
||||
r.resultData, r.resultExtras, false, false);
|
||||
} catch (RemoteException e) {
|
||||
@@ -10881,7 +10934,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
|
||||
if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
|
||||
mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
|
||||
cancelBroadcastTimeoutLocked();
|
||||
|
||||
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
|
||||
+ r);
|
||||
@@ -10906,11 +10959,12 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
|
||||
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast "
|
||||
+ r);
|
||||
}
|
||||
if (! mPendingBroadcastTimeoutMessage) {
|
||||
long timeoutTime = r.receiverTime + BROADCAST_TIMEOUT;
|
||||
if (DEBUG_BROADCAST) Slog.v(TAG,
|
||||
"Submitting BROADCAST_TIMEOUT_MSG for " + r + " at "
|
||||
+ (r.receiverTime + BROADCAST_TIMEOUT));
|
||||
Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
|
||||
mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
|
||||
"Submitting BROADCAST_TIMEOUT_MSG for " + r + " at " + timeoutTime);
|
||||
setBroadcastTimeoutLocked(timeoutTime);
|
||||
}
|
||||
|
||||
Object nextReceiver = r.receivers.get(recIdx);
|
||||
@@ -10921,7 +10975,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
if (DEBUG_BROADCAST) Slog.v(TAG,
|
||||
"Delivering ordered to registered "
|
||||
+ filter + ": " + r);
|
||||
deliverToRegisteredReceiver(r, filter, r.ordered);
|
||||
deliverToRegisteredReceiverLocked(r, filter, r.ordered);
|
||||
if (r.receiver == null || !r.ordered) {
|
||||
// The receiver has already finished, so schedule to
|
||||
// process the next one.
|
||||
@@ -11029,7 +11083,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
+ info.activityInfo.applicationInfo.packageName + "/"
|
||||
+ info.activityInfo.applicationInfo.uid + " for broadcast "
|
||||
+ r.intent + ": process is bad");
|
||||
logBroadcastReceiverDiscard(r);
|
||||
logBroadcastReceiverDiscardLocked(r);
|
||||
finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
|
||||
r.resultExtras, r.resultAbort, true);
|
||||
scheduleBroadcastsLocked();
|
||||
|
||||
Reference in New Issue
Block a user