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 org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertTrue;
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.Mockito.doReturn;
23 
24 import android.app.ActivityManagerInternal;
25 import android.os.SystemClock;
26 import android.platform.test.annotations.Presubmit;
27 
28 import androidx.test.filters.SmallTest;
29 import androidx.test.platform.app.InstrumentationRegistry;
30 
31 import org.junit.Before;
32 import org.junit.Rule;
33 import org.junit.Test;
34 import org.mockito.Mock;
35 import org.mockito.MockitoAnnotations;
36 
37 /**
38  * Test class for {@link ActivityManagerInternal}.
39  *
40  * Build/Install/Run:
41  *  atest FrameworksServicesTests:ActivityManagerInternalTest
42  */
43 @Presubmit
44 @SmallTest
45 public class ActivityManagerInternalTest {
46     private static final int TEST_UID1 = 111;
47     private static final int TEST_UID2 = 112;
48 
49     private static final long TEST_PROC_STATE_SEQ1 = 1111;
50     private static final long TEST_PROC_STATE_SEQ2 = 1112;
51 
52     @Rule public final ApplicationExitInfoTest.ServiceThreadRule
53             mServiceThreadRule = new ApplicationExitInfoTest.ServiceThreadRule();
54 
55     @Mock private ActivityManagerService.Injector mMockInjector;
56 
57     private ActivityManagerService mAms;
58     private ActivityManagerInternal mAmi;
59 
60     @Before
setUp()61     public void setUp() {
62         MockitoAnnotations.initMocks(this);
63 
64         doReturn(InstrumentationRegistry.getInstrumentation().getContext()).when(mMockInjector)
65                 .getContext();
66         doReturn(mServiceThreadRule.getThread().getThreadHandler()).when(mMockInjector)
67                 .getUiHandler(any());
68         final ProcessList dummyList = new ProcessList();
69         doReturn(dummyList).when(mMockInjector).getProcessList(any());
70         mAms = new ActivityManagerService(mMockInjector, mServiceThreadRule.getThread());
71         mAmi = mAms.new LocalService();
72     }
73 
74     @Test
testNotifyNetworkPolicyRulesUpdated()75     public void testNotifyNetworkPolicyRulesUpdated() throws Exception {
76         // Check there is no crash when there are no active uid records.
77         mAmi.notifyNetworkPolicyRulesUpdated(TEST_UID1, TEST_PROC_STATE_SEQ1);
78 
79         // Notify that network policy rules are updated for TEST_UID1 and verify that
80         // UidRecord.lastNetworkUpdateProcStateSeq is updated and any blocked threads are notified.
81         verifyNetworkUpdatedProcStateSeq(
82                 TEST_PROC_STATE_SEQ2, // curProcStateSeq
83                 TEST_PROC_STATE_SEQ1, // lastNetworkUpdateProcStateSeq
84                 TEST_PROC_STATE_SEQ2, // procStateSeq to notify
85                 true); // expectNotify
86 
87         // Notify that network policy rules are updated for TEST_UID1 with already handled
88         // procStateSeq and verify that there is no notify call.
89         verifyNetworkUpdatedProcStateSeq(
90                 TEST_PROC_STATE_SEQ1, // curProcStateSeq
91                 TEST_PROC_STATE_SEQ1, // lastNetworkUpdateProcStateSeq
92                 TEST_PROC_STATE_SEQ1, // procStateSeq to notify
93                 false); // expectNotify
94     }
95 
verifyNetworkUpdatedProcStateSeq(long curProcStateSeq, long lastNetworkUpdatedProcStateSeq, long expectedProcStateSeq, boolean expectNotify)96     private void verifyNetworkUpdatedProcStateSeq(long curProcStateSeq,
97             long lastNetworkUpdatedProcStateSeq, long expectedProcStateSeq, boolean expectNotify)
98             throws Exception {
99         final UidRecord record1 = addActiveUidRecord(TEST_UID1, curProcStateSeq,
100                 lastNetworkUpdatedProcStateSeq);
101         final UidRecord record2 = addActiveUidRecord(TEST_UID2, curProcStateSeq,
102                 lastNetworkUpdatedProcStateSeq);
103 
104         final CustomThread thread1 = new CustomThread(record1.networkStateLock);
105         thread1.startAndWait("Unexpected state for " + record1);
106         final CustomThread thread2 = new CustomThread(record2.networkStateLock);
107         thread2.startAndWait("Unexpected state for " + record2);
108 
109         mAmi.notifyNetworkPolicyRulesUpdated(TEST_UID1, expectedProcStateSeq);
110         assertEquals(record1 + " should be updated",
111                 expectedProcStateSeq, record1.lastNetworkUpdatedProcStateSeq);
112         assertEquals(record2 + " should not be updated",
113                 lastNetworkUpdatedProcStateSeq, record2.lastNetworkUpdatedProcStateSeq);
114 
115         if (expectNotify) {
116             thread1.assertTerminated("Unexpected state for " + record1);
117             assertTrue("Threads waiting for network should be notified: " + record1,
118                     thread1.mNotified);
119         } else {
120             thread1.assertWaiting("Unexpected state for " + record1);
121             thread1.interrupt();
122         }
123         thread2.assertWaiting("Unexpected state for " + record2);
124         thread2.interrupt();
125 
126         clearActiveUids();
127     }
128 
addActiveUidRecord(int uid, long curProcStateSeq, long lastNetworkUpdatedProcStateSeq)129     private UidRecord addActiveUidRecord(int uid, long curProcStateSeq,
130             long lastNetworkUpdatedProcStateSeq) {
131         final UidRecord record = new UidRecord(uid, mAms);
132         record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq;
133         record.curProcStateSeq = curProcStateSeq;
134         record.procStateSeqWaitingForNetwork = 1;
135         addActiveUidRecord(uid, record);
136         return record;
137     }
138 
139     @SuppressWarnings("GuardedBy")
addActiveUidRecord(int uid, UidRecord record)140     private void addActiveUidRecord(int uid, UidRecord record) {
141         mAms.mProcessList.mActiveUids.put(uid, record);
142     }
143 
144     @SuppressWarnings("GuardedBy")
clearActiveUids()145     private void clearActiveUids() {
146         mAms.mProcessList.mActiveUids.clear();
147     }
148 
149     static class CustomThread extends Thread {
150         private static final long WAIT_TIMEOUT_MS = 1000;
151         private static final long WAIT_INTERVAL_MS = 100;
152 
153         private final Object mLock;
154         private Runnable mRunnable;
155         public boolean mNotified;
156 
CustomThread(Object lock)157         CustomThread(Object lock) {
158             mLock = lock;
159         }
160 
CustomThread(Object lock, Runnable runnable)161         CustomThread(Object lock, Runnable runnable) {
162             super(runnable);
163             mLock = lock;
164             mRunnable = runnable;
165         }
166 
167         @SuppressWarnings("WaitNotInLoop")
168         @Override
run()169         public void run() {
170             if (mRunnable != null) {
171                 mRunnable.run();
172             } else {
173                 synchronized (mLock) {
174                     try {
175                         mLock.wait();
176                     } catch (InterruptedException e) {
177                         Thread.interrupted();
178                     }
179                 }
180             }
181             mNotified = !Thread.interrupted();
182         }
183 
startAndWait(String errMsg)184         public void startAndWait(String errMsg) throws Exception {
185             startAndWait(errMsg, false);
186         }
187 
startAndWait(String errMsg, boolean timedWaiting)188         public void startAndWait(String errMsg, boolean timedWaiting) throws Exception {
189             start();
190             final long endTime = SystemClock.elapsedRealtime() + WAIT_TIMEOUT_MS;
191             final Thread.State stateToReach = timedWaiting
192                     ? Thread.State.TIMED_WAITING : Thread.State.WAITING;
193             while (getState() != stateToReach
194                     && SystemClock.elapsedRealtime() < endTime) {
195                 Thread.sleep(WAIT_INTERVAL_MS);
196             }
197             if (timedWaiting) {
198                 assertTimedWaiting(errMsg);
199             } else {
200                 assertWaiting(errMsg);
201             }
202         }
203 
assertWaiting(String errMsg)204         public void assertWaiting(String errMsg) {
205             assertEquals(errMsg, Thread.State.WAITING, getState());
206         }
207 
assertTimedWaiting(String errMsg)208         public void assertTimedWaiting(String errMsg) {
209             assertEquals(errMsg, Thread.State.TIMED_WAITING, getState());
210         }
211 
assertTerminated(String errMsg)212         public void assertTerminated(String errMsg) throws Exception {
213             final long endTime = SystemClock.elapsedRealtime() + WAIT_TIMEOUT_MS;
214             while (getState() != Thread.State.TERMINATED
215                     && SystemClock.elapsedRealtime() < endTime) {
216                 Thread.sleep(WAIT_INTERVAL_MS);
217             }
218             assertEquals(errMsg, Thread.State.TERMINATED, getState());
219         }
220     }
221 }
222