Merge "Increase the active broadcast delivery limit to core components." into udc-dev am: dad2f513c4

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22952908

Change-Id: If3dde10c4c2d4ed3b06be47d14723d0a6d1be891
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Sudheer Shanka
2023-05-09 10:33:57 +00:00
committed by Automerger Merge Worker
4 changed files with 230 additions and 99 deletions

View File

@@ -179,10 +179,38 @@ public class BroadcastConstants {
* being "runnable" to give other processes a chance to run. * being "runnable" to give other processes a chance to run.
*/ */
public int MAX_RUNNING_ACTIVE_BROADCASTS = DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS; public int MAX_RUNNING_ACTIVE_BROADCASTS = DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS;
private static final String KEY_MAX_RUNNING_ACTIVE_BROADCASTS = "bcast_max_running_active_broadcasts"; private static final String KEY_MAX_RUNNING_ACTIVE_BROADCASTS =
"bcast_max_running_active_broadcasts";
private static final int DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS = private static final int DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS =
ActivityManager.isLowRamDeviceStatic() ? 8 : 16; ActivityManager.isLowRamDeviceStatic() ? 8 : 16;
/**
* For {@link BroadcastQueueModernImpl}: Maximum number of active "blocking" broadcasts
* to dispatch to a "running" System process queue before we retire them back to
* being "runnable" to give other processes a chance to run. Here "blocking" refers to
* whether or not we are going to block on the finishReceiver() to be called before moving
* to the next broadcast.
*/
public int MAX_CORE_RUNNING_BLOCKING_BROADCASTS = DEFAULT_MAX_CORE_RUNNING_BLOCKING_BROADCASTS;
private static final String KEY_CORE_MAX_RUNNING_BLOCKING_BROADCASTS =
"bcast_max_core_running_blocking_broadcasts";
private static final int DEFAULT_MAX_CORE_RUNNING_BLOCKING_BROADCASTS =
ActivityManager.isLowRamDeviceStatic() ? 8 : 16;
/**
* For {@link BroadcastQueueModernImpl}: Maximum number of active non-"blocking" broadcasts
* to dispatch to a "running" System process queue before we retire them back to
* being "runnable" to give other processes a chance to run. Here "blocking" refers to
* whether or not we are going to block on the finishReceiver() to be called before moving
* to the next broadcast.
*/
public int MAX_CORE_RUNNING_NON_BLOCKING_BROADCASTS =
DEFAULT_MAX_CORE_RUNNING_NON_BLOCKING_BROADCASTS;
private static final String KEY_CORE_MAX_RUNNING_NON_BLOCKING_BROADCASTS =
"bcast_max_core_running_non_blocking_broadcasts";
private static final int DEFAULT_MAX_CORE_RUNNING_NON_BLOCKING_BROADCASTS =
ActivityManager.isLowRamDeviceStatic() ? 32 : 64;
/** /**
* For {@link BroadcastQueueModernImpl}: Maximum number of pending * For {@link BroadcastQueueModernImpl}: Maximum number of pending
* broadcasts to hold for a process before we ignore any delays that policy * broadcasts to hold for a process before we ignore any delays that policy
@@ -369,6 +397,12 @@ public class BroadcastConstants {
DEFAULT_MAX_CONSECUTIVE_NORMAL_DISPATCHES); DEFAULT_MAX_CONSECUTIVE_NORMAL_DISPATCHES);
MAX_RUNNING_ACTIVE_BROADCASTS = getDeviceConfigInt(KEY_MAX_RUNNING_ACTIVE_BROADCASTS, MAX_RUNNING_ACTIVE_BROADCASTS = getDeviceConfigInt(KEY_MAX_RUNNING_ACTIVE_BROADCASTS,
DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS); DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS);
MAX_CORE_RUNNING_BLOCKING_BROADCASTS = getDeviceConfigInt(
KEY_CORE_MAX_RUNNING_BLOCKING_BROADCASTS,
DEFAULT_MAX_CORE_RUNNING_BLOCKING_BROADCASTS);
MAX_CORE_RUNNING_NON_BLOCKING_BROADCASTS = getDeviceConfigInt(
KEY_CORE_MAX_RUNNING_NON_BLOCKING_BROADCASTS,
DEFAULT_MAX_CORE_RUNNING_NON_BLOCKING_BROADCASTS);
MAX_PENDING_BROADCASTS = getDeviceConfigInt(KEY_MAX_PENDING_BROADCASTS, MAX_PENDING_BROADCASTS = getDeviceConfigInt(KEY_MAX_PENDING_BROADCASTS,
DEFAULT_MAX_PENDING_BROADCASTS); DEFAULT_MAX_PENDING_BROADCASTS);
DELAY_NORMAL_MILLIS = getDeviceConfigLong(KEY_DELAY_NORMAL_MILLIS, DELAY_NORMAL_MILLIS = getDeviceConfigLong(KEY_DELAY_NORMAL_MILLIS,
@@ -418,6 +452,10 @@ public class BroadcastConstants {
pw.print(KEY_MODERN_QUEUE_ENABLED, MODERN_QUEUE_ENABLED).println(); pw.print(KEY_MODERN_QUEUE_ENABLED, MODERN_QUEUE_ENABLED).println();
pw.print(KEY_MAX_RUNNING_PROCESS_QUEUES, MAX_RUNNING_PROCESS_QUEUES).println(); pw.print(KEY_MAX_RUNNING_PROCESS_QUEUES, MAX_RUNNING_PROCESS_QUEUES).println();
pw.print(KEY_MAX_RUNNING_ACTIVE_BROADCASTS, MAX_RUNNING_ACTIVE_BROADCASTS).println(); pw.print(KEY_MAX_RUNNING_ACTIVE_BROADCASTS, MAX_RUNNING_ACTIVE_BROADCASTS).println();
pw.print(KEY_CORE_MAX_RUNNING_BLOCKING_BROADCASTS,
MAX_CORE_RUNNING_BLOCKING_BROADCASTS).println();
pw.print(KEY_CORE_MAX_RUNNING_NON_BLOCKING_BROADCASTS,
MAX_CORE_RUNNING_NON_BLOCKING_BROADCASTS).println();
pw.print(KEY_MAX_PENDING_BROADCASTS, MAX_PENDING_BROADCASTS).println(); pw.print(KEY_MAX_PENDING_BROADCASTS, MAX_PENDING_BROADCASTS).println();
pw.print(KEY_DELAY_NORMAL_MILLIS, pw.print(KEY_DELAY_NORMAL_MILLIS,
TimeUtils.formatDuration(DELAY_NORMAL_MILLIS)).println(); TimeUtils.formatDuration(DELAY_NORMAL_MILLIS)).println();

View File

@@ -142,6 +142,12 @@ class BroadcastProcessQueue {
*/ */
private int mActiveCountSinceIdle; private int mActiveCountSinceIdle;
/**
* Count of {@link #mActive} broadcasts with assumed delivery that have been dispatched
* since this queue was last idle.
*/
private int mActiveAssumedDeliveryCountSinceIdle;
/** /**
* Flag indicating that the currently active broadcast is being dispatched * Flag indicating that the currently active broadcast is being dispatched
* was scheduled via a cold start. * was scheduled via a cold start.
@@ -499,6 +505,14 @@ class BroadcastProcessQueue {
return mActiveCountSinceIdle; return mActiveCountSinceIdle;
} }
/**
* Count of {@link #mActive} broadcasts with assumed delivery that have been dispatched
* since this queue was last idle.
*/
public int getActiveAssumedDeliveryCountSinceIdle() {
return mActiveAssumedDeliveryCountSinceIdle;
}
public void setActiveViaColdStart(boolean activeViaColdStart) { public void setActiveViaColdStart(boolean activeViaColdStart) {
mActiveViaColdStart = activeViaColdStart; mActiveViaColdStart = activeViaColdStart;
} }
@@ -532,6 +546,8 @@ class BroadcastProcessQueue {
mActive = (BroadcastRecord) next.arg1; mActive = (BroadcastRecord) next.arg1;
mActiveIndex = next.argi1; mActiveIndex = next.argi1;
mActiveCountSinceIdle++; mActiveCountSinceIdle++;
mActiveAssumedDeliveryCountSinceIdle +=
(mActive.isAssumedDelivered(mActiveIndex) ? 1 : 0);
mActiveViaColdStart = false; mActiveViaColdStart = false;
mActiveWasStopped = false; mActiveWasStopped = false;
next.recycle(); next.recycle();
@@ -545,6 +561,7 @@ class BroadcastProcessQueue {
mActive = null; mActive = null;
mActiveIndex = 0; mActiveIndex = 0;
mActiveCountSinceIdle = 0; mActiveCountSinceIdle = 0;
mActiveAssumedDeliveryCountSinceIdle = 0;
mActiveViaColdStart = false; mActiveViaColdStart = false;
invalidateRunnableAt(); invalidateRunnableAt();
} }
@@ -1369,6 +1386,7 @@ class BroadcastProcessQueue {
pw.print(" m:"); pw.print(mCountManifest); pw.print(" m:"); pw.print(mCountManifest);
pw.print(" csi:"); pw.print(mActiveCountSinceIdle); pw.print(" csi:"); pw.print(mActiveCountSinceIdle);
pw.print(" adcsi:"); pw.print(mActiveAssumedDeliveryCountSinceIdle);
pw.print(" ccu:"); pw.print(mActiveCountConsecutiveUrgent); pw.print(" ccu:"); pw.print(mActiveCountConsecutiveUrgent);
pw.print(" ccn:"); pw.print(mActiveCountConsecutiveNormal); pw.print(" ccn:"); pw.print(mActiveCountConsecutiveNormal);
pw.println(); pw.println();

View File

@@ -40,6 +40,7 @@ import static com.android.server.am.BroadcastRecord.getReceiverProcessName;
import static com.android.server.am.BroadcastRecord.getReceiverUid; import static com.android.server.am.BroadcastRecord.getReceiverUid;
import static com.android.server.am.BroadcastRecord.isDeliveryStateTerminal; import static com.android.server.am.BroadcastRecord.isDeliveryStateTerminal;
import android.annotation.CheckResult;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.UptimeMillisLong; import android.annotation.UptimeMillisLong;
@@ -446,43 +447,29 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
if (DEBUG_BROADCAST) logv("Promoting " + queue if (DEBUG_BROADCAST) logv("Promoting " + queue
+ " from runnable to running; process is " + queue.app); + " from runnable to running; process is " + queue.app);
promoteToRunningLocked(queue);
// Allocate this available permit and start running! final boolean completed;
final int queueIndex = getRunningIndexOf(null);
mRunning[queueIndex] = queue;
avail--;
// Remove ourselves from linked list of runnable things
mRunnableHead = removeFromRunnableList(mRunnableHead, queue);
// Emit all trace events for this process into a consistent track
queue.runningTraceTrackName = TAG + ".mRunning[" + queueIndex + "]";
queue.runningOomAdjusted = queue.isPendingManifest()
|| queue.isPendingOrdered()
|| queue.isPendingResultTo();
// If already warm, we can make OOM adjust request immediately;
// otherwise we need to wait until process becomes warm
if (processWarm) { if (processWarm) {
notifyStartedRunning(queue);
updateOomAdj |= queue.runningOomAdjusted; updateOomAdj |= queue.runningOomAdjusted;
} completed = scheduleReceiverWarmLocked(queue);
// If we're already warm, schedule next pending broadcast now;
// otherwise we'll wait for the cold start to circle back around
queue.makeActiveNextPending();
if (processWarm) {
queue.traceProcessRunningBegin();
scheduleReceiverWarmLocked(queue);
} else { } else {
queue.traceProcessStartingBegin(); completed = scheduleReceiverColdLocked(queue);
scheduleReceiverColdLocked(queue);
} }
// If we are done with delivering the broadcasts to the process, we can demote it
// from the "running" list.
if (completed) {
demoteFromRunningLocked(queue);
}
// TODO: If delivering broadcasts to a process is finished, we don't have to hold
// a slot for it.
avail--;
// Move to considering next runnable queue // Move to considering next runnable queue
queue = nextQueue; queue = nextQueue;
} }
// TODO: We need to update oomAdj early as this currently doesn't guarantee that the
// procState is updated correctly when the app is handling a broadcast.
if (updateOomAdj) { if (updateOomAdj) {
mService.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_RECEIVER); mService.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_RECEIVER);
} }
@@ -514,7 +501,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
queue.traceProcessEnd(); queue.traceProcessEnd();
queue.traceProcessRunningBegin(); queue.traceProcessRunningBegin();
scheduleReceiverWarmLocked(queue); if (scheduleReceiverWarmLocked(queue)) {
demoteFromRunningLocked(queue);
}
// We might be willing to kick off another cold start // We might be willing to kick off another cold start
enqueueUpdateRunningList(); enqueueUpdateRunningList();
@@ -558,6 +547,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
if (queue.isActive()) { if (queue.isActive()) {
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
"onApplicationCleanupLocked"); "onApplicationCleanupLocked");
demoteFromRunningLocked(queue);
} }
// Skip any pending registered receivers, since the old process // Skip any pending registered receivers, since the old process
@@ -695,8 +685,13 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
* Schedule the currently active broadcast on the given queue when we know * Schedule the currently active broadcast on the given queue when we know
* the process is cold. This kicks off a cold start and will eventually call * the process is cold. This kicks off a cold start and will eventually call
* through to {@link #scheduleReceiverWarmLocked} once it's ready. * through to {@link #scheduleReceiverWarmLocked} once it's ready.
*
* @return {@code true} if the broadcast delivery is finished and the process queue can
* be demoted from the running list. Otherwise {@code false}.
*/ */
private void scheduleReceiverColdLocked(@NonNull BroadcastProcessQueue queue) { @CheckResult
@GuardedBy("mService")
private boolean scheduleReceiverColdLocked(@NonNull BroadcastProcessQueue queue) {
checkState(queue.isActive(), "isActive"); checkState(queue.isActive(), "isActive");
// Remember that active broadcast was scheduled via a cold start // Remember that active broadcast was scheduled via a cold start
@@ -711,12 +706,14 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
mRunningColdStart = null; mRunningColdStart = null;
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED,
"BroadcastFilter for cold app"); "BroadcastFilter for cold app");
return; return true;
} }
if (maybeSkipReceiver(queue, r, index)) { final String skipReason = shouldSkipReceiver(queue, r, index);
if (skipReason != null) {
mRunningColdStart = null; mRunningColdStart = null;
return; finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, skipReason);
return true;
} }
final ApplicationInfo info = ((ResolveInfo) receiver).activityInfo.applicationInfo; final ApplicationInfo info = ((ResolveInfo) receiver).activityInfo.applicationInfo;
@@ -742,8 +739,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
mRunningColdStart = null; mRunningColdStart = null;
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
"startProcessLocked failed"); "startProcessLocked failed");
return; return true;
} }
return false;
} }
/** /**
@@ -754,11 +752,17 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
* results by calling through to {@link #finishReceiverLocked}, both in the * results by calling through to {@link #finishReceiverLocked}, both in the
* case where a broadcast is handled by a remote app, and the case where the * case where a broadcast is handled by a remote app, and the case where the
* broadcast was finished locally without the remote app being involved. * broadcast was finished locally without the remote app being involved.
*
* @return {@code true} if the broadcast delivery is finished and the process queue can
* be demoted from the running list. Otherwise {@code false}.
*/ */
@CheckResult
@GuardedBy("mService") @GuardedBy("mService")
private void scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue) { private boolean scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue) {
checkState(queue.isActive(), "isActive"); checkState(queue.isActive(), "isActive");
final int cookie = traceBegin("scheduleReceiverWarmLocked");
while (queue.isActive()) {
final BroadcastRecord r = queue.getActive(); final BroadcastRecord r = queue.getActive();
final int index = queue.getActiveIndex(); final int index = queue.getActiveIndex();
@@ -768,24 +772,26 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
r.dispatchClockTime = System.currentTimeMillis(); r.dispatchClockTime = System.currentTimeMillis();
} }
if (maybeSkipReceiver(queue, r, index)) { final String skipReason = shouldSkipReceiver(queue, r, index);
return; if (skipReason == null) {
final boolean isBlockingDispatch = dispatchReceivers(queue, r, index);
if (isBlockingDispatch) {
traceEnd(cookie);
return false;
} }
dispatchReceivers(queue, r, index); } else {
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, skipReason);
} }
/** if (shouldRetire(queue)) {
* Examine a receiver and possibly skip it. The method returns true if the receiver is break;
* skipped (and therefore no more work is required).
*/
private boolean maybeSkipReceiver(@NonNull BroadcastProcessQueue queue,
@NonNull BroadcastRecord r, int index) {
final String reason = shouldSkipReceiver(queue, r, index);
if (reason != null) {
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, reason);
return true;
} }
return false;
// We're on a roll; move onto the next broadcast for this process
queue.makeActiveNextPending();
}
traceEnd(cookie);
return true;
} }
/** /**
@@ -825,25 +831,22 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
return null; return null;
} }
/**
* Return true if this receiver should be assumed to have been delivered.
*/
private boolean isAssumedDelivered(BroadcastRecord r, int index) {
return (r.receivers.get(index) instanceof BroadcastFilter) && !r.ordered
&& (r.resultTo == null);
}
/** /**
* A receiver is about to be dispatched. Start ANR timers, if necessary. * A receiver is about to be dispatched. Start ANR timers, if necessary.
*
* @return {@code true} if this a blocking delivery. That is, we are going to block on the
* finishReceiver() to be called before moving to the next broadcast. Otherwise,
* {@code false}.
*/ */
private void dispatchReceivers(@NonNull BroadcastProcessQueue queue, @CheckResult
private boolean dispatchReceivers(@NonNull BroadcastProcessQueue queue,
@NonNull BroadcastRecord r, int index) { @NonNull BroadcastRecord r, int index) {
final ProcessRecord app = queue.app; final ProcessRecord app = queue.app;
final Object receiver = r.receivers.get(index); final Object receiver = r.receivers.get(index);
// Skip ANR tracking early during boot, when requested, or when we // Skip ANR tracking early during boot, when requested, or when we
// immediately assume delivery success // immediately assume delivery success
final boolean assumeDelivered = isAssumedDelivered(r, index); final boolean assumeDelivered = r.isAssumedDelivered(index);
if (mService.mProcessesReady && !r.timeoutExempt && !assumeDelivered) { if (mService.mProcessesReady && !r.timeoutExempt && !assumeDelivered) {
queue.lastCpuDelayTime = queue.app.getCpuDelayTime(); queue.lastCpuDelayTime = queue.app.getCpuDelayTime();
@@ -898,6 +901,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
if (assumeDelivered) { if (assumeDelivered) {
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_DELIVERED, finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_DELIVERED,
"assuming delivered"); "assuming delivered");
return false;
} }
} else { } else {
notifyScheduleReceiver(app, r, (ResolveInfo) receiver); notifyScheduleReceiver(app, r, (ResolveInfo) receiver);
@@ -908,17 +912,21 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
r.shareIdentity ? r.callingUid : Process.INVALID_UID, r.shareIdentity ? r.callingUid : Process.INVALID_UID,
r.shareIdentity ? r.callerPackage : null); r.shareIdentity ? r.callerPackage : null);
} }
return true;
} catch (RemoteException e) { } catch (RemoteException e) {
final String msg = "Failed to schedule " + r + " to " + receiver final String msg = "Failed to schedule " + r + " to " + receiver
+ " via " + app + ": " + e; + " via " + app + ": " + e;
logw(msg); logw(msg);
app.killLocked("Can't deliver broadcast", ApplicationExitInfo.REASON_OTHER, app.killLocked("Can't deliver broadcast", ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_UNDELIVERED_BROADCAST, true); ApplicationExitInfo.SUBREASON_UNDELIVERED_BROADCAST, true);
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app"); finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
"remote app");
return false;
} }
} else { } else {
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
"missing IApplicationThread"); "missing IApplicationThread");
return false;
} }
} }
@@ -989,6 +997,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
private void deliveryTimeoutHardLocked(@NonNull BroadcastProcessQueue queue) { private void deliveryTimeoutHardLocked(@NonNull BroadcastProcessQueue queue) {
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT, finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT,
"deliveryTimeoutHardLocked"); "deliveryTimeoutHardLocked");
demoteFromRunningLocked(queue);
} }
@Override @Override
@@ -1015,7 +1024,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
// To ensure that "beyond" high-water marks are updated in a monotonic // To ensure that "beyond" high-water marks are updated in a monotonic
// way, we finish this receiver before possibly skipping any remaining // way, we finish this receiver before possibly skipping any remaining
// aborted receivers // aborted receivers
final boolean res = finishReceiverActiveLocked(queue, finishReceiverActiveLocked(queue,
BroadcastRecord.DELIVERY_DELIVERED, "remote app"); BroadcastRecord.DELIVERY_DELIVERED, "remote app");
// When the caller aborted an ordered broadcast, we mark all // When the caller aborted an ordered broadcast, we mark all
@@ -1027,30 +1036,52 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
} }
} }
return res; if (shouldRetire(queue)) {
demoteFromRunningLocked(queue);
return true;
}
// We're on a roll; move onto the next broadcast for this process
queue.makeActiveNextPending();
if (scheduleReceiverWarmLocked(queue)) {
demoteFromRunningLocked(queue);
return true;
}
return false;
} }
/** /**
* Return true if there are more broadcasts in the queue and the queue is runnable. * Return true if there are no more broadcasts in the queue or if the queue is not runnable.
*/ */
private boolean shouldContinueScheduling(@NonNull BroadcastProcessQueue queue) { private boolean shouldRetire(@NonNull BroadcastProcessQueue queue) {
// If we've made reasonable progress, periodically retire ourselves to // If we've made reasonable progress, periodically retire ourselves to
// avoid starvation of other processes and stack overflow when a // avoid starvation of other processes and stack overflow when a
// broadcast is immediately finished without waiting // broadcast is immediately finished without waiting
final boolean shouldRetire = final boolean shouldRetire;
if (UserHandle.isCore(queue.uid)) {
final int nonBlockingDeliveryCount = queue.getActiveAssumedDeliveryCountSinceIdle();
final int blockingDeliveryCount = (queue.getActiveCountSinceIdle()
- queue.getActiveAssumedDeliveryCountSinceIdle());
shouldRetire = (blockingDeliveryCount
>= mConstants.MAX_CORE_RUNNING_BLOCKING_BROADCASTS) || (nonBlockingDeliveryCount
>= mConstants.MAX_CORE_RUNNING_NON_BLOCKING_BROADCASTS);
} else {
shouldRetire =
(queue.getActiveCountSinceIdle() >= mConstants.MAX_RUNNING_ACTIVE_BROADCASTS); (queue.getActiveCountSinceIdle() >= mConstants.MAX_RUNNING_ACTIVE_BROADCASTS);
}
return queue.isRunnable() && queue.isProcessWarm() && !shouldRetire; return !queue.isRunnable() || !queue.isProcessWarm() || shouldRetire;
} }
/** /**
* Terminate all active broadcasts on the queue. * Terminate all active broadcasts on the queue.
*/ */
private boolean finishReceiverActiveLocked(@NonNull BroadcastProcessQueue queue, private void finishReceiverActiveLocked(@NonNull BroadcastProcessQueue queue,
@DeliveryState int deliveryState, @NonNull String reason) { @DeliveryState int deliveryState, @NonNull String reason) {
if (!queue.isActive()) { if (!queue.isActive()) {
logw("Ignoring finish; no active broadcast for " + queue); logw("Ignoring finish; no active broadcast for " + queue);
return false; return;
} }
final int cookie = traceBegin("finishReceiver"); final int cookie = traceBegin("finishReceiver");
@@ -1077,12 +1108,50 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
// Given that a receiver just finished, check if the "waitingFor" conditions are met. // Given that a receiver just finished, check if the "waitingFor" conditions are met.
checkAndRemoveWaitingFor(); checkAndRemoveWaitingFor();
final boolean res = shouldContinueScheduling(queue); traceEnd(cookie);
if (res) { }
// We're on a roll; move onto the next broadcast for this process
/**
* Promote a process to the "running" list.
*/
@GuardedBy("mService")
private void promoteToRunningLocked(@NonNull BroadcastProcessQueue queue) {
// Allocate this available permit and start running!
final int queueIndex = getRunningIndexOf(null);
mRunning[queueIndex] = queue;
// Remove ourselves from linked list of runnable things
mRunnableHead = removeFromRunnableList(mRunnableHead, queue);
// Emit all trace events for this process into a consistent track
queue.runningTraceTrackName = TAG + ".mRunning[" + queueIndex + "]";
queue.runningOomAdjusted = queue.isPendingManifest()
|| queue.isPendingOrdered()
|| queue.isPendingResultTo();
// If already warm, we can make OOM adjust request immediately;
// otherwise we need to wait until process becomes warm
final boolean processWarm = queue.isProcessWarm();
if (processWarm) {
notifyStartedRunning(queue);
}
// If we're already warm, schedule next pending broadcast now;
// otherwise we'll wait for the cold start to circle back around
queue.makeActiveNextPending(); queue.makeActiveNextPending();
scheduleReceiverWarmLocked(queue); if (processWarm) {
queue.traceProcessRunningBegin();
} else { } else {
queue.traceProcessStartingBegin();
}
}
/**
* Demote a process from the "running" list.
*/
@GuardedBy("mService")
private void demoteFromRunningLocked(@NonNull BroadcastProcessQueue queue) {
final int cookie = traceBegin("demoteFromRunning");
// We've drained running broadcasts; maybe move back to runnable // We've drained running broadcasts; maybe move back to runnable
queue.makeActiveIdle(); queue.makeActiveIdle();
queue.traceProcessEnd(); queue.traceProcessEnd();
@@ -1095,9 +1164,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
// Tell other OS components that app is not actively running, giving // Tell other OS components that app is not actively running, giving
// a chance to update OOM adjustment // a chance to update OOM adjustment
notifyStoppedRunning(queue); notifyStoppedRunning(queue);
}
traceEnd(cookie); traceEnd(cookie);
return res;
} }
/** /**

View File

@@ -237,6 +237,14 @@ final class BroadcastRecord extends Binder {
} }
} }
/**
* Return true if this receiver should be assumed to have been delivered.
*/
boolean isAssumedDelivered(int index) {
return (receivers.get(index) instanceof BroadcastFilter) && !ordered
&& (resultTo == null);
}
ProcessRecord curApp; // hosting application of current receiver. ProcessRecord curApp; // hosting application of current receiver.
ComponentName curComponent; // the receiver class that is currently running. ComponentName curComponent; // the receiver class that is currently running.
ActivityInfo curReceiver; // the manifest receiver that is currently running. ActivityInfo curReceiver; // the manifest receiver that is currently running.