summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Sudheer Shanka <sudheersai@google.com> 2023-06-11 06:35:59 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-06-11 06:35:59 +0000
commite12e7292f8631fad628e4dff9c9abb0ac06a8a8f (patch)
tree9c9e507c8bcb486adb4f01a53ea752aba7eec24e
parent9186bfb82532e5b7ed0544cefac8c82c470287b2 (diff)
parent1af4c0d40e266024e11578d0cbb1a049012c6f48 (diff)
Merge "Relax delivery group policy constraints for resultTo bcasts." into udc-dev
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueueModernImpl.java53
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java41
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()