ActivityManagerServiceTest.java revision f4923ea0b25edb6e6ca6804ed4c66f57a8ec29c2
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
17package com.android.server.am;
18
19import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
20import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
21import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
22import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
23import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
24import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
25import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
26import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
27import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
28import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
29import static android.app.ActivityManager.PROCESS_STATE_TOP;
30import static android.util.DebugUtils.valueToString;
31import static com.android.server.am.ActivityManagerInternalTest.CustomThread;
32import static com.android.server.am.ActivityManagerService.DISPATCH_UIDS_CHANGED_UI_MSG;
33import static com.android.server.am.ActivityManagerService.Injector;
34import static com.android.server.am.ActivityManagerService.NETWORK_STATE_BLOCK;
35import static com.android.server.am.ActivityManagerService.NETWORK_STATE_NO_CHANGE;
36import static com.android.server.am.ActivityManagerService.NETWORK_STATE_UNBLOCK;
37
38import static org.junit.Assert.assertEquals;
39import static org.junit.Assert.assertFalse;
40import static org.junit.Assert.assertNotEquals;
41import static org.junit.Assert.assertNotNull;
42import static org.junit.Assert.assertNull;
43import static org.junit.Assert.assertTrue;
44import static org.junit.Assert.fail;
45import static org.mockito.Mockito.verify;
46import static org.mockito.Mockito.verifyNoMoreInteractions;
47import static org.mockito.Mockito.verifyZeroInteractions;
48import static org.mockito.Mockito.when;
49
50import android.app.ActivityManager;
51import android.app.AppOpsManager;
52import android.app.IApplicationThread;
53import android.app.IUidObserver;
54import android.content.Context;
55import android.content.pm.ApplicationInfo;
56import android.content.pm.PackageManager;
57import android.os.Handler;
58import android.os.HandlerThread;
59import android.os.IBinder;
60import android.os.Looper;
61import android.os.Message;
62import android.os.Process;
63import android.os.RemoteException;
64import android.os.SystemClock;
65import android.support.test.filters.MediumTest;
66import android.support.test.filters.SmallTest;
67import android.support.test.runner.AndroidJUnit4;
68
69import com.android.internal.os.BatteryStatsImpl;
70import com.android.server.AppOpsService;
71
72import org.junit.After;
73import org.junit.Before;
74import org.junit.Test;
75import org.junit.runner.RunWith;
76import org.mockito.Mock;
77import org.mockito.Mockito;
78import org.mockito.MockitoAnnotations;
79
80import java.io.File;
81import java.util.ArrayList;
82import java.util.HashMap;
83import java.util.HashSet;
84import java.util.Map;
85import java.util.Set;
86import 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)
105public 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
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 = 100;
141
142        when(mContext.getPackageManager()).thenReturn(mPackageManager);
143    }
144
145    @After
146    public void tearDown() {
147        mHandlerThread.quit();
148    }
149
150    @MediumTest
151    @Test
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
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
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
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
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 {
470        void verify(IUidObserver observer, UidRecord.ChangeItem changeItem) throws RemoteException;
471    }
472
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
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
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
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
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
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
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
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
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
782        TestHandler(Looper looper) {
783            super(looper);
784        }
785
786        @Override
787        public void handleMessage(Message msg) {
788            mMsgsHandled.add(msg.what);
789        }
790
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
801        public void reset() {
802            mMsgsHandled.clear();
803        }
804    }
805
806    private class TestInjector extends Injector {
807        private boolean mRestricted = true;
808
809        @Override
810        public Context getContext() {
811            return mContext;
812        }
813
814        @Override
815        public AppOpsService getAppOpsService(File file, Handler handler) {
816            return mAppOpsService;
817        }
818
819        @Override
820        public Handler getUiHandler(ActivityManagerService service) {
821            return mHandler;
822        }
823
824        @Override
825        public boolean isNetworkRestrictedForUid(int uid) {
826            return mRestricted;
827        }
828
829        public void setNetworkRestrictedForUid(boolean restricted) {
830            mRestricted = restricted;
831        }
832    }
833}