diff options
| author | 2023-06-11 06:35:59 +0000 | |
|---|---|---|
| committer | 2023-06-11 06:35:59 +0000 | |
| commit | e12e7292f8631fad628e4dff9c9abb0ac06a8a8f (patch) | |
| tree | 9c9e507c8bcb486adb4f01a53ea752aba7eec24e | |
| parent | 9186bfb82532e5b7ed0544cefac8c82c470287b2 (diff) | |
| parent | 1af4c0d40e266024e11578d0cbb1a049012c6f48 (diff) | |
Merge "Relax delivery group policy constraints for resultTo bcasts." into udc-dev
| -rw-r--r-- | services/core/java/com/android/server/am/BroadcastQueueModernImpl.java | 53 | ||||
| -rw-r--r-- | services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java | 41 |
2 files changed, 85 insertions, 9 deletions
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index 397eef4216a1..76af50de0bd7 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -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; @@ -213,6 +215,13 @@ class BroadcastQueueModernImpl extends BroadcastQueue { 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}. * <p> @@ -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; } /** diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java index ccaaa87f8e06..f4238f678f08 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java @@ -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 @@ -1279,6 +1290,36 @@ public final class BroadcastQueueModernImplTest { } @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); final BroadcastOptions optionsCloseSystemDialog1 = BroadcastOptions.makeBasic() |