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