1 /*
2  * Copyright (C) 2017 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_BOUND_FOREGROUND_SERVICE;
20 import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
21 import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
22 import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
23 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
24 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
25 import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
26 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
27 import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
28 import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
29 import static android.app.ActivityManager.PROCESS_STATE_TOP;
30 import static android.util.DebugUtils.valueToString;
31 import static com.android.server.am.ActivityManagerInternalTest.CustomThread;
32 import static com.android.server.am.ActivityManagerService.DISPATCH_UIDS_CHANGED_UI_MSG;
33 import static com.android.server.am.ActivityManagerService.Injector;
34 import static com.android.server.am.ActivityManagerService.NETWORK_STATE_BLOCK;
35 import static com.android.server.am.ActivityManagerService.NETWORK_STATE_NO_CHANGE;
36 import static com.android.server.am.ActivityManagerService.NETWORK_STATE_UNBLOCK;
37 
38 import static org.junit.Assert.assertEquals;
39 import static org.junit.Assert.assertFalse;
40 import static org.junit.Assert.assertNotEquals;
41 import static org.junit.Assert.assertNotNull;
42 import static org.junit.Assert.assertNull;
43 import static org.junit.Assert.assertTrue;
44 import static org.junit.Assert.fail;
45 import static org.mockito.Mockito.verify;
46 import static org.mockito.Mockito.verifyNoMoreInteractions;
47 import static org.mockito.Mockito.verifyZeroInteractions;
48 import static org.mockito.Mockito.when;
49 
50 import android.app.ActivityManager;
51 import android.app.AppOpsManager;
52 import android.app.IApplicationThread;
53 import android.app.IUidObserver;
54 import android.content.Context;
55 import android.content.pm.ApplicationInfo;
56 import android.content.pm.PackageManager;
57 import android.os.Handler;
58 import android.os.HandlerThread;
59 import android.os.IBinder;
60 import android.os.Looper;
61 import android.os.Message;
62 import android.os.Process;
63 import android.os.RemoteException;
64 import android.os.SystemClock;
65 import android.support.test.filters.MediumTest;
66 import android.support.test.filters.SmallTest;
67 import android.support.test.runner.AndroidJUnit4;
68 
69 import com.android.internal.os.BatteryStatsImpl;
70 import com.android.server.AppOpsService;
71 
72 import org.junit.After;
73 import org.junit.Before;
74 import org.junit.Test;
75 import org.junit.runner.RunWith;
76 import org.mockito.Mock;
77 import org.mockito.Mockito;
78 import org.mockito.MockitoAnnotations;
79 
80 import java.io.File;
81 import java.util.ArrayList;
82 import java.util.HashMap;
83 import java.util.HashSet;
84 import java.util.Map;
85 import java.util.Set;
86 import java.util.function.Function;
87 
88 /**
89  * Test class for {@link ActivityManagerService}.
90  *
91  * To run the tests, use
92  *
93  * runtest -c com.android.server.am.ActivityManagerServiceTest frameworks-services
94  *
95  * or the following steps:
96  *
97  * Build: m FrameworksServicesTests
98  * Install: adb install -r \
99  *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
100  * Run: adb shell am instrument -e class com.android.server.am.ActivityManagerServiceTest -w \
101  *     com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
102  */
103 @SmallTest
104 @RunWith(AndroidJUnit4.class)
105 public class ActivityManagerServiceTest {
106     private static final String TAG = ActivityManagerServiceTest.class.getSimpleName();
107 
108     private static final int TEST_UID = 11111;
109 
110     private static final long TEST_PROC_STATE_SEQ1 = 555;
111     private static final long TEST_PROC_STATE_SEQ2 = 556;
112 
113     private static final int[] UID_RECORD_CHANGES = {
114         UidRecord.CHANGE_PROCSTATE,
115         UidRecord.CHANGE_GONE,
116         UidRecord.CHANGE_GONE_IDLE,
117         UidRecord.CHANGE_IDLE,
118         UidRecord.CHANGE_ACTIVE
119     };
120 
121     @Mock private Context mContext;
122     @Mock private AppOpsService mAppOpsService;
123     @Mock private PackageManager mPackageManager;
124     @Mock private BatteryStatsImpl mBatteryStatsImpl;
125 
126     private TestInjector mInjector;
127     private ActivityManagerService mAms;
128     private HandlerThread mHandlerThread;
129     private TestHandler mHandler;
130 
131     @Before
setUp()132     public void setUp() {
133         MockitoAnnotations.initMocks(this);
134 
135         mHandlerThread = new HandlerThread(TAG);
136         mHandlerThread.start();
137         mHandler = new TestHandler(mHandlerThread.getLooper());
138         mInjector = new TestInjector();
139         mAms = new ActivityManagerService(mInjector);
140         mAms.mWaitForNetworkTimeoutMs = 2000;
141 
142         when(mContext.getPackageManager()).thenReturn(mPackageManager);
143     }
144 
145     @After
tearDown()146     public void tearDown() {
147         mHandlerThread.quit();
148     }
149 
150     @MediumTest
151     @Test
incrementProcStateSeqAndNotifyAppsLocked()152     public void incrementProcStateSeqAndNotifyAppsLocked() throws Exception {
153 
154         final UidRecord uidRec = addUidRecord(TEST_UID);
155         addUidRecord(TEST_UID + 1);
156 
157         // Uid state is not moving from background to foreground or vice versa.
158         verifySeqCounterAndInteractions(uidRec,
159                 PROCESS_STATE_TOP, // prevState
160                 PROCESS_STATE_TOP, // curState
161                 0, // expectedGlobalCounter
162                 0, // exptectedCurProcStateSeq
163                 NETWORK_STATE_NO_CHANGE, // expectedBlockState
164                 false); // expectNotify
165 
166         // Uid state is moving from foreground to background.
167         verifySeqCounterAndInteractions(uidRec,
168                 PROCESS_STATE_FOREGROUND_SERVICE, // prevState
169                 PROCESS_STATE_SERVICE, // curState
170                 1, // expectedGlobalCounter
171                 1, // exptectedCurProcStateSeq
172                 NETWORK_STATE_UNBLOCK, // expectedBlockState
173                 true); // expectNotify
174 
175         // Explicitly setting the seq counter for more verification.
176         mAms.mProcStateSeqCounter = 42;
177 
178         // Uid state is not moving from background to foreground or vice versa.
179         verifySeqCounterAndInteractions(uidRec,
180                 PROCESS_STATE_IMPORTANT_BACKGROUND, // prevState
181                 PROCESS_STATE_IMPORTANT_FOREGROUND, // curState
182                 42, // expectedGlobalCounter
183                 1, // exptectedCurProcStateSeq
184                 NETWORK_STATE_NO_CHANGE, // expectedBlockState
185                 false); // expectNotify
186 
187         // Uid state is moving from background to foreground.
188         verifySeqCounterAndInteractions(uidRec,
189                 PROCESS_STATE_LAST_ACTIVITY, // prevState
190                 PROCESS_STATE_TOP, // curState
191                 43, // expectedGlobalCounter
192                 43, // exptectedCurProcStateSeq
193                 NETWORK_STATE_BLOCK, // expectedBlockState
194                 false); // expectNotify
195 
196         // verify waiting threads are not notified.
197         uidRec.waitingForNetwork = false;
198         // Uid state is moving from foreground to background.
199         verifySeqCounterAndInteractions(uidRec,
200                 PROCESS_STATE_FOREGROUND_SERVICE, // prevState
201                 PROCESS_STATE_SERVICE, // curState
202                 44, // expectedGlobalCounter
203                 44, // exptectedCurProcStateSeq
204                 NETWORK_STATE_UNBLOCK, // expectedBlockState
205                 false); // expectNotify
206 
207         // Verify when uid is not restricted, procStateSeq is not incremented.
208         uidRec.waitingForNetwork = true;
209         mInjector.setNetworkRestrictedForUid(false);
210         verifySeqCounterAndInteractions(uidRec,
211                 PROCESS_STATE_IMPORTANT_BACKGROUND, // prevState
212                 PROCESS_STATE_TOP, // curState
213                 44, // expectedGlobalCounter
214                 44, // exptectedCurProcStateSeq
215                 -1, // expectedBlockState, -1 to verify there are no interactions with main thread.
216                 false); // expectNotify
217 
218         // Verify when waitForNetworkTimeout is 0, then procStateSeq is not incremented.
219         mAms.mWaitForNetworkTimeoutMs = 0;
220         mInjector.setNetworkRestrictedForUid(true);
221         verifySeqCounterAndInteractions(uidRec,
222                 PROCESS_STATE_TOP, // prevState
223                 PROCESS_STATE_IMPORTANT_BACKGROUND, // curState
224                 44, // expectedGlobalCounter
225                 44, // exptectedCurProcStateSeq
226                 -1, // expectedBlockState, -1 to verify there are no interactions with main thread.
227                 false); // expectNotify
228 
229         // Verify when the uid doesn't have internet permission, then procStateSeq is not
230         // incremented.
231         uidRec.hasInternetPermission = false;
232         mAms.mWaitForNetworkTimeoutMs = 111;
233         mInjector.setNetworkRestrictedForUid(true);
234         verifySeqCounterAndInteractions(uidRec,
235                 PROCESS_STATE_CACHED_ACTIVITY, // prevState
236                 PROCESS_STATE_FOREGROUND_SERVICE, // curState
237                 44, // expectedGlobalCounter
238                 44, // exptectedCurProcStateSeq
239                 -1, // expectedBlockState, -1 to verify there are no interactions with main thread.
240                 false); // expectNotify
241 
242         // Verify procStateSeq is not incremented when the uid is not an application, regardless
243         // of the process state.
244         final int notAppUid = 111;
245         final UidRecord uidRec2 = addUidRecord(notAppUid);
246         verifySeqCounterAndInteractions(uidRec2,
247                 PROCESS_STATE_CACHED_EMPTY, // prevState
248                 PROCESS_STATE_TOP, // curState
249                 44, // expectedGlobalCounter
250                 0, // exptectedCurProcStateSeq
251                 -1, // expectedBlockState, -1 to verify there are no interactions with main thread.
252                 false); // expectNotify
253     }
254 
addUidRecord(int uid)255     private UidRecord addUidRecord(int uid) {
256         final UidRecord uidRec = new UidRecord(uid);
257         uidRec.waitingForNetwork = true;
258         uidRec.hasInternetPermission = true;
259         mAms.mActiveUids.put(uid, uidRec);
260 
261         final ProcessRecord appRec = new ProcessRecord(mBatteryStatsImpl,
262                 new ApplicationInfo(), TAG, uid);
263         appRec.thread = Mockito.mock(IApplicationThread.class);
264         mAms.mLruProcesses.add(appRec);
265 
266         return uidRec;
267     }
268 
verifySeqCounterAndInteractions(UidRecord uidRec, int prevState, int curState, int expectedGlobalCounter, int expectedCurProcStateSeq, int expectedBlockState, boolean expectNotify)269     private void verifySeqCounterAndInteractions(UidRecord uidRec, int prevState, int curState,
270             int expectedGlobalCounter, int expectedCurProcStateSeq, int expectedBlockState,
271             boolean expectNotify) throws Exception {
272         CustomThread thread = new CustomThread(uidRec.networkStateLock);
273         thread.startAndWait("Unexpected state for " + uidRec);
274 
275         uidRec.setProcState = prevState;
276         uidRec.curProcState = curState;
277         mAms.incrementProcStateSeqAndNotifyAppsLocked();
278 
279         assertEquals(expectedGlobalCounter, mAms.mProcStateSeqCounter);
280         assertEquals(expectedCurProcStateSeq, uidRec.curProcStateSeq);
281 
282         for (int i = mAms.mLruProcesses.size() - 1; i >= 0; --i) {
283             final ProcessRecord app = mAms.mLruProcesses.get(i);
284             // AMS should notify apps only for block states other than NETWORK_STATE_NO_CHANGE.
285             if (app.uid == uidRec.uid && expectedBlockState == NETWORK_STATE_BLOCK) {
286                 verify(app.thread).setNetworkBlockSeq(uidRec.curProcStateSeq);
287             } else {
288                 verifyZeroInteractions(app.thread);
289             }
290             Mockito.reset(app.thread);
291         }
292 
293         if (expectNotify) {
294             thread.assertTerminated("Unexpected state for " + uidRec);
295         } else {
296             thread.assertWaiting("Unexpected state for " + uidRec);
297             thread.interrupt();
298         }
299     }
300 
301     @Test
testBlockStateForUid()302     public void testBlockStateForUid() {
303         final UidRecord uidRec = new UidRecord(TEST_UID);
304         int expectedBlockState;
305 
306         final String errorTemplate = "Block state should be %s, prevState: %s, curState: %s";
307         Function<Integer, String> errorMsg = (blockState) -> {
308             return String.format(errorTemplate,
309                     valueToString(ActivityManagerService.class, "NETWORK_STATE_", blockState),
310                     valueToString(ActivityManager.class, "PROCESS_STATE_", uidRec.setProcState),
311                     valueToString(ActivityManager.class, "PROCESS_STATE_", uidRec.curProcState));
312         };
313 
314         // No change in uid state
315         uidRec.setProcState = PROCESS_STATE_RECEIVER;
316         uidRec.curProcState = PROCESS_STATE_RECEIVER;
317         expectedBlockState = NETWORK_STATE_NO_CHANGE;
318         assertEquals(errorMsg.apply(expectedBlockState),
319                 expectedBlockState, mAms.getBlockStateForUid(uidRec));
320 
321         // Foreground to foreground
322         uidRec.setProcState = PROCESS_STATE_FOREGROUND_SERVICE;
323         uidRec.curProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
324         expectedBlockState = NETWORK_STATE_NO_CHANGE;
325         assertEquals(errorMsg.apply(expectedBlockState),
326                 expectedBlockState, mAms.getBlockStateForUid(uidRec));
327 
328         // Background to background
329         uidRec.setProcState = PROCESS_STATE_CACHED_ACTIVITY;
330         uidRec.curProcState = PROCESS_STATE_CACHED_EMPTY;
331         expectedBlockState = NETWORK_STATE_NO_CHANGE;
332         assertEquals(errorMsg.apply(expectedBlockState),
333                 expectedBlockState, mAms.getBlockStateForUid(uidRec));
334 
335         // Background to background
336         uidRec.setProcState = PROCESS_STATE_NONEXISTENT;
337         uidRec.curProcState = PROCESS_STATE_CACHED_ACTIVITY;
338         expectedBlockState = NETWORK_STATE_NO_CHANGE;
339         assertEquals(errorMsg.apply(expectedBlockState),
340                 expectedBlockState, mAms.getBlockStateForUid(uidRec));
341 
342         // Background to foreground
343         uidRec.setProcState = PROCESS_STATE_SERVICE;
344         uidRec.curProcState = PROCESS_STATE_FOREGROUND_SERVICE;
345         expectedBlockState = NETWORK_STATE_BLOCK;
346         assertEquals(errorMsg.apply(expectedBlockState),
347                 expectedBlockState, mAms.getBlockStateForUid(uidRec));
348 
349         // Foreground to background
350         uidRec.setProcState = PROCESS_STATE_TOP;
351         uidRec.curProcState = PROCESS_STATE_LAST_ACTIVITY;
352         expectedBlockState = NETWORK_STATE_UNBLOCK;
353         assertEquals(errorMsg.apply(expectedBlockState),
354                 expectedBlockState, mAms.getBlockStateForUid(uidRec));
355     }
356 
357     /**
358      * This test verifies that process state changes are dispatched to observers based on the
359      * changes they wanted to listen (this is specified when registering the observer).
360      */
361     @Test
testDispatchUids_dispatchNeededChanges()362     public void testDispatchUids_dispatchNeededChanges() throws RemoteException {
363         when(mAppOpsService.checkOperation(AppOpsManager.OP_GET_USAGE_STATS, Process.myUid(), null))
364                 .thenReturn(AppOpsManager.MODE_ALLOWED);
365 
366         final int[] changesToObserve = {
367             ActivityManager.UID_OBSERVER_PROCSTATE,
368             ActivityManager.UID_OBSERVER_GONE,
369             ActivityManager.UID_OBSERVER_IDLE,
370             ActivityManager.UID_OBSERVER_ACTIVE,
371             ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE
372                     | ActivityManager.UID_OBSERVER_ACTIVE | ActivityManager.UID_OBSERVER_IDLE
373         };
374         final IUidObserver[] observers = new IUidObserver.Stub[changesToObserve.length];
375         for (int i = 0; i < observers.length; ++i) {
376             observers[i] = Mockito.mock(IUidObserver.Stub.class);
377             when(observers[i].asBinder()).thenReturn((IBinder) observers[i]);
378             mAms.registerUidObserver(observers[i], changesToObserve[i] /* which */,
379                     ActivityManager.PROCESS_STATE_UNKNOWN /* cutpoint */, null /* caller */);
380 
381             // When we invoke AMS.registerUidObserver, there are some interactions with observers[i]
382             // mock in RemoteCallbackList class. We don't want to test those interactions and
383             // at the same time, we don't want those to interfere with verifyNoMoreInteractions.
384             // So, resetting the mock here.
385             Mockito.reset(observers[i]);
386         }
387 
388         // Add pending uid records each corresponding to a different change type UidRecord.CHANGE_*
389         final int[] changesForPendingUidRecords = UID_RECORD_CHANGES;
390 
391         final int[] procStatesForPendingUidRecords = {
392             ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
393             ActivityManager.PROCESS_STATE_NONEXISTENT,
394             ActivityManager.PROCESS_STATE_CACHED_EMPTY,
395             ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
396             ActivityManager.PROCESS_STATE_TOP
397         };
398         final Map<Integer, UidRecord.ChangeItem> changeItems = new HashMap<>();
399         for (int i = 0; i < changesForPendingUidRecords.length; ++i) {
400             final UidRecord.ChangeItem pendingChange = new UidRecord.ChangeItem();
401             pendingChange.change = changesForPendingUidRecords[i];
402             pendingChange.uid = i;
403             pendingChange.processState = procStatesForPendingUidRecords[i];
404             pendingChange.procStateSeq = i;
405             changeItems.put(changesForPendingUidRecords[i], pendingChange);
406             mAms.mPendingUidChanges.add(pendingChange);
407         }
408 
409         mAms.dispatchUidsChanged();
410         // Verify the required changes have been dispatched to observers.
411         for (int i = 0; i < observers.length; ++i) {
412             final int changeToObserve = changesToObserve[i];
413             final IUidObserver observerToTest = observers[i];
414             if ((changeToObserve & ActivityManager.UID_OBSERVER_IDLE) != 0) {
415                 // Observer listens to uid idle changes, so change items corresponding to
416                 // UidRecord.CHANGE_IDLE or UidRecord.CHANGE_IDLE_GONE needs to be
417                 // delivered to this observer.
418                 final int[] changesToVerify = {
419                     UidRecord.CHANGE_IDLE,
420                     UidRecord.CHANGE_GONE_IDLE
421                 };
422                 verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems,
423                         (observer, changeItem) -> {
424                             verify(observer).onUidIdle(changeItem.uid, changeItem.ephemeral);
425                         });
426             }
427             if ((changeToObserve & ActivityManager.UID_OBSERVER_ACTIVE) != 0) {
428                 // Observer listens to uid active changes, so change items corresponding to
429                 // UidRecord.CHANGE_ACTIVE needs to be delivered to this observer.
430                 final int[] changesToVerify = { UidRecord.CHANGE_ACTIVE };
431                 verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems,
432                         (observer, changeItem) -> {
433                             verify(observer).onUidActive(changeItem.uid);
434                         });
435             }
436             if ((changeToObserve & ActivityManager.UID_OBSERVER_GONE) != 0) {
437                 // Observer listens to uid gone changes, so change items corresponding to
438                 // UidRecord.CHANGE_GONE or UidRecord.CHANGE_IDLE_GONE needs to be
439                 // delivered to this observer.
440                 final int[] changesToVerify = {
441                         UidRecord.CHANGE_GONE,
442                         UidRecord.CHANGE_GONE_IDLE
443                 };
444                 verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems,
445                         (observer, changeItem) -> {
446                             verify(observer).onUidGone(changeItem.uid, changeItem.ephemeral);
447                         });
448             }
449             if ((changeToObserve & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) {
450                 // Observer listens to uid procState changes, so change items corresponding to
451                 // UidRecord.CHANGE_PROCSTATE or UidRecord.CHANGE_IDLE or UidRecord.CHANGE_ACTIVE
452                 // needs to be delivered to this observer.
453                 final int[] changesToVerify = {
454                         UidRecord.CHANGE_PROCSTATE,
455                         UidRecord.CHANGE_ACTIVE,
456                         UidRecord.CHANGE_IDLE
457                 };
458                 verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems,
459                         (observer, changeItem) -> {
460                             verify(observer).onUidStateChanged(changeItem.uid,
461                                     changeItem.processState, changeItem.procStateSeq);
462                         });
463             }
464             // Verify there are no other callbacks for this observer.
465             verifyNoMoreInteractions(observerToTest);
466         }
467     }
468 
469     private interface ObserverChangesVerifier {
verify(IUidObserver observer, UidRecord.ChangeItem changeItem)470         void verify(IUidObserver observer, UidRecord.ChangeItem changeItem) throws RemoteException;
471     }
472 
verifyObserverReceivedChanges(IUidObserver observer, int[] changesToVerify, Map<Integer, UidRecord.ChangeItem> changeItems, ObserverChangesVerifier verifier)473     private void verifyObserverReceivedChanges(IUidObserver observer, int[] changesToVerify,
474             Map<Integer, UidRecord.ChangeItem> changeItems, ObserverChangesVerifier verifier)
475             throws RemoteException {
476         for (int change : changesToVerify) {
477             final UidRecord.ChangeItem changeItem = changeItems.get(change);
478             verifier.verify(observer, changeItem);
479         }
480     }
481 
482     /**
483      * This test verifies that process state changes are dispatched to observers only when they
484      * change across the cutpoint (this is specified when registering the observer).
485      */
486     @Test
testDispatchUidChanges_procStateCutpoint()487     public void testDispatchUidChanges_procStateCutpoint() throws RemoteException {
488         final IUidObserver observer = Mockito.mock(IUidObserver.Stub.class);
489 
490         when(observer.asBinder()).thenReturn((IBinder) observer);
491         mAms.registerUidObserver(observer, ActivityManager.UID_OBSERVER_PROCSTATE /* which */,
492                 ActivityManager.PROCESS_STATE_SERVICE /* cutpoint */, null /* callingPackage */);
493         // When we invoke AMS.registerUidObserver, there are some interactions with observer
494         // mock in RemoteCallbackList class. We don't want to test those interactions and
495         // at the same time, we don't want those to interfere with verifyNoMoreInteractions.
496         // So, resetting the mock here.
497         Mockito.reset(observer);
498 
499         final UidRecord.ChangeItem changeItem = new UidRecord.ChangeItem();
500         changeItem.uid = TEST_UID;
501         changeItem.change = UidRecord.CHANGE_PROCSTATE;
502         changeItem.processState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
503         changeItem.procStateSeq = 111;
504         mAms.mPendingUidChanges.add(changeItem);
505         mAms.dispatchUidsChanged();
506         // First process state message is always delivered regardless of whether the process state
507         // change is above or below the cutpoint (PROCESS_STATE_SERVICE).
508         verify(observer).onUidStateChanged(TEST_UID,
509                 changeItem.processState, changeItem.procStateSeq);
510         verifyNoMoreInteractions(observer);
511 
512         changeItem.processState = ActivityManager.PROCESS_STATE_RECEIVER;
513         mAms.mPendingUidChanges.add(changeItem);
514         mAms.dispatchUidsChanged();
515         // Previous process state change is below cutpoint (PROCESS_STATE_SERVICE) and
516         // the current process state change is also below cutpoint, so no callback will be invoked.
517         verifyNoMoreInteractions(observer);
518 
519         changeItem.processState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
520         mAms.mPendingUidChanges.add(changeItem);
521         mAms.dispatchUidsChanged();
522         // Previous process state change is below cutpoint (PROCESS_STATE_SERVICE) and
523         // the current process state change is above cutpoint, so callback will be invoked with the
524         // current process state change.
525         verify(observer).onUidStateChanged(TEST_UID,
526                 changeItem.processState, changeItem.procStateSeq);
527         verifyNoMoreInteractions(observer);
528 
529         changeItem.processState = ActivityManager.PROCESS_STATE_TOP;
530         mAms.mPendingUidChanges.add(changeItem);
531         mAms.dispatchUidsChanged();
532         // Previous process state change is above cutpoint (PROCESS_STATE_SERVICE) and
533         // the current process state change is also above cutpoint, so no callback will be invoked.
534         verifyNoMoreInteractions(observer);
535 
536         changeItem.processState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
537         mAms.mPendingUidChanges.add(changeItem);
538         mAms.dispatchUidsChanged();
539         // Previous process state change is above cutpoint (PROCESS_STATE_SERVICE) and
540         // the current process state change is below cutpoint, so callback will be invoked with the
541         // current process state change.
542         verify(observer).onUidStateChanged(TEST_UID,
543                 changeItem.processState, changeItem.procStateSeq);
544         verifyNoMoreInteractions(observer);
545     }
546 
547     /**
548      * This test verifies that {@link ActivityManagerService#mValidateUids} which is a
549      * part of dumpsys is correctly updated.
550      */
551     @Test
testDispatchUidChanges_validateUidsUpdated()552     public void testDispatchUidChanges_validateUidsUpdated() {
553         final int[] changesForPendingItems = UID_RECORD_CHANGES;
554 
555         final int[] procStatesForPendingItems = {
556             ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
557             ActivityManager.PROCESS_STATE_CACHED_EMPTY,
558             ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
559             ActivityManager.PROCESS_STATE_SERVICE,
560             ActivityManager.PROCESS_STATE_RECEIVER
561         };
562         final ArrayList<UidRecord.ChangeItem> pendingItemsForUids
563                 = new ArrayList<>(changesForPendingItems.length);
564         for (int i = 0; i < changesForPendingItems.length; ++i) {
565             final UidRecord.ChangeItem item = new UidRecord.ChangeItem();
566             item.uid = i;
567             item.change = changesForPendingItems[i];
568             item.processState = procStatesForPendingItems[i];
569             pendingItemsForUids.add(i, item);
570         }
571 
572         // Verify that when there no observers listening to uid state changes, then there will
573         // be no changes to validateUids.
574         mAms.mPendingUidChanges.addAll(pendingItemsForUids);
575         mAms.dispatchUidsChanged();
576         assertEquals("No observers registered, so validateUids should be empty",
577                 0, mAms.mValidateUids.size());
578 
579         final IUidObserver observer = Mockito.mock(IUidObserver.Stub.class);
580         when(observer.asBinder()).thenReturn((IBinder) observer);
581         mAms.registerUidObserver(observer, 0, 0, null);
582         // Verify that when observers are registered, then validateUids is correctly updated.
583         mAms.mPendingUidChanges.addAll(pendingItemsForUids);
584         mAms.dispatchUidsChanged();
585         for (int i = 0; i < pendingItemsForUids.size(); ++i) {
586             final UidRecord.ChangeItem item = pendingItemsForUids.get(i);
587             final UidRecord validateUidRecord = mAms.mValidateUids.get(item.uid);
588             if (item.change == UidRecord.CHANGE_GONE || item.change == UidRecord.CHANGE_GONE_IDLE) {
589                 assertNull("validateUidRecord should be null since the change is either "
590                         + "CHANGE_GONE or CHANGE_GONE_IDLE", validateUidRecord);
591             } else {
592                 assertNotNull("validateUidRecord should not be null since the change is neither "
593                         + "CHANGE_GONE nor CHANGE_GONE_IDLE", validateUidRecord);
594                 assertEquals("processState: " + item.processState + " curProcState: "
595                         + validateUidRecord.curProcState + " should have been equal",
596                         item.processState, validateUidRecord.curProcState);
597                 assertEquals("processState: " + item.processState + " setProcState: "
598                         + validateUidRecord.curProcState + " should have been equal",
599                         item.processState, validateUidRecord.setProcState);
600                 if (item.change == UidRecord.CHANGE_IDLE) {
601                     assertTrue("UidRecord.idle should be updated to true for CHANGE_IDLE",
602                             validateUidRecord.idle);
603                 } else if (item.change == UidRecord.CHANGE_ACTIVE) {
604                     assertFalse("UidRecord.idle should be updated to false for CHANGE_ACTIVE",
605                             validateUidRecord.idle);
606                 }
607             }
608         }
609 
610         // Verify that when uid state changes to CHANGE_GONE or CHANGE_GONE_IDLE, then it
611         // will be removed from validateUids.
612         assertNotEquals("validateUids should not be empty", 0, mAms.mValidateUids.size());
613         for (int i = 0; i < pendingItemsForUids.size(); ++i) {
614             final UidRecord.ChangeItem item = pendingItemsForUids.get(i);
615             // Assign CHANGE_GONE_IDLE to some items and CHANGE_GONE to the others, using even/odd
616             // distribution for this assignment.
617             item.change = (i % 2) == 0 ? UidRecord.CHANGE_GONE_IDLE : UidRecord.CHANGE_GONE;
618         }
619         mAms.mPendingUidChanges.addAll(pendingItemsForUids);
620         mAms.dispatchUidsChanged();
621         assertEquals("validateUids should be empty, validateUids: " + mAms.mValidateUids,
622                 0, mAms.mValidateUids.size());
623     }
624 
625     @Test
testEnqueueUidChangeLocked_procStateSeqUpdated()626     public void testEnqueueUidChangeLocked_procStateSeqUpdated() {
627         final UidRecord uidRecord = new UidRecord(TEST_UID);
628         uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ1;
629 
630         // Verify with no pending changes for TEST_UID.
631         verifyLastProcStateSeqUpdated(uidRecord, -1, TEST_PROC_STATE_SEQ1);
632 
633         // Add a pending change for TEST_UID and verify enqueueUidChangeLocked still works as
634         // expected.
635         final UidRecord.ChangeItem changeItem = new UidRecord.ChangeItem();
636         uidRecord.pendingChange = changeItem;
637         uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ2;
638         verifyLastProcStateSeqUpdated(uidRecord, -1, TEST_PROC_STATE_SEQ2);
639     }
640 
641     @Test
testEnqueueUidChangeLocked_nullUidRecord()642     public void testEnqueueUidChangeLocked_nullUidRecord() {
643         // Use "null" uidRecord to make sure there is no crash.
644         mAms.enqueueUidChangeLocked(null, TEST_UID, UidRecord.CHANGE_ACTIVE);
645     }
646 
verifyLastProcStateSeqUpdated(UidRecord uidRecord, int uid, long curProcstateSeq)647     private void verifyLastProcStateSeqUpdated(UidRecord uidRecord, int uid, long curProcstateSeq) {
648         // Test enqueueUidChangeLocked with every UidRecord.CHANGE_*
649         for (int i = 0; i < UID_RECORD_CHANGES.length; ++i) {
650             final int changeToDispatch = UID_RECORD_CHANGES[i];
651             // Reset lastProcStateSeqDispatchToObservers after every test.
652             uidRecord.lastDispatchedProcStateSeq = 0;
653             mAms.enqueueUidChangeLocked(uidRecord, uid, changeToDispatch);
654             // Verify there is no effect on curProcStateSeq.
655             assertEquals(curProcstateSeq, uidRecord.curProcStateSeq);
656             if (changeToDispatch == UidRecord.CHANGE_GONE
657                     || changeToDispatch == UidRecord.CHANGE_GONE_IDLE) {
658                 // Since the change is CHANGE_GONE or CHANGE_GONE_IDLE, verify that
659                 // lastProcStateSeqDispatchedToObservers is not updated.
660                 assertNotEquals(uidRecord.curProcStateSeq,
661                         uidRecord.lastDispatchedProcStateSeq);
662             } else {
663                 // Since the change is neither CHANGE_GONE nor CHANGE_GONE_IDLE, verify that
664                 // lastProcStateSeqDispatchedToObservers has been updated to curProcStateSeq.
665                 assertEquals(uidRecord.curProcStateSeq,
666                         uidRecord.lastDispatchedProcStateSeq);
667             }
668         }
669     }
670 
671     @MediumTest
672     @Test
testEnqueueUidChangeLocked_dispatchUidsChanged()673     public void testEnqueueUidChangeLocked_dispatchUidsChanged() {
674         final UidRecord uidRecord = new UidRecord(TEST_UID);
675         final int expectedProcState = PROCESS_STATE_SERVICE;
676         uidRecord.setProcState = expectedProcState;
677         uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ1;
678 
679         // Test with no pending uid records.
680         for (int i = 0; i < UID_RECORD_CHANGES.length; ++i) {
681             final int changeToDispatch = UID_RECORD_CHANGES[i];
682 
683             // Reset the current state
684             mHandler.reset();
685             uidRecord.pendingChange = null;
686             mAms.mPendingUidChanges.clear();
687 
688             mAms.enqueueUidChangeLocked(uidRecord, -1, changeToDispatch);
689 
690             // Verify that UidRecord.pendingChange is updated correctly.
691             assertNotNull(uidRecord.pendingChange);
692             assertEquals(TEST_UID, uidRecord.pendingChange.uid);
693             assertEquals(expectedProcState, uidRecord.pendingChange.processState);
694             assertEquals(TEST_PROC_STATE_SEQ1, uidRecord.pendingChange.procStateSeq);
695 
696             // Verify that DISPATCH_UIDS_CHANGED_UI_MSG is posted to handler.
697             mHandler.waitForMessage(DISPATCH_UIDS_CHANGED_UI_MSG);
698         }
699     }
700 
701     @MediumTest
702     @Test
testWaitForNetworkStateUpdate()703     public void testWaitForNetworkStateUpdate() throws Exception {
704         // Check there is no crash when there is no UidRecord for myUid
705         mAms.waitForNetworkStateUpdate(TEST_PROC_STATE_SEQ1);
706 
707         // Verify there is no waiting when UidRecord.curProcStateSeq is greater than
708         // the procStateSeq in the request to wait.
709         verifyWaitingForNetworkStateUpdate(
710                 TEST_PROC_STATE_SEQ1, // curProcStateSeq
711                 TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq
712                 TEST_PROC_STATE_SEQ1 - 4, // lastNetworkUpdatedProcStateSeq
713                 TEST_PROC_STATE_SEQ1 - 2, // procStateSeqToWait
714                 false); // expectWait
715 
716         // Verify there is no waiting when the procStateSeq in the request to wait is
717         // not dispatched to NPMS.
718         verifyWaitingForNetworkStateUpdate(
719                 TEST_PROC_STATE_SEQ1, // curProcStateSeq
720                 TEST_PROC_STATE_SEQ1 - 1, // lastDsipatchedProcStateSeq
721                 TEST_PROC_STATE_SEQ1 - 1, // lastNetworkUpdatedProcStateSeq
722                 TEST_PROC_STATE_SEQ1, // procStateSeqToWait
723                 false); // expectWait
724 
725         // Verify there is not waiting when the procStateSeq in the request already has
726         // an updated network state.
727         verifyWaitingForNetworkStateUpdate(
728                 TEST_PROC_STATE_SEQ1, // curProcStateSeq
729                 TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq
730                 TEST_PROC_STATE_SEQ1, // lastNetworkUpdatedProcStateSeq
731                 TEST_PROC_STATE_SEQ1, // procStateSeqToWait
732                 false); // expectWait
733 
734         // Verify waiting for network works
735         verifyWaitingForNetworkStateUpdate(
736                 TEST_PROC_STATE_SEQ1, // curProcStateSeq
737                 TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq
738                 TEST_PROC_STATE_SEQ1 - 1, // lastNetworkUpdatedProcStateSeq
739                 TEST_PROC_STATE_SEQ1, // procStateSeqToWait
740                 true); // expectWait
741     }
742 
verifyWaitingForNetworkStateUpdate(long curProcStateSeq, long lastDispatchedProcStateSeq, long lastNetworkUpdatedProcStateSeq, final long procStateSeqToWait, boolean expectWait)743     private void verifyWaitingForNetworkStateUpdate(long curProcStateSeq,
744             long lastDispatchedProcStateSeq, long lastNetworkUpdatedProcStateSeq,
745             final long procStateSeqToWait, boolean expectWait) throws Exception {
746         final UidRecord record = new UidRecord(Process.myUid());
747         record.curProcStateSeq = curProcStateSeq;
748         record.lastDispatchedProcStateSeq = lastDispatchedProcStateSeq;
749         record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq;
750         mAms.mActiveUids.put(Process.myUid(), record);
751 
752         CustomThread thread = new CustomThread(record.networkStateLock, new Runnable() {
753             @Override
754             public void run() {
755                 mAms.waitForNetworkStateUpdate(procStateSeqToWait);
756             }
757         });
758         final String errMsg = "Unexpected state for " + record;
759         if (expectWait) {
760             thread.startAndWait(errMsg, true);
761             thread.assertTimedWaiting(errMsg);
762             synchronized (record.networkStateLock) {
763                 record.networkStateLock.notifyAll();
764             }
765             thread.assertTerminated(errMsg);
766             assertTrue(thread.mNotified);
767             assertFalse(record.waitingForNetwork);
768         } else {
769             thread.start();
770             thread.assertTerminated(errMsg);
771         }
772 
773         mAms.mActiveUids.clear();
774     }
775 
776     private class TestHandler extends Handler {
777         private static final long WAIT_FOR_MSG_TIMEOUT_MS = 4000; // 4 sec
778         private static final long WAIT_FOR_MSG_INTERVAL_MS = 400; // 0.4 sec
779 
780         private Set<Integer> mMsgsHandled = new HashSet<>();
781 
TestHandler(Looper looper)782         TestHandler(Looper looper) {
783             super(looper);
784         }
785 
786         @Override
handleMessage(Message msg)787         public void handleMessage(Message msg) {
788             mMsgsHandled.add(msg.what);
789         }
790 
waitForMessage(int msg)791         public void waitForMessage(int msg) {
792             final long endTime = System.currentTimeMillis() + WAIT_FOR_MSG_TIMEOUT_MS;
793             while (!mMsgsHandled.contains(msg) && System.currentTimeMillis() < endTime) {
794                 SystemClock.sleep(WAIT_FOR_MSG_INTERVAL_MS);
795             }
796             if (!mMsgsHandled.contains(msg)) {
797                 fail("Timed out waiting for the message to be handled, msg: " + msg);
798             }
799         }
800 
reset()801         public void reset() {
802             mMsgsHandled.clear();
803         }
804     }
805 
806     private class TestInjector extends Injector {
807         private boolean mRestricted = true;
808 
809         @Override
getContext()810         public Context getContext() {
811             return mContext;
812         }
813 
814         @Override
getAppOpsService(File file, Handler handler)815         public AppOpsService getAppOpsService(File file, Handler handler) {
816             return mAppOpsService;
817         }
818 
819         @Override
getUiHandler(ActivityManagerService service)820         public Handler getUiHandler(ActivityManagerService service) {
821             return mHandler;
822         }
823 
824         @Override
isNetworkRestrictedForUid(int uid)825         public boolean isNetworkRestrictedForUid(int uid) {
826             return mRestricted;
827         }
828 
setNetworkRestrictedForUid(boolean restricted)829         public void setNetworkRestrictedForUid(boolean restricted) {
830             mRestricted = restricted;
831         }
832     }
833 }