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

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

Merge "Prioritize earliest enqueued broadcasts in case of wait-for-barrier."

parents 71548300 90ee47d9
Loading
Loading
Loading
Loading
+18 −4
Original line number Diff line number Diff line
@@ -170,6 +170,8 @@ class BroadcastProcessQueue {
    private int mCountInstrumented;
    private int mCountManifest;

    private boolean mPrioritizeEarliest;

    private @UptimeMillisLong long mRunnableAt = Long.MAX_VALUE;
    private @Reason int mRunnableAtReason = REASON_EMPTY;
    private boolean mRunnableAtInvalidated;
@@ -605,8 +607,9 @@ class BroadcastProcessQueue {
        final BroadcastRecord nextLPRecord = (BroadcastRecord) nextLPArgs.arg1;
        final int nextLPRecordIndex = nextLPArgs.argi1;
        final BroadcastRecord nextHPRecord = (BroadcastRecord) highPriorityQueue.peekFirst().arg1;
        final boolean isLPQueueEligible =
                consecutiveHighPriorityCount >= maxHighPriorityDispatchLimit
        final boolean shouldConsiderLPQueue = (mPrioritizeEarliest
                || consecutiveHighPriorityCount >= maxHighPriorityDispatchLimit);
        final boolean isLPQueueEligible = shouldConsiderLPQueue
                && nextLPRecord.enqueueTime <= nextHPRecord.enqueueTime
                && !blockedOnOrderedDispatch(nextLPRecord, nextLPRecordIndex);
        return isLPQueueEligible ? lowPriorityQueue : highPriorityQueue;
@@ -616,6 +619,17 @@ class BroadcastProcessQueue {
        return (queue == null || queue.isEmpty());
    }

    /**
     * When {@code prioritizeEarliest} is set to {@code true}, then earliest enqueued
     * broadcasts would be prioritized for dispatching, even if there are urgent broadcasts
     * waiting. This is typically used in case there are callers waiting for "barrier" to be
     * reached.
     */
    @VisibleForTesting
    void setPrioritizeEarliest(boolean prioritizeEarliest) {
        mPrioritizeEarliest = prioritizeEarliest;
    }

    /**
     * Returns null if there are no pending broadcasts
     */
+19 −0
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
@@ -1224,6 +1225,17 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        return didSomething;
    }

    private void forEachQueue(@NonNull Consumer<BroadcastProcessQueue> consumer) {
        for (int i = 0; i < mProcessQueues.size(); ++i) {
            BroadcastProcessQueue leaf = mProcessQueues.valueAt(i);
            while (leaf != null) {
                consumer.accept(leaf);
                updateRunnableList(leaf);
                leaf = leaf.processNameNext;
            }
        }
    }

    @Override
    public void start(@NonNull ContentResolver resolver) {
        mFgConstants.startObserving(mHandler, resolver);
@@ -1282,12 +1294,19 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        final CountDownLatch latch = new CountDownLatch(1);
        synchronized (mService) {
            mWaitingFor.add(Pair.create(condition, latch));
            forEachQueue(q -> q.setPrioritizeEarliest(true));
        }
        enqueueUpdateRunningList();
        try {
            latch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            synchronized (mService) {
                if (mWaitingFor.isEmpty()) {
                    forEachQueue(q -> q.setPrioritizeEarliest(false));
                }
            }
        }
    }

+105 −36
Original line number Diff line number Diff line
@@ -195,6 +195,12 @@ public class BroadcastQueueModernImplTest {
                false, null, false, null);
    }

    private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue,
            BroadcastRecord record, int recordIndex, long enqueueTime) {
        queue.enqueueOrReplaceBroadcast(record, recordIndex);
        record.enqueueTime = enqueueTime;
    }

    @Test
    public void testRunnableList_Simple() {
        assertRunnableList(List.of(), mHead);
@@ -549,29 +555,32 @@ public class BroadcastQueueModernImplTest {
        mConstants.MAX_CONSECUTIVE_URGENT_DISPATCHES = 2;
        BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
                PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
        long timeCounter = 100;

        // mix of broadcasts, with more than 2 fg/urgent
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)), 0);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0);
        queue.enqueueOrReplaceBroadcast(
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)),
                        0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)),
                        0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0);
        queue.enqueueOrReplaceBroadcast(
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_APPLICATION_PREFERENCES),
                        optInteractive), 0);
        queue.enqueueOrReplaceBroadcast(
                        optInteractive), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE),
                        optInteractive), 0);
        queue.enqueueOrReplaceBroadcast(
                        optInteractive), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_INPUT_METHOD_CHANGED)
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0);
        queue.enqueueOrReplaceBroadcast(
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_NEW_OUTGOING_CALL),
                        optInteractive), 0);
                        optInteractive), 0, timeCounter++);

        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_LOCALE_CHANGED, queue.getActive().intent.getAction());
@@ -604,35 +613,38 @@ public class BroadcastQueueModernImplTest {
        mConstants.MAX_CONSECUTIVE_NORMAL_DISPATCHES = 2;
        final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
                PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
        long timeCounter = 100;

        // mix of broadcasts, with more than 2 normal
        queue.enqueueOrReplaceBroadcast(
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_BOOT_COMPLETED)
                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0);
        queue.enqueueOrReplaceBroadcast(
                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)),
                        0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_PACKAGE_CHANGED)
                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)), 0);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0);
        queue.enqueueOrReplaceBroadcast(
                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)),
                0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0);
        queue.enqueueOrReplaceBroadcast(
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_APPLICATION_PREFERENCES),
                        optInteractive), 0);
        queue.enqueueOrReplaceBroadcast(
                        optInteractive), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE),
                        optInteractive), 0);
        queue.enqueueOrReplaceBroadcast(
                        optInteractive), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_INPUT_METHOD_CHANGED)
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0);
        queue.enqueueOrReplaceBroadcast(
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_NEW_OUTGOING_CALL),
                        optInteractive), 0);
                        optInteractive), 0, timeCounter++);

        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_LOCALE_CHANGED, queue.getActive().intent.getAction());
@@ -658,6 +670,63 @@ public class BroadcastQueueModernImplTest {
        assertEquals(Intent.ACTION_INPUT_METHOD_CHANGED, queue.getActive().intent.getAction());
    }

    /**
     * Verify that BroadcastProcessQueue#setPrioritizeEarliest() works as expected.
     */
    @Test
    public void testPrioritizeEarliest() {
        final BroadcastOptions optInteractive = BroadcastOptions.makeBasic();
        optInteractive.setInteractive(true);

        BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
                PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
        queue.setPrioritizeEarliest(true);
        long timeCounter = 100;

        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_BOOT_COMPLETED)
                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)),
                        0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_PACKAGE_CHANGED)
                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)),
                        0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)),
                        0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, timeCounter++);
        enqueueOrReplaceBroadcast(queue,
                makeBroadcastRecord(new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE),
                        optInteractive), 0, timeCounter++);

        // When we mark BroadcastProcessQueue to prioritize earliest, we should
        // expect to dispatch broadcasts in the order they were enqueued
        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_BOOT_COMPLETED, queue.getActive().intent.getAction());
        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_TIMEZONE_CHANGED, queue.getActive().intent.getAction());
        // after MAX_CONSECUTIVE_URGENT_DISPATCHES expect an ordinary one next
        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_PACKAGE_CHANGED, queue.getActive().intent.getAction());
        // and then back to prioritizing urgent ones
        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_ALARM_CHANGED, queue.getActive().intent.getAction());
        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_TIME_TICK, queue.getActive().intent.getAction());
        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_LOCALE_CHANGED, queue.getActive().intent.getAction());
        // verify the reset-count-then-resume worked too
        queue.makeActiveNextPending();
        assertEquals(AppWidgetManager.ACTION_APPWIDGET_UPDATE,
                queue.getActive().intent.getAction());
    }

    /**
     * Verify that sending a broadcast that removes any matching pending
     * broadcasts is applied as expected.