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.statsdatom.statsd; 17 18 import static com.google.common.truth.Truth.assertThat; 19 import static com.google.common.truth.Truth.assertWithMessage; 20 21 import android.cts.statsdatom.lib.AtomTestUtils; 22 import android.cts.statsdatom.lib.ConfigUtils; 23 import android.cts.statsdatom.lib.DeviceUtils; 24 import android.cts.statsdatom.lib.ReportUtils; 25 import android.os.BatteryPluggedStateEnum; 26 import android.os.BatteryStatusEnum; 27 import android.os.StatsDataDumpProto; 28 import android.platform.test.annotations.RestrictedBuildTest; 29 import android.server.DeviceIdleModeEnum; 30 import android.view.DisplayStateEnum; 31 32 import com.android.os.AtomsProto.AppBreadcrumbReported; 33 import com.android.os.AtomsProto.Atom; 34 import com.android.os.AtomsProto.BatterySaverModeStateChanged; 35 import com.android.os.AtomsProto.BuildInformation; 36 import com.android.os.AtomsProto.ConnectivityStateChanged; 37 import com.android.os.StatsLog.ConfigMetricsReportList; 38 import com.android.os.StatsLog.EventMetricData; 39 import com.android.tradefed.build.IBuildInfo; 40 import com.android.tradefed.device.DeviceNotAvailableException; 41 import com.android.tradefed.log.LogUtil; 42 import com.android.tradefed.testtype.DeviceTestCase; 43 import com.android.tradefed.testtype.IBuildReceiver; 44 import com.android.tradefed.util.RunUtil; 45 46 import com.google.common.collect.Range; 47 import com.google.protobuf.ByteString; 48 import com.google.protobuf.ExtensionRegistry; 49 50 import java.util.ArrayList; 51 import java.util.Arrays; 52 import java.util.HashSet; 53 import java.util.List; 54 import java.util.Set; 55 import java.util.stream.Collectors; 56 57 /** 58 * Statsd atom tests that are done via adb (hostside). 59 */ 60 public class HostAtomTests extends DeviceTestCase implements IBuildReceiver { 61 62 private static final String TAG = "Statsd.HostAtomTests"; 63 64 private static final String DUMPSYS_STATS_CMD = "dumpsys stats"; 65 66 // Either file must exist to read kernel wake lock stats. 67 private static final String WAKE_LOCK_FILE = "/proc/wakelocks"; 68 private static final String WAKE_SOURCES_FILE = "/d/wakeup_sources"; 69 70 private static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive"; 71 private static final String FEATURE_WATCH = "android.hardware.type.watch"; 72 private static final String FEATURE_TWM = "com.google.clockwork.hardware.traditional_watch_mode"; 73 private static final String FEATURE_WIFI = "android.hardware.wifi"; 74 private static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only"; 75 76 private IBuildInfo mCtsBuild; 77 78 @Override setUp()79 protected void setUp() throws Exception { 80 super.setUp(); 81 assertThat(mCtsBuild).isNotNull(); 82 ConfigUtils.removeConfig(getDevice()); 83 ReportUtils.clearReports(getDevice()); 84 DeviceUtils.installStatsdTestApp(getDevice(), mCtsBuild); 85 DeviceUtils.turnBatteryStatsAutoResetOff(getDevice()); 86 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 87 } 88 89 @Override tearDown()90 protected void tearDown() throws Exception { 91 ConfigUtils.removeConfig(getDevice()); 92 ReportUtils.clearReports(getDevice()); 93 DeviceUtils.uninstallStatsdTestApp(getDevice()); 94 DeviceUtils.turnBatteryStatsAutoResetOn(getDevice()); 95 super.tearDown(); 96 } 97 98 @Override setBuild(IBuildInfo buildInfo)99 public void setBuild(IBuildInfo buildInfo) { 100 mCtsBuild = buildInfo; 101 } 102 testScreenStateChangedAtom()103 public void testScreenStateChangedAtom() throws Exception { 104 // Setup, make sure the screen is off and turn off AoD if it is on. 105 // AoD needs to be turned off because the screen should go into an off state. But, if AoD is 106 // on and the device doesn't support STATE_DOZE, the screen sadly goes back to STATE_ON. 107 String aodState = getAodState(); 108 setAodState("0"); 109 DeviceUtils.turnScreenOn(getDevice()); 110 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 111 DeviceUtils.turnScreenOff(getDevice()); 112 // Ensure that the screen on/off atoms are pushed before the config is uploaded. 113 RunUtil.getDefault().sleep(5_000); 114 115 final int atomTag = Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER; 116 117 Set<Integer> screenOnStates = new HashSet<>( 118 Arrays.asList(DisplayStateEnum.DISPLAY_STATE_ON_VALUE, 119 DisplayStateEnum.DISPLAY_STATE_ON_SUSPEND_VALUE, 120 DisplayStateEnum.DISPLAY_STATE_VR_VALUE)); 121 Set<Integer> screenOffStates = new HashSet<>( 122 Arrays.asList(DisplayStateEnum.DISPLAY_STATE_OFF_VALUE, 123 DisplayStateEnum.DISPLAY_STATE_DOZE_VALUE, 124 DisplayStateEnum.DISPLAY_STATE_DOZE_SUSPEND_VALUE, 125 DisplayStateEnum.DISPLAY_STATE_UNKNOWN_VALUE)); 126 127 // Add state sets to the list in order. 128 List<Set<Integer>> stateSet = Arrays.asList(screenOnStates, screenOffStates); 129 130 ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 131 atomTag); 132 133 // Trigger events in same order. 134 DeviceUtils.turnScreenOn(getDevice()); 135 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 136 DeviceUtils.turnScreenOff(getDevice()); 137 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 138 139 // Sorted list of events in order in which they occurred. 140 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 141 // reset screen to on 142 DeviceUtils.turnScreenOn(getDevice()); 143 // Restores AoD to initial state. 144 setAodState(aodState); 145 // Assert that the events happened in the expected order. 146 AtomTestUtils.assertStatesOccurredInOrder(stateSet, data, AtomTestUtils.WAIT_TIME_LONG, 147 atom -> atom.getScreenStateChanged().getState().getNumber()); 148 } 149 testChargingStateChangedAtom()150 public void testChargingStateChangedAtom() throws Exception { 151 if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return; 152 // Setup, set charging state to full. 153 DeviceUtils.setChargingState(getDevice(), 5); 154 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 155 156 final int atomTag = Atom.CHARGING_STATE_CHANGED_FIELD_NUMBER; 157 158 Set<Integer> batteryUnknownStates = new HashSet<>( 159 Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_UNKNOWN_VALUE)); 160 Set<Integer> batteryChargingStates = new HashSet<>( 161 Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_CHARGING_VALUE)); 162 Set<Integer> batteryDischargingStates = new HashSet<>( 163 Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_DISCHARGING_VALUE)); 164 Set<Integer> batteryNotChargingStates = new HashSet<>( 165 Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_NOT_CHARGING_VALUE)); 166 Set<Integer> batteryFullStates = new HashSet<>( 167 Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_FULL_VALUE)); 168 169 // Add state sets to the list in order. 170 List<Set<Integer>> stateSet = Arrays.asList(batteryUnknownStates, batteryChargingStates, 171 batteryDischargingStates, batteryNotChargingStates, batteryFullStates); 172 173 ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 174 atomTag); 175 176 // Trigger events in same order. 177 DeviceUtils.setChargingState(getDevice(), 1); 178 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 179 DeviceUtils.setChargingState(getDevice(), 2); 180 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 181 DeviceUtils.setChargingState(getDevice(), 3); 182 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 183 DeviceUtils.setChargingState(getDevice(), 4); 184 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 185 DeviceUtils.setChargingState(getDevice(), 5); 186 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 187 188 // Sorted list of events in order in which they occurred. 189 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 190 191 // Unfreeze battery state after test 192 DeviceUtils.resetBatteryStatus(getDevice()); 193 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 194 195 // Assert that the events happened in the expected order. 196 AtomTestUtils.assertStatesOccurredInOrder(stateSet, data, AtomTestUtils.WAIT_TIME_SHORT, 197 atom -> atom.getChargingStateChanged().getState().getNumber()); 198 } 199 testPluggedStateChangedAtom()200 public void testPluggedStateChangedAtom() throws Exception { 201 if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return; 202 // Setup, unplug device. 203 DeviceUtils.unplugDevice(getDevice()); 204 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 205 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 206 207 final int atomTag = Atom.PLUGGED_STATE_CHANGED_FIELD_NUMBER; 208 209 Set<Integer> unpluggedStates = new HashSet<>( 210 Arrays.asList(BatteryPluggedStateEnum.BATTERY_PLUGGED_NONE_VALUE)); 211 Set<Integer> acStates = new HashSet<>( 212 Arrays.asList(BatteryPluggedStateEnum.BATTERY_PLUGGED_AC_VALUE)); 213 Set<Integer> usbStates = new HashSet<>( 214 Arrays.asList(BatteryPluggedStateEnum.BATTERY_PLUGGED_USB_VALUE)); 215 Set<Integer> wirelessStates = new HashSet<>( 216 Arrays.asList(BatteryPluggedStateEnum.BATTERY_PLUGGED_WIRELESS_VALUE)); 217 218 // Add state sets to the list in order. 219 List<Set<Integer>> stateSet = Arrays.asList(acStates, unpluggedStates, usbStates, 220 unpluggedStates, wirelessStates, unpluggedStates); 221 222 ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 223 atomTag); 224 225 // Trigger events in same order. 226 DeviceUtils.plugInAc(getDevice()); 227 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 228 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 229 DeviceUtils.unplugDevice(getDevice()); 230 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 231 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 232 plugInUsb(); 233 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 234 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 235 DeviceUtils.unplugDevice(getDevice()); 236 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 237 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 238 plugInWireless(); 239 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 240 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 241 DeviceUtils.unplugDevice(getDevice()); 242 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 243 244 // Sorted list of events in order in which they occurred. 245 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 246 247 // Unfreeze battery state after test 248 DeviceUtils.resetBatteryStatus(getDevice()); 249 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 250 251 // Assert that the events happened in the expected order. 252 AtomTestUtils.assertStatesOccurredInOrder(stateSet, data, AtomTestUtils.WAIT_TIME_LONG, 253 atom -> atom.getPluggedStateChanged().getState().getNumber()); 254 } 255 testBatteryLevelChangedAtom()256 public void testBatteryLevelChangedAtom() throws Exception { 257 if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return; 258 // Setup, set battery level to full. 259 setBatteryLevel(100); 260 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 261 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 262 263 final int atomTag = Atom.BATTERY_LEVEL_CHANGED_FIELD_NUMBER; 264 265 Set<Integer> batteryLow = new HashSet<>(Arrays.asList(2)); 266 Set<Integer> battery25p = new HashSet<>(Arrays.asList(25)); 267 Set<Integer> battery50p = new HashSet<>(Arrays.asList(50)); 268 Set<Integer> battery75p = new HashSet<>(Arrays.asList(75)); 269 Set<Integer> batteryFull = new HashSet<>(Arrays.asList(100)); 270 271 // Add state sets to the list in order. 272 List<Set<Integer>> stateSet = Arrays.asList(batteryLow, battery25p, battery50p, 273 battery75p, batteryFull); 274 275 ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 276 atomTag); 277 278 // Trigger events in same order. 279 setBatteryLevel(2); 280 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 281 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 282 setBatteryLevel(25); 283 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 284 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 285 setBatteryLevel(50); 286 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 287 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 288 setBatteryLevel(75); 289 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 290 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 291 setBatteryLevel(100); 292 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 293 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 294 295 // Sorted list of events in order in which they occurred. 296 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 297 298 // Unfreeze battery state after test 299 DeviceUtils.resetBatteryStatus(getDevice()); 300 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 301 302 // Assert that the events happened in the expected order. 303 AtomTestUtils.assertStatesOccurredInOrder(stateSet, data, AtomTestUtils.WAIT_TIME_LONG, 304 atom -> atom.getBatteryLevelChanged().getBatteryLevel()); 305 } 306 testDeviceIdleModeStateChangedAtom()307 public void testDeviceIdleModeStateChangedAtom() throws Exception { 308 // Setup, leave doze mode. 309 leaveDozeMode(); 310 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 311 312 final int atomTag = Atom.DEVICE_IDLE_MODE_STATE_CHANGED_FIELD_NUMBER; 313 314 Set<Integer> dozeOff = new HashSet<>( 315 Arrays.asList(DeviceIdleModeEnum.DEVICE_IDLE_MODE_OFF_VALUE)); 316 Set<Integer> dozeLight = new HashSet<>( 317 Arrays.asList(DeviceIdleModeEnum.DEVICE_IDLE_MODE_LIGHT_VALUE)); 318 Set<Integer> dozeDeep = new HashSet<>( 319 Arrays.asList(DeviceIdleModeEnum.DEVICE_IDLE_MODE_DEEP_VALUE)); 320 321 // Add state sets to the list in order. 322 List<Set<Integer>> stateSet = Arrays.asList(dozeLight, dozeDeep, dozeOff); 323 324 ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 325 atomTag); 326 327 // Trigger events in same order. 328 enterDozeModeLight(); 329 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 330 enterDozeModeDeep(); 331 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 332 leaveDozeMode(); 333 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 334 335 // Sorted list of events in order in which they occurred. 336 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 337 338 // Assert that the events happened in the expected order. 339 AtomTestUtils.assertStatesOccurredInOrder(stateSet, data, AtomTestUtils.WAIT_TIME_SHORT, 340 atom -> atom.getDeviceIdleModeStateChanged().getState().getNumber()); 341 } 342 testBatterySaverModeStateChangedAtom()343 public void testBatterySaverModeStateChangedAtom() throws Exception { 344 if (DeviceUtils.hasFeature(getDevice(), FEATURE_TWM)) return; 345 if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return; 346 if (DeviceUtils.hasFeature(getDevice(), FEATURE_WATCH)) return; 347 // Setup, turn off battery saver. 348 turnBatterySaverOff(); 349 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 350 351 final int atomTag = Atom.BATTERY_SAVER_MODE_STATE_CHANGED_FIELD_NUMBER; 352 353 Set<Integer> batterySaverOn = new HashSet<>( 354 Arrays.asList(BatterySaverModeStateChanged.State.ON_VALUE)); 355 Set<Integer> batterySaverOff = new HashSet<>( 356 Arrays.asList(BatterySaverModeStateChanged.State.OFF_VALUE)); 357 358 // Add state sets to the list in order. 359 List<Set<Integer>> stateSet = Arrays.asList(batterySaverOn, batterySaverOff); 360 361 ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 362 atomTag); 363 364 // Trigger events in same order. 365 turnBatterySaverOn(); 366 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 367 turnBatterySaverOff(); 368 DeviceUtils.flushBatteryStatsHandlers(getDevice()); 369 370 // Sorted list of events in order in which they occurred. 371 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 372 373 // Assert that the events happened in the expected order. 374 AtomTestUtils.assertStatesOccurredInOrder(stateSet, data, AtomTestUtils.WAIT_TIME_LONG, 375 atom -> atom.getBatterySaverModeStateChanged().getState().getNumber()); 376 } 377 378 @RestrictedBuildTest testRemainingBatteryCapacity()379 public void testRemainingBatteryCapacity() throws Exception { 380 if (DeviceUtils.hasFeature(getDevice(), FEATURE_WATCH)) return; 381 if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return; 382 383 ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 384 Atom.REMAINING_BATTERY_CAPACITY_FIELD_NUMBER); 385 386 AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); 387 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 388 389 List<Atom> data = ReportUtils.getGaugeMetricAtoms(getDevice()); 390 391 assertThat(data).isNotEmpty(); 392 Atom atom = data.get(0); 393 assertThat(atom.getRemainingBatteryCapacity().hasChargeMicroAmpereHour()).isTrue(); 394 if (DeviceUtils.hasBattery(getDevice())) { 395 assertThat(atom.getRemainingBatteryCapacity().getChargeMicroAmpereHour()) 396 .isGreaterThan(0); 397 } 398 } 399 400 @RestrictedBuildTest testFullBatteryCapacity()401 public void testFullBatteryCapacity() throws Exception { 402 if (DeviceUtils.hasFeature(getDevice(), FEATURE_WATCH)) return; 403 if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return; 404 405 ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 406 Atom.FULL_BATTERY_CAPACITY_FIELD_NUMBER); 407 408 AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); 409 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 410 411 List<Atom> data = ReportUtils.getGaugeMetricAtoms(getDevice()); 412 413 assertThat(data).isNotEmpty(); 414 Atom atom = data.get(0); 415 assertThat(atom.getFullBatteryCapacity().hasCapacityMicroAmpereHour()).isTrue(); 416 if (DeviceUtils.hasBattery(getDevice())) { 417 assertThat(atom.getFullBatteryCapacity().getCapacityMicroAmpereHour()).isGreaterThan(0); 418 } 419 } 420 testBatteryVoltage()421 public void testBatteryVoltage() throws Exception { 422 if (DeviceUtils.hasFeature(getDevice(), FEATURE_WATCH)) return; 423 424 ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 425 Atom.BATTERY_VOLTAGE_FIELD_NUMBER); 426 427 AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); 428 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 429 430 List<Atom> data = ReportUtils.getGaugeMetricAtoms(getDevice()); 431 432 assertThat(data).isNotEmpty(); 433 Atom atom = data.get(0); 434 assertThat(atom.getBatteryVoltage().hasVoltageMillivolt()).isTrue(); 435 if (DeviceUtils.hasBattery(getDevice())) { 436 assertThat(atom.getBatteryVoltage().getVoltageMillivolt()).isGreaterThan(0); 437 } 438 } 439 440 // This test is for the pulled battery level atom. testBatteryLevel()441 public void testBatteryLevel() throws Exception { 442 if (DeviceUtils.hasFeature(getDevice(), FEATURE_WATCH)) return; 443 444 ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 445 Atom.BATTERY_LEVEL_FIELD_NUMBER); 446 447 AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); 448 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 449 450 List<Atom> data = ReportUtils.getGaugeMetricAtoms(getDevice()); 451 452 assertThat(data).isNotEmpty(); 453 Atom atom = data.get(0); 454 assertThat(atom.getBatteryLevel().hasBatteryLevel()).isTrue(); 455 if (DeviceUtils.hasBattery(getDevice())) { 456 assertThat(atom.getBatteryLevel().getBatteryLevel()).isIn(Range.openClosed(0, 100)); 457 } 458 } 459 testKernelWakelock()460 public void testKernelWakelock() throws Exception { 461 if (!kernelWakelockStatsExist()) { 462 return; 463 } 464 465 ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 466 Atom.KERNEL_WAKELOCK_FIELD_NUMBER); 467 468 AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); 469 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 470 471 List<Atom> data = ReportUtils.getGaugeMetricAtoms(getDevice()); 472 473 assertThat(data).isNotEmpty(); 474 for (Atom atom : data) { 475 assertThat(atom.getKernelWakelock().hasName()).isTrue(); 476 assertThat(atom.getKernelWakelock().hasCount()).isTrue(); 477 assertThat(atom.getKernelWakelock().hasVersion()).isTrue(); 478 assertThat(atom.getKernelWakelock().getVersion()).isGreaterThan(0); 479 assertThat(atom.getKernelWakelock().hasTimeMicros()).isTrue(); 480 } 481 } 482 483 // Returns true iff either |WAKE_LOCK_FILE| or |WAKE_SOURCES_FILE| exists. kernelWakelockStatsExist()484 private boolean kernelWakelockStatsExist() { 485 try { 486 return doesFileExist(WAKE_LOCK_FILE) || doesFileExist(WAKE_SOURCES_FILE); 487 } catch(Exception e) { 488 return false; 489 } 490 } 491 testWifiActivityInfo()492 public void testWifiActivityInfo() throws Exception { 493 if (!DeviceUtils.hasFeature(getDevice(), FEATURE_WIFI)) return; 494 if (DeviceUtils.hasFeature(getDevice(), FEATURE_WATCH)) return; 495 if (!DeviceUtils.checkDeviceFor(getDevice(), "checkWifiEnhancedPowerReportingSupported")) { 496 return; 497 } 498 499 ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 500 Atom.WIFI_ACTIVITY_INFO_FIELD_NUMBER); 501 502 AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); 503 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 504 505 List<Atom> dataList = ReportUtils.getGaugeMetricAtoms(getDevice()); 506 507 for (Atom atom : dataList) { 508 assertThat(atom.getWifiActivityInfo().getTimestampMillis()).isGreaterThan(0L); 509 assertThat(atom.getWifiActivityInfo().getStackState()).isAtLeast(0); 510 assertThat(atom.getWifiActivityInfo().getControllerIdleTimeMillis()).isGreaterThan(0L); 511 assertThat(atom.getWifiActivityInfo().getControllerTxTimeMillis()).isAtLeast(0L); 512 assertThat(atom.getWifiActivityInfo().getControllerRxTimeMillis()).isAtLeast(0L); 513 assertThat(atom.getWifiActivityInfo().getControllerEnergyUsed()).isAtLeast(0L); 514 } 515 } 516 testBuildInformation()517 public void testBuildInformation() throws Exception { 518 ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 519 Atom.BUILD_INFORMATION_FIELD_NUMBER); 520 521 AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); 522 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_LONG); 523 524 List<Atom> data = ReportUtils.getGaugeMetricAtoms(getDevice()); 525 526 assertThat(data).isNotEmpty(); 527 BuildInformation atom = data.get(0).getBuildInformation(); 528 assertThat(DeviceUtils.getProperty(getDevice(), "ro.product.brand")).isEqualTo( 529 atom.getBrand()); 530 assertThat(DeviceUtils.getProperty(getDevice(), "ro.product.name")).isEqualTo( 531 atom.getProduct()); 532 assertThat(DeviceUtils.getProperty(getDevice(), "ro.product.device")).isEqualTo( 533 atom.getDevice()); 534 assertThat(DeviceUtils.getProperty(getDevice(), 535 "ro.build.version.release_or_codename")).isEqualTo( 536 atom.getVersionRelease()); 537 assertThat(DeviceUtils.getProperty(getDevice(), "ro.build.id")).isEqualTo(atom.getId()); 538 assertThat(DeviceUtils.getProperty(getDevice(), "ro.build.version.incremental")) 539 .isEqualTo(atom.getVersionIncremental()); 540 assertThat(DeviceUtils.getProperty(getDevice(), "ro.build.type")).isEqualTo(atom.getType()); 541 assertThat(DeviceUtils.getProperty(getDevice(), "ro.build.tags")).isEqualTo(atom.getTags()); 542 } 543 544 // Explicitly tests if the adb command to log a breadcrumb is working. testBreadcrumbAdb()545 public void testBreadcrumbAdb() throws Exception { 546 final int atomTag = Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER; 547 ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 548 atomTag); 549 550 AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); 551 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 552 553 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 554 AppBreadcrumbReported atom = data.get(0).getAtom().getAppBreadcrumbReported(); 555 assertThat(atom.getLabel()).isEqualTo(1); 556 assertThat(atom.getState().getNumber()).isEqualTo(AppBreadcrumbReported.State.START_VALUE); 557 } 558 559 // Test dumpsys stats --proto. testDumpsysStats()560 public void testDumpsysStats() throws Exception { 561 final int atomTag = Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER; 562 ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 563 atomTag); 564 565 AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); 566 RunUtil.getDefault().sleep(AtomTestUtils.WAIT_TIME_SHORT); 567 568 // Get the stats incident section. 569 List<ConfigMetricsReportList> listList = getReportsFromStatsDataDumpProto(); 570 assertThat(listList).isNotEmpty(); 571 572 // Extract the relevant report from the incident section. 573 ConfigMetricsReportList ourList = null; 574 int hostUid = 2000; // Shell UID is always used in ConfigUtils.uploadConfig 575 for (ConfigMetricsReportList list : listList) { 576 ConfigMetricsReportList.ConfigKey configKey = list.getConfigKey(); 577 if (configKey.getUid() == hostUid && configKey.getId() == ConfigUtils.CONFIG_ID) { 578 ourList = list; 579 break; 580 } 581 } 582 assertWithMessage(String.format("Could not find list for uid=%d id=%d", hostUid, 583 ConfigUtils.CONFIG_ID)) 584 .that(ourList).isNotNull(); 585 586 // Make sure that the report is correct. 587 List<EventMetricData> data = ReportUtils.getEventMetricDataList(ourList); 588 AppBreadcrumbReported atom = data.get(0).getAtom().getAppBreadcrumbReported(); 589 assertThat(atom.getLabel()).isEqualTo(1); 590 assertThat(atom.getState().getNumber()).isEqualTo(AppBreadcrumbReported.State.START_VALUE); 591 } 592 testConnectivityStateChange()593 public void testConnectivityStateChange() throws Exception { 594 if (!DeviceUtils.hasFeature(getDevice(), FEATURE_WIFI)) return; 595 if (DeviceUtils.hasFeature(getDevice(), FEATURE_WATCH)) return; 596 if (DeviceUtils.hasFeature(getDevice(), FEATURE_LEANBACK_ONLY)) return; 597 598 final int atomTag = Atom.CONNECTIVITY_STATE_CHANGED_FIELD_NUMBER; 599 ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 600 atomTag); 601 602 turnOnAirplaneMode(); 603 // wait long enough for airplane mode events to propagate. 604 RunUtil.getDefault().sleep(1_200); 605 turnOffAirplaneMode(); 606 // wait long enough for the device to restore connection 607 RunUtil.getDefault().sleep(13_000); 608 609 List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); 610 // at least 1 disconnect and 1 connect 611 assertThat(data.size()).isAtLeast(2); 612 boolean foundDisconnectEvent = false; 613 boolean foundConnectEvent = false; 614 for (EventMetricData d : data) { 615 ConnectivityStateChanged atom = d.getAtom().getConnectivityStateChanged(); 616 if (atom.getState().getNumber() 617 == ConnectivityStateChanged.State.DISCONNECTED_VALUE) { 618 foundDisconnectEvent = true; 619 } 620 if (atom.getState().getNumber() 621 == ConnectivityStateChanged.State.CONNECTED_VALUE) { 622 foundConnectEvent = true; 623 } 624 } 625 assertThat(foundConnectEvent).isTrue(); 626 assertThat(foundDisconnectEvent).isTrue(); 627 } 628 testAtomsLoggedOnBoot()629 public void testAtomsLoggedOnBoot() throws Exception { 630 ConfigUtils.uploadConfigForPushedAtoms(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, 631 new int[] { 632 Atom.DEVICE_IDLE_MODE_STATE_CHANGED_FIELD_NUMBER, 633 Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER, 634 Atom.BATTERY_LEVEL_CHANGED_FIELD_NUMBER, 635 Atom.CHARGING_STATE_CHANGED_FIELD_NUMBER, 636 Atom.PLUGGED_STATE_CHANGED_FIELD_NUMBER 637 } 638 ); 639 640 try { 641 DeviceUtils.rebootDeviceAndWaitUntilReady(getDevice()); 642 } catch (DeviceNotAvailableException e) { 643 // Ignore test if reboot fails. 644 return; 645 } 646 647 RunUtil.getDefault().sleep(10_000); 648 649 // Get events from the report after boot. 650 List<Atom> atoms = ReportUtils 651 .getEventMetricDataList( 652 getDevice(), ExtensionRegistry.getEmptyRegistry(), /*reportIndex*/ 1) 653 .stream() 654 .map(EventMetricData::getAtom) 655 .collect(Collectors.toList()); 656 657 assertThat(atoms.stream().anyMatch(Atom::hasDeviceIdleModeStateChanged)).isTrue(); 658 assertThat(atoms.stream().anyMatch(Atom::hasScreenStateChanged)).isTrue(); 659 if (!DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) { 660 assertThat(atoms.stream().anyMatch(Atom::hasBatteryLevelChanged)).isTrue(); 661 assertThat(atoms.stream().anyMatch(Atom::hasChargingStateChanged)).isTrue(); 662 assertThat(atoms.stream().anyMatch(Atom::hasPluggedStateChanged)).isTrue(); 663 } 664 } 665 666 // Gets whether "Always on Display" setting is enabled. 667 // In rare cases, this is different from whether the device can enter SCREEN_STATE_DOZE. getAodState()668 private String getAodState() throws Exception { 669 return getDevice().executeShellCommand("settings get secure doze_always_on"); 670 } 671 setAodState(String state)672 private void setAodState(String state) throws Exception { 673 getDevice().executeShellCommand("settings put secure doze_always_on " + state); 674 } 675 plugInUsb()676 private void plugInUsb() throws Exception { 677 getDevice().executeShellCommand("cmd battery set usb 1"); 678 } 679 plugInWireless()680 private void plugInWireless() throws Exception { 681 getDevice().executeShellCommand("cmd battery set wireless 1"); 682 } 683 684 /** 685 * Determines if the device has |file|. 686 */ doesFileExist(String file)687 private boolean doesFileExist(String file) throws Exception { 688 return getDevice().doesFileExist(file); 689 } 690 setBatteryLevel(int level)691 private void setBatteryLevel(int level) throws Exception { 692 getDevice().executeShellCommand("cmd battery set level " + level); 693 } 694 leaveDozeMode()695 private void leaveDozeMode() throws Exception { 696 getDevice().executeShellCommand("dumpsys deviceidle unforce"); 697 getDevice().executeShellCommand("dumpsys deviceidle disable"); 698 getDevice().executeShellCommand("dumpsys deviceidle enable"); 699 } 700 enterDozeModeLight()701 private void enterDozeModeLight() throws Exception { 702 getDevice().executeShellCommand("dumpsys deviceidle force-idle light"); 703 } 704 enterDozeModeDeep()705 private void enterDozeModeDeep() throws Exception { 706 getDevice().executeShellCommand("dumpsys deviceidle force-idle deep"); 707 } 708 turnBatterySaverOff()709 private void turnBatterySaverOff() throws Exception { 710 getDevice().executeShellCommand("settings put global low_power 0"); 711 getDevice().executeShellCommand("cmd battery reset"); 712 } 713 turnBatterySaverOn()714 private void turnBatterySaverOn() throws Exception { 715 DeviceUtils.unplugDevice(getDevice()); 716 getDevice().executeShellCommand("settings put global low_power 1"); 717 } 718 turnOnAirplaneMode()719 private void turnOnAirplaneMode() throws Exception { 720 getDevice().executeShellCommand("cmd connectivity airplane-mode enable"); 721 } 722 turnOffAirplaneMode()723 private void turnOffAirplaneMode() throws Exception { 724 getDevice().executeShellCommand("cmd connectivity airplane-mode disable"); 725 } 726 727 /** Gets reports from the statsd data incident section from the stats dumpsys. */ getReportsFromStatsDataDumpProto()728 private List<ConfigMetricsReportList> getReportsFromStatsDataDumpProto() throws Exception { 729 try { 730 StatsDataDumpProto statsProto = DeviceUtils.getShellCommandOutput( 731 getDevice(), 732 StatsDataDumpProto.parser(), 733 String.join(" ", DUMPSYS_STATS_CMD, "--proto")); 734 // statsProto holds repeated bytes, which we must parse into ConfigMetricsReportLists. 735 List<ConfigMetricsReportList> reports 736 = new ArrayList<>(statsProto.getConfigMetricsReportListCount()); 737 for (ByteString reportListBytes : statsProto.getConfigMetricsReportListList()) { 738 reports.add(ConfigMetricsReportList.parseFrom(reportListBytes)); 739 } 740 LogUtil.CLog.d("Got dumpsys stats output:\n " + reports.toString()); 741 return reports; 742 } catch (com.google.protobuf.InvalidProtocolBufferException e) { 743 LogUtil.CLog.e("Failed to dumpsys stats proto"); 744 throw (e); 745 } 746 } 747 } 748