1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.am;
18 
19 import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
20 
21 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
22 import static com.android.internal.util.FrameworkStatsLog.BROADCAST_DELIVERY_EVENT_REPORTED;
23 import static com.android.internal.util.FrameworkStatsLog.BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD;
24 import static com.android.internal.util.FrameworkStatsLog.BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST;
25 import static com.android.server.am.ActivityManagerDebugConfig.LOG_WRITER_INFO;
26 import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_ALARM;
27 import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_FOREGROUND;
28 import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_INTERACTIVE;
29 import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_MANIFEST;
30 import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_ORDERED;
31 import static com.android.server.am.BroadcastProcessQueue.REASON_CONTAINS_PRIORITIZED;
32 import static com.android.server.am.BroadcastProcessQueue.insertIntoRunnableList;
33 import static com.android.server.am.BroadcastProcessQueue.removeFromRunnableList;
34 import static com.android.server.am.BroadcastQueueTest.CLASS_BLUE;
35 import static com.android.server.am.BroadcastQueueTest.CLASS_GREEN;
36 import static com.android.server.am.BroadcastQueueTest.CLASS_RED;
37 import static com.android.server.am.BroadcastQueueTest.CLASS_YELLOW;
38 import static com.android.server.am.BroadcastQueueTest.PACKAGE_BLUE;
39 import static com.android.server.am.BroadcastQueueTest.PACKAGE_GREEN;
40 import static com.android.server.am.BroadcastQueueTest.PACKAGE_RED;
41 import static com.android.server.am.BroadcastQueueTest.PACKAGE_YELLOW;
42 import static com.android.server.am.BroadcastQueueTest.getUidForPackage;
43 import static com.android.server.am.BroadcastQueueTest.makeManifestReceiver;
44 import static com.android.server.am.BroadcastQueueTest.withPriority;
45 import static com.android.server.am.BroadcastRecord.isReceiverEquals;
46 
47 import static com.google.common.truth.Truth.assertThat;
48 
49 import static org.junit.Assert.assertEquals;
50 import static org.junit.Assert.assertFalse;
51 import static org.junit.Assert.assertNotEquals;
52 import static org.junit.Assert.assertNull;
53 import static org.junit.Assert.assertTrue;
54 import static org.junit.Assert.fail;
55 import static org.mockito.ArgumentMatchers.any;
56 import static org.mockito.ArgumentMatchers.anyInt;
57 import static org.mockito.ArgumentMatchers.anyLong;
58 import static org.mockito.ArgumentMatchers.anyString;
59 import static org.mockito.ArgumentMatchers.eq;
60 import static org.mockito.ArgumentMatchers.nullable;
61 import static org.mockito.Mockito.doAnswer;
62 import static org.mockito.Mockito.doReturn;
63 import static org.mockito.Mockito.mock;
64 import static org.mockito.Mockito.spy;
65 import static org.mockito.Mockito.times;
66 
67 import android.annotation.NonNull;
68 import android.app.Activity;
69 import android.app.ActivityManager;
70 import android.app.AppOpsManager;
71 import android.app.BackgroundStartPrivileges;
72 import android.app.BroadcastOptions;
73 import android.appwidget.AppWidgetManager;
74 import android.content.IIntentReceiver;
75 import android.content.Intent;
76 import android.content.IntentFilter;
77 import android.content.pm.ResolveInfo;
78 import android.media.AudioManager;
79 import android.os.Bundle;
80 import android.os.BundleMerger;
81 import android.os.DropBoxManager;
82 import android.os.HandlerThread;
83 import android.os.Process;
84 import android.os.SystemClock;
85 import android.os.TestLooperManager;
86 import android.os.UserHandle;
87 import android.provider.Settings;
88 import android.util.IndentingPrintWriter;
89 import android.util.Pair;
90 
91 import androidx.test.filters.SmallTest;
92 import androidx.test.platform.app.InstrumentationRegistry;
93 
94 import com.android.internal.util.FrameworkStatsLog;
95 import com.android.server.ExtendedMockitoRule;
96 
97 import org.junit.After;
98 import org.junit.Before;
99 import org.junit.Rule;
100 import org.junit.Test;
101 import org.mockito.Mock;
102 
103 import java.io.PrintWriter;
104 import java.io.Writer;
105 import java.lang.reflect.Array;
106 import java.util.ArrayList;
107 import java.util.List;
108 import java.util.Objects;
109 
110 @SmallTest
111 public final class BroadcastQueueModernImplTest {
112     private static final int TEST_UID = android.os.Process.FIRST_APPLICATION_UID;
113     private static final int TEST_UID2 = android.os.Process.FIRST_APPLICATION_UID + 1;
114 
115     @Mock ActivityManagerService mAms;
116     @Mock ProcessRecord mProcess;
117 
118     @Mock BroadcastProcessQueue mQueue1;
119     @Mock BroadcastProcessQueue mQueue2;
120     @Mock BroadcastProcessQueue mQueue3;
121     @Mock BroadcastProcessQueue mQueue4;
122 
123     HandlerThread mHandlerThread;
124     TestLooperManager mLooper;
125 
126     BroadcastConstants mConstants;
127     private BroadcastSkipPolicy mSkipPolicy;
128     BroadcastQueueModernImpl mImpl;
129 
130     BroadcastProcessQueue mHead;
131 
132     @Rule
133     public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this)
134             .spyStatic(FrameworkStatsLog.class)
135             .build();
136 
137     @Before
setUp()138     public void setUp() throws Exception {
139         mHandlerThread = new HandlerThread(getClass().getSimpleName());
140         mHandlerThread.start();
141 
142         // Pause all event processing until a test chooses to resume
143         mLooper = Objects.requireNonNull(InstrumentationRegistry.getInstrumentation()
144                 .acquireLooperManager(mHandlerThread.getLooper()));
145 
146         mConstants = new BroadcastConstants(Settings.Global.BROADCAST_FG_CONSTANTS);
147         mConstants.DELAY_URGENT_MILLIS = -120_000;
148         mConstants.DELAY_NORMAL_MILLIS = 10_000;
149         mConstants.DELAY_CACHED_MILLIS = 120_000;
150 
151         mSkipPolicy = spy(new BroadcastSkipPolicy(mAms));
152         doReturn(null).when(mSkipPolicy).shouldSkipMessage(any(), any());
153         doReturn(false).when(mSkipPolicy).disallowBackgroundStart(any());
154 
155         final BroadcastHistory emptyHistory = new BroadcastHistory(mConstants) {
156             public void addBroadcastToHistoryLocked(BroadcastRecord original) {
157                 // Ignored
158             }
159         };
160 
161         mImpl = new BroadcastQueueModernImpl(mAms, mHandlerThread.getThreadHandler(),
162             mConstants, mConstants, mSkipPolicy, emptyHistory);
163 
164         doReturn(1L).when(mQueue1).getRunnableAt();
165         doReturn(2L).when(mQueue2).getRunnableAt();
166         doReturn(3L).when(mQueue3).getRunnableAt();
167         doReturn(4L).when(mQueue4).getRunnableAt();
168     }
169 
170     @After
tearDown()171     public void tearDown() throws Exception {
172         mHandlerThread.quit();
173     }
174 
175     /**
176      * Un-pause our handler to process pending events, wait for our queue to go
177      * idle, and then re-pause the handler.
178      */
waitForIdle()179     private void waitForIdle() throws Exception {
180         mLooper.release();
181         mImpl.waitForIdle(LOG_WRITER_INFO);
182         mLooper = Objects.requireNonNull(InstrumentationRegistry.getInstrumentation()
183                 .acquireLooperManager(mHandlerThread.getLooper()));
184     }
185 
assertOrphan(BroadcastProcessQueue queue)186     private static void assertOrphan(BroadcastProcessQueue queue) {
187         assertNull(queue.runnableAtNext);
188         assertNull(queue.runnableAtPrev);
189     }
190 
assertRunnableList(@onNull List<BroadcastProcessQueue> expected, @NonNull BroadcastProcessQueue actualHead)191     private static void assertRunnableList(@NonNull List<BroadcastProcessQueue> expected,
192             @NonNull BroadcastProcessQueue actualHead) {
193         BroadcastProcessQueue test = actualHead;
194         final int N = expected.size();
195         for (int i = 0; i < N; i++) {
196             final BroadcastProcessQueue expectedPrev = (i > 0) ? expected.get(i - 1) : null;
197             final BroadcastProcessQueue expectedTest = expected.get(i);
198             final BroadcastProcessQueue expectedNext = (i < N - 1) ? expected.get(i + 1) : null;
199 
200             assertEquals("prev", expectedPrev, test.runnableAtPrev);
201             assertEquals("test", expectedTest, test);
202             assertEquals("next", expectedNext, test.runnableAtNext);
203 
204             test = test.runnableAtNext;
205         }
206         if (N == 0) {
207             assertNull(actualHead);
208         }
209     }
210 
makeMockIntent()211     private static Intent makeMockIntent() {
212         return mock(Intent.class);
213     }
214 
makeMockManifestReceiver()215     private static ResolveInfo makeMockManifestReceiver() {
216         return mock(ResolveInfo.class);
217     }
218 
makeMockRegisteredReceiver()219     private static BroadcastFilter makeMockRegisteredReceiver() {
220         return mock(BroadcastFilter.class);
221     }
222 
makeBroadcastRecord(Intent intent)223     private BroadcastRecord makeBroadcastRecord(Intent intent) {
224         return makeBroadcastRecord(intent, BroadcastOptions.makeBasic(),
225                 List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN)), false);
226     }
227 
makeOrderedBroadcastRecord(Intent intent)228     private BroadcastRecord makeOrderedBroadcastRecord(Intent intent) {
229         return makeBroadcastRecord(intent, BroadcastOptions.makeBasic(),
230                 List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN)), true);
231     }
232 
makeBroadcastRecord(Intent intent, List receivers)233     private BroadcastRecord makeBroadcastRecord(Intent intent, List receivers) {
234         return makeBroadcastRecord(intent, BroadcastOptions.makeBasic(), receivers, false);
235     }
236 
makeBroadcastRecord(Intent intent, BroadcastOptions options)237     private BroadcastRecord makeBroadcastRecord(Intent intent, BroadcastOptions options) {
238         return makeBroadcastRecord(intent, options,
239                 List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN)), false);
240     }
241 
makeBroadcastRecord(Intent intent, BroadcastOptions options, List receivers, boolean ordered)242     private BroadcastRecord makeBroadcastRecord(Intent intent, BroadcastOptions options,
243             List receivers, boolean ordered) {
244         return makeBroadcastRecord(intent, options, receivers, null, ordered);
245     }
246 
makeBroadcastRecord(Intent intent, BroadcastOptions options, List receivers, IIntentReceiver resultTo, boolean ordered)247     private BroadcastRecord makeBroadcastRecord(Intent intent, BroadcastOptions options,
248             List receivers, IIntentReceiver resultTo, boolean ordered) {
249         return new BroadcastRecord(mImpl, intent, mProcess, PACKAGE_RED, null, 21, 42, false, null,
250                 null, null, null, AppOpsManager.OP_NONE, options, receivers, null, resultTo,
251                 Activity.RESULT_OK, null, null, ordered, false, false, UserHandle.USER_SYSTEM,
252                 BackgroundStartPrivileges.NONE, false, null, PROCESS_STATE_UNKNOWN);
253     }
254 
enqueueOrReplaceBroadcast(BroadcastProcessQueue queue, BroadcastRecord record, int recordIndex)255     private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue,
256             BroadcastRecord record, int recordIndex) {
257         enqueueOrReplaceBroadcast(queue, record, recordIndex, 42_000_000L);
258     }
259 
enqueueOrReplaceBroadcast(BroadcastProcessQueue queue, BroadcastRecord record, int recordIndex, long enqueueTime)260     private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue,
261             BroadcastRecord record, int recordIndex, long enqueueTime) {
262         queue.enqueueOrReplaceBroadcast(record, recordIndex, (r, i) -> {
263             throw new UnsupportedOperationException();
264         });
265         record.enqueueTime = enqueueTime;
266         record.enqueueRealTime = enqueueTime;
267         record.enqueueClockTime = enqueueTime;
268     }
269 
270     @Test
testRunnableList_Simple()271     public void testRunnableList_Simple() {
272         assertRunnableList(List.of(), mHead);
273 
274         mHead = insertIntoRunnableList(mHead, mQueue1);
275         assertRunnableList(List.of(mQueue1), mHead);
276 
277         mHead = removeFromRunnableList(mHead, mQueue1);
278         assertRunnableList(List.of(), mHead);
279     }
280 
281     @Test
testRunnableList_InsertLast()282     public void testRunnableList_InsertLast() {
283         mHead = insertIntoRunnableList(mHead, mQueue1);
284         mHead = insertIntoRunnableList(mHead, mQueue2);
285         mHead = insertIntoRunnableList(mHead, mQueue3);
286         mHead = insertIntoRunnableList(mHead, mQueue4);
287         assertRunnableList(List.of(mQueue1, mQueue2, mQueue3, mQueue4), mHead);
288     }
289 
290     @Test
testRunnableList_InsertFirst()291     public void testRunnableList_InsertFirst() {
292         mHead = insertIntoRunnableList(mHead, mQueue4);
293         mHead = insertIntoRunnableList(mHead, mQueue3);
294         mHead = insertIntoRunnableList(mHead, mQueue2);
295         mHead = insertIntoRunnableList(mHead, mQueue1);
296         assertRunnableList(List.of(mQueue1, mQueue2, mQueue3, mQueue4), mHead);
297     }
298 
299     @Test
testRunnableList_InsertMiddle()300     public void testRunnableList_InsertMiddle() {
301         mHead = insertIntoRunnableList(mHead, mQueue1);
302         mHead = insertIntoRunnableList(mHead, mQueue3);
303         mHead = insertIntoRunnableList(mHead, mQueue2);
304         assertRunnableList(List.of(mQueue1, mQueue2, mQueue3), mHead);
305     }
306 
307     @Test
testRunnableList_Remove()308     public void testRunnableList_Remove() {
309         mHead = insertIntoRunnableList(mHead, mQueue1);
310         mHead = insertIntoRunnableList(mHead, mQueue2);
311         mHead = insertIntoRunnableList(mHead, mQueue3);
312         mHead = insertIntoRunnableList(mHead, mQueue4);
313 
314         mHead = removeFromRunnableList(mHead, mQueue3);
315         assertRunnableList(List.of(mQueue1, mQueue2, mQueue4), mHead);
316 
317         mHead = removeFromRunnableList(mHead, mQueue1);
318         assertRunnableList(List.of(mQueue2, mQueue4), mHead);
319 
320         mHead = removeFromRunnableList(mHead, mQueue4);
321         assertRunnableList(List.of(mQueue2), mHead);
322 
323         mHead = removeFromRunnableList(mHead, mQueue2);
324         assertRunnableList(List.of(), mHead);
325 
326         // Verify all links cleaned up during removal
327         assertOrphan(mQueue1);
328         assertOrphan(mQueue2);
329         assertOrphan(mQueue3);
330         assertOrphan(mQueue4);
331     }
332 
333     @Test
testRunnableList_sameRunnableAt()334     public void testRunnableList_sameRunnableAt() {
335         doReturn(2L).when(mQueue1).getRunnableAt();
336         doReturn(2L).when(mQueue2).getRunnableAt();
337         doReturn(2L).when(mQueue3).getRunnableAt();
338         doReturn(2L).when(mQueue4).getRunnableAt();
339 
340         mHead = insertIntoRunnableList(mHead, mQueue1);
341         mHead = insertIntoRunnableList(mHead, mQueue2);
342         mHead = insertIntoRunnableList(mHead, mQueue3);
343         mHead = insertIntoRunnableList(mHead, mQueue4);
344         assertRunnableList(List.of(mQueue1, mQueue2, mQueue3, mQueue4), mHead);
345     }
346 
347     @Test
testProcessQueue_Complex()348     public void testProcessQueue_Complex() {
349         BroadcastProcessQueue red = mImpl.getOrCreateProcessQueue(PACKAGE_RED, TEST_UID);
350         BroadcastProcessQueue green = mImpl.getOrCreateProcessQueue(PACKAGE_GREEN, TEST_UID);
351         BroadcastProcessQueue blue = mImpl.getOrCreateProcessQueue(PACKAGE_BLUE, TEST_UID);
352 
353         assertEquals(PACKAGE_RED, red.processName);
354         assertEquals(PACKAGE_GREEN, green.processName);
355         assertEquals(PACKAGE_BLUE, blue.processName);
356 
357         // Verify that removing middle queue works
358         mImpl.removeProcessQueue(PACKAGE_GREEN, TEST_UID);
359         assertEquals(red, mImpl.getProcessQueue(PACKAGE_RED, TEST_UID));
360         assertNull(mImpl.getProcessQueue(PACKAGE_GREEN, TEST_UID));
361         assertEquals(blue, mImpl.getProcessQueue(PACKAGE_BLUE, TEST_UID));
362         assertNull(mImpl.getProcessQueue(PACKAGE_YELLOW, TEST_UID));
363 
364         // Verify that removing head queue works
365         mImpl.removeProcessQueue(PACKAGE_RED, TEST_UID);
366         assertNull(mImpl.getProcessQueue(PACKAGE_RED, TEST_UID));
367         assertNull(mImpl.getProcessQueue(PACKAGE_GREEN, TEST_UID));
368         assertEquals(blue, mImpl.getProcessQueue(PACKAGE_BLUE, TEST_UID));
369         assertNull(mImpl.getProcessQueue(PACKAGE_YELLOW, TEST_UID));
370 
371         // Verify that removing last queue works
372         mImpl.removeProcessQueue(PACKAGE_BLUE, TEST_UID);
373         assertNull(mImpl.getProcessQueue(PACKAGE_RED, TEST_UID));
374         assertNull(mImpl.getProcessQueue(PACKAGE_GREEN, TEST_UID));
375         assertNull(mImpl.getProcessQueue(PACKAGE_BLUE, TEST_UID));
376         assertNull(mImpl.getProcessQueue(PACKAGE_YELLOW, TEST_UID));
377 
378         // Verify that removing missing doesn't crash
379         mImpl.removeProcessQueue(PACKAGE_YELLOW, TEST_UID);
380 
381         // Verify that we can start all over again safely
382         BroadcastProcessQueue yellow = mImpl.getOrCreateProcessQueue(PACKAGE_YELLOW, TEST_UID);
383         assertEquals(yellow, mImpl.getProcessQueue(PACKAGE_YELLOW, TEST_UID));
384     }
385 
386     /**
387      * Empty queue isn't runnable.
388      */
389     @Test
testRunnableAt_Empty()390     public void testRunnableAt_Empty() {
391         final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
392                 PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
393         assertFalse(queue.isRunnable());
394         assertEquals(Long.MAX_VALUE, queue.getRunnableAt());
395         assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked());
396     }
397 
398     /**
399      * Queue with a "normal" and "deferrable" broadcast is runnable at different times depending
400      * on process cached state; when cached it's delayed indefinitely.
401      */
402     @Test
testRunnableAt_Normal_Deferrable()403     public void testRunnableAt_Normal_Deferrable() {
404         final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
405                 PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
406 
407         final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
408         final BroadcastOptions options = BroadcastOptions.makeBasic()
409                 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE);
410         final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, options,
411                 List.of(makeMockRegisteredReceiver()), false);
412         enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
413 
414         queue.setProcessAndUidState(mProcess, false, false);
415         final long notCachedRunnableAt = queue.getRunnableAt();
416         queue.setProcessAndUidState(mProcess, false, true);
417         final long cachedRunnableAt = queue.getRunnableAt();
418         assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt);
419         assertFalse(queue.isRunnable());
420         assertEquals(BroadcastProcessQueue.REASON_CACHED_INFINITE_DEFER,
421                 queue.getRunnableAtReason());
422         assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked());
423     }
424 
425     /**
426      * Queue with a "normal" broadcast is runnable at different times depending
427      * on process cached state; when cached it's delayed by some amount.
428      */
429     @Test
testRunnableAt_Normal()430     public void testRunnableAt_Normal() {
431         final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
432                 PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
433 
434         final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
435         final BroadcastOptions options = BroadcastOptions.makeBasic()
436                 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_NONE);
437         final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, options,
438                 List.of(makeMockRegisteredReceiver()), false);
439         enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
440 
441         queue.setProcessAndUidState(mProcess, false, false);
442         final long notCachedRunnableAt = queue.getRunnableAt();
443         queue.setProcessAndUidState(mProcess, false, true);
444         final long cachedRunnableAt = queue.getRunnableAt();
445         assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt);
446         assertTrue(queue.isRunnable());
447         assertEquals(BroadcastProcessQueue.REASON_CACHED, queue.getRunnableAtReason());
448         assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked());
449     }
450 
451     /**
452      * Queue with foreground broadcast is always runnable immediately,
453      * regardless of process cached state.
454      */
455     @Test
testRunnableAt_Foreground()456     public void testRunnableAt_Foreground() {
457         final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
458                 PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
459 
460         // enqueue a bg-priority broadcast then a fg-priority one
461         final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
462         final BroadcastRecord timezoneRecord = makeBroadcastRecord(timezone);
463         enqueueOrReplaceBroadcast(queue, timezoneRecord, 0);
464 
465         final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
466         airplane.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
467         final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane);
468         enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
469 
470         // verify that:
471         // (a) the queue is immediately runnable by existence of a fg-priority broadcast
472         // (b) the next one up is the fg-priority broadcast despite its later enqueue time
473         queue.setProcessAndUidState(null, false, false);
474         assertTrue(queue.isRunnable());
475         assertThat(queue.getRunnableAt()).isAtMost(airplaneRecord.enqueueClockTime);
476         assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked());
477         assertEquals(queue.peekNextBroadcastRecord(), airplaneRecord);
478 
479         queue.setProcessAndUidState(null, false, true);
480         assertTrue(queue.isRunnable());
481         assertThat(queue.getRunnableAt()).isAtMost(airplaneRecord.enqueueClockTime);
482         assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked());
483         assertEquals(queue.peekNextBroadcastRecord(), airplaneRecord);
484     }
485 
486     /**
487      * Queue with ordered broadcast is runnable only once we've made enough
488      * progress on earlier blocking items.
489      */
490     @Test
testRunnableAt_Ordered()491     public void testRunnableAt_Ordered() {
492         final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
493                 PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
494 
495         final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
496         final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane, null,
497                 List.of(withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 10),
498                         withPriority(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 0)), true);
499         enqueueOrReplaceBroadcast(queue, airplaneRecord, 1);
500 
501         assertFalse(queue.isRunnable());
502         assertEquals(BroadcastProcessQueue.REASON_BLOCKED, queue.getRunnableAtReason());
503 
504         // Bumping past barrier makes us now runnable
505         airplaneRecord.setDeliveryState(0, BroadcastRecord.DELIVERY_DELIVERED,
506                 "testRunnableAt_Ordered");
507         queue.invalidateRunnableAt();
508         assertTrue(queue.isRunnable());
509         assertNotEquals(BroadcastProcessQueue.REASON_BLOCKED, queue.getRunnableAtReason());
510     }
511 
512     /**
513      * Queue with too many pending broadcasts is runnable.
514      */
515     @Test
testRunnableAt_Huge()516     public void testRunnableAt_Huge() {
517         BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
518                 PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
519 
520         final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
521         final BroadcastRecord airplaneRecord = makeBroadcastRecord(airplane,
522                 List.of(makeMockRegisteredReceiver()));
523         enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
524 
525         mConstants.MAX_PENDING_BROADCASTS = 128;
526         queue.invalidateRunnableAt();
527         assertThat(queue.getRunnableAt()).isGreaterThan(airplaneRecord.enqueueTime);
528         assertEquals(BroadcastProcessQueue.REASON_NORMAL, queue.getRunnableAtReason());
529 
530         mConstants.MAX_PENDING_BROADCASTS = 1;
531         queue.invalidateRunnableAt();
532         assertThat(queue.getRunnableAt()).isAtMost(airplaneRecord.enqueueTime);
533         assertEquals(BroadcastProcessQueue.REASON_MAX_PENDING, queue.getRunnableAtReason());
534     }
535 
536     @Test
testRunnableAt_uidForeground()537     public void testRunnableAt_uidForeground() {
538         final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants, PACKAGE_GREEN,
539                 getUidForPackage(PACKAGE_GREEN));
540 
541         final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
542         final BroadcastRecord timeTickRecord = makeBroadcastRecord(timeTick,
543                 List.of(makeMockRegisteredReceiver()));
544         enqueueOrReplaceBroadcast(queue, timeTickRecord, 0);
545 
546         assertThat(queue.getRunnableAt()).isGreaterThan(timeTickRecord.enqueueTime);
547         assertEquals(BroadcastProcessQueue.REASON_NORMAL, queue.getRunnableAtReason());
548 
549         queue.setProcessAndUidState(mProcess, true, false);
550         assertThat(queue.getRunnableAt()).isLessThan(timeTickRecord.enqueueTime);
551         assertEquals(BroadcastProcessQueue.REASON_FOREGROUND, queue.getRunnableAtReason());
552 
553         queue.setProcessAndUidState(mProcess, false, false);
554         assertThat(queue.getRunnableAt()).isGreaterThan(timeTickRecord.enqueueTime);
555         assertEquals(BroadcastProcessQueue.REASON_NORMAL, queue.getRunnableAtReason());
556     }
557 
558     @Test
testRunnableAt_processTop()559     public void testRunnableAt_processTop() {
560         final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants, PACKAGE_GREEN,
561                 getUidForPackage(PACKAGE_GREEN));
562 
563         doReturn(ActivityManager.PROCESS_STATE_TOP).when(mProcess).getSetProcState();
564         queue.setProcessAndUidState(mProcess, false, false);
565 
566         final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
567         final BroadcastRecord timeTickRecord = makeBroadcastRecord(timeTick,
568                 List.of(makeMockRegisteredReceiver()));
569         enqueueOrReplaceBroadcast(queue, timeTickRecord, 0);
570 
571         assertThat(queue.getRunnableAt()).isLessThan(timeTickRecord.enqueueTime);
572         assertEquals(BroadcastProcessQueue.REASON_TOP_PROCESS, queue.getRunnableAtReason());
573 
574         doReturn(ActivityManager.PROCESS_STATE_SERVICE).when(mProcess).getSetProcState();
575         queue.setProcessAndUidState(mProcess, false, false);
576 
577         // The new process state will only be taken into account the next time a broadcast
578         // is sent to the process.
579         enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(timeTick,
580                 List.of(makeMockRegisteredReceiver())), 0);
581         assertThat(queue.getRunnableAt()).isGreaterThan(timeTickRecord.enqueueTime);
582         assertEquals(BroadcastProcessQueue.REASON_NORMAL, queue.getRunnableAtReason());
583     }
584 
585     @Test
testRunnableAt_persistentProc()586     public void testRunnableAt_persistentProc() {
587         final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants, PACKAGE_GREEN,
588                 getUidForPackage(PACKAGE_GREEN));
589 
590         final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
591         final BroadcastRecord timeTickRecord = makeBroadcastRecord(timeTick,
592                 List.of(makeMockRegisteredReceiver()));
593         enqueueOrReplaceBroadcast(queue, timeTickRecord, 0);
594 
595         assertThat(queue.getRunnableAt()).isGreaterThan(timeTickRecord.enqueueTime);
596         assertEquals(BroadcastProcessQueue.REASON_NORMAL, queue.getRunnableAtReason());
597 
598         doReturn(true).when(mProcess).isPersistent();
599         queue.setProcessAndUidState(mProcess, false, false);
600         assertThat(queue.getRunnableAt()).isLessThan(timeTickRecord.enqueueTime);
601         assertEquals(BroadcastProcessQueue.REASON_PERSISTENT, queue.getRunnableAtReason());
602 
603         doReturn(false).when(mProcess).isPersistent();
604         queue.setProcessAndUidState(mProcess, false, false);
605         assertThat(queue.getRunnableAt()).isGreaterThan(timeTickRecord.enqueueTime);
606         assertEquals(BroadcastProcessQueue.REASON_NORMAL, queue.getRunnableAtReason());
607     }
608 
609     @Test
testRunnableAt_coreUid()610     public void testRunnableAt_coreUid() {
611         final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
612                 "com.android.bluetooth", Process.BLUETOOTH_UID);
613 
614         final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
615         final BroadcastRecord timeTickRecord = makeBroadcastRecord(timeTick,
616                 List.of(makeMockRegisteredReceiver()));
617         enqueueOrReplaceBroadcast(queue, timeTickRecord, 0);
618 
619         assertThat(queue.getRunnableAt()).isEqualTo(timeTickRecord.enqueueTime);
620         assertEquals(BroadcastProcessQueue.REASON_CORE_UID, queue.getRunnableAtReason());
621     }
622 
623     @Test
testRunnableAt_freezableCoreUid()624     public void testRunnableAt_freezableCoreUid() {
625         final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
626                 "com.android.bluetooth", Process.BLUETOOTH_UID);
627 
628         // Mark the process as freezable
629         queue.setProcessAndUidState(mProcess, false, true);
630         final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
631         final BroadcastOptions options = BroadcastOptions.makeWithDeferUntilActive(true);
632         final BroadcastRecord timeTickRecord = makeBroadcastRecord(timeTick, options,
633                 List.of(makeMockRegisteredReceiver()), false);
634         enqueueOrReplaceBroadcast(queue, timeTickRecord, 0);
635 
636         assertEquals(Long.MAX_VALUE, queue.getRunnableAt());
637         assertEquals(BroadcastProcessQueue.REASON_CACHED_INFINITE_DEFER,
638                 queue.getRunnableAtReason());
639 
640         queue.setProcessAndUidState(mProcess, false, false);
641         assertThat(queue.getRunnableAt()).isEqualTo(timeTickRecord.enqueueTime);
642         assertEquals(BroadcastProcessQueue.REASON_CORE_UID, queue.getRunnableAtReason());
643     }
644 
645     /**
646      * Verify that a cached process that would normally be delayed becomes
647      * immediately runnable when the given broadcast is enqueued.
648      */
doRunnableAt_Cached(BroadcastRecord testRecord, int testRunnableAtReason)649     private void doRunnableAt_Cached(BroadcastRecord testRecord, int testRunnableAtReason) {
650         final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
651                 PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
652         queue.setProcessAndUidState(null, false, true);
653 
654         final BroadcastRecord lazyRecord = makeBroadcastRecord(
655                 new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED),
656                 List.of(makeMockRegisteredReceiver()));
657 
658         enqueueOrReplaceBroadcast(queue, lazyRecord, 0);
659         assertThat(queue.getRunnableAt()).isGreaterThan(lazyRecord.enqueueTime);
660         assertThat(queue.getRunnableAtReason()).isNotEqualTo(testRunnableAtReason);
661 
662         enqueueOrReplaceBroadcast(queue, testRecord, 0);
663         assertThat(queue.getRunnableAt()).isAtMost(testRecord.enqueueTime);
664         assertThat(queue.getRunnableAtReason()).isEqualTo(testRunnableAtReason);
665     }
666 
667     @Test
testRunnableAt_Cached_Manifest()668     public void testRunnableAt_Cached_Manifest() {
669         doRunnableAt_Cached(makeBroadcastRecord(makeMockIntent(), null,
670                 List.of(makeMockManifestReceiver()), null, false), REASON_CONTAINS_MANIFEST);
671     }
672 
673     @Test
testRunnableAt_Cached_Ordered()674     public void testRunnableAt_Cached_Ordered() {
675         doRunnableAt_Cached(makeBroadcastRecord(makeMockIntent(), null,
676                 List.of(makeMockRegisteredReceiver()), null, true), REASON_CONTAINS_ORDERED);
677     }
678 
679     @Test
testRunnableAt_Cached_Foreground()680     public void testRunnableAt_Cached_Foreground() {
681         final Intent foregroundIntent = new Intent();
682         foregroundIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
683         doRunnableAt_Cached(makeBroadcastRecord(foregroundIntent, null,
684                 List.of(makeMockRegisteredReceiver()), null, false), REASON_CONTAINS_FOREGROUND);
685     }
686 
687     @Test
testRunnableAt_Cached_Interactive()688     public void testRunnableAt_Cached_Interactive() {
689         final BroadcastOptions options = BroadcastOptions.makeBasic();
690         options.setInteractive(true);
691         doRunnableAt_Cached(makeBroadcastRecord(makeMockIntent(), options,
692                 List.of(makeMockRegisteredReceiver()), null, false), REASON_CONTAINS_INTERACTIVE);
693     }
694 
695     @Test
testRunnableAt_Cached_Alarm()696     public void testRunnableAt_Cached_Alarm() {
697         final BroadcastOptions options = BroadcastOptions.makeBasic();
698         options.setAlarmBroadcast(true);
699         doRunnableAt_Cached(makeBroadcastRecord(makeMockIntent(), options,
700                 List.of(makeMockRegisteredReceiver()), null, false), REASON_CONTAINS_ALARM);
701     }
702 
703     @Test
testRunnableAt_Cached_Prioritized_NonDeferrable()704     public void testRunnableAt_Cached_Prioritized_NonDeferrable() {
705         final List receivers = List.of(
706                 withPriority(makeManifestReceiver(PACKAGE_RED, PACKAGE_RED), 10),
707                 withPriority(makeManifestReceiver(PACKAGE_GREEN, PACKAGE_GREEN), -10));
708         final BroadcastOptions options = BroadcastOptions.makeBasic()
709                 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_NONE);
710         doRunnableAt_Cached(makeBroadcastRecord(makeMockIntent(), options,
711                 receivers, null, false), REASON_CONTAINS_PRIORITIZED);
712     }
713 
714     /**
715      * Confirm that we always prefer running pending items marked as "urgent",
716      * then "normal", then "offload", dispatching by the relative ordering
717      * within each of those clustering groups.
718      */
719     @Test
testMakeActiveNextPending()720     public void testMakeActiveNextPending() {
721         BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
722                 PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
723 
724         enqueueOrReplaceBroadcast(queue,
725                 makeBroadcastRecord(new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED)
726                         .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0);
727         enqueueOrReplaceBroadcast(queue,
728                 makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0);
729         enqueueOrReplaceBroadcast(queue,
730                 makeBroadcastRecord(new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED)
731                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0);
732         enqueueOrReplaceBroadcast(queue,
733                 makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)
734                         .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0);
735         enqueueOrReplaceBroadcast(queue,
736                 makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0);
737         enqueueOrReplaceBroadcast(queue,
738                 makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
739                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0);
740 
741         queue.makeActiveNextPending();
742         assertEquals(Intent.ACTION_LOCKED_BOOT_COMPLETED, queue.getActive().intent.getAction());
743 
744         // To maximize test coverage, dump current state; we're not worried
745         // about the actual output, just that we don't crash
746         queue.getActive().setDeliveryState(0, BroadcastRecord.DELIVERY_SCHEDULED, "Test-driven");
747         queue.dumpLocked(SystemClock.uptimeMillis(),
748                 new IndentingPrintWriter(new PrintWriter(Writer.nullWriter())));
749 
750         queue.makeActiveNextPending();
751         assertEquals(Intent.ACTION_LOCALE_CHANGED, queue.getActive().intent.getAction());
752         queue.makeActiveNextPending();
753         assertEquals(Intent.ACTION_TIMEZONE_CHANGED, queue.getActive().intent.getAction());
754         queue.makeActiveNextPending();
755         assertEquals(Intent.ACTION_TIME_TICK, queue.getActive().intent.getAction());
756         queue.makeActiveNextPending();
757         assertEquals(Intent.ACTION_AIRPLANE_MODE_CHANGED, queue.getActive().intent.getAction());
758         queue.makeActiveNextPending();
759         assertEquals(Intent.ACTION_ALARM_CHANGED, queue.getActive().intent.getAction());
760         assertTrue(queue.isEmpty());
761     }
762 
763     /**
764      * Verify that we don't let urgent broadcasts starve delivery of non-urgent
765      */
766     @Test
testUrgentStarvation()767     public void testUrgentStarvation() {
768         final BroadcastOptions optInteractive = BroadcastOptions.makeBasic();
769         optInteractive.setInteractive(true);
770 
771         mConstants.MAX_CONSECUTIVE_URGENT_DISPATCHES = 2;
772         BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
773                 PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
774         long timeCounter = 100;
775 
776         // mix of broadcasts, with more than 2 fg/urgent
777         enqueueOrReplaceBroadcast(queue,
778                 makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)),
779                         0, timeCounter++);
780         enqueueOrReplaceBroadcast(queue,
781                 makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)),
782                         0, timeCounter++);
783         enqueueOrReplaceBroadcast(queue,
784                 makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0, timeCounter++);
785         enqueueOrReplaceBroadcast(queue,
786                 makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
787                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, timeCounter++);
788         enqueueOrReplaceBroadcast(queue,
789                 makeBroadcastRecord(new Intent(Intent.ACTION_APPLICATION_PREFERENCES),
790                         optInteractive), 0, timeCounter++);
791         enqueueOrReplaceBroadcast(queue,
792                 makeBroadcastRecord(new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE),
793                         optInteractive), 0, timeCounter++);
794         enqueueOrReplaceBroadcast(queue,
795                 makeBroadcastRecord(new Intent(Intent.ACTION_INPUT_METHOD_CHANGED)
796                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, timeCounter++);
797         enqueueOrReplaceBroadcast(queue,
798                 makeBroadcastRecord(new Intent(Intent.ACTION_NEW_OUTGOING_CALL),
799                         optInteractive), 0, timeCounter++);
800 
801         queue.makeActiveNextPending();
802         assertEquals(Intent.ACTION_LOCALE_CHANGED, queue.getActive().intent.getAction());
803         queue.makeActiveNextPending();
804         assertEquals(Intent.ACTION_APPLICATION_PREFERENCES, queue.getActive().intent.getAction());
805         // after MAX_CONSECUTIVE_URGENT_DISPATCHES expect an ordinary one next
806         queue.makeActiveNextPending();
807         assertEquals(Intent.ACTION_TIMEZONE_CHANGED, queue.getActive().intent.getAction());
808         // and then back to prioritizing urgent ones
809         queue.makeActiveNextPending();
810         assertEquals(AppWidgetManager.ACTION_APPWIDGET_UPDATE,
811                 queue.getActive().intent.getAction());
812         queue.makeActiveNextPending();
813         assertEquals(Intent.ACTION_INPUT_METHOD_CHANGED, queue.getActive().intent.getAction());
814         // verify the reset-count-then-resume worked too
815         queue.makeActiveNextPending();
816         assertEquals(Intent.ACTION_ALARM_CHANGED, queue.getActive().intent.getAction());
817     }
818 
819     /**
820      * Verify that offload broadcasts are not starved because of broadcasts in higher priority
821      * queues.
822      */
823     @Test
testOffloadStarvation()824     public void testOffloadStarvation() {
825         final BroadcastOptions optInteractive = BroadcastOptions.makeBasic();
826         optInteractive.setInteractive(true);
827 
828         mConstants.MAX_CONSECUTIVE_URGENT_DISPATCHES = 1;
829         mConstants.MAX_CONSECUTIVE_NORMAL_DISPATCHES = 2;
830         final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
831                 PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
832         long timeCounter = 100;
833 
834         // mix of broadcasts, with more than 2 normal
835         enqueueOrReplaceBroadcast(queue,
836                 makeBroadcastRecord(new Intent(Intent.ACTION_BOOT_COMPLETED)
837                         .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, timeCounter++);
838         enqueueOrReplaceBroadcast(queue,
839                 makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)),
840                         0, timeCounter++);
841         enqueueOrReplaceBroadcast(queue,
842                 makeBroadcastRecord(new Intent(Intent.ACTION_PACKAGE_CHANGED)
843                         .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, timeCounter++);
844         enqueueOrReplaceBroadcast(queue,
845                 makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)),
846                 0, timeCounter++);
847         enqueueOrReplaceBroadcast(queue,
848                 makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0, timeCounter++);
849         enqueueOrReplaceBroadcast(queue,
850                 makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
851                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, timeCounter++);
852         enqueueOrReplaceBroadcast(queue,
853                 makeBroadcastRecord(new Intent(Intent.ACTION_APPLICATION_PREFERENCES),
854                         optInteractive), 0, timeCounter++);
855         enqueueOrReplaceBroadcast(queue,
856                 makeBroadcastRecord(new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE),
857                         optInteractive), 0, timeCounter++);
858         enqueueOrReplaceBroadcast(queue,
859                 makeBroadcastRecord(new Intent(Intent.ACTION_INPUT_METHOD_CHANGED)
860                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, timeCounter++);
861         enqueueOrReplaceBroadcast(queue,
862                 makeBroadcastRecord(new Intent(Intent.ACTION_NEW_OUTGOING_CALL),
863                         optInteractive), 0, timeCounter++);
864 
865         queue.makeActiveNextPending();
866         assertEquals(Intent.ACTION_LOCALE_CHANGED, queue.getActive().intent.getAction());
867         // after MAX_CONSECUTIVE_URGENT_DISPATCHES expect an ordinary one next
868         queue.makeActiveNextPending();
869         assertEquals(Intent.ACTION_TIMEZONE_CHANGED, queue.getActive().intent.getAction());
870         // and then back to prioritizing urgent ones
871         queue.makeActiveNextPending();
872         assertEquals(Intent.ACTION_APPLICATION_PREFERENCES, queue.getActive().intent.getAction());
873         // after MAX_CONSECUTIVE_URGENT_DISPATCHES, again an ordinary one next
874         queue.makeActiveNextPending();
875         assertEquals(Intent.ACTION_ALARM_CHANGED, queue.getActive().intent.getAction());
876         // and then back to prioritizing urgent ones
877         queue.makeActiveNextPending();
878         assertEquals(AppWidgetManager.ACTION_APPWIDGET_UPDATE,
879                 queue.getActive().intent.getAction());
880         // after MAX_CONSECUTIVE_URGENT_DISPATCHES and MAX_CONSECUTIVE_NORMAL_DISPATCHES,
881         // expect an offload one
882         queue.makeActiveNextPending();
883         assertEquals(Intent.ACTION_BOOT_COMPLETED, queue.getActive().intent.getAction());
884         // and then back to prioritizing urgent ones
885         queue.makeActiveNextPending();
886         assertEquals(Intent.ACTION_INPUT_METHOD_CHANGED, queue.getActive().intent.getAction());
887     }
888 
889     /**
890      * Verify that BroadcastProcessQueue#setPrioritizeEarliest() works as expected.
891      */
892     @Test
testPrioritizeEarliest()893     public void testPrioritizeEarliest() {
894         final BroadcastOptions optInteractive = BroadcastOptions.makeBasic();
895         optInteractive.setInteractive(true);
896 
897         BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
898                 PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
899         queue.addPrioritizeEarliestRequest();
900         long timeCounter = 100;
901 
902         enqueueOrReplaceBroadcast(queue,
903                 makeBroadcastRecord(new Intent(Intent.ACTION_BOOT_COMPLETED)
904                         .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, timeCounter++);
905         enqueueOrReplaceBroadcast(queue,
906                 makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)),
907                         0, timeCounter++);
908         enqueueOrReplaceBroadcast(queue,
909                 makeBroadcastRecord(new Intent(Intent.ACTION_PACKAGE_CHANGED)
910                         .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, timeCounter++);
911         enqueueOrReplaceBroadcast(queue,
912                 makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)),
913                         0, timeCounter++);
914         enqueueOrReplaceBroadcast(queue,
915                 makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)),
916                         0, timeCounter++);
917         enqueueOrReplaceBroadcast(queue,
918                 makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
919                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, timeCounter++);
920         enqueueOrReplaceBroadcast(queue,
921                 makeBroadcastRecord(new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE),
922                         optInteractive), 0, timeCounter++);
923 
924         // When we mark BroadcastProcessQueue to prioritize earliest, we should
925         // expect to dispatch broadcasts in the order they were enqueued
926         queue.makeActiveNextPending();
927         assertEquals(Intent.ACTION_BOOT_COMPLETED, queue.getActive().intent.getAction());
928         queue.makeActiveNextPending();
929         assertEquals(Intent.ACTION_TIMEZONE_CHANGED, queue.getActive().intent.getAction());
930         // after MAX_CONSECUTIVE_URGENT_DISPATCHES expect an ordinary one next
931         queue.makeActiveNextPending();
932         assertEquals(Intent.ACTION_PACKAGE_CHANGED, queue.getActive().intent.getAction());
933         // and then back to prioritizing urgent ones
934         queue.makeActiveNextPending();
935         assertEquals(Intent.ACTION_ALARM_CHANGED, queue.getActive().intent.getAction());
936         queue.makeActiveNextPending();
937         assertEquals(Intent.ACTION_TIME_TICK, queue.getActive().intent.getAction());
938         queue.makeActiveNextPending();
939         assertEquals(Intent.ACTION_LOCALE_CHANGED, queue.getActive().intent.getAction());
940         // verify the reset-count-then-resume worked too
941         queue.makeActiveNextPending();
942         assertEquals(AppWidgetManager.ACTION_APPWIDGET_UPDATE,
943                 queue.getActive().intent.getAction());
944 
945 
946         queue.removePrioritizeEarliestRequest();
947 
948         enqueueOrReplaceBroadcast(queue,
949                 makeBroadcastRecord(new Intent(Intent.ACTION_BOOT_COMPLETED)
950                         .addFlags(Intent.FLAG_RECEIVER_OFFLOAD)), 0, timeCounter++);
951         enqueueOrReplaceBroadcast(queue,
952                 makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)),
953                 0, timeCounter++);
954         enqueueOrReplaceBroadcast(queue,
955                 makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
956                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0, timeCounter++);
957 
958         // Once the request to prioritize earliest is removed, we should expect broadcasts
959         // to be dispatched in the order of foreground, normal and then offload.
960         queue.makeActiveNextPending();
961         assertEquals(Intent.ACTION_LOCALE_CHANGED, queue.getActive().intent.getAction());
962         queue.makeActiveNextPending();
963         assertEquals(Intent.ACTION_TIMEZONE_CHANGED, queue.getActive().intent.getAction());
964         queue.makeActiveNextPending();
965         assertEquals(Intent.ACTION_BOOT_COMPLETED, queue.getActive().intent.getAction());
966     }
967 
968     /**
969      * Verify that sending a broadcast with DELIVERY_GROUP_POLICY_MOST_RECENT works as expected.
970      */
971     @Test
testDeliveryGroupPolicy_mostRecent()972     public void testDeliveryGroupPolicy_mostRecent() {
973         final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
974         final BroadcastOptions optionsTimeTick = BroadcastOptions.makeBasic();
975         optionsTimeTick.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
976 
977         final Intent musicVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
978         musicVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE,
979                 AudioManager.STREAM_MUSIC);
980         final BroadcastOptions optionsMusicVolumeChanged = BroadcastOptions.makeBasic();
981         optionsMusicVolumeChanged.setDeliveryGroupPolicy(
982                 BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
983         optionsMusicVolumeChanged.setDeliveryGroupMatchingKey("audio",
984                 String.valueOf(AudioManager.STREAM_MUSIC));
985 
986         final Intent alarmVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
987         alarmVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE,
988                 AudioManager.STREAM_ALARM);
989         final BroadcastOptions optionsAlarmVolumeChanged = BroadcastOptions.makeBasic();
990         optionsAlarmVolumeChanged.setDeliveryGroupPolicy(
991                 BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
992         optionsAlarmVolumeChanged.setDeliveryGroupMatchingKey("audio",
993                 String.valueOf(AudioManager.STREAM_ALARM));
994 
995         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick));
996         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(musicVolumeChanged,
997                 optionsMusicVolumeChanged));
998         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(alarmVolumeChanged,
999                 optionsAlarmVolumeChanged));
1000         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(musicVolumeChanged,
1001                 optionsMusicVolumeChanged));
1002 
1003         final BroadcastProcessQueue queue = mImpl.getProcessQueue(PACKAGE_GREEN,
1004                 getUidForPackage(PACKAGE_GREEN));
1005         // Verify that the older musicVolumeChanged has been removed.
1006         verifyPendingRecords(queue,
1007                 List.of(timeTick, alarmVolumeChanged, musicVolumeChanged));
1008 
1009         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick));
1010         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(alarmVolumeChanged,
1011                 optionsAlarmVolumeChanged));
1012         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(musicVolumeChanged,
1013                 optionsMusicVolumeChanged));
1014         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(alarmVolumeChanged,
1015                 optionsAlarmVolumeChanged));
1016         // Verify that the older alarmVolumeChanged has been removed.
1017         verifyPendingRecords(queue,
1018                 List.of(timeTick, musicVolumeChanged, alarmVolumeChanged));
1019 
1020         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick));
1021         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(musicVolumeChanged,
1022                 optionsMusicVolumeChanged));
1023         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(alarmVolumeChanged,
1024                 optionsAlarmVolumeChanged));
1025         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick));
1026         // Verify that the older timeTick has been removed.
1027         verifyPendingRecords(queue,
1028                 List.of(musicVolumeChanged, alarmVolumeChanged, timeTick));
1029     }
1030 
1031     @Test
testDeliveryGroupPolicy_diffReceivers()1032     public void testDeliveryGroupPolicy_diffReceivers() {
1033         final Intent screenOn = new Intent(Intent.ACTION_SCREEN_ON);
1034         final Intent screenOff = new Intent(Intent.ACTION_SCREEN_OFF);
1035         final BroadcastOptions screenOnOffOptions = BroadcastOptions.makeBasic()
1036                 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
1037                 .setDeliveryGroupMatchingKey("screenOnOff", Intent.ACTION_SCREEN_ON);
1038 
1039         final Object greenReceiver = makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN);
1040         final Object redReceiver = makeManifestReceiver(PACKAGE_RED, CLASS_RED);
1041         final Object blueReceiver = makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE);
1042 
1043         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOn, screenOnOffOptions,
1044                 List.of(greenReceiver, blueReceiver), false));
1045         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOff, screenOnOffOptions,
1046                 List.of(greenReceiver, redReceiver, blueReceiver), false));
1047         final BroadcastProcessQueue greenQueue = mImpl.getProcessQueue(PACKAGE_GREEN,
1048                 getUidForPackage(PACKAGE_GREEN));
1049         final BroadcastProcessQueue redQueue = mImpl.getProcessQueue(PACKAGE_RED,
1050                 getUidForPackage(PACKAGE_RED));
1051         final BroadcastProcessQueue blueQueue = mImpl.getProcessQueue(PACKAGE_BLUE,
1052                 getUidForPackage(PACKAGE_BLUE));
1053         verifyPendingRecords(greenQueue, List.of(screenOff));
1054         verifyPendingRecords(redQueue, List.of(screenOff));
1055         verifyPendingRecords(blueQueue, List.of(screenOff));
1056 
1057         assertTrue(greenQueue.isEmpty());
1058         assertTrue(redQueue.isEmpty());
1059         assertTrue(blueQueue.isEmpty());
1060 
1061         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOff, screenOnOffOptions,
1062                 List.of(greenReceiver, redReceiver, blueReceiver), false));
1063         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOn, screenOnOffOptions,
1064                 List.of(greenReceiver, blueReceiver), false));
1065         verifyPendingRecords(greenQueue, List.of(screenOn));
1066         verifyPendingRecords(redQueue, List.of(screenOff));
1067         verifyPendingRecords(blueQueue, List.of(screenOn));
1068     }
1069 
1070     @Test
testDeliveryGroupPolicy_ordered_diffReceivers()1071     public void testDeliveryGroupPolicy_ordered_diffReceivers() {
1072         final Intent screenOn = new Intent(Intent.ACTION_SCREEN_ON);
1073         final Intent screenOff = new Intent(Intent.ACTION_SCREEN_OFF);
1074         final BroadcastOptions screenOnOffOptions = BroadcastOptions.makeBasic()
1075                 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
1076                 .setDeliveryGroupMatchingKey("screenOnOff", Intent.ACTION_SCREEN_ON);
1077 
1078         final Object greenReceiver = makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN);
1079         final Object redReceiver = makeManifestReceiver(PACKAGE_RED, CLASS_RED);
1080         final Object blueReceiver = makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE);
1081 
1082         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOn, screenOnOffOptions,
1083                 List.of(greenReceiver, blueReceiver), true));
1084         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOff, screenOnOffOptions,
1085                 List.of(greenReceiver, redReceiver, blueReceiver), true));
1086         final BroadcastProcessQueue greenQueue = mImpl.getProcessQueue(PACKAGE_GREEN,
1087                 getUidForPackage(PACKAGE_GREEN));
1088         final BroadcastProcessQueue redQueue = mImpl.getProcessQueue(PACKAGE_RED,
1089                 getUidForPackage(PACKAGE_RED));
1090         final BroadcastProcessQueue blueQueue = mImpl.getProcessQueue(PACKAGE_BLUE,
1091                 getUidForPackage(PACKAGE_BLUE));
1092         verifyPendingRecords(greenQueue, List.of(screenOff));
1093         verifyPendingRecords(redQueue, List.of(screenOff));
1094         verifyPendingRecords(blueQueue, List.of(screenOff));
1095 
1096         assertTrue(greenQueue.isEmpty());
1097         assertTrue(redQueue.isEmpty());
1098         assertTrue(blueQueue.isEmpty());
1099 
1100         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOff, screenOnOffOptions,
1101                 List.of(greenReceiver, redReceiver, blueReceiver), true));
1102         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOn, screenOnOffOptions,
1103                 List.of(greenReceiver, blueReceiver), true));
1104         verifyPendingRecords(greenQueue, List.of(screenOff, screenOn));
1105         verifyPendingRecords(redQueue, List.of(screenOff));
1106         verifyPendingRecords(blueQueue, List.of(screenOff, screenOn));
1107     }
1108 
1109     @Test
testDeliveryGroupPolicy_resultTo_diffReceivers()1110     public void testDeliveryGroupPolicy_resultTo_diffReceivers() {
1111         final Intent screenOn = new Intent(Intent.ACTION_SCREEN_ON);
1112         final Intent screenOff = new Intent(Intent.ACTION_SCREEN_OFF);
1113         final BroadcastOptions screenOnOffOptions = BroadcastOptions.makeBasic()
1114                 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
1115                 .setDeliveryGroupMatchingKey("screenOnOff", Intent.ACTION_SCREEN_ON);
1116 
1117         final Object greenReceiver = makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN);
1118         final Object redReceiver = makeManifestReceiver(PACKAGE_RED, CLASS_RED);
1119         final Object blueReceiver = makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE);
1120         final IIntentReceiver resultTo = mock(IIntentReceiver.class);
1121 
1122         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOn, screenOnOffOptions,
1123                 List.of(greenReceiver, blueReceiver), resultTo, false));
1124         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOff, screenOnOffOptions,
1125                 List.of(greenReceiver, redReceiver, blueReceiver), resultTo, false));
1126         final BroadcastProcessQueue greenQueue = mImpl.getProcessQueue(PACKAGE_GREEN,
1127                 getUidForPackage(PACKAGE_GREEN));
1128         final BroadcastProcessQueue redQueue = mImpl.getProcessQueue(PACKAGE_RED,
1129                 getUidForPackage(PACKAGE_RED));
1130         final BroadcastProcessQueue blueQueue = mImpl.getProcessQueue(PACKAGE_BLUE,
1131                 getUidForPackage(PACKAGE_BLUE));
1132         verifyPendingRecords(greenQueue, List.of(screenOff));
1133         verifyPendingRecords(redQueue, List.of(screenOff));
1134         verifyPendingRecords(blueQueue, List.of(screenOff));
1135 
1136         assertTrue(greenQueue.isEmpty());
1137         assertTrue(redQueue.isEmpty());
1138         assertTrue(blueQueue.isEmpty());
1139 
1140         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOff, screenOnOffOptions,
1141                 List.of(greenReceiver, redReceiver, blueReceiver), resultTo, false));
1142         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOn, screenOnOffOptions,
1143                 List.of(greenReceiver, blueReceiver), resultTo, false));
1144         verifyPendingRecords(greenQueue, List.of(screenOff, screenOn));
1145         verifyPendingRecords(redQueue, List.of(screenOff));
1146         verifyPendingRecords(blueQueue, List.of(screenOff, screenOn));
1147 
1148         final BroadcastRecord screenOffRecord = makeBroadcastRecord(screenOff, screenOnOffOptions,
1149                 List.of(greenReceiver, redReceiver, blueReceiver), resultTo, false);
1150         screenOffRecord.setDeliveryState(2, BroadcastRecord.DELIVERY_DEFERRED,
1151                 "testDeliveryGroupPolicy_resultTo_diffReceivers");
1152         mImpl.enqueueBroadcastLocked(screenOffRecord);
1153         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOn, screenOnOffOptions,
1154                 List.of(greenReceiver, blueReceiver), resultTo, false));
1155         verifyPendingRecords(greenQueue, List.of(screenOff, screenOn));
1156         verifyPendingRecords(redQueue, List.of(screenOff));
1157         verifyPendingRecords(blueQueue, List.of(screenOn));
1158     }
1159 
1160     @Test
testDeliveryGroupPolicy_prioritized_diffReceivers()1161     public void testDeliveryGroupPolicy_prioritized_diffReceivers() {
1162         final Intent screenOn = new Intent(Intent.ACTION_SCREEN_ON);
1163         final Intent screenOff = new Intent(Intent.ACTION_SCREEN_OFF);
1164         final BroadcastOptions screenOnOffOptions = BroadcastOptions.makeBasic()
1165                 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
1166                 .setDeliveryGroupMatchingKey("screenOnOff", Intent.ACTION_SCREEN_ON);
1167 
1168         final Object greenReceiver = withPriority(
1169                 makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN), 10);
1170         final Object redReceiver = withPriority(
1171                 makeManifestReceiver(PACKAGE_RED, CLASS_RED), 5);
1172         final Object blueReceiver = withPriority(
1173                 makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE), 0);
1174 
1175         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOn, screenOnOffOptions,
1176                 List.of(greenReceiver, blueReceiver), false));
1177         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOff, screenOnOffOptions,
1178                 List.of(greenReceiver, redReceiver, blueReceiver), false));
1179         final BroadcastProcessQueue greenQueue = mImpl.getProcessQueue(PACKAGE_GREEN,
1180                 getUidForPackage(PACKAGE_GREEN));
1181         final BroadcastProcessQueue redQueue = mImpl.getProcessQueue(PACKAGE_RED,
1182                 getUidForPackage(PACKAGE_RED));
1183         final BroadcastProcessQueue blueQueue = mImpl.getProcessQueue(PACKAGE_BLUE,
1184                 getUidForPackage(PACKAGE_BLUE));
1185         verifyPendingRecords(greenQueue, List.of(screenOff));
1186         verifyPendingRecords(redQueue, List.of(screenOff));
1187         verifyPendingRecords(blueQueue, List.of(screenOff));
1188 
1189         assertTrue(greenQueue.isEmpty());
1190         assertTrue(redQueue.isEmpty());
1191         assertTrue(blueQueue.isEmpty());
1192 
1193         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOff, screenOnOffOptions,
1194                 List.of(greenReceiver, redReceiver, blueReceiver), false));
1195         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(screenOn, screenOnOffOptions,
1196                 List.of(greenReceiver, blueReceiver), false));
1197         verifyPendingRecords(greenQueue, List.of(screenOff, screenOn));
1198         verifyPendingRecords(redQueue, List.of(screenOff));
1199         verifyPendingRecords(blueQueue, List.of(screenOff, screenOn));
1200     }
1201 
1202     /**
1203      * Verify that sending a broadcast with DELIVERY_GROUP_POLICY_MERGED works as expected.
1204      */
1205     @Test
testDeliveryGroupPolicy_merged()1206     public void testDeliveryGroupPolicy_merged() {
1207         final BundleMerger extrasMerger = new BundleMerger();
1208         extrasMerger.setMergeStrategy(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST,
1209                 BundleMerger.STRATEGY_ARRAY_APPEND);
1210 
1211         final Intent packageChangedForUid = createPackageChangedIntent(TEST_UID,
1212                 List.of("com.testuid.component1"));
1213         final BroadcastOptions optionsPackageChangedForUid = BroadcastOptions.makeBasic();
1214         optionsPackageChangedForUid.setDeliveryGroupPolicy(
1215                 BroadcastOptions.DELIVERY_GROUP_POLICY_MERGED);
1216         optionsPackageChangedForUid.setDeliveryGroupMatchingKey("package",
1217                 String.valueOf(TEST_UID));
1218         optionsPackageChangedForUid.setDeliveryGroupExtrasMerger(extrasMerger);
1219 
1220         final Intent secondPackageChangedForUid = createPackageChangedIntent(TEST_UID,
1221                 List.of("com.testuid.component2", "com.testuid.component3"));
1222 
1223         final Intent packageChangedForUid2 = createPackageChangedIntent(TEST_UID2,
1224                 List.of("com.testuid2.component1"));
1225         final BroadcastOptions optionsPackageChangedForUid2 = BroadcastOptions.makeBasic();
1226         optionsPackageChangedForUid.setDeliveryGroupPolicy(
1227                 BroadcastOptions.DELIVERY_GROUP_POLICY_MERGED);
1228         optionsPackageChangedForUid.setDeliveryGroupMatchingKey("package",
1229                 String.valueOf(TEST_UID2));
1230         optionsPackageChangedForUid.setDeliveryGroupExtrasMerger(extrasMerger);
1231 
1232         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(packageChangedForUid,
1233                 optionsPackageChangedForUid));
1234         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(packageChangedForUid2,
1235                 optionsPackageChangedForUid2));
1236         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(secondPackageChangedForUid,
1237                 optionsPackageChangedForUid));
1238 
1239         final BroadcastProcessQueue queue = mImpl.getProcessQueue(PACKAGE_GREEN,
1240                 getUidForPackage(PACKAGE_GREEN));
1241         final Intent expectedPackageChangedForUid = createPackageChangedIntent(TEST_UID,
1242                 List.of("com.testuid.component2", "com.testuid.component3",
1243                         "com.testuid.component1"));
1244         // Verify that packageChangedForUid and secondPackageChangedForUid broadcasts
1245         // have been merged.
1246         verifyPendingRecords(queue, List.of(packageChangedForUid2, expectedPackageChangedForUid));
1247     }
1248 
1249     @Test
testDeliveryGroupPolicy_matchingFilter()1250     public void testDeliveryGroupPolicy_matchingFilter() {
1251         final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
1252         final BroadcastOptions optionsTimeTick = BroadcastOptions.makeBasic();
1253         optionsTimeTick.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
1254 
1255         final Intent musicVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
1256         musicVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE,
1257                 AudioManager.STREAM_MUSIC);
1258         final IntentFilter filterMusicVolumeChanged = new IntentFilter(
1259                 AudioManager.VOLUME_CHANGED_ACTION);
1260         filterMusicVolumeChanged.addExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE,
1261                 AudioManager.STREAM_MUSIC);
1262         final BroadcastOptions optionsMusicVolumeChanged = BroadcastOptions.makeBasic();
1263         optionsMusicVolumeChanged.setDeliveryGroupPolicy(
1264                 BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
1265         optionsMusicVolumeChanged.setDeliveryGroupMatchingFilter(filterMusicVolumeChanged);
1266 
1267         final Intent alarmVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
1268         alarmVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE,
1269                 AudioManager.STREAM_ALARM);
1270         final IntentFilter filterAlarmVolumeChanged = new IntentFilter(
1271                 AudioManager.VOLUME_CHANGED_ACTION);
1272         filterAlarmVolumeChanged.addExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE,
1273                 AudioManager.STREAM_ALARM);
1274         final BroadcastOptions optionsAlarmVolumeChanged = BroadcastOptions.makeBasic();
1275         optionsAlarmVolumeChanged.setDeliveryGroupPolicy(
1276                 BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
1277         optionsAlarmVolumeChanged.setDeliveryGroupMatchingFilter(filterAlarmVolumeChanged);
1278 
1279         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick));
1280         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(musicVolumeChanged,
1281                 optionsMusicVolumeChanged));
1282         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(alarmVolumeChanged,
1283                 optionsAlarmVolumeChanged));
1284         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(musicVolumeChanged,
1285                 optionsMusicVolumeChanged));
1286 
1287         final BroadcastProcessQueue queue = mImpl.getProcessQueue(PACKAGE_GREEN,
1288                 getUidForPackage(PACKAGE_GREEN));
1289         // Verify that the older musicVolumeChanged has been removed.
1290         verifyPendingRecords(queue,
1291                 List.of(timeTick, alarmVolumeChanged, musicVolumeChanged));
1292 
1293         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick));
1294         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(alarmVolumeChanged,
1295                 optionsAlarmVolumeChanged));
1296         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(musicVolumeChanged,
1297                 optionsMusicVolumeChanged));
1298         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(alarmVolumeChanged,
1299                 optionsAlarmVolumeChanged));
1300         // Verify that the older alarmVolumeChanged has been removed.
1301         verifyPendingRecords(queue,
1302                 List.of(timeTick, musicVolumeChanged, alarmVolumeChanged));
1303 
1304         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick));
1305         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(musicVolumeChanged,
1306                 optionsMusicVolumeChanged));
1307         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(alarmVolumeChanged,
1308                 optionsAlarmVolumeChanged));
1309         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick));
1310         // Verify that the older timeTick has been removed.
1311         verifyPendingRecords(queue,
1312                 List.of(musicVolumeChanged, alarmVolumeChanged, timeTick));
1313     }
1314 
1315     @Test
testDeliveryGroupPolicy_merged_matchingFilter()1316     public void testDeliveryGroupPolicy_merged_matchingFilter() {
1317         final long now = SystemClock.elapsedRealtime();
1318         final Pair<Intent, BroadcastOptions> dropboxEntryBroadcast1 = createDropboxBroadcast(
1319                 "TAG_A", now, 2);
1320         final Pair<Intent, BroadcastOptions> dropboxEntryBroadcast2 = createDropboxBroadcast(
1321                 "TAG_B", now + 1000, 4);
1322         final Pair<Intent, BroadcastOptions> dropboxEntryBroadcast3 = createDropboxBroadcast(
1323                 "TAG_A", now + 2000, 7);
1324 
1325         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(dropboxEntryBroadcast1.first,
1326                 dropboxEntryBroadcast1.second));
1327         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(dropboxEntryBroadcast2.first,
1328                 dropboxEntryBroadcast2.second));
1329         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(dropboxEntryBroadcast3.first,
1330                 dropboxEntryBroadcast3.second));
1331 
1332         final BroadcastProcessQueue queue = mImpl.getProcessQueue(PACKAGE_GREEN,
1333                 getUidForPackage(PACKAGE_GREEN));
1334         // dropboxEntryBroadcast1 and dropboxEntryBroadcast3 should be merged as they use the same
1335         // tag and there shouldn't be a change to dropboxEntryBroadcast2.
1336         final Pair<Intent, BroadcastOptions> expectedMergedBroadcast = createDropboxBroadcast(
1337                 "TAG_A", now + 2000, 10);
1338         verifyPendingRecords(queue, List.of(
1339                 dropboxEntryBroadcast2.first, expectedMergedBroadcast.first));
1340     }
1341 
1342     @Test
testDeliveryGroupPolicy_merged_multipleReceivers()1343     public void testDeliveryGroupPolicy_merged_multipleReceivers() {
1344         final long now = SystemClock.elapsedRealtime();
1345         final Pair<Intent, BroadcastOptions> dropboxEntryBroadcast1 = createDropboxBroadcast(
1346                 "TAG_A", now, 2);
1347         final Pair<Intent, BroadcastOptions> dropboxEntryBroadcast2 = createDropboxBroadcast(
1348                 "TAG_A", now + 1000, 4);
1349 
1350         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(dropboxEntryBroadcast1.first,
1351                 dropboxEntryBroadcast1.second,
1352                 List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
1353                         makeManifestReceiver(PACKAGE_RED, CLASS_RED)),
1354                 false));
1355         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(dropboxEntryBroadcast2.first,
1356                 dropboxEntryBroadcast2.second,
1357                 List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
1358                         makeManifestReceiver(PACKAGE_RED, CLASS_RED)),
1359                 false));
1360 
1361         final BroadcastProcessQueue greenQueue = mImpl.getProcessQueue(PACKAGE_GREEN,
1362                 getUidForPackage(PACKAGE_GREEN));
1363         final BroadcastProcessQueue redQueue = mImpl.getProcessQueue(PACKAGE_RED,
1364                 getUidForPackage(PACKAGE_RED));
1365 
1366         verifyPendingRecords(greenQueue,
1367                 List.of(dropboxEntryBroadcast1.first, dropboxEntryBroadcast2.first));
1368         verifyPendingRecords(redQueue,
1369                 List.of(dropboxEntryBroadcast1.first, dropboxEntryBroadcast2.first));
1370     }
1371 
1372     @Test
testDeliveryGroupPolicy_sameAction_differentMatchingCriteria()1373     public void testDeliveryGroupPolicy_sameAction_differentMatchingCriteria() {
1374         final Intent closeSystemDialogs1 = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
1375         final BroadcastOptions optionsCloseSystemDialog1 = BroadcastOptions.makeBasic()
1376                 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
1377 
1378         final Intent closeSystemDialogs2 = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
1379                 .putExtra("reason", "testing");
1380         final BroadcastOptions optionsCloseSystemDialog2 = BroadcastOptions.makeBasic()
1381                 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
1382                 .setDeliveryGroupMatchingKey(Intent.ACTION_CLOSE_SYSTEM_DIALOGS, "testing");
1383 
1384         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(
1385                 closeSystemDialogs1, optionsCloseSystemDialog1));
1386         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(
1387                 closeSystemDialogs2, optionsCloseSystemDialog2));
1388         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(
1389                 closeSystemDialogs1, optionsCloseSystemDialog1));
1390         // Verify that only the older broadcast with no extras was removed.
1391         final BroadcastProcessQueue queue = mImpl.getProcessQueue(PACKAGE_GREEN,
1392                 getUidForPackage(PACKAGE_GREEN));
1393         verifyPendingRecords(queue, List.of(closeSystemDialogs2, closeSystemDialogs1));
1394 
1395         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(
1396                 closeSystemDialogs2, optionsCloseSystemDialog2));
1397         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(
1398                 closeSystemDialogs1, optionsCloseSystemDialog1));
1399         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(
1400                 closeSystemDialogs2, optionsCloseSystemDialog2));
1401         // Verify that only the older broadcast with no extras was removed.
1402         verifyPendingRecords(queue, List.of(closeSystemDialogs1, closeSystemDialogs2));
1403     }
1404 
createDropboxBroadcast(String tag, long timestampMs, int droppedCount)1405     private Pair<Intent, BroadcastOptions> createDropboxBroadcast(String tag, long timestampMs,
1406             int droppedCount) {
1407         final Intent dropboxEntryAdded = new Intent(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED);
1408         dropboxEntryAdded.putExtra(DropBoxManager.EXTRA_TAG, tag);
1409         dropboxEntryAdded.putExtra(DropBoxManager.EXTRA_TIME, timestampMs);
1410         dropboxEntryAdded.putExtra(DropBoxManager.EXTRA_DROPPED_COUNT, droppedCount);
1411 
1412         final BundleMerger extrasMerger = new BundleMerger();
1413         extrasMerger.setDefaultMergeStrategy(BundleMerger.STRATEGY_FIRST);
1414         extrasMerger.setMergeStrategy(DropBoxManager.EXTRA_TIME,
1415                 BundleMerger.STRATEGY_COMPARABLE_MAX);
1416         extrasMerger.setMergeStrategy(DropBoxManager.EXTRA_DROPPED_COUNT,
1417                 BundleMerger.STRATEGY_NUMBER_INCREMENT_FIRST_AND_ADD);
1418         final IntentFilter matchingFilter = new IntentFilter(
1419                 DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED);
1420         matchingFilter.addExtra(DropBoxManager.EXTRA_TAG, tag);
1421         final BroadcastOptions optionsDropboxEntryAdded = BroadcastOptions.makeBasic()
1422                 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MERGED)
1423                 .setDeliveryGroupMatchingFilter(matchingFilter)
1424                 .setDeliveryGroupExtrasMerger(extrasMerger);
1425         return Pair.create(dropboxEntryAdded, optionsDropboxEntryAdded);
1426     }
1427 
1428     @Test
testVerifyEnqueuedTime_withReplacePending()1429     public void testVerifyEnqueuedTime_withReplacePending() {
1430         final Intent userPresent = new Intent(Intent.ACTION_USER_PRESENT);
1431         userPresent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
1432 
1433         final BroadcastRecord userPresentRecord1 = makeBroadcastRecord(userPresent);
1434         final BroadcastRecord userPresentRecord2 = makeBroadcastRecord(userPresent);
1435 
1436         mImpl.enqueueBroadcastLocked(userPresentRecord1);
1437         mImpl.enqueueBroadcastLocked(userPresentRecord2);
1438 
1439         final BroadcastProcessQueue queue = mImpl.getProcessQueue(PACKAGE_GREEN,
1440                 getUidForPackage(PACKAGE_GREEN));
1441         queue.makeActiveNextPending();
1442 
1443         // Verify that there is only one record pending and its enqueueTime is
1444         // same as that of userPresentRecord1.
1445         final BroadcastRecord activeRecord = queue.getActive();
1446         assertEquals(userPresentRecord1.enqueueTime, activeRecord.enqueueTime);
1447         assertEquals(userPresentRecord1.enqueueRealTime, activeRecord.enqueueRealTime);
1448         assertEquals(userPresentRecord1.enqueueClockTime, activeRecord.enqueueClockTime);
1449         assertThat(activeRecord.originalEnqueueClockTime)
1450                 .isGreaterThan(activeRecord.enqueueClockTime);
1451         assertTrue(queue.isEmpty());
1452     }
1453 
1454     @Test
testCleanupDisabledPackageReceiversLocked()1455     public void testCleanupDisabledPackageReceiversLocked() {
1456         final Intent userPresent = new Intent(Intent.ACTION_USER_PRESENT);
1457         final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
1458 
1459         final BroadcastRecord record1 = makeBroadcastRecord(userPresent, List.of(
1460                 makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
1461                 makeManifestReceiver(PACKAGE_RED, CLASS_BLUE),
1462                 makeManifestReceiver(PACKAGE_YELLOW, CLASS_RED),
1463                 makeManifestReceiver(PACKAGE_BLUE, CLASS_GREEN)
1464         ));
1465         final BroadcastRecord record2 = makeBroadcastRecord(timeTick, List.of(
1466                 makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
1467                 makeManifestReceiver(PACKAGE_RED, CLASS_RED),
1468                 makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW)
1469         ));
1470 
1471         mImpl.enqueueBroadcastLocked(record1);
1472         mImpl.enqueueBroadcastLocked(record2);
1473 
1474         mImpl.cleanupDisabledPackageReceiversLocked(null, null, UserHandle.USER_SYSTEM);
1475 
1476         // Verify that all receivers have been marked as "skipped".
1477         for (BroadcastRecord record : new BroadcastRecord[] {record1, record2}) {
1478             for (int i = 0; i < record.receivers.size(); ++i) {
1479                 final String errMsg = "Unexpected delivery state for record:" + record
1480                         + "; receiver=" + record.receivers.get(i);
1481                 assertEquals(errMsg, BroadcastRecord.DELIVERY_SKIPPED, record.getDeliveryState(i));
1482             }
1483         }
1484     }
1485 
1486     @Test
testBroadcastDeliveryEventReported()1487     public void testBroadcastDeliveryEventReported() throws Exception {
1488         final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
1489         final BroadcastOptions optionsTimeTick = BroadcastOptions.makeBasic();
1490         optionsTimeTick.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
1491 
1492         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick));
1493         mImpl.enqueueBroadcastLocked(makeBroadcastRecord(timeTick, optionsTimeTick));
1494         waitForIdle();
1495 
1496         // Verify that there is only one delivery event reported since one of the broadcasts
1497         // should have been skipped.
1498         verify(() -> FrameworkStatsLog.write(eq(BROADCAST_DELIVERY_EVENT_REPORTED),
1499                 eq(getUidForPackage(PACKAGE_GREEN)), anyInt(), eq(Intent.ACTION_TIME_TICK),
1500                 eq(BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST),
1501                 eq(BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD),
1502                 anyLong(), anyLong(), anyLong(), anyInt(), nullable(String.class),
1503                 anyString(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt()),
1504                 times(1));
1505     }
1506 
1507     @Test
testGetPreferredSchedulingGroup()1508     public void testGetPreferredSchedulingGroup() throws Exception {
1509         final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
1510                 PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
1511 
1512         assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked());
1513 
1514         final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK)
1515                 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
1516         enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(timeTick,
1517                 List.of(makeMockRegisteredReceiver())), 0);
1518         assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked());
1519 
1520         // Make the foreground broadcast as active.
1521         queue.makeActiveNextPending();
1522         assertEquals(ProcessList.SCHED_GROUP_DEFAULT, queue.getPreferredSchedulingGroupLocked());
1523 
1524         queue.makeActiveIdle();
1525         assertEquals(ProcessList.SCHED_GROUP_UNDEFINED, queue.getPreferredSchedulingGroupLocked());
1526 
1527         final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
1528         enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(airplane,
1529                 List.of(makeMockRegisteredReceiver())), 0);
1530 
1531         // Make the background broadcast as active.
1532         queue.makeActiveNextPending();
1533         assertEquals(ProcessList.SCHED_GROUP_BACKGROUND, queue.getPreferredSchedulingGroupLocked());
1534 
1535         enqueueOrReplaceBroadcast(queue, makeBroadcastRecord(timeTick,
1536                 List.of(makeMockRegisteredReceiver())), 0);
1537         // Even though the active broadcast is not a foreground one, scheduling group will be
1538         // DEFAULT since there is a foreground broadcast waiting to be delivered.
1539         assertEquals(ProcessList.SCHED_GROUP_DEFAULT, queue.getPreferredSchedulingGroupLocked());
1540     }
1541 
1542     @Test
testSkipPolicy_atEnqueueTime()1543     public void testSkipPolicy_atEnqueueTime() throws Exception {
1544         final Intent userPresent = new Intent(Intent.ACTION_USER_PRESENT);
1545         final Object greenReceiver = makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN);
1546         final Object redReceiver = makeManifestReceiver(PACKAGE_RED, CLASS_RED);
1547 
1548         final BroadcastRecord userPresentRecord = makeBroadcastRecord(userPresent,
1549                 List.of(greenReceiver, redReceiver));
1550 
1551         final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
1552         final BroadcastRecord timeTickRecord = makeBroadcastRecord(timeTick,
1553                 List.of(greenReceiver, redReceiver));
1554 
1555         doAnswer(invocation -> {
1556             final BroadcastRecord r = invocation.getArgument(0);
1557             final Object o = invocation.getArgument(1);
1558             if (userPresent.getAction().equals(r.intent.getAction())
1559                     && isReceiverEquals(o, greenReceiver)) {
1560                 return "receiver skipped by test";
1561             }
1562             return null;
1563         }).when(mSkipPolicy).shouldSkipMessage(any(BroadcastRecord.class), any());
1564 
1565         mImpl.enqueueBroadcastLocked(userPresentRecord);
1566         mImpl.enqueueBroadcastLocked(timeTickRecord);
1567 
1568         final BroadcastProcessQueue greenQueue = mImpl.getProcessQueue(PACKAGE_GREEN,
1569                 getUidForPackage(PACKAGE_GREEN));
1570         // There should be only one broadcast for green process as the other would have
1571         // been skipped.
1572         verifyPendingRecords(greenQueue, List.of(timeTick));
1573         final BroadcastProcessQueue redQueue = mImpl.getProcessQueue(PACKAGE_RED,
1574                 getUidForPackage(PACKAGE_RED));
1575         verifyPendingRecords(redQueue, List.of(userPresent, timeTick));
1576     }
1577 
createPackageChangedIntent(int uid, List<String> componentNameList)1578     private Intent createPackageChangedIntent(int uid, List<String> componentNameList) {
1579         final Intent packageChangedIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED);
1580         packageChangedIntent.putExtra(Intent.EXTRA_UID, uid);
1581         packageChangedIntent.putExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST,
1582                 componentNameList.toArray());
1583         return packageChangedIntent;
1584     }
1585 
verifyPendingRecords(BroadcastProcessQueue queue, List<Intent> intents)1586     private void verifyPendingRecords(BroadcastProcessQueue queue,
1587             List<Intent> intents) {
1588         for (int i = 0; i < intents.size(); i++) {
1589             queue.makeActiveNextPending();
1590 
1591             // While we're here, give our health check some test coverage
1592             queue.assertHealthLocked();
1593             queue.dumpLocked(0L, new IndentingPrintWriter(Writer.nullWriter()));
1594 
1595             final Intent actualIntent = queue.getActive().intent;
1596             final Intent expectedIntent = intents.get(i);
1597             final String errMsg = "actual=" + actualIntent + ", expected=" + expectedIntent
1598                     + ", actual_extras=" + actualIntent.getExtras()
1599                     + ", expected_extras=" + expectedIntent.getExtras();
1600             assertTrue(errMsg, actualIntent.filterEquals(expectedIntent));
1601             assertBundleEquals(expectedIntent.getExtras(), actualIntent.getExtras());
1602         }
1603         assertTrue(queue.isEmpty());
1604     }
1605 
assertBundleEquals(Bundle expected, Bundle actual)1606     private void assertBundleEquals(Bundle expected, Bundle actual) {
1607         final String errMsg = "expected=" + expected + ", actual=" + actual;
1608         if (expected == actual) {
1609             return;
1610         } else if (expected == null || actual == null) {
1611             fail(errMsg);
1612         }
1613         if (!expected.keySet().equals(actual.keySet())) {
1614             fail(errMsg);
1615         }
1616         for (String key : expected.keySet()) {
1617             final Object expectedValue = expected.get(key);
1618             final Object actualValue = actual.get(key);
1619             if (expectedValue == actualValue) {
1620                 continue;
1621             } else if (expectedValue == null || actualValue == null) {
1622                 fail(errMsg);
1623             }
1624             assertEquals(errMsg, expectedValue.getClass(), actualValue.getClass());
1625             if (expectedValue.getClass().isArray()) {
1626                 assertEquals(errMsg, Array.getLength(expectedValue), Array.getLength(actualValue));
1627                 for (int i = 0; i < Array.getLength(expectedValue); ++i) {
1628                     assertEquals(errMsg, Array.get(expectedValue, i), Array.get(actualValue, i));
1629                 }
1630             } else if (expectedValue instanceof ArrayList) {
1631                 final ArrayList<?> expectedList = (ArrayList<?>) expectedValue;
1632                 final ArrayList<?> actualList = (ArrayList<?>) actualValue;
1633                 assertEquals(errMsg, expectedList.size(), actualList.size());
1634                 for (int i = 0; i < expectedList.size(); ++i) {
1635                     assertEquals(errMsg, expectedList.get(i), actualList.get(i));
1636                 }
1637             } else {
1638                 assertEquals(errMsg, expectedValue, actualValue);
1639             }
1640         }
1641     }
1642 }
1643