Loading services/core/java/com/android/server/am/BroadcastConstants.java +39 −1 Original line number Diff line number Diff line Loading @@ -179,10 +179,38 @@ public class BroadcastConstants { * being "runnable" to give other processes a chance to run. */ 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 = 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 * broadcasts to hold for a process before we ignore any delays that policy Loading Loading @@ -369,6 +397,12 @@ public class BroadcastConstants { DEFAULT_MAX_CONSECUTIVE_NORMAL_DISPATCHES); MAX_RUNNING_ACTIVE_BROADCASTS = getDeviceConfigInt(KEY_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, DEFAULT_MAX_PENDING_BROADCASTS); DELAY_NORMAL_MILLIS = getDeviceConfigLong(KEY_DELAY_NORMAL_MILLIS, Loading Loading @@ -418,6 +452,10 @@ public class BroadcastConstants { 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_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_DELAY_NORMAL_MILLIS, TimeUtils.formatDuration(DELAY_NORMAL_MILLIS)).println(); Loading services/core/java/com/android/server/am/BroadcastProcessQueue.java +18 −0 Original line number Diff line number Diff line Loading @@ -142,6 +142,12 @@ class BroadcastProcessQueue { */ 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 * was scheduled via a cold start. Loading Loading @@ -499,6 +505,14 @@ class BroadcastProcessQueue { 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) { mActiveViaColdStart = activeViaColdStart; } Loading Loading @@ -532,6 +546,8 @@ class BroadcastProcessQueue { mActive = (BroadcastRecord) next.arg1; mActiveIndex = next.argi1; mActiveCountSinceIdle++; mActiveAssumedDeliveryCountSinceIdle += (mActive.isAssumedDelivered(mActiveIndex) ? 1 : 0); mActiveViaColdStart = false; mActiveWasStopped = false; next.recycle(); Loading @@ -545,6 +561,7 @@ class BroadcastProcessQueue { mActive = null; mActiveIndex = 0; mActiveCountSinceIdle = 0; mActiveAssumedDeliveryCountSinceIdle = 0; mActiveViaColdStart = false; invalidateRunnableAt(); } Loading Loading @@ -1369,6 +1386,7 @@ class BroadcastProcessQueue { pw.print(" m:"); pw.print(mCountManifest); pw.print(" csi:"); pw.print(mActiveCountSinceIdle); pw.print(" adcsi:"); pw.print(mActiveAssumedDeliveryCountSinceIdle); pw.print(" ccu:"); pw.print(mActiveCountConsecutiveUrgent); pw.print(" ccn:"); pw.print(mActiveCountConsecutiveNormal); pw.println(); Loading services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +162 −95 Original line number Diff line number Diff line Loading @@ -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.isDeliveryStateTerminal; import android.annotation.CheckResult; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UptimeMillisLong; Loading Loading @@ -446,43 +447,29 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (DEBUG_BROADCAST) logv("Promoting " + queue + " from runnable to running; process is " + queue.app); // Allocate this available permit and start running! 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 promoteToRunningLocked(queue); final boolean completed; if (processWarm) { notifyStartedRunning(queue); updateOomAdj |= queue.runningOomAdjusted; } // 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); completed = scheduleReceiverWarmLocked(queue); } else { queue.traceProcessStartingBegin(); scheduleReceiverColdLocked(queue); completed = 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 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) { mService.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_RECEIVER); } Loading Loading @@ -514,7 +501,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue { queue.traceProcessEnd(); queue.traceProcessRunningBegin(); scheduleReceiverWarmLocked(queue); if (scheduleReceiverWarmLocked(queue)) { demoteFromRunningLocked(queue); } // We might be willing to kick off another cold start enqueueUpdateRunningList(); Loading Loading @@ -558,6 +547,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (queue.isActive()) { finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "onApplicationCleanupLocked"); demoteFromRunningLocked(queue); } // Skip any pending registered receivers, since the old process Loading Loading @@ -695,8 +685,13 @@ class BroadcastQueueModernImpl extends BroadcastQueue { * 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 * 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"); // Remember that active broadcast was scheduled via a cold start Loading @@ -711,12 +706,14 @@ class BroadcastQueueModernImpl extends BroadcastQueue { mRunningColdStart = null; finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, "BroadcastFilter for cold app"); return; return true; } if (maybeSkipReceiver(queue, r, index)) { final String skipReason = shouldSkipReceiver(queue, r, index); if (skipReason != null) { mRunningColdStart = null; return; finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, skipReason); return true; } final ApplicationInfo info = ((ResolveInfo) receiver).activityInfo.applicationInfo; Loading @@ -742,8 +739,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue { mRunningColdStart = null; finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "startProcessLocked failed"); return; return true; } return false; } /** Loading @@ -754,11 +752,17 @@ class BroadcastQueueModernImpl extends BroadcastQueue { * 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 * 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") private void scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue) { private boolean scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue) { checkState(queue.isActive(), "isActive"); final int cookie = traceBegin("scheduleReceiverWarmLocked"); while (queue.isActive()) { final BroadcastRecord r = queue.getActive(); final int index = queue.getActiveIndex(); Loading @@ -768,24 +772,26 @@ class BroadcastQueueModernImpl extends BroadcastQueue { r.dispatchClockTime = System.currentTimeMillis(); } if (maybeSkipReceiver(queue, r, index)) { return; final String skipReason = shouldSkipReceiver(queue, r, index); 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); } /** * Examine a receiver and possibly skip it. The method returns true if the receiver is * 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; if (shouldRetire(queue)) { break; } return false; // We're on a roll; move onto the next broadcast for this process queue.makeActiveNextPending(); } traceEnd(cookie); return true; } /** Loading Loading @@ -825,25 +831,22 @@ class BroadcastQueueModernImpl extends BroadcastQueue { 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. * * @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) { final ProcessRecord app = queue.app; final Object receiver = r.receivers.get(index); // Skip ANR tracking early during boot, when requested, or when we // immediately assume delivery success final boolean assumeDelivered = isAssumedDelivered(r, index); final boolean assumeDelivered = r.isAssumedDelivered(index); if (mService.mProcessesReady && !r.timeoutExempt && !assumeDelivered) { queue.lastCpuDelayTime = queue.app.getCpuDelayTime(); Loading Loading @@ -898,6 +901,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (assumeDelivered) { finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_DELIVERED, "assuming delivered"); return false; } } else { notifyScheduleReceiver(app, r, (ResolveInfo) receiver); Loading @@ -908,17 +912,21 @@ class BroadcastQueueModernImpl extends BroadcastQueue { r.shareIdentity ? r.callingUid : Process.INVALID_UID, r.shareIdentity ? r.callerPackage : null); } return true; } catch (RemoteException e) { final String msg = "Failed to schedule " + r + " to " + receiver + " via " + app + ": " + e; logw(msg); app.killLocked("Can't deliver broadcast", ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_UNDELIVERED_BROADCAST, true); finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app"); finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app"); return false; } } else { finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "missing IApplicationThread"); return false; } } Loading Loading @@ -989,6 +997,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { private void deliveryTimeoutHardLocked(@NonNull BroadcastProcessQueue queue) { finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT, "deliveryTimeoutHardLocked"); demoteFromRunningLocked(queue); } @Override Loading @@ -1015,7 +1024,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // To ensure that "beyond" high-water marks are updated in a monotonic // way, we finish this receiver before possibly skipping any remaining // aborted receivers final boolean res = finishReceiverActiveLocked(queue, finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_DELIVERED, "remote app"); // When the caller aborted an ordered broadcast, we mark all Loading @@ -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 // avoid starvation of other processes and stack overflow when a // 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); } return queue.isRunnable() && queue.isProcessWarm() && !shouldRetire; return !queue.isRunnable() || !queue.isProcessWarm() || shouldRetire; } /** * 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) { if (!queue.isActive()) { logw("Ignoring finish; no active broadcast for " + queue); return false; return; } final int cookie = traceBegin("finishReceiver"); Loading @@ -1077,12 +1108,50 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // Given that a receiver just finished, check if the "waitingFor" conditions are met. checkAndRemoveWaitingFor(); final boolean res = shouldContinueScheduling(queue); if (res) { // We're on a roll; move onto the next broadcast for this process traceEnd(cookie); } /** * 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(); scheduleReceiverWarmLocked(queue); 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(); Loading @@ -1095,9 +1164,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // Tell other OS components that app is not actively running, giving // a chance to update OOM adjustment notifyStoppedRunning(queue); } traceEnd(cookie); return res; } /** Loading services/core/java/com/android/server/am/BroadcastRecord.java +8 −0 Original line number Diff line number Diff line Loading @@ -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. ComponentName curComponent; // the receiver class that is currently running. ActivityInfo curReceiver; // the manifest receiver that is currently running. Loading Loading
services/core/java/com/android/server/am/BroadcastConstants.java +39 −1 Original line number Diff line number Diff line Loading @@ -179,10 +179,38 @@ public class BroadcastConstants { * being "runnable" to give other processes a chance to run. */ 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 = 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 * broadcasts to hold for a process before we ignore any delays that policy Loading Loading @@ -369,6 +397,12 @@ public class BroadcastConstants { DEFAULT_MAX_CONSECUTIVE_NORMAL_DISPATCHES); MAX_RUNNING_ACTIVE_BROADCASTS = getDeviceConfigInt(KEY_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, DEFAULT_MAX_PENDING_BROADCASTS); DELAY_NORMAL_MILLIS = getDeviceConfigLong(KEY_DELAY_NORMAL_MILLIS, Loading Loading @@ -418,6 +452,10 @@ public class BroadcastConstants { 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_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_DELAY_NORMAL_MILLIS, TimeUtils.formatDuration(DELAY_NORMAL_MILLIS)).println(); Loading
services/core/java/com/android/server/am/BroadcastProcessQueue.java +18 −0 Original line number Diff line number Diff line Loading @@ -142,6 +142,12 @@ class BroadcastProcessQueue { */ 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 * was scheduled via a cold start. Loading Loading @@ -499,6 +505,14 @@ class BroadcastProcessQueue { 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) { mActiveViaColdStart = activeViaColdStart; } Loading Loading @@ -532,6 +546,8 @@ class BroadcastProcessQueue { mActive = (BroadcastRecord) next.arg1; mActiveIndex = next.argi1; mActiveCountSinceIdle++; mActiveAssumedDeliveryCountSinceIdle += (mActive.isAssumedDelivered(mActiveIndex) ? 1 : 0); mActiveViaColdStart = false; mActiveWasStopped = false; next.recycle(); Loading @@ -545,6 +561,7 @@ class BroadcastProcessQueue { mActive = null; mActiveIndex = 0; mActiveCountSinceIdle = 0; mActiveAssumedDeliveryCountSinceIdle = 0; mActiveViaColdStart = false; invalidateRunnableAt(); } Loading Loading @@ -1369,6 +1386,7 @@ class BroadcastProcessQueue { pw.print(" m:"); pw.print(mCountManifest); pw.print(" csi:"); pw.print(mActiveCountSinceIdle); pw.print(" adcsi:"); pw.print(mActiveAssumedDeliveryCountSinceIdle); pw.print(" ccu:"); pw.print(mActiveCountConsecutiveUrgent); pw.print(" ccn:"); pw.print(mActiveCountConsecutiveNormal); pw.println(); Loading
services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +162 −95 Original line number Diff line number Diff line Loading @@ -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.isDeliveryStateTerminal; import android.annotation.CheckResult; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UptimeMillisLong; Loading Loading @@ -446,43 +447,29 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (DEBUG_BROADCAST) logv("Promoting " + queue + " from runnable to running; process is " + queue.app); // Allocate this available permit and start running! 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 promoteToRunningLocked(queue); final boolean completed; if (processWarm) { notifyStartedRunning(queue); updateOomAdj |= queue.runningOomAdjusted; } // 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); completed = scheduleReceiverWarmLocked(queue); } else { queue.traceProcessStartingBegin(); scheduleReceiverColdLocked(queue); completed = 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 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) { mService.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_RECEIVER); } Loading Loading @@ -514,7 +501,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue { queue.traceProcessEnd(); queue.traceProcessRunningBegin(); scheduleReceiverWarmLocked(queue); if (scheduleReceiverWarmLocked(queue)) { demoteFromRunningLocked(queue); } // We might be willing to kick off another cold start enqueueUpdateRunningList(); Loading Loading @@ -558,6 +547,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (queue.isActive()) { finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "onApplicationCleanupLocked"); demoteFromRunningLocked(queue); } // Skip any pending registered receivers, since the old process Loading Loading @@ -695,8 +685,13 @@ class BroadcastQueueModernImpl extends BroadcastQueue { * 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 * 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"); // Remember that active broadcast was scheduled via a cold start Loading @@ -711,12 +706,14 @@ class BroadcastQueueModernImpl extends BroadcastQueue { mRunningColdStart = null; finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, "BroadcastFilter for cold app"); return; return true; } if (maybeSkipReceiver(queue, r, index)) { final String skipReason = shouldSkipReceiver(queue, r, index); if (skipReason != null) { mRunningColdStart = null; return; finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_SKIPPED, skipReason); return true; } final ApplicationInfo info = ((ResolveInfo) receiver).activityInfo.applicationInfo; Loading @@ -742,8 +739,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue { mRunningColdStart = null; finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "startProcessLocked failed"); return; return true; } return false; } /** Loading @@ -754,11 +752,17 @@ class BroadcastQueueModernImpl extends BroadcastQueue { * 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 * 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") private void scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue) { private boolean scheduleReceiverWarmLocked(@NonNull BroadcastProcessQueue queue) { checkState(queue.isActive(), "isActive"); final int cookie = traceBegin("scheduleReceiverWarmLocked"); while (queue.isActive()) { final BroadcastRecord r = queue.getActive(); final int index = queue.getActiveIndex(); Loading @@ -768,24 +772,26 @@ class BroadcastQueueModernImpl extends BroadcastQueue { r.dispatchClockTime = System.currentTimeMillis(); } if (maybeSkipReceiver(queue, r, index)) { return; final String skipReason = shouldSkipReceiver(queue, r, index); 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); } /** * Examine a receiver and possibly skip it. The method returns true if the receiver is * 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; if (shouldRetire(queue)) { break; } return false; // We're on a roll; move onto the next broadcast for this process queue.makeActiveNextPending(); } traceEnd(cookie); return true; } /** Loading Loading @@ -825,25 +831,22 @@ class BroadcastQueueModernImpl extends BroadcastQueue { 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. * * @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) { final ProcessRecord app = queue.app; final Object receiver = r.receivers.get(index); // Skip ANR tracking early during boot, when requested, or when we // immediately assume delivery success final boolean assumeDelivered = isAssumedDelivered(r, index); final boolean assumeDelivered = r.isAssumedDelivered(index); if (mService.mProcessesReady && !r.timeoutExempt && !assumeDelivered) { queue.lastCpuDelayTime = queue.app.getCpuDelayTime(); Loading Loading @@ -898,6 +901,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (assumeDelivered) { finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_DELIVERED, "assuming delivered"); return false; } } else { notifyScheduleReceiver(app, r, (ResolveInfo) receiver); Loading @@ -908,17 +912,21 @@ class BroadcastQueueModernImpl extends BroadcastQueue { r.shareIdentity ? r.callingUid : Process.INVALID_UID, r.shareIdentity ? r.callerPackage : null); } return true; } catch (RemoteException e) { final String msg = "Failed to schedule " + r + " to " + receiver + " via " + app + ": " + e; logw(msg); app.killLocked("Can't deliver broadcast", ApplicationExitInfo.REASON_OTHER, ApplicationExitInfo.SUBREASON_UNDELIVERED_BROADCAST, true); finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app"); finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app"); return false; } } else { finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE, "missing IApplicationThread"); return false; } } Loading Loading @@ -989,6 +997,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { private void deliveryTimeoutHardLocked(@NonNull BroadcastProcessQueue queue) { finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT, "deliveryTimeoutHardLocked"); demoteFromRunningLocked(queue); } @Override Loading @@ -1015,7 +1024,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // To ensure that "beyond" high-water marks are updated in a monotonic // way, we finish this receiver before possibly skipping any remaining // aborted receivers final boolean res = finishReceiverActiveLocked(queue, finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_DELIVERED, "remote app"); // When the caller aborted an ordered broadcast, we mark all Loading @@ -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 // avoid starvation of other processes and stack overflow when a // 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); } return queue.isRunnable() && queue.isProcessWarm() && !shouldRetire; return !queue.isRunnable() || !queue.isProcessWarm() || shouldRetire; } /** * 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) { if (!queue.isActive()) { logw("Ignoring finish; no active broadcast for " + queue); return false; return; } final int cookie = traceBegin("finishReceiver"); Loading @@ -1077,12 +1108,50 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // Given that a receiver just finished, check if the "waitingFor" conditions are met. checkAndRemoveWaitingFor(); final boolean res = shouldContinueScheduling(queue); if (res) { // We're on a roll; move onto the next broadcast for this process traceEnd(cookie); } /** * 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(); scheduleReceiverWarmLocked(queue); 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(); Loading @@ -1095,9 +1164,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // Tell other OS components that app is not actively running, giving // a chance to update OOM adjustment notifyStoppedRunning(queue); } traceEnd(cookie); return res; } /** Loading
services/core/java/com/android/server/am/BroadcastRecord.java +8 −0 Original line number Diff line number Diff line Loading @@ -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. ComponentName curComponent; // the receiver class that is currently running. ActivityInfo curReceiver; // the manifest receiver that is currently running. Loading