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 package android.cts.statsd.atom; 17 18 import android.net.wifi.WifiModeEnum; 19 import android.os.WakeLockLevelEnum; 20 import android.platform.test.annotations.RestrictedBuildTest; 21 import android.server.ErrorSource; 22 23 import com.android.internal.os.StatsdConfigProto.FieldMatcher; 24 import com.android.internal.os.StatsdConfigProto.StatsdConfig; 25 import com.android.os.AtomsProto; 26 import com.android.os.AtomsProto.ANROccurred; 27 import com.android.os.AtomsProto.AppCrashOccurred; 28 import com.android.os.AtomsProto.AppStartOccurred; 29 import com.android.os.AtomsProto.Atom; 30 import com.android.os.AtomsProto.AttributionNode; 31 import com.android.os.AtomsProto.AudioStateChanged; 32 import com.android.os.AtomsProto.BinderCalls; 33 import com.android.os.AtomsProto.BleScanResultReceived; 34 import com.android.os.AtomsProto.BleScanStateChanged; 35 import com.android.os.AtomsProto.CameraStateChanged; 36 import com.android.os.AtomsProto.CpuActiveTime; 37 import com.android.os.AtomsProto.DangerousPermissionState; 38 import com.android.os.AtomsProto.DeviceCalculatedPowerBlameUid; 39 import com.android.os.AtomsProto.FlashlightStateChanged; 40 import com.android.os.AtomsProto.ForegroundServiceStateChanged; 41 import com.android.os.AtomsProto.GpsScanStateChanged; 42 import com.android.os.AtomsProto.HiddenApiUsed; 43 import com.android.os.AtomsProto.LooperStats; 44 import com.android.os.AtomsProto.LmkKillOccurred; 45 import com.android.os.AtomsProto.MediaCodecStateChanged; 46 import com.android.os.AtomsProto.NativeProcessMemoryState; 47 import com.android.os.AtomsProto.OverlayStateChanged; 48 import com.android.os.AtomsProto.PictureInPictureStateChanged; 49 import com.android.os.AtomsProto.ProcessMemoryHighWaterMark; 50 import com.android.os.AtomsProto.ProcessMemoryState; 51 import com.android.os.AtomsProto.ScheduledJobStateChanged; 52 import com.android.os.AtomsProto.SyncStateChanged; 53 import com.android.os.AtomsProto.TestAtomReported; 54 import com.android.os.AtomsProto.VibratorStateChanged; 55 import com.android.os.AtomsProto.WakelockStateChanged; 56 import com.android.os.AtomsProto.WakeupAlarmOccurred; 57 import com.android.os.AtomsProto.WifiLockStateChanged; 58 import com.android.os.AtomsProto.WifiMulticastLockStateChanged; 59 import com.android.os.AtomsProto.WifiScanStateChanged; 60 import com.android.os.StatsLog.EventMetricData; 61 import com.android.tradefed.log.LogUtil; 62 63 import java.util.Arrays; 64 import java.util.HashSet; 65 import java.util.List; 66 import java.util.Set; 67 68 /** 69 * Statsd atom tests that are done via app, for atoms that report a uid. 70 */ 71 public class UidAtomTests extends DeviceAtomTestCase { 72 73 private static final String TAG = "Statsd.UidAtomTests"; 74 75 private static final boolean DAVEY_ENABLED = false; 76 77 @Override 78 protected void setUp() throws Exception { 79 super.setUp(); 80 } 81 82 @Override 83 protected void tearDown() throws Exception { 84 resetBatteryStatus(); 85 super.tearDown(); 86 } 87 88 public void testLmkKillOccurred() throws Exception { 89 if (statsdDisabled() || !"true".equals(getProperty("ro.lmk.log_stats"))) { 90 return; 91 } 92 93 StatsdConfig.Builder conf = createConfigBuilder() 94 .addAllowedLogSource("AID_LMKD"); 95 final int atomTag = Atom.LMK_KILL_OCCURRED_FIELD_NUMBER; 96 addAtomEvent(conf, atomTag, false); 97 uploadConfig(conf); 98 99 Thread.sleep(WAIT_TIME_SHORT); 100 101 executeBackgroundService(ACTION_LMK); 102 Thread.sleep(5_000); 103 104 // Sorted list of events in order in which they occurred. 105 List<EventMetricData> data = getEventMetricDataList(); 106 107 assertEquals(1, data.size()); 108 assertTrue(data.get(0).getAtom().hasLmkKillOccurred()); 109 LmkKillOccurred atom = data.get(0).getAtom().getLmkKillOccurred(); 110 assertEquals(getUid(), atom.getUid()); 111 assertEquals(DEVICE_SIDE_TEST_PACKAGE, atom.getProcessName()); 112 assertTrue(500 <= atom.getOomAdjScore()); 113 } 114 115 public void testAppCrashOccurred() throws Exception { 116 if (statsdDisabled()) { 117 return; 118 } 119 final int atomTag = Atom.APP_CRASH_OCCURRED_FIELD_NUMBER; 120 createAndUploadConfig(atomTag, false); 121 Thread.sleep(WAIT_TIME_SHORT); 122 123 runActivity("StatsdCtsForegroundActivity", "action", "action.crash"); 124 125 Thread.sleep(WAIT_TIME_SHORT); 126 // Sorted list of events in order in which they occurred. 127 List<EventMetricData> data = getEventMetricDataList(); 128 129 AppCrashOccurred atom = data.get(0).getAtom().getAppCrashOccurred(); 130 assertEquals("crash", atom.getEventType()); 131 assertEquals(AppCrashOccurred.InstantApp.FALSE_VALUE, atom.getIsInstantApp().getNumber()); 132 assertEquals(AppCrashOccurred.ForegroundState.FOREGROUND_VALUE, 133 atom.getForegroundState().getNumber()); 134 assertEquals("com.android.server.cts.device.statsd", atom.getPackageName()); 135 } 136 137 public void testAppStartOccurred() throws Exception { 138 if (statsdDisabled()) { 139 return; 140 } 141 final int atomTag = Atom.APP_START_OCCURRED_FIELD_NUMBER; 142 143 createAndUploadConfig(atomTag, false); 144 Thread.sleep(WAIT_TIME_SHORT); 145 146 runActivity("StatsdCtsForegroundActivity", "action", "action.sleep_top"); 147 148 // Sorted list of events in order in which they occurred. 149 List<EventMetricData> data = getEventMetricDataList(); 150 151 AppStartOccurred atom = data.get(0).getAtom().getAppStartOccurred(); 152 assertEquals("com.android.server.cts.device.statsd", atom.getPkgName()); 153 assertEquals("com.android.server.cts.device.statsd.StatsdCtsForegroundActivity", 154 atom.getActivityName()); 155 assertFalse(atom.getIsInstantApp()); 156 assertTrue(atom.getActivityStartMillis() > 0); 157 assertTrue(atom.getTransitionDelayMillis() > 0); 158 } 159 160 public void testAudioState() throws Exception { 161 if (statsdDisabled()) { 162 return; 163 } 164 if (!hasFeature(FEATURE_AUDIO_OUTPUT, true)) return; 165 166 final int atomTag = Atom.AUDIO_STATE_CHANGED_FIELD_NUMBER; 167 final String name = "testAudioState"; 168 169 Set<Integer> onState = new HashSet<>( 170 Arrays.asList(AudioStateChanged.State.ON_VALUE)); 171 Set<Integer> offState = new HashSet<>( 172 Arrays.asList(AudioStateChanged.State.OFF_VALUE)); 173 174 // Add state sets to the list in order. 175 List<Set<Integer>> stateSet = Arrays.asList(onState, offState); 176 177 createAndUploadConfig(atomTag, true); // True: uses attribution. 178 Thread.sleep(WAIT_TIME_SHORT); 179 180 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", name); 181 182 Thread.sleep(WAIT_TIME_SHORT); 183 // Sorted list of events in order in which they occurred. 184 List<EventMetricData> data = getEventMetricDataList(); 185 186 // AudioStateChanged timestamp is fuzzed to 5min buckets 187 assertStatesOccurred(stateSet, data, 0, 188 atom -> atom.getAudioStateChanged().getState().getNumber()); 189 } 190 191 public void testBleScan() throws Exception { 192 if (statsdDisabled()) { 193 return; 194 } 195 if (!hasFeature(FEATURE_BLUETOOTH_LE, true)) return; 196 197 final int atom = Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER; 198 final int field = BleScanStateChanged.STATE_FIELD_NUMBER; 199 final int stateOn = BleScanStateChanged.State.ON_VALUE; 200 final int stateOff = BleScanStateChanged.State.OFF_VALUE; 201 final int minTimeDiffMillis = 1_500; 202 final int maxTimeDiffMillis = 3_000; 203 204 List<EventMetricData> data = doDeviceMethodOnOff("testBleScanUnoptimized", atom, field, 205 stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, true); 206 207 BleScanStateChanged a0 = data.get(0).getAtom().getBleScanStateChanged(); 208 BleScanStateChanged a1 = data.get(1).getAtom().getBleScanStateChanged(); 209 assertTrue(a0.getState().getNumber() == stateOn); 210 assertTrue(a1.getState().getNumber() == stateOff); 211 } 212 213 public void testBleUnoptimizedScan() throws Exception { 214 if (statsdDisabled()) { 215 return; 216 } 217 if (!hasFeature(FEATURE_BLUETOOTH_LE, true)) return; 218 219 final int atom = Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER; 220 final int field = BleScanStateChanged.STATE_FIELD_NUMBER; 221 final int stateOn = BleScanStateChanged.State.ON_VALUE; 222 final int stateOff = BleScanStateChanged.State.OFF_VALUE; 223 final int minTimeDiffMillis = 1_500; 224 final int maxTimeDiffMillis = 3_000; 225 226 List<EventMetricData> data = doDeviceMethodOnOff("testBleScanUnoptimized", atom, field, 227 stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, true); 228 229 BleScanStateChanged a0 = data.get(0).getAtom().getBleScanStateChanged(); 230 assertTrue(a0.getState().getNumber() == stateOn); 231 assertFalse(a0.getIsFiltered()); 232 assertFalse(a0.getIsFirstMatch()); 233 assertFalse(a0.getIsOpportunistic()); 234 BleScanStateChanged a1 = data.get(1).getAtom().getBleScanStateChanged(); 235 assertTrue(a1.getState().getNumber() == stateOff); 236 assertFalse(a1.getIsFiltered()); 237 assertFalse(a1.getIsFirstMatch()); 238 assertFalse(a1.getIsOpportunistic()); 239 240 241 // Now repeat the test for opportunistic scanning and make sure it is reported correctly. 242 data = doDeviceMethodOnOff("testBleScanOpportunistic", atom, field, 243 stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, true); 244 245 a0 = data.get(0).getAtom().getBleScanStateChanged(); 246 assertTrue(a0.getState().getNumber() == stateOn); 247 assertFalse(a0.getIsFiltered()); 248 assertFalse(a0.getIsFirstMatch()); 249 assertTrue(a0.getIsOpportunistic()); // This scan is opportunistic. 250 a1 = data.get(1).getAtom().getBleScanStateChanged(); 251 assertTrue(a1.getState().getNumber() == stateOff); 252 assertFalse(a1.getIsFiltered()); 253 assertFalse(a1.getIsFirstMatch()); 254 assertTrue(a1.getIsOpportunistic()); 255 } 256 257 public void testBleScanResult() throws Exception { 258 if (statsdDisabled()) { 259 return; 260 } 261 if (!hasFeature(FEATURE_BLUETOOTH_LE, true)) return; 262 263 final int atom = Atom.BLE_SCAN_RESULT_RECEIVED_FIELD_NUMBER; 264 final int field = BleScanResultReceived.NUM_RESULTS_FIELD_NUMBER; 265 266 StatsdConfig.Builder conf = createConfigBuilder(); 267 addAtomEvent(conf, atom, createFvm(field).setGteInt(0)); 268 List<EventMetricData> data = doDeviceMethod("testBleScanResult", conf); 269 270 assertTrue(data.size() >= 1); 271 BleScanResultReceived a0 = data.get(0).getAtom().getBleScanResultReceived(); 272 assertTrue(a0.getNumResults() >= 1); 273 } 274 275 public void testHiddenApiUsed() throws Exception { 276 if (statsdDisabled()) { 277 return; 278 } 279 280 String oldRate = getDevice().executeShellCommand( 281 "device_config get app_compat hidden_api_access_statslog_sampling_rate").trim(); 282 283 getDevice().executeShellCommand( 284 "device_config put app_compat hidden_api_access_statslog_sampling_rate 65536"); 285 try { 286 final int atomTag = Atom.HIDDEN_API_USED_FIELD_NUMBER; 287 288 createAndUploadConfig(atomTag, false); 289 290 runActivity("HiddenApiUsedActivity", null, null); 291 292 293 List<EventMetricData> data = getEventMetricDataList(); 294 assertTrue(data.size() == 1); 295 296 HiddenApiUsed atom = data.get(0).getAtom().getHiddenApiUsed(); 297 298 int uid = getUid(); 299 assertEquals(uid, atom.getUid()); 300 assertFalse(atom.getAccessDenied()); 301 assertEquals("Landroid/app/Activity;->mWindow:Landroid/view/Window;", 302 atom.getSignature()); 303 } finally { 304 if (!oldRate.equals("null")) { 305 getDevice().executeShellCommand( 306 "device_config put app_compat hidden_api_access_statslog_sampling_rate " 307 + oldRate); 308 } else { 309 getDevice().executeShellCommand( 310 "device_config delete hidden_api_access_statslog_sampling_rate"); 311 } 312 } 313 } 314 315 public void testCameraState() throws Exception { 316 if (statsdDisabled()) { 317 return; 318 } 319 if (!hasFeature(FEATURE_CAMERA, true) && !hasFeature(FEATURE_CAMERA_FRONT, true)) return; 320 321 final int atomTag = Atom.CAMERA_STATE_CHANGED_FIELD_NUMBER; 322 Set<Integer> cameraOn = new HashSet<>(Arrays.asList(CameraStateChanged.State.ON_VALUE)); 323 Set<Integer> cameraOff = new HashSet<>(Arrays.asList(CameraStateChanged.State.OFF_VALUE)); 324 325 // Add state sets to the list in order. 326 List<Set<Integer>> stateSet = Arrays.asList(cameraOn, cameraOff); 327 328 createAndUploadConfig(atomTag, true); // True: uses attribution. 329 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testCameraState"); 330 331 // Sorted list of events in order in which they occurred. 332 List<EventMetricData> data = getEventMetricDataList(); 333 334 // Assert that the events happened in the expected order. 335 assertStatesOccurred(stateSet, data, WAIT_TIME_LONG, 336 atom -> atom.getCameraStateChanged().getState().getNumber()); 337 } 338 339 public void testCpuTimePerUid() throws Exception { 340 if (statsdDisabled()) { 341 return; 342 } 343 if (!hasFeature(FEATURE_WATCH, false)) return; 344 StatsdConfig.Builder config = getPulledConfig(); 345 addGaugeAtomWithDimensions(config, Atom.CPU_TIME_PER_UID_FIELD_NUMBER, null); 346 347 uploadConfig(config); 348 349 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu"); 350 351 Thread.sleep(WAIT_TIME_SHORT); 352 setAppBreadcrumbPredicate(); 353 Thread.sleep(WAIT_TIME_LONG); 354 355 List<Atom> atomList = getGaugeMetricDataList(); 356 357 // TODO: We don't have atom matching on gauge yet. Let's refactor this after that feature is 358 // implemented. 359 boolean found = false; 360 int uid = getUid(); 361 for (Atom atom : atomList) { 362 if (atom.getCpuTimePerUid().getUid() == uid) { 363 found = true; 364 assertTrue(atom.getCpuTimePerUid().getUserTimeMicros() > 0); 365 assertTrue(atom.getCpuTimePerUid().getSysTimeMicros() > 0); 366 } 367 } 368 assertTrue("found uid " + uid, found); 369 } 370 371 @RestrictedBuildTest 372 public void testCpuActiveTime() throws Exception { 373 if (statsdDisabled()) { 374 return; 375 } 376 if (!hasFeature(FEATURE_WATCH, false)) return; 377 StatsdConfig.Builder config = getPulledConfig(); 378 FieldMatcher.Builder dimension = FieldMatcher.newBuilder() 379 .setField(Atom.CPU_ACTIVE_TIME_FIELD_NUMBER) 380 .addChild(FieldMatcher.newBuilder() 381 .setField(CpuActiveTime.UID_FIELD_NUMBER)); 382 addGaugeAtomWithDimensions(config, Atom.CPU_ACTIVE_TIME_FIELD_NUMBER, dimension); 383 384 uploadConfig(config); 385 386 Thread.sleep(WAIT_TIME_LONG); 387 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu"); 388 Thread.sleep(WAIT_TIME_SHORT); 389 setAppBreadcrumbPredicate(); 390 Thread.sleep(WAIT_TIME_LONG); 391 392 List<Atom> atomList = getGaugeMetricDataList(); 393 394 boolean found = false; 395 int uid = getUid(); 396 long timeSpent = 0; 397 for (Atom atom : atomList) { 398 if (atom.getCpuActiveTime().getUid() == uid) { 399 found = true; 400 timeSpent += atom.getCpuActiveTime().getTimeMillis(); 401 } 402 } 403 assertTrue(timeSpent > 0); 404 assertTrue("found uid " + uid, found); 405 } 406 407 public void testDeviceCalculatedPowerUse() throws Exception { 408 if (statsdDisabled()) { 409 return; 410 } 411 if (!hasFeature(FEATURE_LEANBACK_ONLY, false)) return; 412 413 StatsdConfig.Builder config = getPulledConfig(); 414 addGaugeAtomWithDimensions(config, Atom.DEVICE_CALCULATED_POWER_USE_FIELD_NUMBER, null); 415 uploadConfig(config); 416 unplugDevice(); 417 418 Thread.sleep(WAIT_TIME_LONG); 419 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu"); 420 Thread.sleep(WAIT_TIME_SHORT); 421 setAppBreadcrumbPredicate(); 422 Thread.sleep(WAIT_TIME_LONG); 423 424 Atom atom = getGaugeMetricDataList().get(0); 425 assertTrue(atom.getDeviceCalculatedPowerUse().getComputedPowerNanoAmpSecs() > 0); 426 } 427 428 429 public void testDeviceCalculatedPowerBlameUid() throws Exception { 430 if (statsdDisabled()) { 431 return; 432 } 433 if (!hasFeature(FEATURE_LEANBACK_ONLY, false)) return; 434 435 StatsdConfig.Builder config = getPulledConfig(); 436 addGaugeAtomWithDimensions(config, 437 Atom.DEVICE_CALCULATED_POWER_BLAME_UID_FIELD_NUMBER, null); 438 uploadConfig(config); 439 unplugDevice(); 440 441 Thread.sleep(WAIT_TIME_LONG); 442 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu"); 443 Thread.sleep(WAIT_TIME_SHORT); 444 setAppBreadcrumbPredicate(); 445 Thread.sleep(WAIT_TIME_LONG); 446 447 List<Atom> atomList = getGaugeMetricDataList(); 448 boolean uidFound = false; 449 int uid = getUid(); 450 long uidPower = 0; 451 for (Atom atom : atomList) { 452 DeviceCalculatedPowerBlameUid item = atom.getDeviceCalculatedPowerBlameUid(); 453 if (item.getUid() == uid) { 454 assertFalse("Found multiple power values for uid " + uid, uidFound); 455 uidFound = true; 456 uidPower = item.getPowerNanoAmpSecs(); 457 } 458 } 459 assertTrue("No power value for uid " + uid, uidFound); 460 assertTrue("Non-positive power value for uid " + uid, uidPower > 0); 461 } 462 463 public void testDavey() throws Exception { 464 if (statsdDisabled()) { 465 return; 466 } 467 if (!DAVEY_ENABLED ) return; 468 long MAX_DURATION = 2000; 469 long MIN_DURATION = 750; 470 final int atomTag = Atom.DAVEY_OCCURRED_FIELD_NUMBER; 471 createAndUploadConfig(atomTag, false); // UID is logged without attribution node 472 473 runActivity("DaveyActivity", null, null); 474 475 List<EventMetricData> data = getEventMetricDataList(); 476 assertTrue(data.size() == 1); 477 long duration = data.get(0).getAtom().getDaveyOccurred().getJankDurationMillis(); 478 assertTrue("Jank duration of " + duration + "ms was less than " + MIN_DURATION + "ms", 479 duration >= MIN_DURATION); 480 assertTrue("Jank duration of " + duration + "ms was longer than " + MAX_DURATION + "ms", 481 duration <= MAX_DURATION); 482 } 483 484 public void testFlashlightState() throws Exception { 485 if (statsdDisabled()) { 486 return; 487 } 488 if (!hasFeature(FEATURE_CAMERA_FLASH, true)) return; 489 490 final int atomTag = Atom.FLASHLIGHT_STATE_CHANGED_FIELD_NUMBER; 491 final String name = "testFlashlight"; 492 493 Set<Integer> flashlightOn = new HashSet<>( 494 Arrays.asList(FlashlightStateChanged.State.ON_VALUE)); 495 Set<Integer> flashlightOff = new HashSet<>( 496 Arrays.asList(FlashlightStateChanged.State.OFF_VALUE)); 497 498 // Add state sets to the list in order. 499 List<Set<Integer>> stateSet = Arrays.asList(flashlightOn, flashlightOff); 500 501 createAndUploadConfig(atomTag, true); // True: uses attribution. 502 Thread.sleep(WAIT_TIME_SHORT); 503 504 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", name); 505 506 // Sorted list of events in order in which they occurred. 507 List<EventMetricData> data = getEventMetricDataList(); 508 509 // Assert that the events happened in the expected order. 510 assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT, 511 atom -> atom.getFlashlightStateChanged().getState().getNumber()); 512 } 513 514 public void testForegroundServiceState() throws Exception { 515 if (statsdDisabled()) { 516 return; 517 } 518 final int atomTag = Atom.FOREGROUND_SERVICE_STATE_CHANGED_FIELD_NUMBER; 519 final String name = "testForegroundService"; 520 521 Set<Integer> enterForeground = new HashSet<>( 522 Arrays.asList(ForegroundServiceStateChanged.State.ENTER_VALUE)); 523 Set<Integer> exitForeground = new HashSet<>( 524 Arrays.asList(ForegroundServiceStateChanged.State.EXIT_VALUE)); 525 526 // Add state sets to the list in order. 527 List<Set<Integer>> stateSet = Arrays.asList(enterForeground, exitForeground); 528 529 createAndUploadConfig(atomTag, false); 530 Thread.sleep(WAIT_TIME_SHORT); 531 532 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", name); 533 534 // Sorted list of events in order in which they occurred. 535 List<EventMetricData> data = getEventMetricDataList(); 536 537 // Assert that the events happened in the expected order. 538 assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT, 539 atom -> atom.getForegroundServiceStateChanged().getState().getNumber()); 540 } 541 542 public void testGpsScan() throws Exception { 543 if (statsdDisabled()) { 544 return; 545 } 546 if (!hasFeature(FEATURE_LOCATION_GPS, true)) return; 547 // Whitelist this app against background location request throttling 548 String origWhitelist = getDevice().executeShellCommand( 549 "settings get global location_background_throttle_package_whitelist").trim(); 550 getDevice().executeShellCommand(String.format( 551 "settings put global location_background_throttle_package_whitelist %s", 552 DEVICE_SIDE_TEST_PACKAGE)); 553 554 try { 555 final int atom = Atom.GPS_SCAN_STATE_CHANGED_FIELD_NUMBER; 556 final int key = GpsScanStateChanged.STATE_FIELD_NUMBER; 557 final int stateOn = GpsScanStateChanged.State.ON_VALUE; 558 final int stateOff = GpsScanStateChanged.State.OFF_VALUE; 559 final int minTimeDiffMillis = 500; 560 final int maxTimeDiffMillis = 60_000; 561 562 List<EventMetricData> data = doDeviceMethodOnOff("testGpsScan", atom, key, 563 stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, true); 564 565 GpsScanStateChanged a0 = data.get(0).getAtom().getGpsScanStateChanged(); 566 GpsScanStateChanged a1 = data.get(1).getAtom().getGpsScanStateChanged(); 567 assertTrue(a0.getState().getNumber() == stateOn); 568 assertTrue(a1.getState().getNumber() == stateOff); 569 } finally { 570 if ("null".equals(origWhitelist) || "".equals(origWhitelist)) { 571 getDevice().executeShellCommand( 572 "settings delete global location_background_throttle_package_whitelist"); 573 } else { 574 getDevice().executeShellCommand(String.format( 575 "settings put global location_background_throttle_package_whitelist %s", 576 origWhitelist)); 577 } 578 } 579 } 580 581 public void testMediaCodecActivity() throws Exception { 582 if (statsdDisabled()) { 583 return; 584 } 585 if (!hasFeature(FEATURE_WATCH, false)) return; 586 final int atomTag = Atom.MEDIA_CODEC_STATE_CHANGED_FIELD_NUMBER; 587 588 Set<Integer> onState = new HashSet<>( 589 Arrays.asList(MediaCodecStateChanged.State.ON_VALUE)); 590 Set<Integer> offState = new HashSet<>( 591 Arrays.asList(MediaCodecStateChanged.State.OFF_VALUE)); 592 593 // Add state sets to the list in order. 594 List<Set<Integer>> stateSet = Arrays.asList(onState, offState); 595 596 createAndUploadConfig(atomTag, true); // True: uses attribution. 597 Thread.sleep(WAIT_TIME_SHORT); 598 599 runActivity("VideoPlayerActivity", "action", "action.play_video"); 600 601 // Sorted list of events in order in which they occurred. 602 List<EventMetricData> data = getEventMetricDataList(); 603 604 // Assert that the events happened in the expected order. 605 assertStatesOccurred(stateSet, data, WAIT_TIME_LONG, 606 atom -> atom.getMediaCodecStateChanged().getState().getNumber()); 607 } 608 609 public void testOverlayState() throws Exception { 610 if (statsdDisabled()) { 611 return; 612 } 613 if (!hasFeature(FEATURE_WATCH, false)) return; 614 final int atomTag = Atom.OVERLAY_STATE_CHANGED_FIELD_NUMBER; 615 616 Set<Integer> entered = new HashSet<>( 617 Arrays.asList(OverlayStateChanged.State.ENTERED_VALUE)); 618 Set<Integer> exited = new HashSet<>( 619 Arrays.asList(OverlayStateChanged.State.EXITED_VALUE)); 620 621 // Add state sets to the list in order. 622 List<Set<Integer>> stateSet = Arrays.asList(entered, exited); 623 624 createAndUploadConfig(atomTag, false); 625 626 runActivity("StatsdCtsForegroundActivity", "action", "action.show_application_overlay", 627 3_000); 628 629 // Sorted list of events in order in which they occurred. 630 List<EventMetricData> data = getEventMetricDataList(); 631 632 // Assert that the events happened in the expected order. 633 // The overlay box should appear about 2sec after the app start 634 assertStatesOccurred(stateSet, data, 0, 635 atom -> atom.getOverlayStateChanged().getState().getNumber()); 636 } 637 638 public void testPictureInPictureState() throws Exception { 639 if (statsdDisabled()) { 640 return; 641 } 642 String supported = getDevice().executeShellCommand("am supports-multiwindow"); 643 if (!hasFeature(FEATURE_WATCH, false) || 644 !hasFeature(FEATURE_PICTURE_IN_PICTURE, true) || 645 !supported.contains("true")) { 646 LogUtil.CLog.d("Skipping picture in picture atom test."); 647 return; 648 } 649 650 final int atomTag = Atom.PICTURE_IN_PICTURE_STATE_CHANGED_FIELD_NUMBER; 651 652 Set<Integer> entered = new HashSet<>( 653 Arrays.asList(PictureInPictureStateChanged.State.ENTERED_VALUE)); 654 655 // Add state sets to the list in order. 656 List<Set<Integer>> stateSet = Arrays.asList(entered); 657 658 createAndUploadConfig(atomTag, false); 659 660 LogUtil.CLog.d("Playing video in Picture-in-Picture mode"); 661 runActivity("VideoPlayerActivity", "action", "action.play_video_picture_in_picture_mode"); 662 663 // Sorted list of events in order in which they occurred. 664 List<EventMetricData> data = getEventMetricDataList(); 665 666 // Assert that the events happened in the expected order. 667 assertStatesOccurred(stateSet, data, WAIT_TIME_LONG, 668 atom -> atom.getPictureInPictureStateChanged().getState().getNumber()); 669 } 670 671 public void testScheduledJobState() throws Exception { 672 if (statsdDisabled()) { 673 return; 674 } 675 String expectedName = "com.android.server.cts.device.statsd/.StatsdJobService"; 676 final int atomTag = Atom.SCHEDULED_JOB_STATE_CHANGED_FIELD_NUMBER; 677 Set<Integer> jobSchedule = new HashSet<>( 678 Arrays.asList(ScheduledJobStateChanged.State.SCHEDULED_VALUE)); 679 Set<Integer> jobOn = new HashSet<>( 680 Arrays.asList(ScheduledJobStateChanged.State.STARTED_VALUE)); 681 Set<Integer> jobOff = new HashSet<>( 682 Arrays.asList(ScheduledJobStateChanged.State.FINISHED_VALUE)); 683 684 // Add state sets to the list in order. 685 List<Set<Integer>> stateSet = Arrays.asList(jobSchedule, jobOn, jobOff); 686 687 createAndUploadConfig(atomTag, true); // True: uses attribution. 688 allowImmediateSyncs(); 689 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testScheduledJob"); 690 691 // Sorted list of events in order in which they occurred. 692 List<EventMetricData> data = getEventMetricDataList(); 693 694 assertStatesOccurred(stateSet, data, 0, 695 atom -> atom.getScheduledJobStateChanged().getState().getNumber()); 696 697 for (EventMetricData e : data) { 698 assertTrue(e.getAtom().getScheduledJobStateChanged().getJobName().equals(expectedName)); 699 } 700 } 701 702 //Note: this test does not have uid, but must run on the device 703 public void testScreenBrightness() throws Exception { 704 if (statsdDisabled()) { 705 return; 706 } 707 int initialBrightness = getScreenBrightness(); 708 boolean isInitialManual = isScreenBrightnessModeManual(); 709 setScreenBrightnessMode(true); 710 setScreenBrightness(200); 711 Thread.sleep(WAIT_TIME_LONG); 712 713 final int atomTag = Atom.SCREEN_BRIGHTNESS_CHANGED_FIELD_NUMBER; 714 715 Set<Integer> screenMin = new HashSet<>(Arrays.asList(47)); 716 Set<Integer> screen100 = new HashSet<>(Arrays.asList(100)); 717 Set<Integer> screen200 = new HashSet<>(Arrays.asList(198)); 718 // Set<Integer> screenMax = new HashSet<>(Arrays.asList(255)); 719 720 // Add state sets to the list in order. 721 List<Set<Integer>> stateSet = Arrays.asList(screenMin, screen100, screen200); 722 723 createAndUploadConfig(atomTag); 724 Thread.sleep(WAIT_TIME_SHORT); 725 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testScreenBrightness"); 726 727 // Sorted list of events in order in which they occurred. 728 List<EventMetricData> data = getEventMetricDataList(); 729 730 // Restore initial screen brightness 731 setScreenBrightness(initialBrightness); 732 setScreenBrightnessMode(isInitialManual); 733 734 popUntilFind(data, screenMin, atom->atom.getScreenBrightnessChanged().getLevel()); 735 popUntilFindFromEnd(data, screen200, atom->atom.getScreenBrightnessChanged().getLevel()); 736 // Assert that the events happened in the expected order. 737 assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT, 738 atom -> atom.getScreenBrightnessChanged().getLevel()); 739 } 740 public void testSyncState() throws Exception { 741 if (statsdDisabled()) { 742 return; 743 } 744 final int atomTag = Atom.SYNC_STATE_CHANGED_FIELD_NUMBER; 745 Set<Integer> syncOn = new HashSet<>(Arrays.asList(SyncStateChanged.State.ON_VALUE)); 746 Set<Integer> syncOff = new HashSet<>(Arrays.asList(SyncStateChanged.State.OFF_VALUE)); 747 748 // Add state sets to the list in order. 749 List<Set<Integer>> stateSet = Arrays.asList(syncOn, syncOff, syncOn, syncOff); 750 751 createAndUploadConfig(atomTag, true); 752 allowImmediateSyncs(); 753 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSyncState"); 754 755 // Sorted list of events in order in which they occurred. 756 List<EventMetricData> data = getEventMetricDataList(); 757 758 // Assert that the events happened in the expected order. 759 assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT, 760 atom -> atom.getSyncStateChanged().getState().getNumber()); 761 } 762 763 public void testVibratorState() throws Exception { 764 if (statsdDisabled()) { 765 return; 766 } 767 if (!checkDeviceFor("checkVibratorSupported")) return; 768 769 final int atomTag = Atom.VIBRATOR_STATE_CHANGED_FIELD_NUMBER; 770 final String name = "testVibratorState"; 771 772 Set<Integer> onState = new HashSet<>( 773 Arrays.asList(VibratorStateChanged.State.ON_VALUE)); 774 Set<Integer> offState = new HashSet<>( 775 Arrays.asList(VibratorStateChanged.State.OFF_VALUE)); 776 777 // Add state sets to the list in order. 778 List<Set<Integer>> stateSet = Arrays.asList(onState, offState); 779 780 createAndUploadConfig(atomTag, true); // True: uses attribution. 781 Thread.sleep(WAIT_TIME_SHORT); 782 783 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", name); 784 785 Thread.sleep(WAIT_TIME_LONG); 786 // Sorted list of events in order in which they occurred. 787 List<EventMetricData> data = getEventMetricDataList(); 788 789 assertStatesOccurred(stateSet, data, 300, 790 atom -> atom.getVibratorStateChanged().getState().getNumber()); 791 } 792 793 public void testWakelockState() throws Exception { 794 if (statsdDisabled()) { 795 return; 796 } 797 final int atomTag = Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER; 798 Set<Integer> wakelockOn = new HashSet<>(Arrays.asList( 799 WakelockStateChanged.State.ACQUIRE_VALUE, 800 WakelockStateChanged.State.CHANGE_ACQUIRE_VALUE)); 801 Set<Integer> wakelockOff = new HashSet<>(Arrays.asList( 802 WakelockStateChanged.State.RELEASE_VALUE, 803 WakelockStateChanged.State.CHANGE_RELEASE_VALUE)); 804 805 final String EXPECTED_TAG = "StatsdPartialWakelock"; 806 final WakeLockLevelEnum EXPECTED_LEVEL = WakeLockLevelEnum.PARTIAL_WAKE_LOCK; 807 808 // Add state sets to the list in order. 809 List<Set<Integer>> stateSet = Arrays.asList(wakelockOn, wakelockOff); 810 811 createAndUploadConfig(atomTag, true); // True: uses attribution. 812 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWakelockState"); 813 814 // Sorted list of events in order in which they occurred. 815 List<EventMetricData> data = getEventMetricDataList(); 816 817 // Assert that the events happened in the expected order. 818 assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT, 819 atom -> atom.getWakelockStateChanged().getState().getNumber()); 820 821 for (EventMetricData event: data) { 822 String tag = event.getAtom().getWakelockStateChanged().getTag(); 823 WakeLockLevelEnum type = event.getAtom().getWakelockStateChanged().getType(); 824 assertTrue("Expected tag: " + EXPECTED_TAG + ", but got tag: " + tag, 825 tag.equals(EXPECTED_TAG)); 826 assertTrue("Expected wakelock type: " + EXPECTED_LEVEL + ", but got level: " + type, 827 type == EXPECTED_LEVEL); 828 } 829 } 830 831 public void testWakeupAlarm() throws Exception { 832 if (statsdDisabled()) { 833 return; 834 } 835 // For automotive, all wakeup alarm becomes normal alarm. So this 836 // test does not work. 837 if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return; 838 final int atomTag = Atom.WAKEUP_ALARM_OCCURRED_FIELD_NUMBER; 839 840 StatsdConfig.Builder config = createConfigBuilder(); 841 addAtomEvent(config, atomTag, true); // True: uses attribution. 842 843 List<EventMetricData> data = doDeviceMethod("testWakeupAlarm", config); 844 assertTrue(data.size() >= 1); 845 for (int i = 0; i < data.size(); i++) { 846 WakeupAlarmOccurred wao = data.get(i).getAtom().getWakeupAlarmOccurred(); 847 assertEquals("*walarm*:android.cts.statsd.testWakeupAlarm", wao.getTag()); 848 assertEquals(DEVICE_SIDE_TEST_PACKAGE, wao.getPackageName()); 849 } 850 } 851 852 public void testWifiLockHighPerf() throws Exception { 853 if (statsdDisabled()) { 854 return; 855 } 856 if (!hasFeature(FEATURE_WIFI, true)) return; 857 if (!hasFeature(FEATURE_PC, false)) return; 858 859 final int atomTag = Atom.WIFI_LOCK_STATE_CHANGED_FIELD_NUMBER; 860 Set<Integer> lockOn = new HashSet<>(Arrays.asList(WifiLockStateChanged.State.ON_VALUE)); 861 Set<Integer> lockOff = new HashSet<>(Arrays.asList(WifiLockStateChanged.State.OFF_VALUE)); 862 863 // Add state sets to the list in order. 864 List<Set<Integer>> stateSet = Arrays.asList(lockOn, lockOff); 865 866 createAndUploadConfig(atomTag, true); // True: uses attribution. 867 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWifiLockHighPerf"); 868 869 // Sorted list of events in order in which they occurred. 870 List<EventMetricData> data = getEventMetricDataList(); 871 872 // Assert that the events happened in the expected order. 873 assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT, 874 atom -> atom.getWifiLockStateChanged().getState().getNumber()); 875 876 for (EventMetricData event : data) { 877 assertEquals(WifiModeEnum.WIFI_MODE_FULL_HIGH_PERF, 878 event.getAtom().getWifiLockStateChanged().getMode()); 879 } 880 } 881 882 public void testWifiLockLowLatency() throws Exception { 883 if (statsdDisabled()) { 884 return; 885 } 886 if (!hasFeature(FEATURE_WIFI, true)) return; 887 if (!hasFeature(FEATURE_PC, false)) return; 888 889 final int atomTag = Atom.WIFI_LOCK_STATE_CHANGED_FIELD_NUMBER; 890 Set<Integer> lockOn = new HashSet<>(Arrays.asList(WifiLockStateChanged.State.ON_VALUE)); 891 Set<Integer> lockOff = new HashSet<>(Arrays.asList(WifiLockStateChanged.State.OFF_VALUE)); 892 893 // Add state sets to the list in order. 894 List<Set<Integer>> stateSet = Arrays.asList(lockOn, lockOff); 895 896 createAndUploadConfig(atomTag, true); // True: uses attribution. 897 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWifiLockLowLatency"); 898 899 // Sorted list of events in order in which they occurred. 900 List<EventMetricData> data = getEventMetricDataList(); 901 902 // Assert that the events happened in the expected order. 903 assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT, 904 atom -> atom.getWifiLockStateChanged().getState().getNumber()); 905 906 for (EventMetricData event : data) { 907 assertEquals(WifiModeEnum.WIFI_MODE_FULL_LOW_LATENCY, 908 event.getAtom().getWifiLockStateChanged().getMode()); 909 } 910 } 911 912 public void testWifiMulticastLock() throws Exception { 913 if (statsdDisabled()) { 914 return; 915 } 916 if (!hasFeature(FEATURE_WIFI, true)) return; 917 if (!hasFeature(FEATURE_PC, false)) return; 918 919 final int atomTag = Atom.WIFI_MULTICAST_LOCK_STATE_CHANGED_FIELD_NUMBER; 920 Set<Integer> lockOn = new HashSet<>( 921 Arrays.asList(WifiMulticastLockStateChanged.State.ON_VALUE)); 922 Set<Integer> lockOff = new HashSet<>( 923 Arrays.asList(WifiMulticastLockStateChanged.State.OFF_VALUE)); 924 925 final String EXPECTED_TAG = "StatsdCTSMulticastLock"; 926 927 // Add state sets to the list in order. 928 List<Set<Integer>> stateSet = Arrays.asList(lockOn, lockOff); 929 930 createAndUploadConfig(atomTag, true); 931 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWifiMulticastLock"); 932 933 // Sorted list of events in order in which they occurred. 934 List<EventMetricData> data = getEventMetricDataList(); 935 936 // Assert that the events happened in the expected order. 937 assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT, 938 atom -> atom.getWifiMulticastLockStateChanged().getState().getNumber()); 939 940 for (EventMetricData event: data) { 941 String tag = event.getAtom().getWifiMulticastLockStateChanged().getTag(); 942 assertEquals("Wrong tag.", EXPECTED_TAG, tag); 943 } 944 } 945 946 public void testWifiScan() throws Exception { 947 if (statsdDisabled()) { 948 return; 949 } 950 if (!hasFeature(FEATURE_WIFI, true)) return; 951 952 final int atom = Atom.WIFI_SCAN_STATE_CHANGED_FIELD_NUMBER; 953 final int key = WifiScanStateChanged.STATE_FIELD_NUMBER; 954 final int stateOn = WifiScanStateChanged.State.ON_VALUE; 955 final int stateOff = WifiScanStateChanged.State.OFF_VALUE; 956 final int minTimeDiffMillis = 250; 957 final int maxTimeDiffMillis = 60_000; 958 final boolean demandExactlyTwo = false; // Two scans are performed, so up to 4 atoms logged. 959 960 List<EventMetricData> data = doDeviceMethodOnOff("testWifiScan", atom, key, 961 stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, demandExactlyTwo); 962 963 assertTrue(data.size() >= 2); 964 assertTrue(data.size() <= 4); 965 WifiScanStateChanged a0 = data.get(0).getAtom().getWifiScanStateChanged(); 966 WifiScanStateChanged a1 = data.get(1).getAtom().getWifiScanStateChanged(); 967 assertTrue(a0.getState().getNumber() == stateOn); 968 assertTrue(a1.getState().getNumber() == stateOff); 969 } 970 971 public void testBinderStats() throws Exception { 972 if (statsdDisabled()) { 973 return; 974 } 975 try { 976 unplugDevice(); 977 Thread.sleep(WAIT_TIME_SHORT); 978 enableBinderStats(); 979 binderStatsNoSampling(); 980 resetBinderStats(); 981 StatsdConfig.Builder config = getPulledConfig(); 982 addGaugeAtomWithDimensions(config, Atom.BINDER_CALLS_FIELD_NUMBER, null); 983 984 uploadConfig(config); 985 Thread.sleep(WAIT_TIME_SHORT); 986 987 runActivity("StatsdCtsForegroundActivity", "action", "action.show_notification",3_000); 988 989 setAppBreadcrumbPredicate(); 990 Thread.sleep(WAIT_TIME_SHORT); 991 992 boolean found = false; 993 int uid = getUid(); 994 List<Atom> atomList = getGaugeMetricDataList(); 995 for (Atom atom : atomList) { 996 BinderCalls calls = atom.getBinderCalls(); 997 boolean classMatches = calls.getServiceClassName().contains( 998 "com.android.server.notification.NotificationManagerService"); 999 boolean methodMatches = calls.getServiceMethodName() 1000 .equals("createNotificationChannels"); 1001 1002 if (calls.getUid() == uid && classMatches && methodMatches) { 1003 found = true; 1004 assertTrue("Call count should not be negative or equal to 0.", 1005 calls.getRecordedCallCount() > 0); 1006 assertTrue("Call count should not be negative or equal to 0.", 1007 calls.getCallCount() > 0); 1008 assertTrue("Wrong latency", 1009 calls.getRecordedTotalLatencyMicros() > 0 1010 && calls.getRecordedTotalLatencyMicros() < 1000000); 1011 assertTrue("Wrong cpu usage", 1012 calls.getRecordedTotalCpuMicros() > 0 1013 && calls.getRecordedTotalCpuMicros() < 1000000); 1014 } 1015 } 1016 1017 assertTrue("Did not find a matching atom for uid " + uid, found); 1018 1019 } finally { 1020 disableBinderStats(); 1021 plugInAc(); 1022 } 1023 } 1024 1025 public void testLooperStats() throws Exception { 1026 if (statsdDisabled()) { 1027 return; 1028 } 1029 try { 1030 unplugDevice(); 1031 setUpLooperStats(); 1032 StatsdConfig.Builder config = getPulledConfig(); 1033 addGaugeAtomWithDimensions(config, Atom.LOOPER_STATS_FIELD_NUMBER, null); 1034 uploadConfig(config); 1035 Thread.sleep(WAIT_TIME_SHORT); 1036 1037 runActivity("StatsdCtsForegroundActivity", "action", "action.show_notification", 3_000); 1038 1039 setAppBreadcrumbPredicate(); 1040 Thread.sleep(WAIT_TIME_SHORT); 1041 1042 List<Atom> atomList = getGaugeMetricDataList(); 1043 1044 boolean found = false; 1045 int uid = getUid(); 1046 for (Atom atom : atomList) { 1047 LooperStats stats = atom.getLooperStats(); 1048 String notificationServiceFullName = 1049 "com.android.server.notification.NotificationManagerService"; 1050 boolean handlerMatches = 1051 stats.getHandlerClassName().equals( 1052 notificationServiceFullName + "$WorkerHandler"); 1053 boolean messageMatches = 1054 stats.getMessageName().equals( 1055 notificationServiceFullName + "$EnqueueNotificationRunnable"); 1056 if (atom.getLooperStats().getUid() == uid && handlerMatches && messageMatches) { 1057 found = true; 1058 assertTrue(stats.getMessageCount() > 0); 1059 assertTrue("Message count should be non-negative.", 1060 stats.getMessageCount() > 0); 1061 assertTrue("Recorded message count should be non-negative.", 1062 stats.getRecordedMessageCount() > 0); 1063 assertTrue("Wrong latency", 1064 stats.getRecordedTotalLatencyMicros() > 0 1065 && stats.getRecordedTotalLatencyMicros() < 1000000); 1066 assertTrue("Wrong cpu usage", 1067 stats.getRecordedTotalCpuMicros() > 0 1068 && stats.getRecordedTotalCpuMicros() < 1000000); 1069 assertTrue("Wrong max latency", 1070 stats.getRecordedMaxLatencyMicros() > 0 1071 && stats.getRecordedMaxLatencyMicros() < 1000000); 1072 assertTrue("Wrong max cpu usage", 1073 stats.getRecordedMaxCpuMicros() > 0 1074 && stats.getRecordedMaxCpuMicros() < 1000000); 1075 assertTrue("Recorded delay message count should be non-negative.", 1076 stats.getRecordedDelayMessageCount() > 0); 1077 assertTrue("Wrong delay", 1078 stats.getRecordedTotalDelayMillis() >= 0 1079 && stats.getRecordedTotalDelayMillis() < 5000); 1080 assertTrue("Wrong max delay", 1081 stats.getRecordedMaxDelayMillis() >= 0 1082 && stats.getRecordedMaxDelayMillis() < 5000); 1083 } 1084 } 1085 assertTrue("Did not find a matching atom for uid " + uid, found); 1086 } finally { 1087 cleanUpLooperStats(); 1088 plugInAc(); 1089 } 1090 } 1091 1092 public void testProcessMemoryState() throws Exception { 1093 if (statsdDisabled()) { 1094 return; 1095 } 1096 1097 // Get ProcessMemoryState as a simple gauge metric. 1098 StatsdConfig.Builder config = getPulledConfig(); 1099 addGaugeAtomWithDimensions(config, Atom.PROCESS_MEMORY_STATE_FIELD_NUMBER, null); 1100 uploadConfig(config); 1101 Thread.sleep(WAIT_TIME_SHORT); 1102 1103 // Start test app. 1104 try (AutoCloseable a = withActivity("StatsdCtsForegroundActivity", "action", 1105 "action.show_notification")) { 1106 Thread.sleep(WAIT_TIME_SHORT); 1107 // Trigger new pull. 1108 setAppBreadcrumbPredicate(); 1109 } 1110 1111 // Assert about ProcessMemoryState for the test app. 1112 List<Atom> atoms = getGaugeMetricDataList(); 1113 int uid = getUid(); 1114 boolean found = false; 1115 for (Atom atom : atoms) { 1116 ProcessMemoryState state = atom.getProcessMemoryState(); 1117 if (state.getUid() != uid) { 1118 continue; 1119 } 1120 found = true; 1121 assertEquals(DEVICE_SIDE_TEST_PACKAGE, state.getProcessName()); 1122 assertTrue("oom_score should not be negative", state.getOomAdjScore() >= 0); 1123 assertTrue("page_fault should not be negative", state.getPageFault() >= 0); 1124 assertTrue("page_major_fault should not be negative", state.getPageMajorFault() >= 0); 1125 assertTrue("rss_in_bytes should be positive", state.getRssInBytes() > 0); 1126 assertTrue("cache_in_bytes should not be negative", state.getCacheInBytes() >= 0); 1127 assertTrue("swap_in_bytes should not be negative", state.getSwapInBytes() >= 0); 1128 assertTrue("start_time_nanos should be positive", state.getStartTimeNanos() > 0); 1129 assertTrue("start_time_nanos should be in the past", 1130 state.getStartTimeNanos() < System.nanoTime()); 1131 } 1132 assertTrue("Did not find a matching atom for uid=" + uid, found); 1133 } 1134 1135 public void testNativeProcessMemoryState() throws Exception { 1136 if (statsdDisabled()) { 1137 return; 1138 } 1139 1140 // Get NativeProcessState as a simple gauge metric. 1141 StatsdConfig.Builder config = getPulledConfig(); 1142 addGaugeAtomWithDimensions(config, Atom.NATIVE_PROCESS_MEMORY_STATE_FIELD_NUMBER, null); 1143 uploadConfig(config); 1144 Thread.sleep(WAIT_TIME_SHORT); 1145 1146 // Trigger new pull. 1147 setAppBreadcrumbPredicate(); 1148 1149 // Assert about NativeProcessMemoryState for statsd. 1150 List<Atom> atoms = getGaugeMetricDataList(); 1151 boolean found = false; 1152 for (Atom atom : atoms) { 1153 NativeProcessMemoryState state = atom.getNativeProcessMemoryState(); 1154 if (!state.getProcessName().contains("/statsd")) { 1155 continue; 1156 } 1157 found = true; 1158 assertTrue("uid is below 10000", state.getUid() < 10000); 1159 assertTrue("page_fault should not be negative", state.getPageFault() >= 0); 1160 assertTrue("page_major_fault should not be negative", state.getPageMajorFault() >= 0); 1161 assertTrue("rss_in_bytes should be positive", state.getRssInBytes() > 0); 1162 assertTrue("start_time_nanos should be positive", state.getStartTimeNanos() > 0); 1163 assertTrue("start_time_nanos should be in the past", 1164 state.getStartTimeNanos() < System.nanoTime()); 1165 } 1166 assertTrue("Did not find a matching atom for statsd", found); 1167 } 1168 1169 public void testProcessMemoryHighWaterMark() throws Exception { 1170 if (statsdDisabled()) { 1171 return; 1172 } 1173 1174 // Get ProcessMemoryState as a simple gauge metric. 1175 StatsdConfig.Builder config = getPulledConfig(); 1176 addGaugeAtomWithDimensions(config, Atom.PROCESS_MEMORY_HIGH_WATER_MARK_FIELD_NUMBER, null); 1177 uploadConfig(config); 1178 Thread.sleep(WAIT_TIME_SHORT); 1179 1180 // Start test app and trigger a pull while its running. 1181 try (AutoCloseable a = withActivity("StatsdCtsForegroundActivity", "action", 1182 "action.show_notification")) { 1183 setAppBreadcrumbPredicate(); 1184 } 1185 Thread.sleep(WAIT_TIME_SHORT); 1186 1187 // Assert about ProcessMemoryHighWaterMark for the test app, statsd and system server. 1188 List<Atom> atoms = getGaugeMetricDataList(); 1189 int uid = getUid(); 1190 boolean foundTestApp = false; 1191 boolean foundStatsd = false; 1192 boolean foundSystemServer = false; 1193 for (Atom atom : atoms) { 1194 ProcessMemoryHighWaterMark state = atom.getProcessMemoryHighWaterMark(); 1195 if (state.getUid() == uid) { 1196 foundTestApp = true; 1197 assertEquals(DEVICE_SIDE_TEST_PACKAGE, state.getProcessName()); 1198 assertTrue("rss_high_water_mark_in_bytes should be positive", 1199 state.getRssHighWaterMarkInBytes() > 0); 1200 } else if (state.getProcessName().contains("/statsd")) { 1201 foundStatsd = true; 1202 assertTrue("rss_high_water_mark_in_bytes should be positive", 1203 state.getRssHighWaterMarkInBytes() > 0); 1204 } else if (state.getProcessName().equals("system")) { 1205 foundSystemServer = true; 1206 assertTrue("rss_high_water_mark_in_bytes should be positive", 1207 state.getRssHighWaterMarkInBytes() > 0); 1208 } 1209 } 1210 assertTrue("Did not find a matching atom for test app uid=" + uid, foundTestApp); 1211 assertTrue("Did not find a matching atom for statsd", foundStatsd); 1212 assertTrue("Did not find a matching atom for system server", foundSystemServer); 1213 } 1214 1215 /** 1216 * The the app id from a uid. 1217 * 1218 * @param uid The uid of the app 1219 * 1220 * @return The app id of the app 1221 * 1222 * @see android.os.UserHandle#getAppId 1223 */ 1224 private static int getAppId(int uid) { 1225 return uid % 100000; 1226 } 1227 1228 public void testRoleHolder() throws Exception { 1229 if (statsdDisabled()) { 1230 return; 1231 } 1232 1233 // Make device side test package a role holder 1234 String callScreenAppRole = "android.app.role.CALL_SCREENING"; 1235 getDevice().executeShellCommand( 1236 "cmd role add-role-holder " + callScreenAppRole + " " + DEVICE_SIDE_TEST_PACKAGE); 1237 1238 // Set up what to collect 1239 StatsdConfig.Builder config = getPulledConfig(); 1240 addGaugeAtomWithDimensions(config, Atom.ROLE_HOLDER_FIELD_NUMBER, null); 1241 uploadConfig(config); 1242 Thread.sleep(WAIT_TIME_SHORT); 1243 1244 boolean verifiedKnowRoleState = false; 1245 1246 // Pull a report 1247 setAppBreadcrumbPredicate(); 1248 Thread.sleep(WAIT_TIME_SHORT); 1249 1250 int testAppId = getAppId(getUid()); 1251 1252 for (Atom atom : getGaugeMetricDataList()) { 1253 AtomsProto.RoleHolder roleHolder = atom.getRoleHolder(); 1254 1255 assertNotNull(roleHolder.getPackageName()); 1256 assertTrue(roleHolder.getUid() >= 0); 1257 assertNotNull(roleHolder.getRole()); 1258 1259 if (roleHolder.getPackageName().equals(DEVICE_SIDE_TEST_PACKAGE)) { 1260 assertEquals(testAppId, getAppId(roleHolder.getUid())); 1261 assertEquals(DEVICE_SIDE_TEST_PACKAGE, roleHolder.getPackageName()); 1262 assertEquals(callScreenAppRole, roleHolder.getRole()); 1263 1264 verifiedKnowRoleState = true; 1265 } 1266 } 1267 1268 assertTrue(verifiedKnowRoleState); 1269 } 1270 1271 public void testDangerousPermissionState() throws Exception { 1272 if (statsdDisabled()) { 1273 return; 1274 } 1275 1276 final int FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED = 1 << 8; 1277 final int FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED = 1 << 9; 1278 1279 // Set up what to collect 1280 StatsdConfig.Builder config = getPulledConfig(); 1281 addGaugeAtomWithDimensions(config, Atom.DANGEROUS_PERMISSION_STATE_FIELD_NUMBER, null); 1282 uploadConfig(config); 1283 Thread.sleep(WAIT_TIME_SHORT); 1284 1285 boolean verifiedKnowPermissionState = false; 1286 1287 // Pull a report 1288 setAppBreadcrumbPredicate(); 1289 Thread.sleep(WAIT_TIME_SHORT); 1290 1291 int testAppId = getAppId(getUid()); 1292 1293 for (Atom atom : getGaugeMetricDataList()) { 1294 DangerousPermissionState permissionState = atom.getDangerousPermissionState(); 1295 1296 assertNotNull(permissionState.getPermissionName()); 1297 assertTrue(permissionState.getUid() >= 0); 1298 assertNotNull(permissionState.getPackageName()); 1299 1300 if (permissionState.getPackageName().equals(DEVICE_SIDE_TEST_PACKAGE)) { 1301 assertEquals(testAppId, getAppId(permissionState.getUid())); 1302 1303 if (permissionState.getPermissionName().equals( 1304 "android.permission.ACCESS_FINE_LOCATION")) { 1305 assertTrue(permissionState.getIsGranted()); 1306 assertEquals(0, permissionState.getPermissionFlags() & (~( 1307 FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED 1308 | FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED))); 1309 1310 verifiedKnowPermissionState = true; 1311 } 1312 } 1313 } 1314 1315 assertTrue(verifiedKnowPermissionState); 1316 } 1317 1318 public void testANROccurred() throws Exception { 1319 if (statsdDisabled()) { 1320 return; 1321 } 1322 final int atomTag = Atom.ANR_OCCURRED_FIELD_NUMBER; 1323 createAndUploadConfig(atomTag, false); 1324 Thread.sleep(WAIT_TIME_SHORT); 1325 1326 try (AutoCloseable a = withActivity("ANRActivity", null, null)) { 1327 Thread.sleep(WAIT_TIME_SHORT); 1328 getDevice().executeShellCommand( 1329 "am broadcast -a action_anr -p " + DEVICE_SIDE_TEST_PACKAGE); 1330 Thread.sleep(11_000); 1331 } 1332 1333 // Sorted list of events in order in which they occurred. 1334 List<EventMetricData> data = getEventMetricDataList(); 1335 1336 assertEquals(1, data.size()); 1337 assertTrue(data.get(0).getAtom().hasAnrOccurred()); 1338 ANROccurred atom = data.get(0).getAtom().getAnrOccurred(); 1339 assertEquals(ANROccurred.InstantApp.FALSE_VALUE, atom.getIsInstantApp().getNumber()); 1340 assertEquals(ANROccurred.ForegroundState.FOREGROUND_VALUE, 1341 atom.getForegroundState().getNumber()); 1342 assertEquals(ErrorSource.DATA_APP, atom.getErrorSource()); 1343 assertEquals(DEVICE_SIDE_TEST_PACKAGE, atom.getPackageName()); 1344 } 1345 1346 public void testWriteRawTestAtom() throws Exception { 1347 if (statsdDisabled()) { 1348 return; 1349 } 1350 final int atomTag = Atom.TEST_ATOM_REPORTED_FIELD_NUMBER; 1351 createAndUploadConfig(atomTag, true); 1352 Thread.sleep(WAIT_TIME_SHORT); 1353 1354 runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWriteRawTestAtom"); 1355 1356 Thread.sleep(WAIT_TIME_SHORT); 1357 // Sorted list of events in order in which they occurred. 1358 List<EventMetricData> data = getEventMetricDataList(); 1359 assertEquals(data.size(), 4); 1360 1361 TestAtomReported atom = data.get(0).getAtom().getTestAtomReported(); 1362 List<AttributionNode> attrChain = atom.getAttributionNodeList(); 1363 assertEquals(2, attrChain.size()); 1364 assertEquals(1234, attrChain.get(0).getUid()); 1365 assertEquals("tag1", attrChain.get(0).getTag()); 1366 assertEquals(getUid(), attrChain.get(1).getUid()); 1367 assertEquals("tag2", attrChain.get(1).getTag()); 1368 1369 assertEquals(42, atom.getIntField()); 1370 assertEquals(Long.MAX_VALUE, atom.getLongField()); 1371 assertEquals(3.14f, atom.getFloatField()); 1372 assertEquals("This is a basic test!", atom.getStringField()); 1373 assertEquals(false, atom.getBooleanField()); 1374 assertEquals(TestAtomReported.State.ON_VALUE, atom.getState().getNumber()); 1375 List<Long> expIds = atom.getBytesField().getExperimentIdList(); 1376 assertEquals(3, expIds.size()); 1377 assertEquals(1L, (long) expIds.get(0)); 1378 assertEquals(2L, (long) expIds.get(1)); 1379 assertEquals(3L, (long) expIds.get(2)); 1380 1381 atom = data.get(1).getAtom().getTestAtomReported(); 1382 attrChain = atom.getAttributionNodeList(); 1383 assertEquals(2, attrChain.size()); 1384 assertEquals(9999, attrChain.get(0).getUid()); 1385 assertEquals("tag9999", attrChain.get(0).getTag()); 1386 assertEquals(getUid(), attrChain.get(1).getUid()); 1387 assertEquals("", attrChain.get(1).getTag()); 1388 1389 assertEquals(100, atom.getIntField()); 1390 assertEquals(Long.MIN_VALUE, atom.getLongField()); 1391 assertEquals(-2.5f, atom.getFloatField()); 1392 assertEquals("Test null uid", atom.getStringField()); 1393 assertEquals(true, atom.getBooleanField()); 1394 assertEquals(TestAtomReported.State.UNKNOWN_VALUE, atom.getState().getNumber()); 1395 expIds = atom.getBytesField().getExperimentIdList(); 1396 assertEquals(3, expIds.size()); 1397 assertEquals(1L, (long) expIds.get(0)); 1398 assertEquals(2L, (long) expIds.get(1)); 1399 assertEquals(3L, (long) expIds.get(2)); 1400 1401 atom = data.get(2).getAtom().getTestAtomReported(); 1402 attrChain = atom.getAttributionNodeList(); 1403 assertEquals(1, attrChain.size()); 1404 assertEquals(getUid(), attrChain.get(0).getUid()); 1405 assertEquals("tag1", attrChain.get(0).getTag()); 1406 1407 assertEquals(-256, atom.getIntField()); 1408 assertEquals(-1234567890L, atom.getLongField()); 1409 assertEquals(42.01f, atom.getFloatField()); 1410 assertEquals("Test non chained", atom.getStringField()); 1411 assertEquals(true, atom.getBooleanField()); 1412 assertEquals(TestAtomReported.State.OFF_VALUE, atom.getState().getNumber()); 1413 expIds = atom.getBytesField().getExperimentIdList(); 1414 assertEquals(3, expIds.size()); 1415 assertEquals(1L, (long) expIds.get(0)); 1416 assertEquals(2L, (long) expIds.get(1)); 1417 assertEquals(3L, (long) expIds.get(2)); 1418 1419 atom = data.get(3).getAtom().getTestAtomReported(); 1420 attrChain = atom.getAttributionNodeList(); 1421 assertEquals(1, attrChain.size()); 1422 assertEquals(getUid(), attrChain.get(0).getUid()); 1423 assertEquals("", attrChain.get(0).getTag()); 1424 1425 assertEquals(0, atom.getIntField()); 1426 assertEquals(0L, atom.getLongField()); 1427 assertEquals(0f, atom.getFloatField()); 1428 assertEquals("", atom.getStringField()); 1429 assertEquals(true, atom.getBooleanField()); 1430 assertEquals(TestAtomReported.State.OFF_VALUE, atom.getState().getNumber()); 1431 expIds = atom.getBytesField().getExperimentIdList(); 1432 assertEquals(0, expIds.size()); 1433 } 1434 1435 } 1436