diff options
4 files changed, 225 insertions, 87 deletions
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java index 9a93e1b9e1f9..d06b0ce1a2d8 100644 --- a/core/java/android/util/TimeUtils.java +++ b/core/java/android/util/TimeUtils.java @@ -354,6 +354,15 @@ public class TimeUtils { } /** @hide Just for debugging; not internationalized. */ + public static void formatDuration(long time, long now, StringBuilder sb) { + if (time == 0) { + sb.append("--"); + return; + } + formatDuration(time-now, sb, 0); + } + + /** @hide Just for debugging; not internationalized. */ public static void formatDuration(long time, long now, PrintWriter pw) { if (time == 0) { pw.print("--"); diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index 9e61ce405ca7..0767218ec065 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -20,6 +20,7 @@ import static com.android.internal.util.Preconditions.checkState; import static com.android.server.am.BroadcastRecord.deliveryStateToString; import static com.android.server.am.BroadcastRecord.isReceiverEquals; +import android.annotation.CheckResult; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -187,6 +188,12 @@ class BroadcastProcessQueue { private @Reason int mRunnableAtReason = REASON_EMPTY; private boolean mRunnableAtInvalidated; + /** + * Last state applied by {@link #updateDeferredStates}, used to quickly + * determine if a state transition is occurring. + */ + private boolean mLastDeferredStates; + private boolean mUidCached; private boolean mProcessInstrumented; private boolean mProcessPersistent; @@ -235,7 +242,15 @@ class BroadcastProcessQueue { */ @Nullable public BroadcastRecord enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record, - int recordIndex, boolean wouldBeSkipped) { + int recordIndex, boolean wouldBeSkipped, + @NonNull BroadcastConsumer deferredStatesApplyConsumer) { + // When updateDeferredStates() has already applied a deferred state to + // all pending items, apply to this new broadcast too + if (mLastDeferredStates && record.deferUntilActive + && (record.getDeliveryState(recordIndex) == BroadcastRecord.DELIVERY_PENDING)) { + deferredStatesApplyConsumer.accept(record, recordIndex); + } + if (record.isReplacePending()) { final BroadcastRecord replacedBroadcastRecord = replaceBroadcast(record, recordIndex, wouldBeSkipped); @@ -340,7 +355,12 @@ class BroadcastProcessQueue { * Predicates that choose to remove a broadcast <em>must</em> finish * delivery of the matched broadcast, to ensure that situations like ordered * broadcasts are handled consistently. + * + * @return if this operation may have changed internal state, indicating + * that the caller is responsible for invoking + * {@link BroadcastQueueModernImpl#updateRunnableList} */ + @CheckResult public boolean forEachMatchingBroadcast(@NonNull BroadcastPredicate predicate, @NonNull BroadcastConsumer consumer, boolean andRemove) { boolean didSomething = false; @@ -353,6 +373,7 @@ class BroadcastProcessQueue { return didSomething; } + @CheckResult private boolean forEachMatchingBroadcastInQueue(@NonNull ArrayDeque<SomeArgs> queue, @NonNull BroadcastPredicate predicate, @NonNull BroadcastConsumer consumer, boolean andRemove) { @@ -369,6 +390,10 @@ class BroadcastProcessQueue { args.recycle(); it.remove(); onBroadcastDequeued(record, recordIndex, recordWouldBeSkipped); + } else { + // Even if we're leaving broadcast in queue, it may have + // been mutated in such a way to change our runnable time + invalidateRunnableAt(); } didSomething = true; } @@ -380,32 +405,44 @@ class BroadcastProcessQueue { /** * Update the actively running "warm" process for this process. + * + * @return if this operation may have changed internal state, indicating + * that the caller is responsible for invoking + * {@link BroadcastQueueModernImpl#updateRunnableList} */ - public void setProcessAndUidCached(@Nullable ProcessRecord app, boolean uidCached) { + @CheckResult + public boolean setProcessAndUidCached(@Nullable ProcessRecord app, boolean uidCached) { this.app = app; - if (app != null) { - setUidCached(uidCached); - setProcessInstrumented(app.getActiveInstrumentation() != null); - setProcessPersistent(app.isPersistent()); - } else { - setUidCached(uidCached); - setProcessInstrumented(false); - setProcessPersistent(false); - } // Since we may have just changed our PID, invalidate cached strings mCachedToString = null; mCachedToShortString = null; + + boolean didSomething = false; + if (app != null) { + didSomething |= setUidCached(uidCached); + didSomething |= setProcessInstrumented(app.getActiveInstrumentation() != null); + didSomething |= setProcessPersistent(app.isPersistent()); + } else { + didSomething |= setUidCached(uidCached); + didSomething |= setProcessInstrumented(false); + didSomething |= setProcessPersistent(false); + } + return didSomething; } /** * Update if this process is in the "cached" state, typically signaling that * broadcast dispatch should be paused or delayed. */ - private void setUidCached(boolean uidCached) { + @CheckResult + private boolean setUidCached(boolean uidCached) { if (mUidCached != uidCached) { mUidCached = uidCached; invalidateRunnableAt(); + return true; + } else { + return false; } } @@ -414,10 +451,14 @@ class BroadcastProcessQueue { * signaling that broadcast dispatch should bypass all pauses or delays, to * avoid holding up test suites. */ - private void setProcessInstrumented(boolean instrumented) { + @CheckResult + private boolean setProcessInstrumented(boolean instrumented) { if (mProcessInstrumented != instrumented) { mProcessInstrumented = instrumented; invalidateRunnableAt(); + return true; + } else { + return false; } } @@ -425,10 +466,14 @@ class BroadcastProcessQueue { * Update if this process is in the "persistent" state, which signals broadcast dispatch should * bypass all pauses or delays to prevent the system from becoming out of sync with itself. */ - private void setProcessPersistent(boolean persistent) { + @CheckResult + private boolean setProcessPersistent(boolean persistent) { if (mProcessPersistent != persistent) { mProcessPersistent = persistent; invalidateRunnableAt(); + return true; + } else { + return false; } } @@ -648,8 +693,20 @@ class BroadcastProcessQueue { return mActive != null; } - void forceDelayBroadcastDelivery(long delayedDurationMs) { - mForcedDelayedDurationMs = delayedDurationMs; + /** + * @return if this operation may have changed internal state, indicating + * that the caller is responsible for invoking + * {@link BroadcastQueueModernImpl#updateRunnableList} + */ + @CheckResult + boolean forceDelayBroadcastDelivery(long delayedDurationMs) { + if (mForcedDelayedDurationMs != delayedDurationMs) { + mForcedDelayedDurationMs = delayedDurationMs; + invalidateRunnableAt(); + return true; + } else { + return false; + } } /** @@ -721,10 +778,21 @@ class BroadcastProcessQueue { * broadcasts would be prioritized for dispatching, even if there are urgent broadcasts * waiting. This is typically used in case there are callers waiting for "barrier" to be * reached. + * + * @return if this operation may have changed internal state, indicating + * that the caller is responsible for invoking + * {@link BroadcastQueueModernImpl#updateRunnableList} */ + @CheckResult @VisibleForTesting - void setPrioritizeEarliest(boolean prioritizeEarliest) { - mPrioritizeEarliest = prioritizeEarliest; + boolean setPrioritizeEarliest(boolean prioritizeEarliest) { + if (mPrioritizeEarliest != prioritizeEarliest) { + mPrioritizeEarliest = prioritizeEarliest; + invalidateRunnableAt(); + return true; + } else { + return false; + } } /** @@ -912,9 +980,9 @@ class BroadcastProcessQueue { } /** - * Update {@link #getRunnableAt()} if it's currently invalidated. + * Update {@link #getRunnableAt()}, when needed. */ - private void updateRunnableAt() { + void updateRunnableAt() { if (!mRunnableAtInvalidated) return; mRunnableAtInvalidated = false; @@ -1027,10 +1095,44 @@ class BroadcastProcessQueue { } /** + * Update {@link BroadcastRecord.DELIVERY_DEFERRED} states of all our + * pending broadcasts, when needed. + */ + void updateDeferredStates(@NonNull BroadcastConsumer applyConsumer, + @NonNull BroadcastConsumer clearConsumer) { + // When all we have pending is deferred broadcasts, and we're cached, + // then we want everything to be marked deferred + final boolean wantDeferredStates = (mCountDeferred > 0) + && (mCountDeferred == mCountEnqueued) && mUidCached; + + if (mLastDeferredStates != wantDeferredStates) { + mLastDeferredStates = wantDeferredStates; + if (wantDeferredStates) { + forEachMatchingBroadcast((r, i) -> { + return r.deferUntilActive + && (r.getDeliveryState(i) == BroadcastRecord.DELIVERY_PENDING); + }, applyConsumer, false); + } else { + forEachMatchingBroadcast((r, i) -> { + return r.deferUntilActive + && (r.getDeliveryState(i) == BroadcastRecord.DELIVERY_DEFERRED); + }, clearConsumer, false); + } + } + } + + /** * Check overall health, confirming things are in a reasonable state and * that we're not wedged. */ public void assertHealthLocked() { + // If we're not actively running, we should be sorted into the runnable + // list, and if we're invalidated then someone likely forgot to invoke + // updateRunnableList() to re-sort us into place + if (!isActive()) { + checkState(!mRunnableAtInvalidated, "mRunnableAtInvalidated"); + } + assertHealthLocked(mPending); assertHealthLocked(mPendingUrgent); assertHealthLocked(mPendingOffload); @@ -1133,19 +1235,30 @@ class BroadcastProcessQueue { return mCachedToShortString; } + public String describeStateLocked() { + return describeStateLocked(SystemClock.uptimeMillis()); + } + + public String describeStateLocked(@UptimeMillisLong long now) { + final StringBuilder sb = new StringBuilder(); + if (isRunnable()) { + sb.append("runnable at "); + TimeUtils.formatDuration(getRunnableAt(), now, sb); + } else { + sb.append("not runnable"); + } + sb.append(" because "); + sb.append(reasonToString(mRunnableAtReason)); + return sb.toString(); + } + @NeverCompile public void dumpLocked(@UptimeMillisLong long now, @NonNull IndentingPrintWriter pw) { if ((mActive == null) && isEmpty()) return; pw.print(toShortString()); - if (isRunnable()) { - pw.print(" runnable at "); - TimeUtils.formatDuration(getRunnableAt(), now, pw); - } else { - pw.print(" not runnable"); - } - pw.print(" because "); - pw.print(reasonToString(mRunnableAtReason)); + pw.print(" "); + pw.print(describeStateLocked(now)); pw.println(); pw.increaseIndent(); diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index e532c15addd0..8735f8a37b8b 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -327,6 +327,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue { return; } + // To place ourselves correctly in the runnable list, we may need to + // update internals that may have been invalidated; we wait until now at + // the last possible moment to avoid duplicated work + queue.updateDeferredStates(mBroadcastConsumerDeferApply, mBroadcastConsumerDeferClear); + queue.updateRunnableAt(); + final boolean wantQueue = queue.isRunnable(); final boolean inQueue = (queue == mRunnableHead) || (queue.runnableAtPrev != null) || (queue.runnableAtNext != null); @@ -352,8 +358,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // If app isn't running, and there's nothing in the queue, clean up if (queue.isEmpty() && !queue.isActive() && !queue.isProcessWarm()) { removeProcessQueue(queue.processName, queue.uid); - } else { - updateQueueDeferred(queue); } } @@ -619,14 +623,10 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } enqueuedBroadcast = true; final BroadcastRecord replacedBroadcast = queue.enqueueOrReplaceBroadcast( - r, i, wouldBeSkipped); + r, i, wouldBeSkipped, mBroadcastConsumerDeferApply); if (replacedBroadcast != null) { replacedBroadcasts.add(replacedBroadcast); } - if (r.isDeferUntilActive() && queue.isDeferredUntilActive()) { - setDeliveryState(queue, null, r, i, receiver, BroadcastRecord.DELIVERY_DEFERRED, - "deferred at enqueue time"); - } updateRunnableList(queue); enqueueUpdateRunningList(); } @@ -1249,14 +1249,14 @@ class BroadcastQueueModernImpl extends BroadcastQueue { r.resultExtras = null; }; - private final BroadcastConsumer mBroadcastConsumerDefer = (r, i) -> { + private final BroadcastConsumer mBroadcastConsumerDeferApply = (r, i) -> { setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_DEFERRED, - "mBroadcastConsumerDefer"); + "mBroadcastConsumerDeferApply"); }; - private final BroadcastConsumer mBroadcastConsumerUndoDefer = (r, i) -> { + private final BroadcastConsumer mBroadcastConsumerDeferClear = (r, i) -> { setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_PENDING, - "mBroadcastConsumerUndoDefer"); + "mBroadcastConsumerDeferClear"); }; /** @@ -1272,7 +1272,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue { final long now = SystemClock.uptimeMillis(); if (now > mLastTestFailureTime + DateUtils.SECOND_IN_MILLIS) { mLastTestFailureTime = now; - pw.println("Test " + label + " failed due to " + leaf.toShortString()); + pw.println("Test " + label + " failed due to " + leaf.toShortString() + " " + + leaf.describeStateLocked()); pw.flush(); } return false; @@ -1309,34 +1310,25 @@ class BroadcastQueueModernImpl extends BroadcastQueue { return didSomething; } - private void forEachMatchingQueue( + private boolean forEachMatchingQueue( @NonNull Predicate<BroadcastProcessQueue> queuePredicate, @NonNull Consumer<BroadcastProcessQueue> queueConsumer) { + boolean didSomething = false; for (int i = mProcessQueues.size() - 1; i >= 0; i--) { BroadcastProcessQueue leaf = mProcessQueues.valueAt(i); while (leaf != null) { if (queuePredicate.test(leaf)) { queueConsumer.accept(leaf); updateRunnableList(leaf); + didSomething = true; } leaf = leaf.processNameNext; } } - } - - private void updateQueueDeferred( - @NonNull BroadcastProcessQueue leaf) { - if (leaf.isDeferredUntilActive()) { - leaf.forEachMatchingBroadcast((r, i) -> { - return r.deferUntilActive && (r.getDeliveryState(i) - == BroadcastRecord.DELIVERY_PENDING); - }, mBroadcastConsumerDefer, false); - } else if (leaf.hasDeferredBroadcasts()) { - leaf.forEachMatchingBroadcast((r, i) -> { - return r.deferUntilActive && (r.getDeliveryState(i) - == BroadcastRecord.DELIVERY_DEFERRED); - }, mBroadcastConsumerUndoDefer, false); + if (didSomething) { + enqueueUpdateRunningList(); } + return didSomething; } @Override @@ -1359,8 +1351,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // Update internal state by refreshing values previously // read from any known running process setQueueProcess(leaf, leaf.app); - updateQueueDeferred(leaf); - updateRunnableList(leaf); leaf = leaf.processNameNext; } enqueueUpdateRunningList(); @@ -1529,19 +1519,31 @@ class BroadcastQueueModernImpl extends BroadcastQueue { } } + @SuppressWarnings("CheckResult") private void updateWarmProcess(@NonNull BroadcastProcessQueue queue) { if (!queue.isProcessWarm()) { - setQueueProcess(queue, mService.getProcessRecordLocked(queue.processName, queue.uid)); + // This is a bit awkward; we're in the middle of traversing the + // runnable queue, so we can't reorder that list if the runnable + // time changes here. However, if this process was just found to be + // warm via this operation, we're going to immediately promote it to + // be running, and any side effect of this operation will then apply + // after it's finished and is returned to the runnable list. + queue.setProcessAndUidCached( + mService.getProcessRecordLocked(queue.processName, queue.uid), + mUidCached.get(queue.uid, false)); } } /** * Update the {@link ProcessRecord} associated with the given - * {@link BroadcastProcessQueue}. + * {@link BroadcastProcessQueue}. Also updates any runnable status that + * might have changed as a side-effect. */ private void setQueueProcess(@NonNull BroadcastProcessQueue queue, @Nullable ProcessRecord app) { - queue.setProcessAndUidCached(app, mUidCached.get(queue.uid, false)); + if (queue.setProcessAndUidCached(app, mUidCached.get(queue.uid, false))) { + updateRunnableList(queue); + } } /** 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 ec177c9ac33d..bc3f5ab5c42b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java @@ -237,9 +237,23 @@ public final class BroadcastQueueModernImplTest { } private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue, + BroadcastRecord record, int recordIndex) { + enqueueOrReplaceBroadcast(queue, record, recordIndex, false, 42_000_000L); + } + + private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue, BroadcastRecord record, int recordIndex, long enqueueTime) { - queue.enqueueOrReplaceBroadcast(record, recordIndex, false); + enqueueOrReplaceBroadcast(queue, record, recordIndex, false, enqueueTime); + } + + private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue, + BroadcastRecord record, int recordIndex, boolean wouldBeSkipped, long enqueueTime) { + queue.enqueueOrReplaceBroadcast(record, recordIndex, wouldBeSkipped, (r, i) -> { + throw new UnsupportedOperationException(); + }); record.enqueueTime = enqueueTime; + record.enqueueRealTime = enqueueTime; + record.enqueueClockTime = enqueueTime; } @Test @@ -370,7 +384,7 @@ public final class BroadcastQueueModernImplTest { .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE); final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, options, List.of(makeMockRegisteredReceiver()), false); - queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false); + enqueueOrReplaceBroadcast(queue, airplaneRecord, 0); queue.setProcessAndUidCached(null, false); final long notCachedRunnableAt = queue.getRunnableAt(); @@ -397,7 +411,7 @@ public final class BroadcastQueueModernImplTest { .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_NONE); final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, options, List.of(makeMockRegisteredReceiver()), false); - queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false); + enqueueOrReplaceBroadcast(queue, airplaneRecord, 0); queue.setProcessAndUidCached(null, false); final long notCachedRunnableAt = queue.getRunnableAt(); @@ -421,12 +435,12 @@ public final 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, false); + enqueueOrReplaceBroadcast(queue, timezoneRecord, 0); 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, false); + enqueueOrReplaceBroadcast(queue, airplaneRecord, 0); // verify that: // (a) the queue is immediately runnable by existence of a fg-priority broadcast @@ -457,7 +471,7 @@ public final 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, false); + enqueueOrReplaceBroadcast(queue, airplaneRecord, 1); assertFalse(queue.isRunnable()); assertEquals(BroadcastProcessQueue.REASON_BLOCKED, queue.getRunnableAtReason()); @@ -481,7 +495,7 @@ public final class BroadcastQueueModernImplTest { final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, List.of(makeMockRegisteredReceiver())); - queue.enqueueOrReplaceBroadcast(airplaneRecord, 0, false); + enqueueOrReplaceBroadcast(queue, airplaneRecord, 0); mConstants.MAX_PENDING_BROADCASTS = 128; queue.invalidateRunnableAt(); @@ -507,11 +521,11 @@ public final class BroadcastQueueModernImplTest { new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED), List.of(makeMockRegisteredReceiver())); - queue.enqueueOrReplaceBroadcast(lazyRecord, 0, false); + enqueueOrReplaceBroadcast(queue, lazyRecord, 0); assertThat(queue.getRunnableAt()).isGreaterThan(lazyRecord.enqueueTime); assertThat(queue.getRunnableAtReason()).isNotEqualTo(testRunnableAtReason); - queue.enqueueOrReplaceBroadcast(testRecord, 0, false); + enqueueOrReplaceBroadcast(queue, testRecord, 0); assertThat(queue.getRunnableAt()).isAtMost(testRecord.enqueueTime); assertThat(queue.getRunnableAtReason()).isEqualTo(testRunnableAtReason); } @@ -573,22 +587,22 @@ public final class BroadcastQueueModernImplTest { BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants, PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN)); - queue.enqueueOrReplaceBroadcast( + enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED) - .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, false); - queue.enqueueOrReplaceBroadcast( - makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0, false); - queue.enqueueOrReplaceBroadcast( + .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0); + enqueueOrReplaceBroadcast(queue, + makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0); + enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED) - .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, false); - queue.enqueueOrReplaceBroadcast( + .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0); + enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED) - .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, false); - queue.enqueueOrReplaceBroadcast( - makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0, false); - queue.enqueueOrReplaceBroadcast( + .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0); + enqueueOrReplaceBroadcast(queue, + makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0); + enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED) - .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, false); + .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0); queue.makeActiveNextPending(); assertEquals(Intent.ACTION_LOCKED_BOOT_COMPLETED, queue.getActive().intent.getAction()); @@ -1164,8 +1178,8 @@ public final class BroadcastQueueModernImplTest { final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK) .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - queue.enqueueOrReplaceBroadcast(makeBroadcastRecord(timeTick, - List.of(makeMockRegisteredReceiver())), 0, false); + enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(timeTick, + List.of(makeMockRegisteredReceiver())), 0); assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked()); // Make the foreground broadcast as active. @@ -1176,15 +1190,15 @@ public final class BroadcastQueueModernImplTest { assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked()); final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - queue.enqueueOrReplaceBroadcast(makeBroadcastRecord(airplane, - List.of(makeMockRegisteredReceiver())), 0, false); + enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(airplane, + List.of(makeMockRegisteredReceiver())), 0); // Make the background broadcast as active. queue.makeActiveNextPending(); assertEquals(ProcessList.SCHED_GROUP_BACKGROUND, queue.getPreferredSchedulingGroupLocked()); - queue.enqueueOrReplaceBroadcast(makeBroadcastRecord(timeTick, - List.of(makeMockRegisteredReceiver())), 0, false); + enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(timeTick, + List.of(makeMockRegisteredReceiver())), 0); // Even though the active broadcast is not a foreground one, scheduling group will be // DEFAULT since there is a foreground broadcast waiting to be delivered. assertEquals(ProcessList.SCHED_GROUP_DEFAULT, queue.getPreferredSchedulingGroupLocked()); |