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