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

Commit 56490373 authored by Christopher Tate's avatar Christopher Tate
Browse files

Don't allow bg traffic to stall urgent traffic

We now permit a tuneable degree of additional broadcast dispatch
parallelism in order to allow urgent traffic to proceed even if the
system is nominally fully occupied with non-urgent dispatches.

Bug: 251902289
Test: atest FrameworksMockingServicesTests:BroadcastQueueModernImplTest
Test: atest FrameworksMockingServicesTests:BroadcastQueueTest
Test: atest android.app.activity.BroadcastTest#testBroadcastOption_interactive
Change-Id: I3282d7f97b22e0fa520cda6a7c1abc9ab8233e11
parent 560f3927
Loading
Loading
Loading
Loading
+18 −2
Original line number Diff line number Diff line
@@ -136,14 +136,23 @@ public class BroadcastConstants {
    private static final boolean DEFAULT_MODERN_QUEUE_ENABLED = true;

    /**
     * For {@link BroadcastQueueModernImpl}: Maximum number of process queues to
     * dispatch broadcasts to simultaneously.
     * For {@link BroadcastQueueModernImpl}: Maximum dispatch parallelism
     * that we'll tolerate for ordinary broadcast dispatch.
     */
    public int MAX_RUNNING_PROCESS_QUEUES = DEFAULT_MAX_RUNNING_PROCESS_QUEUES;
    private static final String KEY_MAX_RUNNING_PROCESS_QUEUES = "bcast_max_running_process_queues";
    private static final int DEFAULT_MAX_RUNNING_PROCESS_QUEUES =
            ActivityManager.isLowRamDeviceStatic() ? 2 : 4;

    /**
     * For {@link BroadcastQueueModernImpl}: Additional running process queue parallelism beyond
     * {@link #MAX_RUNNING_PROCESS_QUEUES} for dispatch of "urgent" broadcasts.
     */
    public int EXTRA_RUNNING_URGENT_PROCESS_QUEUES = DEFAULT_EXTRA_RUNNING_URGENT_PROCESS_QUEUES;
    private static final String KEY_EXTRA_RUNNING_URGENT_PROCESS_QUEUES =
            "bcast_extra_running_urgent_process_queues";
    private static final int DEFAULT_EXTRA_RUNNING_URGENT_PROCESS_QUEUES = 1;

    /**
     * For {@link BroadcastQueueModernImpl}: Maximum number of active broadcasts
     * to dispatch to a "running" process queue before we retire them back to
@@ -250,6 +259,10 @@ public class BroadcastConstants {
        updateDeviceConfigConstants();
    }

    public int getMaxRunningQueues() {
        return MAX_RUNNING_PROCESS_QUEUES + EXTRA_RUNNING_URGENT_PROCESS_QUEUES;
    }

    private void updateSettingsConstants() {
        synchronized (this) {
            try {
@@ -317,6 +330,9 @@ public class BroadcastConstants {
                    DEFAULT_MODERN_QUEUE_ENABLED);
            MAX_RUNNING_PROCESS_QUEUES = getDeviceConfigInt(KEY_MAX_RUNNING_PROCESS_QUEUES,
                    DEFAULT_MAX_RUNNING_PROCESS_QUEUES);
            EXTRA_RUNNING_URGENT_PROCESS_QUEUES = getDeviceConfigInt(
                    KEY_EXTRA_RUNNING_URGENT_PROCESS_QUEUES,
                    DEFAULT_EXTRA_RUNNING_URGENT_PROCESS_QUEUES);
            MAX_RUNNING_ACTIVE_BROADCASTS = getDeviceConfigInt(KEY_MAX_RUNNING_ACTIVE_BROADCASTS,
                    DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS);
            MAX_PENDING_BROADCASTS = getDeviceConfigInt(KEY_MAX_PENDING_BROADCASTS,
+8 −0
Original line number Diff line number Diff line
@@ -583,6 +583,14 @@ class BroadcastProcessQueue {
        return mCountManifest > 0;
    }

    /**
     * Report whether this queue is currently handling an urgent broadcast.
     */
    public boolean isPendingUrgent() {
        BroadcastRecord next = peekNextBroadcastRecord();
        return (next != null) ? next.isUrgent() : false;
    }

    /**
     * Quickly determine if this queue has broadcasts that are still waiting to
     * be delivered at some point in the future.
+32 −2
Original line number Diff line number Diff line
@@ -138,7 +138,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {

        // We configure runnable size only once at boot; it'd be too complex to
        // try resizing dynamically at runtime
        mRunning = new BroadcastProcessQueue[mConstants.MAX_RUNNING_PROCESS_QUEUES];
        mRunning = new BroadcastProcessQueue[mConstants.getMaxRunningQueues()];
    }

    /**
@@ -292,6 +292,19 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        return size;
    }

    /**
     * Return the number of active queues that are delivering "urgent" broadcasts
     */
    private int getRunningUrgentCount() {
        int count = 0;
        for (int i = 0; i < mRunning.length; i++) {
            if (mRunning[i] != null && mRunning[i].getActive().isUrgent()) {
                count++;
            }
        }
        return count;
    }

    /**
     * Return the first index of the given value contained inside
     * {@link #mRunning}, otherwise {@code -1}.
@@ -356,7 +369,15 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
     */
    @GuardedBy("mService")
    private void updateRunningListLocked() {
        int avail = mRunning.length - getRunningSize();
        // Allocated size here implicitly includes the extra reservation for urgent
        // dispatches beyond the MAX_RUNNING_QUEUES soft limit for normal
        // parallelism.  If we're already dispatching some urgent broadcasts,
        // count that against the extra first - its role is to permit progress of
        // urgent broadcast traffic when the normal reservation is fully occupied
        // with less-urgent dispatches, not to generally expand parallelism.
        final int usedExtra = Math.min(getRunningUrgentCount(),
                mConstants.EXTRA_RUNNING_URGENT_PROCESS_QUEUES);
        int avail = mRunning.length - getRunningSize() - usedExtra;
        if (avail == 0) return;

        final int cookie = traceBegin("updateRunningList");
@@ -382,6 +403,15 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                continue;
            }

            // If we've hit the soft limit for non-urgent dispatch parallelism,
            // only consider delivering from queues whose ready broadcast is urgent
            if (getRunningSize() >= mConstants.MAX_RUNNING_PROCESS_QUEUES) {
                if (!queue.isPendingUrgent()) {
                    queue = nextQueue;
                    continue;
                }
            }

            // If queues beyond this point aren't ready to run yet, schedule
            // another pass when they'll be runnable
            if (runnableAt > now && !waitingFor) {