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

Commit fbfdf88b authored by Sudheer Shanka's avatar Sudheer Shanka Committed by Automerger Merge Worker
Browse files

Merge "Relax delivery group policy constraints for resultTo bcasts." into udc-dev am: e12e7292

parents 9322e0e9 e12e7292
Loading
Loading
Loading
Loading
+44 −9
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.LOG_WRITER_INFO;
import static com.android.server.am.BroadcastProcessQueue.insertIntoRunnableList;
import static com.android.server.am.BroadcastProcessQueue.reasonToString;
import static com.android.server.am.BroadcastProcessQueue.removeFromRunnableList;
import static com.android.server.am.BroadcastRecord.DELIVERY_DEFERRED;
import static com.android.server.am.BroadcastRecord.deliveryStateToString;
import static com.android.server.am.BroadcastRecord.getReceiverClassName;
import static com.android.server.am.BroadcastRecord.getReceiverPackageName;
@@ -68,6 +69,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.MathUtils;
@@ -212,6 +214,13 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
    private final AtomicReference<ArraySet<BroadcastRecord>> mReplacedBroadcastsCache =
            new AtomicReference<>();

    /**
     * Container for holding the set of broadcast records that satisfied a certain criteria.
     */
    @GuardedBy("mService")
    private final AtomicReference<ArrayMap<BroadcastRecord, Boolean>> mRecordsLookupCache =
            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}.
@@ -742,13 +751,16 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                broadcastConsumer = mBroadcastConsumerSkipAndCanceled;
                break;
            case BroadcastOptions.DELIVERY_GROUP_POLICY_MERGED:
                // TODO: Allow applying MERGED policy for broadcasts with more than one receiver.
                if (r.receivers.size() > 1) {
                    return;
                }
                final BundleMerger extrasMerger = r.options.getDeliveryGroupExtrasMerger();
                if (extrasMerger == null) {
                    // Extras merger is required to be able to merge the extras. So, if it's not
                    // supplied, then ignore the delivery group policy.
                    return;
                }
                // TODO: Don't merge with the same BroadcastRecord more than once.
                broadcastConsumer = (record, recordIndex) -> {
                    r.intent.mergeExtras(record.intent, extrasMerger);
                    mBroadcastConsumerSkipAndCanceled.accept(record, recordIndex);
@@ -758,6 +770,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                logw("Unknown delivery group policy: " + policy);
                return;
        }
        final ArrayMap<BroadcastRecord, Boolean> recordsLookupCache = getRecordsLookupCache();
        forEachMatchingBroadcast(QUEUE_PREDICATE_ANY, (testRecord, testIndex) -> {
            // If the receiver is already in a terminal state, then ignore it.
            if (isDeliveryStateTerminal(testRecord.getDeliveryState(testIndex))) {
@@ -769,22 +782,44 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
                    || !r.matchesDeliveryGroup(testRecord)) {
                return false;
            }
            // TODO: If a process is in a deferred state, we can always apply the policy as long
            // as it is one of the receivers for the new broadcast.

            // For ordered broadcast, check if the receivers for the new broadcast is a superset
            // of those for the previous one as skipping and removing only one of them could result
            // in an inconsistent state.
            if (testRecord.ordered || testRecord.resultTo != null) {
                // TODO: Cache this result in some way so that we don't have to perform the
                // same check for all the broadcast receivers.
                return r.containsAllReceivers(testRecord.receivers);
            } else if (testRecord.prioritized) {
                return r.containsAllReceivers(testRecord.receivers);
            if (testRecord.ordered || testRecord.prioritized) {
                return containsAllReceivers(r, testRecord, recordsLookupCache);
            } else if (testRecord.resultTo != null) {
                return testRecord.getDeliveryState(testIndex) == DELIVERY_DEFERRED
                        ? r.containsReceiver(testRecord.receivers.get(testIndex))
                        : containsAllReceivers(r, testRecord, recordsLookupCache);
            } else {
                return r.containsReceiver(testRecord.receivers.get(testIndex));
            }
        }, broadcastConsumer, true);
        recordsLookupCache.clear();
        mRecordsLookupCache.compareAndSet(null, recordsLookupCache);
    }

    @NonNull
    private ArrayMap<BroadcastRecord, Boolean> getRecordsLookupCache() {
        ArrayMap<BroadcastRecord, Boolean> recordsLookupCache =
                mRecordsLookupCache.getAndSet(null);
        if (recordsLookupCache == null) {
            recordsLookupCache = new ArrayMap<>();
        }
        return recordsLookupCache;
    }

    private boolean containsAllReceivers(@NonNull BroadcastRecord record,
            @NonNull BroadcastRecord testRecord,
            @NonNull ArrayMap<BroadcastRecord, Boolean> recordsLookupCache) {
        final int idx = recordsLookupCache.indexOfKey(testRecord);
        if (idx > 0) {
            return recordsLookupCache.valueAt(idx);
        }
        final boolean containsAll = record.containsAllReceivers(testRecord.receivers);
        recordsLookupCache.put(testRecord, containsAll);
        return containsAll;
    }

    /**
+41 −0
Original line number Diff line number Diff line
@@ -1094,6 +1094,17 @@ public final class BroadcastQueueModernImplTest {
        verifyPendingRecords(greenQueue, List.of(screenOff, screenOn));
        verifyPendingRecords(redQueue, List.of(screenOff));
        verifyPendingRecords(blueQueue, List.of(screenOff, screenOn));

        final BroadcastRecord screenOffRecord = makeBroadcastRecord(screenOff, screenOnOffOptions,
                List.of(greenReceiver, redReceiver, blueReceiver), resultTo, false);
        screenOffRecord.setDeliveryState(2, BroadcastRecord.DELIVERY_DEFERRED,
                "testDeliveryGroupPolicy_resultTo_diffReceivers");
        mImpl.enqueueBroadcastLocked(screenOffRecord);
        mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOn, screenOnOffOptions,
                List.of(greenReceiver, blueReceiver), resultTo, false));
        verifyPendingRecords(greenQueue, List.of(screenOff, screenOn));
        verifyPendingRecords(redQueue, List.of(screenOff));
        verifyPendingRecords(blueQueue, List.of(screenOn));
    }

    @Test
@@ -1278,6 +1289,36 @@ public final class BroadcastQueueModernImplTest {
                dropboxEntryBroadcast2.first, expectedMergedBroadcast.first));
    }

    @Test
    public void testDeliveryGroupPolicy_merged_multipleReceivers() {
        final long now = SystemClock.elapsedRealtime();
        final Pair<Intent, BroadcastOptions> dropboxEntryBroadcast1 = createDropboxBroadcast(
                "TAG_A", now, 2);
        final Pair<Intent, BroadcastOptions> dropboxEntryBroadcast2 = createDropboxBroadcast(
                "TAG_A", now + 1000, 4);

        mImpl.enqueueBroadcastLocked(makeBroadcastRecord(dropboxEntryBroadcast1.first,
                dropboxEntryBroadcast1.second,
                List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
                        makeManifestReceiver(PACKAGE_RED, CLASS_RED)),
                false));
        mImpl.enqueueBroadcastLocked(makeBroadcastRecord(dropboxEntryBroadcast2.first,
                dropboxEntryBroadcast2.second,
                List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
                        makeManifestReceiver(PACKAGE_RED, CLASS_RED)),
                false));

        final BroadcastProcessQueue greenQueue = mImpl.getProcessQueue(PACKAGE_GREEN,
                getUidForPackage(PACKAGE_GREEN));
        final BroadcastProcessQueue redQueue = mImpl.getProcessQueue(PACKAGE_RED,
                getUidForPackage(PACKAGE_RED));

        verifyPendingRecords(greenQueue,
                List.of(dropboxEntryBroadcast1.first, dropboxEntryBroadcast2.first));
        verifyPendingRecords(redQueue,
                List.of(dropboxEntryBroadcast1.first, dropboxEntryBroadcast2.first));
    }

    @Test
    public void testDeliveryGroupPolicy_sameAction_differentMatchingCriteria() {
        final Intent closeSystemDialogs1 = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);