Merge "Increase the active broadcast delivery limit to core components." into udc-dev am: dad2f513c4 am: 2774480fa8 am: fbfce72407
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22952908 Change-Id: Ib859fce7d82371d49191a4a53c8c989376e2e446 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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,38 +752,46 @@ 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 BroadcastRecord r = queue.getActive();
|
final int cookie = traceBegin("scheduleReceiverWarmLocked");
|
||||||
final int index = queue.getActiveIndex();
|
while (queue.isActive()) {
|
||||||
|
final BroadcastRecord r = queue.getActive();
|
||||||
|
final int index = queue.getActiveIndex();
|
||||||
|
|
||||||
if (r.terminalCount == 0) {
|
if (r.terminalCount == 0) {
|
||||||
r.dispatchTime = SystemClock.uptimeMillis();
|
r.dispatchTime = SystemClock.uptimeMillis();
|
||||||
r.dispatchRealTime = SystemClock.elapsedRealtime();
|
r.dispatchRealTime = SystemClock.elapsedRealtime();
|
||||||
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);
|
||||||
dispatchReceivers(queue, r, index);
|
if (isBlockingDispatch) {
|
||||||
}
|
traceEnd(cookie);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} 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,
|
// We're on a roll; move onto the next broadcast for this process
|
||||||
@NonNull BroadcastRecord r, int index) {
|
queue.makeActiveNextPending();
|
||||||
final String reason = shouldSkipReceiver(queue, r, index);
|
|
||||||
if (reason != null) {
|
|
||||||
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, reason);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
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;
|
||||||
(queue.getActiveCountSinceIdle() >= mConstants.MAX_RUNNING_ACTIVE_BROADCASTS);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
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,27 +1108,63 @@ 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);
|
|
||||||
if (res) {
|
|
||||||
// We're on a roll; move onto the next broadcast for this process
|
|
||||||
queue.makeActiveNextPending();
|
|
||||||
scheduleReceiverWarmLocked(queue);
|
|
||||||
} else {
|
|
||||||
// We've drained running broadcasts; maybe move back to runnable
|
|
||||||
queue.makeActiveIdle();
|
|
||||||
queue.traceProcessEnd();
|
|
||||||
|
|
||||||
final int queueIndex = getRunningIndexOf(queue);
|
|
||||||
mRunning[queueIndex] = null;
|
|
||||||
updateRunnableList(queue);
|
|
||||||
enqueueUpdateRunningList();
|
|
||||||
|
|
||||||
// Tell other OS components that app is not actively running, giving
|
|
||||||
// a chance to update OOM adjustment
|
|
||||||
notifyStoppedRunning(queue);
|
|
||||||
}
|
|
||||||
traceEnd(cookie);
|
traceEnd(cookie);
|
||||||
return res;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
if (processWarm) {
|
||||||
|
queue.traceProcessRunningBegin();
|
||||||
|
} 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
|
||||||
|
queue.makeActiveIdle();
|
||||||
|
queue.traceProcessEnd();
|
||||||
|
|
||||||
|
final int queueIndex = getRunningIndexOf(queue);
|
||||||
|
mRunning[queueIndex] = null;
|
||||||
|
updateRunnableList(queue);
|
||||||
|
enqueueUpdateRunningList();
|
||||||
|
|
||||||
|
// Tell other OS components that app is not actively running, giving
|
||||||
|
// a chance to update OOM adjustment
|
||||||
|
notifyStoppedRunning(queue);
|
||||||
|
traceEnd(cookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user