1 /* 2 * Copyright (C) 2022 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.appop; 18 19 import static android.app.AppOpsManager.MODE_ALLOWED; 20 import static android.app.AppOpsManager.MODE_FOREGROUND; 21 import static android.app.AppOpsManager.MODE_IGNORED; 22 import static android.app.AppOpsManager.OP_CAMERA; 23 import static android.app.AppOpsManager.OP_COARSE_LOCATION; 24 import static android.app.AppOpsManager.OP_FINE_LOCATION; 25 import static android.app.AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO; 26 import static android.app.AppOpsManager.OP_RECORD_AUDIO; 27 import static android.app.AppOpsManager.OP_WIFI_SCAN; 28 import static android.app.AppOpsManager.UID_STATE_BACKGROUND; 29 import static android.app.AppOpsManager.UID_STATE_CACHED; 30 import static android.app.AppOpsManager.UID_STATE_FOREGROUND; 31 import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE; 32 import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED; 33 import static android.app.AppOpsManager.UID_STATE_TOP; 34 35 import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState; 36 37 import static org.junit.Assert.assertEquals; 38 import static org.junit.Assert.assertFalse; 39 import static org.junit.Assert.assertTrue; 40 import static org.mockito.ArgumentMatchers.anyBoolean; 41 import static org.mockito.ArgumentMatchers.anyInt; 42 import static org.mockito.ArgumentMatchers.eq; 43 import static org.mockito.Mockito.atLeastOnce; 44 import static org.mockito.Mockito.doReturn; 45 import static org.mockito.Mockito.never; 46 import static org.mockito.Mockito.times; 47 import static org.mockito.Mockito.verify; 48 49 import android.app.ActivityManager; 50 import android.app.ActivityManagerInternal; 51 import android.app.AppOpsManager; 52 import android.util.SparseArray; 53 54 import com.android.dx.mockito.inline.extended.ExtendedMockito; 55 import com.android.dx.mockito.inline.extended.StaticMockitoSession; 56 import com.android.internal.os.Clock; 57 import com.android.server.appop.AppOpsUidStateTracker.UidStateChangedCallback; 58 import com.android.server.appop.AppOpsUidStateTrackerImpl.DelayableExecutor; 59 60 import org.junit.After; 61 import org.junit.Before; 62 import org.junit.Test; 63 import org.mockito.Mock; 64 import org.mockito.Mockito; 65 import org.mockito.quality.Strictness; 66 67 import java.util.PriorityQueue; 68 69 public class AppOpsUidStateTrackerTest { 70 71 private static final int UID = 10001; 72 73 // An op code that's not location/cam/mic so that we can test the code for evaluating mode 74 // without a specific capability associated with it. 75 public static final int OP_NO_CAPABILITIES = OP_WIFI_SCAN; 76 77 @Mock 78 ActivityManagerInternal mAmi; 79 80 @Mock 81 AppOpsService.Constants mConstants; 82 83 AppOpsUidStateTrackerTestExecutor mExecutor = new AppOpsUidStateTrackerTestExecutor(); 84 85 AppOpsUidStateTrackerTestClock mClock = new AppOpsUidStateTrackerTestClock(mExecutor); 86 87 AppOpsUidStateTracker mIntf; 88 89 StaticMockitoSession mSession; 90 91 @Before setUp()92 public void setUp() { 93 mSession = ExtendedMockito.mockitoSession() 94 .initMocks(this) 95 .strictness(Strictness.LENIENT) 96 .startMocking(); 97 mConstants.TOP_STATE_SETTLE_TIME = 10 * 1000L; 98 mConstants.FG_SERVICE_STATE_SETTLE_TIME = 5 * 1000L; 99 mConstants.BG_STATE_SETTLE_TIME = 1 * 1000L; 100 mIntf = new AppOpsUidStateTrackerImpl(mAmi, mExecutor, mClock, mConstants, 101 Thread.currentThread()); 102 } 103 104 @After tearDown()105 public void tearDown() { 106 mSession.finishMocking(); 107 } 108 109 /** 110 * This class makes the assumption that all ops are restricted at the same state, this is likely 111 * to be the case forever or become obsolete with the capability mechanism. If this fails 112 * something in {@link AppOpsUidStateTrackerImpl} might break when reporting if foreground mode 113 * might change. 114 */ 115 @Test testConstantFirstUnrestrictedUidState()116 public void testConstantFirstUnrestrictedUidState() { 117 for (int i = 0; i < AppOpsManager.getNumOps(); i++) { 118 assertEquals(UID_STATE_MAX_LAST_NON_RESTRICTED, 119 AppOpsManager.resolveFirstUnrestrictedUidState(i)); 120 } 121 } 122 123 @Test testNoCapability()124 public void testNoCapability() { 125 procStateBuilder(UID) 126 .topState() 127 .update(); 128 129 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); 130 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); 131 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); 132 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); 133 assertEquals(MODE_IGNORED, 134 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); 135 } 136 137 @Test testForegroundWithMicrophoneCapability()138 public void testForegroundWithMicrophoneCapability() { 139 procStateBuilder(UID) 140 .topState() 141 .microphoneCapability() 142 .update(); 143 144 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); 145 assertEquals(MODE_ALLOWED, 146 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); 147 148 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); 149 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); 150 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); 151 } 152 153 @Test testBackgroundWithMicrophoneCapability()154 public void testBackgroundWithMicrophoneCapability() { 155 procStateBuilder(UID) 156 .backgroundState() 157 .microphoneCapability() 158 .update(); 159 160 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); 161 assertEquals(MODE_ALLOWED, 162 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); 163 164 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); 165 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); 166 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); 167 } 168 169 @Test testForegroundWithCameraCapability()170 public void testForegroundWithCameraCapability() { 171 procStateBuilder(UID) 172 .topState() 173 .cameraCapability() 174 .update(); 175 176 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); 177 178 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); 179 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); 180 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); 181 assertEquals(MODE_IGNORED, 182 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); 183 } 184 185 @Test testBackgroundWithCameraCapability()186 public void testBackgroundWithCameraCapability() { 187 procStateBuilder(UID) 188 .backgroundState() 189 .cameraCapability() 190 .update(); 191 192 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); 193 194 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); 195 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); 196 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); 197 assertEquals(MODE_IGNORED, 198 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); 199 } 200 201 @Test testForegroundWithLocationCapability()202 public void testForegroundWithLocationCapability() { 203 procStateBuilder(UID) 204 .topState() 205 .locationCapability() 206 .update(); 207 208 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); 209 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); 210 211 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); 212 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); 213 assertEquals(MODE_IGNORED, 214 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); 215 } 216 217 @Test testBackgroundWithLocationCapability()218 public void testBackgroundWithLocationCapability() { 219 procStateBuilder(UID) 220 .backgroundState() 221 .locationCapability() 222 .update(); 223 224 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); 225 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); 226 227 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); 228 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); 229 assertEquals(MODE_IGNORED, 230 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); 231 } 232 233 @Test testForegroundNotCapabilitiesTracked()234 public void testForegroundNotCapabilitiesTracked() { 235 procStateBuilder(UID) 236 .topState() 237 .update(); 238 239 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_NO_CAPABILITIES, MODE_FOREGROUND)); 240 } 241 242 @Test testBackgroundNotCapabilitiesTracked()243 public void testBackgroundNotCapabilitiesTracked() { 244 procStateBuilder(UID) 245 .backgroundState() 246 .update(); 247 248 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_NO_CAPABILITIES, MODE_FOREGROUND)); 249 } 250 251 @Test testBackgroundToForegroundTransition()252 public void testBackgroundToForegroundTransition() { 253 procStateBuilder(UID) 254 .backgroundState() 255 .update(); 256 assertBackground(UID); 257 258 procStateBuilder(UID) 259 .topState() 260 .update(); 261 assertForeground(UID); 262 } 263 264 @Test testForegroundToBackgroundTransition()265 public void testForegroundToBackgroundTransition() { 266 procStateBuilder(UID) 267 .topState() 268 .update(); 269 assertForeground(UID); 270 271 procStateBuilder(UID) 272 .backgroundState() 273 .update(); 274 // Still in foreground due to settle time 275 assertForeground(UID); 276 277 mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME - 1); 278 assertForeground(UID); 279 280 mClock.advanceTime(1); 281 assertBackground(UID); 282 } 283 284 @Test testForegroundServiceToBackgroundTransition()285 public void testForegroundServiceToBackgroundTransition() { 286 procStateBuilder(UID) 287 .foregroundServiceState() 288 .update(); 289 assertForeground(UID); 290 291 procStateBuilder(UID) 292 .backgroundState() 293 .update(); 294 // Still in foreground due to settle time 295 assertForeground(UID); 296 297 mClock.advanceTime(mConstants.FG_SERVICE_STATE_SETTLE_TIME - 1); 298 assertForeground(UID); 299 300 mClock.advanceTime(1); 301 assertBackground(UID); 302 } 303 304 @Test testEarlyUpdateDoesntCommit()305 public void testEarlyUpdateDoesntCommit() { 306 procStateBuilder(UID) 307 .foregroundServiceState() 308 .update(); 309 assertForeground(UID); 310 311 procStateBuilder(UID) 312 .backgroundState() 313 .update(); 314 // Still in foreground due to settle time 315 assertForeground(UID); 316 317 // 1 ms short of settle time 318 mClock.advanceTime(mConstants.FG_SERVICE_STATE_SETTLE_TIME - 1); 319 assertForeground(UID); 320 } 321 322 @Test testMicrophoneCapabilityAdded()323 public void testMicrophoneCapabilityAdded() { 324 procStateBuilder(UID) 325 .backgroundState() 326 .update(); 327 328 procStateBuilder(UID) 329 .backgroundState() 330 .microphoneCapability() 331 .update(); 332 333 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); 334 assertEquals(MODE_ALLOWED, 335 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); 336 } 337 338 @Test testMicrophoneCapabilityRemoved()339 public void testMicrophoneCapabilityRemoved() { 340 procStateBuilder(UID) 341 .backgroundState() 342 .microphoneCapability() 343 .update(); 344 345 procStateBuilder(UID) 346 .backgroundState() 347 .update(); 348 349 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); 350 assertEquals(MODE_IGNORED, 351 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); 352 } 353 354 @Test testCameraCapabilityAdded()355 public void testCameraCapabilityAdded() { 356 procStateBuilder(UID) 357 .backgroundState() 358 .update(); 359 360 procStateBuilder(UID) 361 .backgroundState() 362 .cameraCapability() 363 .update(); 364 365 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); 366 } 367 368 @Test testCameraCapabilityRemoved()369 public void testCameraCapabilityRemoved() { 370 procStateBuilder(UID) 371 .backgroundState() 372 .cameraCapability() 373 .update(); 374 375 procStateBuilder(UID) 376 .backgroundState() 377 .update(); 378 379 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); 380 } 381 382 @Test testLocationCapabilityAdded()383 public void testLocationCapabilityAdded() { 384 procStateBuilder(UID) 385 .backgroundState() 386 .update(); 387 388 procStateBuilder(UID) 389 .backgroundState() 390 .locationCapability() 391 .update(); 392 393 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); 394 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); 395 } 396 397 @Test testLocationCapabilityRemoved()398 public void testLocationCapabilityRemoved() { 399 procStateBuilder(UID) 400 .backgroundState() 401 .locationCapability() 402 .update(); 403 404 procStateBuilder(UID) 405 .backgroundState() 406 .update(); 407 408 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); 409 assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); 410 } 411 412 @Test testVisibleAppWidget()413 public void testVisibleAppWidget() { 414 procStateBuilder(UID) 415 .backgroundState() 416 .update(); 417 418 SparseArray<String> appPackageNames = new SparseArray<>(); 419 appPackageNames.put(UID, ""); 420 mIntf.updateAppWidgetVisibility(appPackageNames, true); 421 422 assertForeground(UID); 423 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); 424 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); 425 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); 426 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); 427 assertEquals(MODE_ALLOWED, 428 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); 429 } 430 431 @Test testPendingTop()432 public void testPendingTop() { 433 procStateBuilder(UID) 434 .backgroundState() 435 .update(); 436 437 doReturn(true).when(mAmi).isPendingTopUid(eq(UID)); 438 439 assertForeground(UID); 440 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); 441 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); 442 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); 443 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); 444 assertEquals(MODE_ALLOWED, 445 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); 446 } 447 448 @Test testTempAllowlist()449 public void testTempAllowlist() { 450 procStateBuilder(UID) 451 .backgroundState() 452 .update(); 453 454 doReturn(true).when(mAmi).isTempAllowlistedForFgsWhileInUse(eq(UID)); 455 456 assertForeground(UID); 457 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); 458 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); 459 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); 460 assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); 461 assertEquals(MODE_ALLOWED, 462 mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); 463 } 464 465 @Test testUidStateChangedCallbackNewProcessTop()466 public void testUidStateChangedCallbackNewProcessTop() { 467 UidStateChangedCallback cb = addUidStateChangeCallback(); 468 469 procStateBuilder(UID) 470 .topState() 471 .update(); 472 473 verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_TOP), eq(true)); 474 } 475 476 @Test testUidStateChangedCallbackNewProcessForegroundService()477 public void testUidStateChangedCallbackNewProcessForegroundService() { 478 UidStateChangedCallback cb = addUidStateChangeCallback(); 479 480 procStateBuilder(UID) 481 .foregroundServiceState() 482 .update(); 483 484 verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_FOREGROUND_SERVICE), eq(true)); 485 } 486 487 @Test testUidStateChangedCallbackNewProcessForeground()488 public void testUidStateChangedCallbackNewProcessForeground() { 489 UidStateChangedCallback cb = addUidStateChangeCallback(); 490 491 procStateBuilder(UID) 492 .foregroundState() 493 .update(); 494 495 verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_FOREGROUND), eq(true)); 496 } 497 498 @Test testUidStateChangedCallbackNewProcessBackground()499 public void testUidStateChangedCallbackNewProcessBackground() { 500 UidStateChangedCallback cb = addUidStateChangeCallback(); 501 502 procStateBuilder(UID) 503 .backgroundState() 504 .update(); 505 506 verify(cb).onUidStateChanged(eq(UID), eq(UID_STATE_BACKGROUND), eq(false)); 507 } 508 509 @Test testUidStateChangedCallbackNewProcessCached()510 public void testUidStateChangedCallbackNewProcessCached() { 511 UidStateChangedCallback cb = addUidStateChangeCallback(); 512 513 procStateBuilder(UID) 514 .cachedState() 515 .update(); 516 517 // Cached is the default, no change in uid state. 518 verify(cb, times(0)).onUidStateChanged(anyInt(), anyInt(), anyBoolean()); 519 } 520 521 @Test testUidStateChangedCallbackCachedToBackground()522 public void testUidStateChangedCallbackCachedToBackground() { 523 testUidStateChangedCallback( 524 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, 525 ActivityManager.PROCESS_STATE_RECEIVER); 526 } 527 528 @Test testUidStateChangedCallbackCachedToForeground()529 public void testUidStateChangedCallbackCachedToForeground() { 530 testUidStateChangedCallback( 531 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, 532 ActivityManager.PROCESS_STATE_BOUND_TOP); 533 } 534 535 @Test testUidStateChangedCallbackCachedToForegroundService()536 public void testUidStateChangedCallbackCachedToForegroundService() { 537 testUidStateChangedCallback( 538 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, 539 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); 540 } 541 542 @Test testUidStateChangedCallbackCachedToTop()543 public void testUidStateChangedCallbackCachedToTop() { 544 testUidStateChangedCallback( 545 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, 546 ActivityManager.PROCESS_STATE_TOP); 547 } 548 549 @Test testUidStateChangedCallbackBackgroundToCached()550 public void testUidStateChangedCallbackBackgroundToCached() { 551 testUidStateChangedCallback( 552 ActivityManager.PROCESS_STATE_RECEIVER, 553 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY); 554 } 555 556 @Test testUidStateChangedCallbackBackgroundToForeground()557 public void testUidStateChangedCallbackBackgroundToForeground() { 558 testUidStateChangedCallback( 559 ActivityManager.PROCESS_STATE_RECEIVER, 560 ActivityManager.PROCESS_STATE_BOUND_TOP); 561 } 562 563 @Test testUidStateChangedCallbackBackgroundToForegroundService()564 public void testUidStateChangedCallbackBackgroundToForegroundService() { 565 testUidStateChangedCallback( 566 ActivityManager.PROCESS_STATE_RECEIVER, 567 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); 568 } 569 570 @Test testUidStateChangedCallbackBackgroundToTop()571 public void testUidStateChangedCallbackBackgroundToTop() { 572 testUidStateChangedCallback( 573 ActivityManager.PROCESS_STATE_RECEIVER, 574 ActivityManager.PROCESS_STATE_TOP); 575 } 576 577 @Test testUidStateChangedCallbackForegroundToCached()578 public void testUidStateChangedCallbackForegroundToCached() { 579 testUidStateChangedCallback( 580 ActivityManager.PROCESS_STATE_BOUND_TOP, 581 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY); 582 } 583 584 @Test testUidStateChangedCallbackForegroundToBackground()585 public void testUidStateChangedCallbackForegroundToBackground() { 586 testUidStateChangedCallback( 587 ActivityManager.PROCESS_STATE_BOUND_TOP, 588 ActivityManager.PROCESS_STATE_RECEIVER); 589 } 590 591 @Test testUidStateChangedCallbackForegroundToForegroundService()592 public void testUidStateChangedCallbackForegroundToForegroundService() { 593 testUidStateChangedCallback( 594 ActivityManager.PROCESS_STATE_BOUND_TOP, 595 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); 596 } 597 598 @Test testUidStateChangedCallbackForegroundToTop()599 public void testUidStateChangedCallbackForegroundToTop() { 600 testUidStateChangedCallback( 601 ActivityManager.PROCESS_STATE_BOUND_TOP, 602 ActivityManager.PROCESS_STATE_TOP); 603 } 604 605 @Test testUidStateChangedCallbackForegroundServiceToCached()606 public void testUidStateChangedCallbackForegroundServiceToCached() { 607 testUidStateChangedCallback( 608 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 609 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY); 610 } 611 612 @Test testUidStateChangedCallbackForegroundServiceToBackground()613 public void testUidStateChangedCallbackForegroundServiceToBackground() { 614 testUidStateChangedCallback( 615 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 616 ActivityManager.PROCESS_STATE_RECEIVER); 617 } 618 619 @Test testUidStateChangedCallbackForegroundServiceToForeground()620 public void testUidStateChangedCallbackForegroundServiceToForeground() { 621 testUidStateChangedCallback( 622 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 623 ActivityManager.PROCESS_STATE_BOUND_TOP); 624 } 625 626 @Test testUidStateChangedCallbackForegroundServiceToTop()627 public void testUidStateChangedCallbackForegroundServiceToTop() { 628 testUidStateChangedCallback( 629 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, 630 ActivityManager.PROCESS_STATE_TOP); 631 } 632 633 @Test testUidStateChangedCallbackTopToCached()634 public void testUidStateChangedCallbackTopToCached() { 635 testUidStateChangedCallback( 636 ActivityManager.PROCESS_STATE_TOP, 637 ActivityManager.PROCESS_STATE_CACHED_ACTIVITY); 638 } 639 640 @Test testUidStateChangedCallbackTopToBackground()641 public void testUidStateChangedCallbackTopToBackground() { 642 testUidStateChangedCallback( 643 ActivityManager.PROCESS_STATE_TOP, 644 ActivityManager.PROCESS_STATE_RECEIVER); 645 } 646 647 @Test testUidStateChangedCallbackTopToForeground()648 public void testUidStateChangedCallbackTopToForeground() { 649 testUidStateChangedCallback( 650 ActivityManager.PROCESS_STATE_TOP, 651 ActivityManager.PROCESS_STATE_BOUND_TOP); 652 } 653 654 @Test testUidStateChangedCallbackTopToForegroundService()655 public void testUidStateChangedCallbackTopToForegroundService() { 656 testUidStateChangedCallback( 657 ActivityManager.PROCESS_STATE_TOP, 658 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE); 659 } 660 661 @Test testUidStateChangedCallbackCachedToNonexistent()662 public void testUidStateChangedCallbackCachedToNonexistent() { 663 UidStateChangedCallback cb = addUidStateChangeCallback(); 664 665 procStateBuilder(UID) 666 .cachedState() 667 .update(); 668 669 procStateBuilder(UID) 670 .nonExistentState() 671 .update(); 672 673 verify(cb, never()).onUidStateChanged(anyInt(), anyInt(), anyBoolean()); 674 } 675 676 @Test testUidStateChangedCallbackBackgroundToNonexistent()677 public void testUidStateChangedCallbackBackgroundToNonexistent() { 678 UidStateChangedCallback cb = addUidStateChangeCallback(); 679 680 procStateBuilder(UID) 681 .backgroundState() 682 .update(); 683 684 procStateBuilder(UID) 685 .nonExistentState() 686 .update(); 687 688 verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(false)); 689 } 690 691 @Test testUidStateChangedCallbackForegroundToNonexistent()692 public void testUidStateChangedCallbackForegroundToNonexistent() { 693 UidStateChangedCallback cb = addUidStateChangeCallback(); 694 695 procStateBuilder(UID) 696 .foregroundState() 697 .update(); 698 699 procStateBuilder(UID) 700 .nonExistentState() 701 .update(); 702 703 verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true)); 704 } 705 706 @Test testUidStateChangedCallbackForegroundServiceToNonexistent()707 public void testUidStateChangedCallbackForegroundServiceToNonexistent() { 708 UidStateChangedCallback cb = addUidStateChangeCallback(); 709 710 procStateBuilder(UID) 711 .foregroundServiceState() 712 .update(); 713 714 procStateBuilder(UID) 715 .nonExistentState() 716 .update(); 717 718 verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true)); 719 } 720 721 @Test testUidStateChangedCallbackTopToNonexistent()722 public void testUidStateChangedCallbackTopToNonexistent() { 723 UidStateChangedCallback cb = addUidStateChangeCallback(); 724 725 procStateBuilder(UID) 726 .topState() 727 .update(); 728 729 procStateBuilder(UID) 730 .nonExistentState() 731 .update(); 732 733 verify(cb, atLeastOnce()).onUidStateChanged(eq(UID), eq(UID_STATE_CACHED), eq(true)); 734 } 735 736 @Test testUidStateChangedBackgroundThenForegroundImmediately()737 public void testUidStateChangedBackgroundThenForegroundImmediately() { 738 procStateBuilder(UID) 739 .topState() 740 .update(); 741 742 UidStateChangedCallback cb = addUidStateChangeCallback(); 743 744 procStateBuilder(UID) 745 .backgroundState() 746 .update(); 747 748 mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME - 1); 749 750 procStateBuilder(UID) 751 .topState() 752 .update(); 753 754 mClock.advanceTime(1); 755 756 verify(cb, never()).onUidStateChanged(anyInt(), anyInt(), anyBoolean()); 757 } 758 759 @Test testIsUidInForegroundForBackgroundState()760 public void testIsUidInForegroundForBackgroundState() { 761 procStateBuilder(UID) 762 .backgroundState() 763 .update(); 764 assertFalse(mIntf.isUidInForeground(UID)); 765 766 procStateBuilder(UID) 767 .nonExistentState() 768 .update(); 769 assertFalse(mIntf.isUidInForeground(UID)); 770 } 771 772 @Test testIsUidInForegroundForForegroundState()773 public void testIsUidInForegroundForForegroundState() { 774 procStateBuilder(UID) 775 .topState() 776 .update(); 777 assertTrue(mIntf.isUidInForeground(UID)); 778 779 procStateBuilder(UID) 780 .foregroundServiceState() 781 .update(); 782 assertTrue(mIntf.isUidInForeground(UID)); 783 } 784 785 @Test testAppWidgetVisibleDoesntChangeUidState()786 public void testAppWidgetVisibleDoesntChangeUidState() { 787 procStateBuilder(UID) 788 .topState() 789 .update(); 790 791 SparseArray<String> updatedAppWidgetVisibilities = new SparseArray<>(); 792 updatedAppWidgetVisibilities.put(UID, ""); 793 794 mIntf.updateAppWidgetVisibility(updatedAppWidgetVisibilities, true); 795 796 assertEquals(UID_STATE_TOP, mIntf.getUidState(UID)); 797 } 798 799 @Test testAppWidgetNotVisibleDoesntChangeUidState()800 public void testAppWidgetNotVisibleDoesntChangeUidState() { 801 SparseArray<String> updatedAppWidgetVisibilities = new SparseArray<>(); 802 updatedAppWidgetVisibilities.put(UID, ""); 803 mIntf.updateAppWidgetVisibility(updatedAppWidgetVisibilities, true); 804 procStateBuilder(UID) 805 .topState() 806 .update(); 807 808 mIntf.updateAppWidgetVisibility(updatedAppWidgetVisibilities, false); 809 810 assertEquals(UID_STATE_TOP, mIntf.getUidState(UID)); 811 } 812 testUidStateChangedCallback(int initialState, int finalState)813 public void testUidStateChangedCallback(int initialState, int finalState) { 814 int initialUidState = processStateToUidState(initialState); 815 int finalUidState = processStateToUidState(finalState); 816 boolean foregroundChange = initialUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED 817 != finalUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED; 818 boolean finalUidStateIsBackgroundAndLessImportant = 819 finalUidState > UID_STATE_MAX_LAST_NON_RESTRICTED 820 && finalUidState > initialUidState; 821 822 UidStateChangedCallback cb = addUidStateChangeCallback(); 823 824 procStateBuilder(UID) 825 .setState(initialState) 826 .update(); 827 828 procStateBuilder(UID) 829 .setState(finalState) 830 .update(); 831 832 if (finalUidStateIsBackgroundAndLessImportant) { 833 mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME + 1); 834 } 835 836 verify(cb, atLeastOnce()) 837 .onUidStateChanged(eq(UID), eq(finalUidState), eq(foregroundChange)); 838 } 839 addUidStateChangeCallback()840 private UidStateChangedCallback addUidStateChangeCallback() { 841 UidStateChangedCallback cb = 842 Mockito.mock(UidStateChangedCallback.class); 843 mIntf.addUidStateChangedCallback(r -> r.run(), cb); 844 return cb; 845 } 846 847 /* If testForegroundNotCapabilitiesTracked fails, this assertion is probably incorrect */ assertForeground(int uid)848 private void assertForeground(int uid) { 849 assertEquals(MODE_ALLOWED, mIntf.evalMode(uid, OP_NO_CAPABILITIES, MODE_FOREGROUND)); 850 } 851 852 /* If testBackgroundNotCapabilitiesTracked fails, this assertion is probably incorrect */ assertBackground(int uid)853 private void assertBackground(int uid) { 854 assertEquals(MODE_IGNORED, mIntf.evalMode(uid, OP_NO_CAPABILITIES, MODE_FOREGROUND)); 855 } 856 procStateBuilder(int uid)857 private UidProcStateUpdateBuilder procStateBuilder(int uid) { 858 return new UidProcStateUpdateBuilder(mIntf, uid); 859 } 860 861 private static class UidProcStateUpdateBuilder { 862 private AppOpsUidStateTracker mIntf; 863 private int mUid; 864 private int mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT; 865 private int mCapability = ActivityManager.PROCESS_CAPABILITY_NONE; 866 UidProcStateUpdateBuilder(AppOpsUidStateTracker intf, int uid)867 private UidProcStateUpdateBuilder(AppOpsUidStateTracker intf, int uid) { 868 mUid = uid; 869 mIntf = intf; 870 } 871 update()872 public void update() { 873 mIntf.updateUidProcState(mUid, mProcState, mCapability); 874 } 875 persistentState()876 public UidProcStateUpdateBuilder persistentState() { 877 mProcState = ActivityManager.PROCESS_STATE_PERSISTENT; 878 return this; 879 } 880 setState(int procState)881 public UidProcStateUpdateBuilder setState(int procState) { 882 mProcState = procState; 883 return this; 884 } 885 topState()886 public UidProcStateUpdateBuilder topState() { 887 mProcState = ActivityManager.PROCESS_STATE_TOP; 888 return this; 889 } 890 foregroundServiceState()891 public UidProcStateUpdateBuilder foregroundServiceState() { 892 mProcState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; 893 return this; 894 } 895 foregroundState()896 public UidProcStateUpdateBuilder foregroundState() { 897 mProcState = ActivityManager.PROCESS_STATE_BOUND_TOP; 898 return this; 899 } 900 backgroundState()901 public UidProcStateUpdateBuilder backgroundState() { 902 mProcState = ActivityManager.PROCESS_STATE_SERVICE; 903 return this; 904 } 905 cachedState()906 public UidProcStateUpdateBuilder cachedState() { 907 mProcState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; 908 return this; 909 } 910 nonExistentState()911 public UidProcStateUpdateBuilder nonExistentState() { 912 mProcState = ActivityManager.PROCESS_STATE_NONEXISTENT; 913 return this; 914 } 915 locationCapability()916 public UidProcStateUpdateBuilder locationCapability() { 917 mCapability |= ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION; 918 return this; 919 } 920 cameraCapability()921 public UidProcStateUpdateBuilder cameraCapability() { 922 mCapability |= ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA; 923 return this; 924 } 925 microphoneCapability()926 public UidProcStateUpdateBuilder microphoneCapability() { 927 mCapability |= ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; 928 return this; 929 } 930 } 931 932 private static class AppOpsUidStateTrackerTestClock extends Clock { 933 934 private AppOpsUidStateTrackerTestExecutor mExecutor; 935 long mElapsedRealTime = 0x5f3759df; 936 AppOpsUidStateTrackerTestClock(AppOpsUidStateTrackerTestExecutor executor)937 AppOpsUidStateTrackerTestClock(AppOpsUidStateTrackerTestExecutor executor) { 938 mExecutor = executor; 939 executor.setUptime(mElapsedRealTime); 940 } 941 942 @Override elapsedRealtime()943 public long elapsedRealtime() { 944 return mElapsedRealTime; 945 } 946 advanceTime(long time)947 void advanceTime(long time) { 948 mElapsedRealTime += time; 949 mExecutor.setUptime(mElapsedRealTime); // assume uptime == elapsedtime 950 } 951 } 952 953 private static class AppOpsUidStateTrackerTestExecutor implements DelayableExecutor { 954 955 private static class QueueElement implements Comparable<QueueElement> { 956 957 private long mExecutionTime; 958 private Runnable mRunnable; 959 QueueElement(long executionTime, Runnable runnable)960 private QueueElement(long executionTime, Runnable runnable) { 961 mExecutionTime = executionTime; 962 mRunnable = runnable; 963 } 964 965 @Override compareTo(QueueElement queueElement)966 public int compareTo(QueueElement queueElement) { 967 return Long.compare(mExecutionTime, queueElement.mExecutionTime); 968 } 969 } 970 971 private long mUptime = 0; 972 973 private PriorityQueue<QueueElement> mDelayedMessages = new PriorityQueue(); 974 975 @Override execute(Runnable runnable)976 public void execute(Runnable runnable) { 977 runnable.run(); 978 } 979 980 @Override executeDelayed(Runnable runnable, long delay)981 public void executeDelayed(Runnable runnable, long delay) { 982 if (delay <= 0) { 983 execute(runnable); 984 } 985 986 mDelayedMessages.add(new QueueElement(mUptime + delay, runnable)); 987 } 988 setUptime(long uptime)989 private void setUptime(long uptime) { 990 while (!mDelayedMessages.isEmpty() 991 && mDelayedMessages.peek().mExecutionTime <= uptime) { 992 mDelayedMessages.poll().mRunnable.run(); 993 } 994 995 mUptime = uptime; 996 } 997 } 998 } 999