ActivityManagerServiceTest.java revision 51ab3acf270c655ed90706895b43915433d022c7
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.ActivityManagerService.DISPATCH_UIDS_CHANGED_UI_MSG; 32import static com.android.server.am.ActivityManagerService.Injector; 33 34import static org.junit.Assert.assertEquals; 35import static org.junit.Assert.assertFalse; 36import static org.junit.Assert.assertNotEquals; 37import static org.junit.Assert.assertNotNull; 38import static org.junit.Assert.assertNull; 39import static org.junit.Assert.assertTrue; 40import static org.junit.Assert.fail; 41import static org.mockito.Mockito.verify; 42import static org.mockito.Mockito.verifyNoMoreInteractions; 43import static org.mockito.Mockito.when; 44 45import android.app.ActivityManager; 46import android.app.AppOpsManager; 47import android.app.IUidObserver; 48import android.os.Handler; 49import android.os.HandlerThread; 50import android.os.IBinder; 51import android.os.Looper; 52import android.os.Message; 53import android.os.Process; 54import android.os.RemoteException; 55import android.os.SystemClock; 56import android.support.test.filters.MediumTest; 57import android.support.test.filters.SmallTest; 58import android.support.test.runner.AndroidJUnit4; 59 60import com.android.server.AppOpsService; 61 62import org.junit.After; 63import org.junit.Before; 64import org.junit.Test; 65import org.junit.runner.RunWith; 66import org.mockito.Mock; 67import org.mockito.Mockito; 68import org.mockito.MockitoAnnotations; 69 70import java.util.ArrayList; 71import java.util.HashMap; 72import java.util.HashSet; 73import java.util.Map; 74import java.util.Set; 75import java.util.function.Function; 76 77/** 78 * Test class for {@link ActivityManagerService}. 79 * 80 * To run the tests, use 81 * 82 * runtest -c com.android.server.am.ActivityManagerServiceTest frameworks-services 83 * 84 * or the following steps: 85 * 86 * Build: m FrameworksServicesTests 87 * Install: adb install -r \ 88 * ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk 89 * Run: adb shell am instrument -e class com.android.server.am.ActivityManagerServiceTest -w \ 90 * com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner 91 */ 92@SmallTest 93@RunWith(AndroidJUnit4.class) 94public class ActivityManagerServiceTest { 95 private static final String TAG = ActivityManagerServiceTest.class.getSimpleName(); 96 97 private static final int TEST_UID = 111; 98 99 private static final long TEST_PROC_STATE_SEQ1 = 555; 100 private static final long TEST_PROC_STATE_SEQ2 = 556; 101 102 private static final int[] UID_RECORD_CHANGES = { 103 UidRecord.CHANGE_PROCSTATE, 104 UidRecord.CHANGE_GONE, 105 UidRecord.CHANGE_GONE_IDLE, 106 UidRecord.CHANGE_IDLE, 107 UidRecord.CHANGE_ACTIVE 108 }; 109 110 @Mock private AppOpsService mAppOpsService; 111 112 private ActivityManagerService mAms; 113 private HandlerThread mHandlerThread; 114 private TestHandler mHandler; 115 116 @Before 117 public void setUp() { 118 MockitoAnnotations.initMocks(this); 119 120 mHandlerThread = new HandlerThread(TAG); 121 mHandlerThread.start(); 122 mHandler = new TestHandler(mHandlerThread.getLooper()); 123 mAms = new ActivityManagerService(new TestInjector()); 124 } 125 126 @After 127 public void tearDown() { 128 mHandlerThread.quit(); 129 } 130 131 @Test 132 public void testIncrementProcStateSeqIfNeeded() { 133 final UidRecord uidRec = new UidRecord(TEST_UID); 134 135 assertEquals("Initially global seq counter should be 0", 0, mAms.mProcStateSeqCounter); 136 assertEquals("Initially seq counter in uidRecord should be 0", 0, uidRec.curProcStateSeq); 137 138 // Uid state is not moving from background to foreground or vice versa. 139 uidRec.setProcState = PROCESS_STATE_TOP; 140 uidRec.curProcState = PROCESS_STATE_TOP; 141 mAms.incrementProcStateSeqIfNeeded(uidRec); 142 assertEquals(0, mAms.mProcStateSeqCounter); 143 assertEquals(0, uidRec.curProcStateSeq); 144 145 // Uid state is moving from foreground to background. 146 uidRec.curProcState = PROCESS_STATE_FOREGROUND_SERVICE; 147 uidRec.setProcState = PROCESS_STATE_SERVICE; 148 mAms.incrementProcStateSeqIfNeeded(uidRec); 149 assertEquals(1, mAms.mProcStateSeqCounter); 150 assertEquals(1, uidRec.curProcStateSeq); 151 152 // Explicitly setting the seq counter for more verification. 153 mAms.mProcStateSeqCounter = 42; 154 155 // Uid state is not moving from background to foreground or vice versa. 156 uidRec.setProcState = PROCESS_STATE_IMPORTANT_BACKGROUND; 157 uidRec.curProcState = PROCESS_STATE_IMPORTANT_FOREGROUND; 158 mAms.incrementProcStateSeqIfNeeded(uidRec); 159 assertEquals(42, mAms.mProcStateSeqCounter); 160 assertEquals(1, uidRec.curProcStateSeq); 161 162 // Uid state is moving from background to foreground. 163 uidRec.setProcState = PROCESS_STATE_LAST_ACTIVITY; 164 uidRec.curProcState = PROCESS_STATE_TOP; 165 mAms.incrementProcStateSeqIfNeeded(uidRec); 166 assertEquals(43, mAms.mProcStateSeqCounter); 167 assertEquals(43, uidRec.curProcStateSeq); 168 } 169 170 @Test 171 public void testShouldIncrementProcStateSeq() { 172 final UidRecord uidRec = new UidRecord(TEST_UID); 173 174 final String error1 = "Seq should be incremented: prevState: %s, curState: %s"; 175 final String error2 = "Seq should not be incremented: prevState: %s, curState: %s"; 176 Function<String, String> errorMsg = errorTemplate -> { 177 return String.format(errorTemplate, 178 valueToString(ActivityManager.class, "PROCESS_STATE_", uidRec.setProcState), 179 valueToString(ActivityManager.class, "PROCESS_STATE_", uidRec.curProcState)); 180 }; 181 182 // No change in uid state 183 uidRec.setProcState = PROCESS_STATE_RECEIVER; 184 uidRec.curProcState = PROCESS_STATE_RECEIVER; 185 assertFalse(errorMsg.apply(error2), mAms.shouldIncrementProcStateSeq(uidRec)); 186 187 // Foreground to foreground 188 uidRec.setProcState = PROCESS_STATE_FOREGROUND_SERVICE; 189 uidRec.curProcState = PROCESS_STATE_BOUND_FOREGROUND_SERVICE; 190 assertFalse(errorMsg.apply(error2), mAms.shouldIncrementProcStateSeq(uidRec)); 191 192 // Background to background 193 uidRec.setProcState = PROCESS_STATE_CACHED_ACTIVITY; 194 uidRec.curProcState = PROCESS_STATE_CACHED_EMPTY; 195 assertFalse(errorMsg.apply(error2), mAms.shouldIncrementProcStateSeq(uidRec)); 196 197 // Background to background 198 uidRec.setProcState = PROCESS_STATE_NONEXISTENT; 199 uidRec.curProcState = PROCESS_STATE_CACHED_ACTIVITY; 200 assertFalse(errorMsg.apply(error2), mAms.shouldIncrementProcStateSeq(uidRec)); 201 202 // Background to foreground 203 uidRec.setProcState = PROCESS_STATE_SERVICE; 204 uidRec.curProcState = PROCESS_STATE_FOREGROUND_SERVICE; 205 assertTrue(errorMsg.apply(error1), mAms.shouldIncrementProcStateSeq(uidRec)); 206 207 // Foreground to background 208 uidRec.setProcState = PROCESS_STATE_TOP; 209 uidRec.curProcState = PROCESS_STATE_LAST_ACTIVITY; 210 assertTrue(errorMsg.apply(error1), mAms.shouldIncrementProcStateSeq(uidRec)); 211 } 212 213 /** 214 * This test verifies that process state changes are dispatched to observers based on the 215 * changes they wanted to listen (this is specified when registering the observer). 216 */ 217 @Test 218 public void testDispatchUids_dispatchNeededChanges() throws RemoteException { 219 when(mAppOpsService.checkOperation(AppOpsManager.OP_GET_USAGE_STATS, Process.myUid(), null)) 220 .thenReturn(AppOpsManager.MODE_ALLOWED); 221 222 final int[] changesToObserve = { 223 ActivityManager.UID_OBSERVER_PROCSTATE, 224 ActivityManager.UID_OBSERVER_GONE, 225 ActivityManager.UID_OBSERVER_IDLE, 226 ActivityManager.UID_OBSERVER_ACTIVE, 227 ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE 228 | ActivityManager.UID_OBSERVER_ACTIVE | ActivityManager.UID_OBSERVER_IDLE 229 }; 230 final IUidObserver[] observers = new IUidObserver.Stub[changesToObserve.length]; 231 for (int i = 0; i < observers.length; ++i) { 232 observers[i] = Mockito.mock(IUidObserver.Stub.class); 233 when(observers[i].asBinder()).thenReturn((IBinder) observers[i]); 234 mAms.registerUidObserver(observers[i], changesToObserve[i] /* which */, 235 ActivityManager.PROCESS_STATE_UNKNOWN /* cutpoint */, null /* caller */); 236 237 // When we invoke AMS.registerUidObserver, there are some interactions with observers[i] 238 // mock in RemoteCallbackList class. We don't want to test those interactions and 239 // at the same time, we don't want those to interfere with verifyNoMoreInteractions. 240 // So, resetting the mock here. 241 Mockito.reset(observers[i]); 242 } 243 244 // Add pending uid records each corresponding to a different change type UidRecord.CHANGE_* 245 final int[] changesForPendingUidRecords = UID_RECORD_CHANGES; 246 247 final int[] procStatesForPendingUidRecords = { 248 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 249 ActivityManager.PROCESS_STATE_NONEXISTENT, 250 ActivityManager.PROCESS_STATE_CACHED_EMPTY, 251 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, 252 ActivityManager.PROCESS_STATE_TOP 253 }; 254 final Map<Integer, UidRecord.ChangeItem> changeItems = new HashMap<>(); 255 for (int i = 0; i < changesForPendingUidRecords.length; ++i) { 256 final UidRecord.ChangeItem pendingChange = new UidRecord.ChangeItem(); 257 pendingChange.change = changesForPendingUidRecords[i]; 258 pendingChange.uid = i; 259 pendingChange.processState = procStatesForPendingUidRecords[i]; 260 pendingChange.procStateSeq = i; 261 changeItems.put(changesForPendingUidRecords[i], pendingChange); 262 mAms.mPendingUidChanges.add(pendingChange); 263 } 264 265 mAms.dispatchUidsChanged(); 266 // Verify the required changes have been dispatched to observers. 267 for (int i = 0; i < observers.length; ++i) { 268 final int changeToObserve = changesToObserve[i]; 269 final IUidObserver observerToTest = observers[i]; 270 if ((changeToObserve & ActivityManager.UID_OBSERVER_IDLE) != 0) { 271 // Observer listens to uid idle changes, so change items corresponding to 272 // UidRecord.CHANGE_IDLE or UidRecord.CHANGE_IDLE_GONE needs to be 273 // delivered to this observer. 274 final int[] changesToVerify = { 275 UidRecord.CHANGE_IDLE, 276 UidRecord.CHANGE_GONE_IDLE 277 }; 278 verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems, 279 (observer, changeItem) -> { 280 verify(observer).onUidIdle(changeItem.uid, changeItem.ephemeral); 281 }); 282 } 283 if ((changeToObserve & ActivityManager.UID_OBSERVER_ACTIVE) != 0) { 284 // Observer listens to uid active changes, so change items corresponding to 285 // UidRecord.CHANGE_ACTIVE needs to be delivered to this observer. 286 final int[] changesToVerify = { UidRecord.CHANGE_ACTIVE }; 287 verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems, 288 (observer, changeItem) -> { 289 verify(observer).onUidActive(changeItem.uid); 290 }); 291 } 292 if ((changeToObserve & ActivityManager.UID_OBSERVER_GONE) != 0) { 293 // Observer listens to uid gone changes, so change items corresponding to 294 // UidRecord.CHANGE_GONE or UidRecord.CHANGE_IDLE_GONE needs to be 295 // delivered to this observer. 296 final int[] changesToVerify = { 297 UidRecord.CHANGE_GONE, 298 UidRecord.CHANGE_GONE_IDLE 299 }; 300 verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems, 301 (observer, changeItem) -> { 302 verify(observer).onUidGone(changeItem.uid, changeItem.ephemeral); 303 }); 304 } 305 if ((changeToObserve & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { 306 // Observer listens to uid procState changes, so change items corresponding to 307 // UidRecord.CHANGE_PROCSTATE or UidRecord.CHANGE_IDLE or UidRecord.CHANGE_ACTIVE 308 // needs to be delivered to this observer. 309 final int[] changesToVerify = { 310 UidRecord.CHANGE_PROCSTATE, 311 UidRecord.CHANGE_ACTIVE, 312 UidRecord.CHANGE_IDLE 313 }; 314 verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems, 315 (observer, changeItem) -> { 316 verify(observer).onUidStateChanged(changeItem.uid, 317 changeItem.processState, changeItem.procStateSeq); 318 }); 319 } 320 // Verify there are no other callbacks for this observer. 321 verifyNoMoreInteractions(observerToTest); 322 } 323 } 324 325 private interface ObserverChangesVerifier { 326 void verify(IUidObserver observer, UidRecord.ChangeItem changeItem) throws RemoteException; 327 } 328 329 private void verifyObserverReceivedChanges(IUidObserver observer, int[] changesToVerify, 330 Map<Integer, UidRecord.ChangeItem> changeItems, ObserverChangesVerifier verifier) 331 throws RemoteException { 332 for (int change : changesToVerify) { 333 final UidRecord.ChangeItem changeItem = changeItems.get(change); 334 verifier.verify(observer, changeItem); 335 } 336 } 337 338 /** 339 * This test verifies that process state changes are dispatched to observers only when they 340 * change across the cutpoint (this is specified when registering the observer). 341 */ 342 @Test 343 public void testDispatchUidChanges_procStateCutpoint() throws RemoteException { 344 final IUidObserver observer = Mockito.mock(IUidObserver.Stub.class); 345 346 when(observer.asBinder()).thenReturn((IBinder) observer); 347 mAms.registerUidObserver(observer, ActivityManager.UID_OBSERVER_PROCSTATE /* which */, 348 ActivityManager.PROCESS_STATE_SERVICE /* cutpoint */, null /* callingPackage */); 349 // When we invoke AMS.registerUidObserver, there are some interactions with observer 350 // mock in RemoteCallbackList class. We don't want to test those interactions and 351 // at the same time, we don't want those to interfere with verifyNoMoreInteractions. 352 // So, resetting the mock here. 353 Mockito.reset(observer); 354 355 final UidRecord.ChangeItem changeItem = new UidRecord.ChangeItem(); 356 changeItem.uid = TEST_UID; 357 changeItem.change = UidRecord.CHANGE_PROCSTATE; 358 changeItem.processState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY; 359 changeItem.procStateSeq = 111; 360 mAms.mPendingUidChanges.add(changeItem); 361 mAms.dispatchUidsChanged(); 362 // First process state message is always delivered regardless of whether the process state 363 // change is above or below the cutpoint (PROCESS_STATE_SERVICE). 364 verify(observer).onUidStateChanged(TEST_UID, 365 changeItem.processState, changeItem.procStateSeq); 366 verifyNoMoreInteractions(observer); 367 368 changeItem.processState = ActivityManager.PROCESS_STATE_RECEIVER; 369 mAms.mPendingUidChanges.add(changeItem); 370 mAms.dispatchUidsChanged(); 371 // Previous process state change is below cutpoint (PROCESS_STATE_SERVICE) and 372 // the current process state change is also below cutpoint, so no callback will be invoked. 373 verifyNoMoreInteractions(observer); 374 375 changeItem.processState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; 376 mAms.mPendingUidChanges.add(changeItem); 377 mAms.dispatchUidsChanged(); 378 // Previous process state change is below cutpoint (PROCESS_STATE_SERVICE) and 379 // the current process state change is above cutpoint, so callback will be invoked with the 380 // current process state change. 381 verify(observer).onUidStateChanged(TEST_UID, 382 changeItem.processState, changeItem.procStateSeq); 383 verifyNoMoreInteractions(observer); 384 385 changeItem.processState = ActivityManager.PROCESS_STATE_TOP; 386 mAms.mPendingUidChanges.add(changeItem); 387 mAms.dispatchUidsChanged(); 388 // Previous process state change is above cutpoint (PROCESS_STATE_SERVICE) and 389 // the current process state change is also above cutpoint, so no callback will be invoked. 390 verifyNoMoreInteractions(observer); 391 392 changeItem.processState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; 393 mAms.mPendingUidChanges.add(changeItem); 394 mAms.dispatchUidsChanged(); 395 // Previous process state change is above cutpoint (PROCESS_STATE_SERVICE) and 396 // the current process state change is below cutpoint, so callback will be invoked with the 397 // current process state change. 398 verify(observer).onUidStateChanged(TEST_UID, 399 changeItem.processState, changeItem.procStateSeq); 400 verifyNoMoreInteractions(observer); 401 } 402 403 /** 404 * This test verifies that {@link ActivityManagerService#mValidateUids} which is a 405 * part of dumpsys is correctly updated. 406 */ 407 @Test 408 public void testDispatchUidChanges_validateUidsUpdated() { 409 final int[] changesForPendingItems = UID_RECORD_CHANGES; 410 411 final int[] procStatesForPendingItems = { 412 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 413 ActivityManager.PROCESS_STATE_CACHED_EMPTY, 414 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, 415 ActivityManager.PROCESS_STATE_SERVICE, 416 ActivityManager.PROCESS_STATE_RECEIVER 417 }; 418 final ArrayList<UidRecord.ChangeItem> pendingItemsForUids 419 = new ArrayList<>(changesForPendingItems.length); 420 for (int i = 0; i < changesForPendingItems.length; ++i) { 421 final UidRecord.ChangeItem item = new UidRecord.ChangeItem(); 422 item.uid = i; 423 item.change = changesForPendingItems[i]; 424 item.processState = procStatesForPendingItems[i]; 425 pendingItemsForUids.add(i, item); 426 } 427 428 // Verify that when there no observers listening to uid state changes, then there will 429 // be no changes to validateUids. 430 mAms.mPendingUidChanges.addAll(pendingItemsForUids); 431 mAms.dispatchUidsChanged(); 432 assertEquals("No observers registered, so validateUids should be empty", 433 0, mAms.mValidateUids.size()); 434 435 final IUidObserver observer = Mockito.mock(IUidObserver.Stub.class); 436 when(observer.asBinder()).thenReturn((IBinder) observer); 437 mAms.registerUidObserver(observer, 0, 0, null); 438 // Verify that when observers are registered, then validateUids is correctly updated. 439 mAms.mPendingUidChanges.addAll(pendingItemsForUids); 440 mAms.dispatchUidsChanged(); 441 for (int i = 0; i < pendingItemsForUids.size(); ++i) { 442 final UidRecord.ChangeItem item = pendingItemsForUids.get(i); 443 final UidRecord validateUidRecord = mAms.mValidateUids.get(item.uid); 444 if (item.change == UidRecord.CHANGE_GONE || item.change == UidRecord.CHANGE_GONE_IDLE) { 445 assertNull("validateUidRecord should be null since the change is either " 446 + "CHANGE_GONE or CHANGE_GONE_IDLE", validateUidRecord); 447 } else { 448 assertNotNull("validateUidRecord should not be null since the change is neither " 449 + "CHANGE_GONE nor CHANGE_GONE_IDLE", validateUidRecord); 450 assertEquals("processState: " + item.processState + " curProcState: " 451 + validateUidRecord.curProcState + " should have been equal", 452 item.processState, validateUidRecord.curProcState); 453 assertEquals("processState: " + item.processState + " setProcState: " 454 + validateUidRecord.curProcState + " should have been equal", 455 item.processState, validateUidRecord.setProcState); 456 if (item.change == UidRecord.CHANGE_IDLE) { 457 assertTrue("UidRecord.idle should be updated to true for CHANGE_IDLE", 458 validateUidRecord.idle); 459 } else if (item.change == UidRecord.CHANGE_ACTIVE) { 460 assertFalse("UidRecord.idle should be updated to false for CHANGE_ACTIVE", 461 validateUidRecord.idle); 462 } 463 } 464 } 465 466 // Verify that when uid state changes to CHANGE_GONE or CHANGE_GONE_IDLE, then it 467 // will be removed from validateUids. 468 assertNotEquals("validateUids should not be empty", 0, mAms.mValidateUids.size()); 469 for (int i = 0; i < pendingItemsForUids.size(); ++i) { 470 final UidRecord.ChangeItem item = pendingItemsForUids.get(i); 471 // Assign CHANGE_GONE_IDLE to some items and CHANGE_GONE to the others, using even/odd 472 // distribution for this assignment. 473 item.change = (i % 2) == 0 ? UidRecord.CHANGE_GONE_IDLE : UidRecord.CHANGE_GONE; 474 } 475 mAms.mPendingUidChanges.addAll(pendingItemsForUids); 476 mAms.dispatchUidsChanged(); 477 assertEquals("validateUids should be empty, validateUids: " + mAms.mValidateUids, 478 0, mAms.mValidateUids.size()); 479 } 480 481 @Test 482 public void testEnqueueUidChangeLocked_procStateSeqUpdated() { 483 final UidRecord uidRecord = new UidRecord(TEST_UID); 484 uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ1; 485 486 // Verify with no pending changes for TEST_UID. 487 verifyLastProcStateSeqUpdated(uidRecord, -1, TEST_PROC_STATE_SEQ1); 488 489 // Add a pending change for TEST_UID and verify enqueueUidChangeLocked still works as 490 // expected. 491 final UidRecord.ChangeItem changeItem = new UidRecord.ChangeItem(); 492 uidRecord.pendingChange = changeItem; 493 uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ2; 494 verifyLastProcStateSeqUpdated(uidRecord, -1, TEST_PROC_STATE_SEQ2); 495 496 // Use "null" uidRecord to make sure there is no crash. 497 // TODO: currently it crashes, uncomment after fixing it. 498 // mAms.enqueueUidChangeLocked(null, TEST_UID, UidRecord.CHANGE_ACTIVE); 499 } 500 501 private void verifyLastProcStateSeqUpdated(UidRecord uidRecord, int uid, long curProcstateSeq) { 502 // Test enqueueUidChangeLocked with every UidRecord.CHANGE_* 503 for (int i = 0; i < UID_RECORD_CHANGES.length; ++i) { 504 final int changeToDispatch = UID_RECORD_CHANGES[i]; 505 // Reset lastProcStateSeqDispatchToObservers after every test. 506 uidRecord.lastDispatchedProcStateSeq = 0; 507 mAms.enqueueUidChangeLocked(uidRecord, uid, changeToDispatch); 508 // Verify there is no effect on curProcStateSeq. 509 assertEquals(curProcstateSeq, uidRecord.curProcStateSeq); 510 if (changeToDispatch == UidRecord.CHANGE_GONE 511 || changeToDispatch == UidRecord.CHANGE_GONE_IDLE) { 512 // Since the change is CHANGE_GONE or CHANGE_GONE_IDLE, verify that 513 // lastProcStateSeqDispatchedToObservers is not updated. 514 assertNotEquals(uidRecord.curProcStateSeq, 515 uidRecord.lastDispatchedProcStateSeq); 516 } else { 517 // Since the change is neither CHANGE_GONE nor CHANGE_GONE_IDLE, verify that 518 // lastProcStateSeqDispatchedToObservers has been updated to curProcStateSeq. 519 assertEquals(uidRecord.curProcStateSeq, 520 uidRecord.lastDispatchedProcStateSeq); 521 } 522 } 523 } 524 525 @MediumTest 526 @Test 527 public void testEnqueueUidChangeLocked_dispatchUidsChanged() { 528 final UidRecord uidRecord = new UidRecord(TEST_UID); 529 final int expectedProcState = PROCESS_STATE_SERVICE; 530 uidRecord.setProcState = expectedProcState; 531 uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ1; 532 533 // Test with no pending uid records. 534 for (int i = 0; i < UID_RECORD_CHANGES.length; ++i) { 535 final int changeToDispatch = UID_RECORD_CHANGES[i]; 536 537 // Reset the current state 538 mHandler.reset(); 539 uidRecord.pendingChange = null; 540 mAms.mPendingUidChanges.clear(); 541 542 mAms.enqueueUidChangeLocked(uidRecord, -1, changeToDispatch); 543 544 // Verify that UidRecord.pendingChange is updated correctly. 545 assertNotNull(uidRecord.pendingChange); 546 assertEquals(TEST_UID, uidRecord.pendingChange.uid); 547 assertEquals(expectedProcState, uidRecord.pendingChange.processState); 548 assertEquals(TEST_PROC_STATE_SEQ1, uidRecord.pendingChange.procStateSeq); 549 550 // Verify that DISPATCH_UIDS_CHANGED_UI_MSG is posted to handler. 551 mHandler.waitForMessage(DISPATCH_UIDS_CHANGED_UI_MSG); 552 } 553 } 554 555 private class TestHandler extends Handler { 556 private static final long WAIT_FOR_MSG_TIMEOUT_MS = 4000; // 4 sec 557 private static final long WAIT_FOR_MSG_INTERVAL_MS = 400; // 0.4 sec 558 559 private Set<Integer> mMsgsHandled = new HashSet<>(); 560 561 TestHandler(Looper looper) { 562 super(looper); 563 } 564 565 @Override 566 public void handleMessage(Message msg) { 567 mMsgsHandled.add(msg.what); 568 } 569 570 public void waitForMessage(int msg) { 571 final long endTime = System.currentTimeMillis() + WAIT_FOR_MSG_TIMEOUT_MS; 572 while (!mMsgsHandled.contains(msg) && System.currentTimeMillis() < endTime) { 573 SystemClock.sleep(WAIT_FOR_MSG_INTERVAL_MS); 574 } 575 if (!mMsgsHandled.contains(msg)) { 576 fail("Timed out waiting for the message to be handled, msg: " + msg); 577 } 578 } 579 580 public void reset() { 581 mMsgsHandled.clear(); 582 } 583 } 584 585 private class TestInjector implements Injector { 586 @Override 587 public AppOpsService getAppOpsService() { 588 return mAppOpsService; 589 } 590 591 @Override 592 public Handler getHandler() { 593 return mHandler; 594 } 595 } 596}