Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dad2f513 authored by Sudheer Shanka's avatar Sudheer Shanka Committed by Android (Google) Code Review
Browse files

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

parents 7981d137 80566f8e
Loading
Loading
Loading
Loading
+39 −1
Original line number Diff line number Diff line
@@ -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
@@ -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,
@@ -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();
+18 −0
Original line number Diff line number Diff line
@@ -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.
@@ -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;
    }
@@ -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();
@@ -545,6 +561,7 @@ class BroadcastProcessQueue {
        mActive = null;
        mActiveIndex = 0;
        mActiveCountSinceIdle = 0;
        mActiveAssumedDeliveryCountSinceIdle = 0;
        mActiveViaColdStart = false;
        invalidateRunnableAt();
    }
@@ -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();
+162 −95
Original line number Diff line number Diff line
@@ -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;
@@ -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);
        }
@@ -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();
@@ -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
@@ -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
@@ -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;
@@ -742,8 +739,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
            mRunningColdStart = null;
            finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
                    "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
     * 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();

@@ -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;
    }

    /**
@@ -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();

@@ -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);
@@ -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;
        }
    }

@@ -989,6 +997,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    private void deliveryTimeoutHardLocked(@NonNull BroadcastProcessQueue queue) {
        finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT,
                "deliveryTimeoutHardLocked");
        demoteFromRunningLocked(queue);
    }

    @Override
@@ -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
@@ -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");
@@ -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();
@@ -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;
    }

    /**
+8 −0
Original line number Diff line number Diff line
@@ -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.