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