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

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

Merge "Replace only matching records when enqueuing a broadcast." into main

parents 337a6e55 8ff393d2
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -361,7 +361,8 @@ class BroadcastProcessQueue {
                    && (record.userId == testRecord.userId)
                    && record.intent.filterEquals(testRecord.intent)
                    && isReceiverEquals(receiver, testReceiver)
                    && testRecord.allReceiversPending()) {
                    && testRecord.allReceiversPending()
                    && record.isMatchingRecord(testRecord)) {
                // Exact match found; perform in-place swap
                args.arg1 = record;
                args.argi1 = recordIndex;
+17 −0
Original line number Diff line number Diff line
@@ -229,6 +229,14 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    private final AtomicReference<ArrayMap<BroadcastRecord, Boolean>> mRecordsLookupCache =
            new AtomicReference<>();

    /**
     * Container for holding the set of broadcast records that matches an enqueueing record.
     * @see BroadcastRecord#isMatchingRecord(BroadcastRecord)
     */
    @GuardedBy("mService")
    private final AtomicReference<ArrayMap<BroadcastRecord, Boolean>> mMatchingRecordsCache =
            new AtomicReference<>();

    /**
     * Map from UID to its last known "foreground" state. A UID is considered to be in
     * "foreground" state when it's procState is {@link ActivityManager#PROCESS_STATE_TOP}.
@@ -747,6 +755,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        if (replacedBroadcasts == null) {
            replacedBroadcasts = new ArraySet<>();
        }
        ArrayMap<BroadcastRecord, Boolean> matchingBroadcasts =
                mMatchingRecordsCache.getAndSet(null);
        if (matchingBroadcasts == null) {
            matchingBroadcasts = new ArrayMap<>();
        }
        r.setMatchingRecordsCache(matchingBroadcasts);
        boolean enqueuedBroadcast = false;

        for (int i = 0; i < r.receivers.size(); i++) {
@@ -780,6 +794,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
        skipAndCancelReplacedBroadcasts(replacedBroadcasts);
        replacedBroadcasts.clear();
        mReplacedBroadcastsCache.compareAndSet(null, replacedBroadcasts);
        matchingBroadcasts.clear();
        r.clearMatchingRecordsCache();
        mMatchingRecordsCache.compareAndSet(null, matchingBroadcasts);

        // If nothing to dispatch, send any pending result immediately
        if (r.receivers.isEmpty() || !enqueuedBroadcast) {
+33 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.PrintWriterPrinter;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -164,6 +165,11 @@ final class BroadcastRecord extends Binder {
    @Nullable
    final BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver;

    // Cache of records that are "matching" this. Only used at the time of enqueuing this record
    // into the queue.
    @Nullable
    private ArrayMap<BroadcastRecord, Boolean> mMatchingRecordsCache;

    private @Nullable String mCachedToString;
    private @Nullable String mCachedToShortString;

@@ -1250,6 +1256,33 @@ final class BroadcastRecord extends Binder {
        return (terminalCount == 0 && dispatchTime <= 0);
    }

    boolean isMatchingRecord(@NonNull BroadcastRecord record) {
        final int idx = mMatchingRecordsCache.indexOfKey(record);
        if (idx > 0) {
            return mMatchingRecordsCache.valueAt(idx);
        }
        // Consider a record to be matching if has the same receivers in the same order.
        boolean matches = (receivers.size() == record.receivers.size());
        if (matches) {
            for (int i = receivers.size() - 1; i >= 0; --i) {
                if (!isReceiverEquals(receivers.get(i), record.receivers.get(i))) {
                    matches = false;
                    break;
                }
            }
        }
        mMatchingRecordsCache.put(record, matches);
        return matches;
    }

    void setMatchingRecordsCache(@NonNull ArrayMap<BroadcastRecord, Boolean> matchingRecordsCache) {
        mMatchingRecordsCache = matchingRecordsCache;
    }

    void clearMatchingRecordsCache() {
        mMatchingRecordsCache = null;
    }

    @Override
    public String toString() {
        if (mCachedToString == null) {
+49 −4
Original line number Diff line number Diff line
@@ -1665,7 +1665,8 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest {
        enqueueBroadcast(makeBroadcastRecord(airplane, callerApp,
                List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_RED))));
        enqueueBroadcast(makeOrderedBroadcastRecord(timezoneSecond, callerApp,
                List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_GREEN)),
                List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE),
                        makeManifestReceiver(PACKAGE_BLUE, CLASS_GREEN)),
                resultToSecond, null));

        waitForIdle();
@@ -1681,6 +1682,11 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest {
                anyInt(), anyInt(), any());

        // We deliver second broadcast to app
        timezoneSecond.setClassName(PACKAGE_BLUE, CLASS_BLUE);
        inOrder.verify(blueThread).scheduleReceiver(
                argThat(filterAndExtrasEquals(timezoneSecond)), any(), any(),
                anyInt(), any(), any(), eq(true), eq(false), anyInt(),
                anyInt(), anyInt(), any());
        timezoneSecond.setClassName(PACKAGE_BLUE, CLASS_GREEN);
        inOrder.verify(blueThread).scheduleReceiver(
                argThat(filterAndExtrasEquals(timezoneSecond)), any(), any(),
@@ -1797,10 +1803,16 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest {

        waitForIdle();

        if (mImpl == Impl.MODERN) {
            verifyScheduleRegisteredReceiver(times(2), receiverGreenApp, airplane);
            verifyScheduleRegisteredReceiver(times(2), receiverBlueApp, airplane);
            verifyScheduleRegisteredReceiver(times(1), receiverYellowApp, airplane);
        } else {
            verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, airplane);
            verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, airplane);
            verifyScheduleRegisteredReceiver(never(), receiverYellowApp, airplane);
        }
    }

    @Test
    public void testReplacePending_sameProcess_diffReceivers() throws Exception {
@@ -1829,6 +1841,39 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest {
        }
    }

    @Test
    public void testReplacePending_existingDiffReceivers() throws Exception {
        final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
        final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN);
        final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
        final BroadcastFilter receiverGreen = makeRegisteredReceiver(receiverGreenApp);
        final BroadcastFilter receiverBlue = makeRegisteredReceiver(receiverBlueApp);

        final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED)
                .addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
        final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);

        enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, List.of(
                withPriority(receiverGreen, 5))));
        enqueueBroadcast(makeBroadcastRecord(timeTick, callerApp, List.of(
                withPriority(receiverGreen, 10),
                withPriority(receiverBlue, 5))));
        enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, List.of(
                withPriority(receiverBlue, 10),
                withPriority(receiverGreen, 5))));

        waitForIdle();

        verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, timeTick);
        verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, timeTick);
        if (mImpl == Impl.MODERN) {
            verifyScheduleRegisteredReceiver(times(2), receiverGreenApp, airplane);
        } else {
            verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, airplane);
        }
        verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, airplane);
    }

    @Test
    public void testIdleAndBarrier() throws Exception {
        final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);