Merge "Exempt PRE_BOOT_COMPLETED from timeout & deferral policy"
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 29baacb..9a4fdd8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -14099,7 +14099,8 @@
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, -1, -1, false, null, null, OP_NONE, null, receivers,
- null, 0, null, null, false, true, true, -1, false);
+ null, 0, null, null, false, true, true, -1, false,
+ false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
@@ -14484,6 +14485,8 @@
}
}
+ boolean timeoutExempt = false;
+
if (action != null) {
if (getBackgroundLaunchBroadcasts().contains(action)) {
if (DEBUG_BACKGROUND_CHECK) {
@@ -14709,6 +14712,9 @@
Log.w(TAG, "Broadcast " + action
+ " no longer supported. It will not be delivered.");
return ActivityManager.BROADCAST_SUCCESS;
+ case Intent.ACTION_PRE_BOOT_COMPLETED:
+ timeoutExempt = true;
+ break;
}
if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
@@ -14851,7 +14857,7 @@
callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
resultCode, resultData, resultExtras, ordered, sticky, false, userId,
- allowBackgroundActivityStarts);
+ allowBackgroundActivityStarts, timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
@@ -14948,7 +14954,7 @@
callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, false, userId,
- allowBackgroundActivityStarts);
+ allowBackgroundActivityStarts, timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 1fb11ba..a11ebfd 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -461,14 +461,21 @@
// if this receiver was slow, impose deferral policy on the app. This will kick in
// when processNextBroadcastLocked() next finds this uid as a receiver identity.
- if (mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
- if (DEBUG_BROADCAST_DEFERRAL) {
- Slog.i(TAG, "Broadcast receiver was slow: " + receiver + " br=" + r);
+ if (!r.timeoutExempt) {
+ if (mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
+ if (DEBUG_BROADCAST_DEFERRAL) {
+ Slog.i(TAG, "Broadcast receiver was slow: " + receiver + " br=" + r);
+ }
+ if (r.curApp != null) {
+ mDispatcher.startDeferring(r.curApp.uid);
+ } else {
+ Slog.d(TAG, "finish receiver curApp is null? " + r);
+ }
}
- if (r.curApp != null) {
- mDispatcher.startDeferring(r.curApp.uid);
- } else {
- Slog.d(TAG, "finish receiver curApp is null? " + r);
+ } else {
+ if (DEBUG_BROADCAST_DEFERRAL) {
+ Slog.i(TAG_BROADCAST, "Finished broadcast " + r.intent.getAction()
+ + " is exempt from deferral policy");
}
}
@@ -1008,12 +1015,11 @@
// 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.
+ // This is only done if the system is ready so that early-stage receivers
+ // don't get executed with timeouts; and of course other timeout-
+ // exempt broadcasts are ignored.
int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
- if (mService.mProcessesReady && r.dispatchTime > 0) {
+ if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) {
if ((numReceivers > 0) &&
(now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {
Slog.w(TAG, "Hung broadcast ["
@@ -1619,9 +1625,17 @@
BroadcastRecord r = mDispatcher.getActiveBroadcastLocked();
if (fromMsg) {
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.
+ // Only process broadcast timeouts if the system is ready; some early
+ // broadcasts do heavy work setting up system facilities
+ return;
+ }
+
+ // If the broadcast is generally exempt from timeout tracking, we're done
+ if (r.timeoutExempt) {
+ if (DEBUG_BROADCAST) {
+ Slog.i(TAG_BROADCAST, "Broadcast timeout but it's exempt: "
+ + r.intent.getAction());
+ }
return;
}
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index d9e03f8..fa9b79d 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -74,6 +74,7 @@
long dispatchClockTime; // the clock time the dispatch started
long receiverTime; // when current receiver started for timeouts.
long finishTime; // when we finished the broadcast.
+ boolean timeoutExempt; // true if this broadcast is not subject to receiver timeouts
int resultCode; // current result code value.
String resultData; // current result data value.
Bundle resultExtras; // current result extra data values.
@@ -236,7 +237,7 @@
String[] _requiredPermissions, int _appOp, BroadcastOptions _options, List _receivers,
IIntentReceiver _resultTo, int _resultCode, String _resultData, Bundle _resultExtras,
boolean _serialized, boolean _sticky, boolean _initialSticky, int _userId,
- boolean _allowBackgroundActivityStarts) {
+ boolean _allowBackgroundActivityStarts, boolean _timeoutExempt) {
if (_intent == null) {
throw new NullPointerException("Can't construct with a null intent");
}
@@ -266,6 +267,7 @@
nextReceiver = 0;
state = IDLE;
allowBackgroundActivityStarts = _allowBackgroundActivityStarts;
+ timeoutExempt = _timeoutExempt;
}
/**
@@ -310,6 +312,7 @@
manifestSkipCount = from.manifestSkipCount;
queue = from.queue;
allowBackgroundActivityStarts = from.allowBackgroundActivityStarts;
+ timeoutExempt = from.timeoutExempt;
}
/**
@@ -345,7 +348,7 @@
callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, options, splitReceivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, initialSticky, userId,
- allowBackgroundActivityStarts);
+ allowBackgroundActivityStarts, timeoutExempt);
return split;
}
diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
index d4bb636..089a79b 100644
--- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -194,6 +194,7 @@
false /* sticky */,
false /* initialSticky */,
userId,
- false /* allowBackgroundActivityStarts */);
+ false, /* allowBackgroundActivityStarts */
+ false /* timeoutExempt */ );
}
}