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

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

Merge "Avoid new allocations in enqueueBroadcastRecord()."

parents 79ba403f bdca950f
Loading
Loading
Loading
Loading
+28 −21
Original line number Diff line number Diff line
@@ -229,14 +229,19 @@ class BroadcastProcessQueue {
     * When defined, this receiver is considered "blocked" until at least the
     * given count of other receivers have reached a terminal state; typically
     * used for ordered broadcasts and priority traunches.
     *
     * @return the existing broadcast record in the queue that was replaced with a newer broadcast
     *         sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING} or {@code null} if there
     *         wasn't any broadcast that was replaced.
     */
    public void enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
            @NonNull BroadcastConsumer replacedBroadcastConsumer, boolean wouldBeSkipped) {
    @Nullable
    public BroadcastRecord enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record,
            int recordIndex, boolean wouldBeSkipped) {
        if (record.isReplacePending()) {
            final boolean didReplace = replaceBroadcast(record, recordIndex,
                    replacedBroadcastConsumer, wouldBeSkipped);
            if (didReplace) {
                return;
            final BroadcastRecord replacedBroadcastRecord = replaceBroadcast(record, recordIndex,
                    wouldBeSkipped);
            if (replacedBroadcastRecord != null) {
                return replacedBroadcastRecord;
            }
        }

@@ -253,34 +258,37 @@ class BroadcastProcessQueue {
        // with implicit responsiveness expectations.
        getQueueForBroadcast(record).addLast(newBroadcastArgs);
        onBroadcastEnqueued(record, recordIndex, wouldBeSkipped);
        return null;
    }

    /**
     * Searches from newest to oldest in the pending broadcast queues, and at the first matching
     * pending broadcast it finds, replaces it in-place and returns -- does not attempt to handle
     * "duplicate" broadcasts in the queue.
     * <p>
     * @return {@code true} if it found and replaced an existing record in the queue;
     * {@code false} otherwise.
     *
     * @return the existing broadcast record in the queue that was replaced with a newer broadcast
     *         sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING} or {@code null} if there
     *         wasn't any broadcast that was replaced.
     */
    private boolean replaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
            @NonNull BroadcastConsumer replacedBroadcastConsumer, boolean wouldBeSkipped) {
    @Nullable
    private BroadcastRecord replaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
            boolean wouldBeSkipped) {
        final ArrayDeque<SomeArgs> queue = getQueueForBroadcast(record);
        return replaceBroadcastInQueue(queue, record, recordIndex,
                replacedBroadcastConsumer, wouldBeSkipped);
        return replaceBroadcastInQueue(queue, record, recordIndex, wouldBeSkipped);
    }

    /**
     * Searches from newest to oldest, and at the first matching pending broadcast
     * it finds, replaces it in-place and returns -- does not attempt to handle
     * "duplicate" broadcasts in the queue.
     * <p>
     * @return {@code true} if it found and replaced an existing record in the queue;
     * {@code false} otherwise.
     *
     * @return the existing broadcast record in the queue that was replaced with a newer broadcast
     *         sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING} or {@code null} if there
     *         wasn't any broadcast that was replaced.
     */
    private boolean replaceBroadcastInQueue(@NonNull ArrayDeque<SomeArgs> queue,
    @Nullable
    private BroadcastRecord replaceBroadcastInQueue(@NonNull ArrayDeque<SomeArgs> queue,
            @NonNull BroadcastRecord record, int recordIndex,
            @NonNull BroadcastConsumer replacedBroadcastConsumer,
            boolean wouldBeSkipped) {
        final Iterator<SomeArgs> it = queue.descendingIterator();
        final Object receiver = record.receivers.get(recordIndex);
@@ -302,11 +310,10 @@ class BroadcastProcessQueue {
                record.copyEnqueueTimeFrom(testRecord);
                onBroadcastDequeued(testRecord, testRecordIndex, testWouldBeSkipped);
                onBroadcastEnqueued(record, recordIndex, wouldBeSkipped);
                replacedBroadcastConsumer.accept(testRecord, testRecordIndex);
                return true;
                return testRecord;
            }
        }
        return false;
        return null;
    }

    /**
+22 −4
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ import java.util.Arrays;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -204,6 +205,14 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    @GuardedBy("mService")
    private final ArrayList<Pair<BooleanSupplier, CountDownLatch>> mWaitingFor = new ArrayList<>();

    /**
     * Container for holding the set of broadcasts that have been replaced by a newer broadcast
     * sent with {@link Intent#FLAG_RECEIVER_REPLACE_PENDING}.
     */
    @GuardedBy("mService")
    private final AtomicReference<ArraySet<BroadcastRecord>> mReplacedBroadcastsCache =
            new AtomicReference<>();

    private final BroadcastConstants mConstants;
    private final BroadcastConstants mFgConstants;
    private final BroadcastConstants mBgConstants;
@@ -627,9 +636,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        r.enqueueRealTime = SystemClock.elapsedRealtime();
        r.enqueueClockTime = System.currentTimeMillis();

        final ArraySet<BroadcastRecord> replacedBroadcasts = new ArraySet<>();
        final BroadcastConsumer replacedBroadcastConsumer =
                (record, i) -> replacedBroadcasts.add(record);
        ArraySet<BroadcastRecord> replacedBroadcasts = mReplacedBroadcastsCache.getAndSet(null);
        if (replacedBroadcasts == null) {
            replacedBroadcasts = new ArraySet<>();
        }
        boolean enqueuedBroadcast = false;

        for (int i = 0; i < r.receivers.size(); i++) {
@@ -653,7 +663,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                }
            }
            enqueuedBroadcast = true;
            queue.enqueueOrReplaceBroadcast(r, i, replacedBroadcastConsumer, wouldBeSkipped);
            final BroadcastRecord replacedBroadcast = queue.enqueueOrReplaceBroadcast(
                    r, i, wouldBeSkipped);
            if (replacedBroadcast != null) {
                replacedBroadcasts.add(replacedBroadcast);
            }
            if (r.isDeferUntilActive() && queue.isDeferredUntilActive()) {
                setDeliveryState(queue, null, r, i, receiver, BroadcastRecord.DELIVERY_DEFERRED,
                        "deferred at enqueue time");
@@ -664,7 +678,11 @@ class BroadcastQueueModernImpl extends BroadcastQueue {

        // Skip any broadcasts that have been replaced by newer broadcasts with
        // FLAG_RECEIVER_REPLACE_PENDING.
        // TODO: Optimize and reuse mBroadcastConsumerSkipAndCanceled for the case of
        // cancelling all receivers for a broadcast.
        skipAndCancelReplacedBroadcasts(replacedBroadcasts);
        replacedBroadcasts.clear();
        mReplacedBroadcastsCache.compareAndSet(null, replacedBroadcasts);

        // If nothing to dispatch, send any pending result immediately
        if (r.receivers.isEmpty() || !enqueuedBroadcast) {
+14 −28
Original line number Diff line number Diff line
@@ -223,8 +223,7 @@ public class BroadcastQueueModernImplTest {

    private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue,
            BroadcastRecord record, int recordIndex, long enqueueTime) {
        queue.enqueueOrReplaceBroadcast(record, recordIndex,
                null /* replacedBroadcastConsumer */, false);
        queue.enqueueOrReplaceBroadcast(record, recordIndex, false);
        record.enqueueTime = enqueueTime;
    }

@@ -354,8 +353,7 @@ public class BroadcastQueueModernImplTest {
        final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane,
                List.of(makeMockRegisteredReceiver()));
        queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
                null /* replacedBroadcastConsumer */, false);
        queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false);

        queue.setProcessCached(false);
        final long notCachedRunnableAt = queue.getRunnableAt();
@@ -377,14 +375,12 @@ public class BroadcastQueueModernImplTest {
        // enqueue a bg-priority broadcast then a fg-priority one
        final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
        final BroadcastRecord timezoneRecord = makeBroadcastRecord(timezone);
        queue.enqueueOrReplaceBroadcast(timezoneRecord, 0,
                null /* replacedBroadcastConsumer */, false);
        queue.enqueueOrReplaceBroadcast(timezoneRecord, 0, false);

        final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        airplane.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane);
        queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
                null /* replacedBroadcastConsumer */, false);
        queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false);

        // verify that:
        // (a) the queue is immediately runnable by existence of a fg-priority broadcast
@@ -415,8 +411,7 @@ public class BroadcastQueueModernImplTest {
        final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, null,
                List.of(withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 10),
                        withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 0)), true);
        queue.enqueueOrReplaceBroadcast(airplaneRecord, 1,
                null /* replacedBroadcastConsumer */, false);
        queue.enqueueOrReplaceBroadcast(airplaneRecord, 1, false);

        assertFalse(queue.isRunnable());
        assertEquals(BroadcastProcessQueue.REASON_BLOCKED, queue.getRunnableAtReason());
@@ -439,8 +434,7 @@ public class BroadcastQueueModernImplTest {
        final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane,
                List.of(makeMockRegisteredReceiver()));
        queue.enqueueOrReplaceBroadcast(airplaneRecord, 0,
                null /* replacedBroadcastConsumer */, false);
        queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false);

        mConstants.MAX_PENDING_BROADCASTS = 128;
        queue.invalidateRunnableAt();
@@ -466,13 +460,11 @@ public class BroadcastQueueModernImplTest {
                new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED),
                List.of(makeMockRegisteredReceiver()));

        queue.enqueueOrReplaceBroadcast(lazyRecord, 0,
                null /* replacedBroadcastConsumer */, false);
        queue.enqueueOrReplaceBroadcast(lazyRecord, 0, false);
        assertThat(queue.getRunnableAt()).isGreaterThan(lazyRecord.enqueueTime);
        assertThat(queue.getRunnableAtReason()).isNotEqualTo(testRunnableAtReason);

        queue.enqueueOrReplaceBroadcast(testRecord, 0,
                null /* replacedBroadcastConsumer */, false);
        queue.enqueueOrReplaceBroadcast(testRecord, 0, false);
        assertThat(queue.getRunnableAt()).isAtMost(testRecord.enqueueTime);
        assertThat(queue.getRunnableAtReason()).isEqualTo(testRunnableAtReason);
    }
@@ -534,26 +526,20 @@ public class BroadcastQueueModernImplTest {

        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED)
                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0,
                null /* replacedBroadcastConsumer */, false);
                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, false);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0,
                null /* replacedBroadcastConsumer */, false);
                makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0, false);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED)
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0,
                null /* replacedBroadcastConsumer */, false);
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, false);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)
                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0,
                null /* replacedBroadcastConsumer */, false);
                        .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, false);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0,
                null /* replacedBroadcastConsumer */, false);
                makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0, false);
        queue.enqueueOrReplaceBroadcast(
                makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0,
                null /* replacedBroadcastConsumer */, false);
                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, false);

        queue.makeActiveNextPending();
        assertEquals(Intent.ACTION_LOCKED_BOOT_COMPLETED, queue.getActive().intent.getAction());