| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package android.cts.statsdatom.statsd; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static com.google.common.truth.Truth.assertWithMessage; |
| |
| import android.cts.statsdatom.lib.AtomTestUtils; |
| import android.cts.statsdatom.lib.ConfigUtils; |
| import android.cts.statsdatom.lib.DeviceUtils; |
| import android.cts.statsdatom.lib.ReportUtils; |
| import android.os.BatteryPluggedStateEnum; |
| import android.os.BatteryStatusEnum; |
| import android.os.StatsDataDumpProto; |
| import android.platform.test.annotations.RestrictedBuildTest; |
| import android.server.DeviceIdleModeEnum; |
| import android.view.DisplayStateEnum; |
| |
| import com.android.os.AtomsProto.AppBreadcrumbReported; |
| import com.android.os.AtomsProto.Atom; |
| import com.android.os.AtomsProto.BatterySaverModeStateChanged; |
| import com.android.os.AtomsProto.BuildInformation; |
| import com.android.os.AtomsProto.ConnectivityStateChanged; |
| import com.android.os.StatsLog.ConfigMetricsReportList; |
| import com.android.os.StatsLog.EventMetricData; |
| import com.android.tradefed.build.IBuildInfo; |
| import com.android.tradefed.log.LogUtil; |
| import com.android.tradefed.testtype.DeviceTestCase; |
| import com.android.tradefed.testtype.IBuildReceiver; |
| |
| import com.google.common.collect.Range; |
| import com.google.protobuf.ByteString; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| /** |
| * Statsd atom tests that are done via adb (hostside). |
| */ |
| public class HostAtomTests extends DeviceTestCase implements IBuildReceiver { |
| |
| private static final String TAG = "Statsd.HostAtomTests"; |
| |
| private static final String DUMPSYS_STATS_CMD = "dumpsys stats"; |
| |
| // Either file must exist to read kernel wake lock stats. |
| private static final String WAKE_LOCK_FILE = "/proc/wakelocks"; |
| private static final String WAKE_SOURCES_FILE = "/d/wakeup_sources"; |
| |
| private static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive"; |
| private static final String FEATURE_WATCH = "android.hardware.type.watch"; |
| private static final String FEATURE_TWM = "com.google.clockwork.hardware.traditional_watch_mode"; |
| private static final String FEATURE_WIFI = "android.hardware.wifi"; |
| private static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only"; |
| |
| private IBuildInfo mCtsBuild; |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| assertThat(mCtsBuild).isNotNull(); |
| ConfigUtils.removeConfig(getDevice()); |
| ReportUtils.clearReports(getDevice()); |
| DeviceUtils.installStatsdTestApp(getDevice(), mCtsBuild); |
| DeviceUtils.turnBatteryStatsAutoResetOff(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| } |
| |
| @Override |
| protected void tearDown() throws Exception { |
| ConfigUtils.removeConfig(getDevice()); |
| ReportUtils.clearReports(getDevice()); |
| DeviceUtils.uninstallStatsdTestApp(getDevice()); |
| DeviceUtils.turnBatteryStatsAutoResetOn(getDevice()); |
| super.tearDown(); |
| } |
| |
| @Override |
| public void setBuild(IBuildInfo buildInfo) { |
| mCtsBuild = buildInfo; |
| } |
| |
| public void testScreenStateChangedAtom() throws Exception { |
| // Setup, make sure the screen is off and turn off AoD if it is on. |
| // AoD needs to be turned off because the screen should go into an off state. But, if AoD is |
| // on and the device doesn't support STATE_DOZE, the screen sadly goes back to STATE_ON. |
| String aodState = getAodState(); |
| setAodState("0"); |
| DeviceUtils.turnScreenOn(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| DeviceUtils.turnScreenOff(getDevice()); |
| // Ensure that the screen on/off atoms are pushed before the config is uploaded. |
| Thread.sleep(5_000); |
| |
| final int atomTag = Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER; |
| |
| Set<Integer> screenOnStates = new HashSet<>( |
| Arrays.asList(DisplayStateEnum.DISPLAY_STATE_ON_VALUE, |
| DisplayStateEnum.DISPLAY_STATE_ON_SUSPEND_VALUE, |
| DisplayStateEnum.DISPLAY_STATE_VR_VALUE)); |
| Set<Integer> screenOffStates = new HashSet<>( |
| Arrays.asList(DisplayStateEnum.DISPLAY_STATE_OFF_VALUE, |
| DisplayStateEnum.DISPLAY_STATE_DOZE_VALUE, |
| DisplayStateEnum.DISPLAY_STATE_DOZE_SUSPEND_VALUE, |
| DisplayStateEnum.DISPLAY_STATE_UNKNOWN_VALUE)); |
| |
| // Add state sets to the list in order. |
| List<Set<Integer>> stateSet = Arrays.asList(screenOnStates, screenOffStates); |
| |
| ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| atomTag); |
| |
| // Trigger events in same order. |
| DeviceUtils.turnScreenOn(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| DeviceUtils.turnScreenOff(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| |
| // Sorted list of events in order in which they occurred. |
| List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); |
| // reset screen to on |
| DeviceUtils.turnScreenOn(getDevice()); |
| // Restores AoD to initial state. |
| setAodState(aodState); |
| // Assert that the events happened in the expected order. |
| AtomTestUtils.assertStatesOccurredInOrder(stateSet, data, AtomTestUtils.WAIT_TIME_LONG, |
| atom -> atom.getScreenStateChanged().getState().getNumber()); |
| } |
| |
| public void testChargingStateChangedAtom() throws Exception { |
| if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return; |
| // Setup, set charging state to full. |
| DeviceUtils.setChargingState(getDevice(), 5); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| |
| final int atomTag = Atom.CHARGING_STATE_CHANGED_FIELD_NUMBER; |
| |
| Set<Integer> batteryUnknownStates = new HashSet<>( |
| Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_UNKNOWN_VALUE)); |
| Set<Integer> batteryChargingStates = new HashSet<>( |
| Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_CHARGING_VALUE)); |
| Set<Integer> batteryDischargingStates = new HashSet<>( |
| Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_DISCHARGING_VALUE)); |
| Set<Integer> batteryNotChargingStates = new HashSet<>( |
| Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_NOT_CHARGING_VALUE)); |
| Set<Integer> batteryFullStates = new HashSet<>( |
| Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_FULL_VALUE)); |
| |
| // Add state sets to the list in order. |
| List<Set<Integer>> stateSet = Arrays.asList(batteryUnknownStates, batteryChargingStates, |
| batteryDischargingStates, batteryNotChargingStates, batteryFullStates); |
| |
| ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| atomTag); |
| |
| // Trigger events in same order. |
| DeviceUtils.setChargingState(getDevice(), 1); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| DeviceUtils.setChargingState(getDevice(), 2); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| DeviceUtils.setChargingState(getDevice(), 3); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| DeviceUtils.setChargingState(getDevice(), 4); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| DeviceUtils.setChargingState(getDevice(), 5); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| |
| // Sorted list of events in order in which they occurred. |
| List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); |
| |
| // Unfreeze battery state after test |
| DeviceUtils.resetBatteryStatus(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| |
| // Assert that the events happened in the expected order. |
| AtomTestUtils.assertStatesOccurredInOrder(stateSet, data, AtomTestUtils.WAIT_TIME_SHORT, |
| atom -> atom.getChargingStateChanged().getState().getNumber()); |
| } |
| |
| public void testPluggedStateChangedAtom() throws Exception { |
| if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return; |
| // Setup, unplug device. |
| DeviceUtils.unplugDevice(getDevice()); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| |
| final int atomTag = Atom.PLUGGED_STATE_CHANGED_FIELD_NUMBER; |
| |
| Set<Integer> unpluggedStates = new HashSet<>( |
| Arrays.asList(BatteryPluggedStateEnum.BATTERY_PLUGGED_NONE_VALUE)); |
| Set<Integer> acStates = new HashSet<>( |
| Arrays.asList(BatteryPluggedStateEnum.BATTERY_PLUGGED_AC_VALUE)); |
| Set<Integer> usbStates = new HashSet<>( |
| Arrays.asList(BatteryPluggedStateEnum.BATTERY_PLUGGED_USB_VALUE)); |
| Set<Integer> wirelessStates = new HashSet<>( |
| Arrays.asList(BatteryPluggedStateEnum.BATTERY_PLUGGED_WIRELESS_VALUE)); |
| |
| // Add state sets to the list in order. |
| List<Set<Integer>> stateSet = Arrays.asList(acStates, unpluggedStates, usbStates, |
| unpluggedStates, wirelessStates, unpluggedStates); |
| |
| ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| atomTag); |
| |
| // Trigger events in same order. |
| DeviceUtils.plugInAc(getDevice()); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| DeviceUtils.unplugDevice(getDevice()); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| plugInUsb(); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| DeviceUtils.unplugDevice(getDevice()); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| plugInWireless(); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| DeviceUtils.unplugDevice(getDevice()); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| |
| // Sorted list of events in order in which they occurred. |
| List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); |
| |
| // Unfreeze battery state after test |
| DeviceUtils.resetBatteryStatus(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| |
| // Assert that the events happened in the expected order. |
| AtomTestUtils.assertStatesOccurredInOrder(stateSet, data, AtomTestUtils.WAIT_TIME_LONG, |
| atom -> atom.getPluggedStateChanged().getState().getNumber()); |
| } |
| |
| public void testBatteryLevelChangedAtom() throws Exception { |
| if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return; |
| // Setup, set battery level to full. |
| setBatteryLevel(100); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| |
| final int atomTag = Atom.BATTERY_LEVEL_CHANGED_FIELD_NUMBER; |
| |
| Set<Integer> batteryLow = new HashSet<>(Arrays.asList(2)); |
| Set<Integer> battery25p = new HashSet<>(Arrays.asList(25)); |
| Set<Integer> battery50p = new HashSet<>(Arrays.asList(50)); |
| Set<Integer> battery75p = new HashSet<>(Arrays.asList(75)); |
| Set<Integer> batteryFull = new HashSet<>(Arrays.asList(100)); |
| |
| // Add state sets to the list in order. |
| List<Set<Integer>> stateSet = Arrays.asList(batteryLow, battery25p, battery50p, |
| battery75p, batteryFull); |
| |
| ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| atomTag); |
| |
| // Trigger events in same order. |
| setBatteryLevel(2); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| setBatteryLevel(25); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| setBatteryLevel(50); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| setBatteryLevel(75); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| setBatteryLevel(100); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| |
| // Sorted list of events in order in which they occurred. |
| List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); |
| |
| // Unfreeze battery state after test |
| DeviceUtils.resetBatteryStatus(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| |
| // Assert that the events happened in the expected order. |
| AtomTestUtils.assertStatesOccurredInOrder(stateSet, data, AtomTestUtils.WAIT_TIME_LONG, |
| atom -> atom.getBatteryLevelChanged().getBatteryLevel()); |
| } |
| |
| public void testDeviceIdleModeStateChangedAtom() throws Exception { |
| // Setup, leave doze mode. |
| leaveDozeMode(); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| |
| final int atomTag = Atom.DEVICE_IDLE_MODE_STATE_CHANGED_FIELD_NUMBER; |
| |
| Set<Integer> dozeOff = new HashSet<>( |
| Arrays.asList(DeviceIdleModeEnum.DEVICE_IDLE_MODE_OFF_VALUE)); |
| Set<Integer> dozeLight = new HashSet<>( |
| Arrays.asList(DeviceIdleModeEnum.DEVICE_IDLE_MODE_LIGHT_VALUE)); |
| Set<Integer> dozeDeep = new HashSet<>( |
| Arrays.asList(DeviceIdleModeEnum.DEVICE_IDLE_MODE_DEEP_VALUE)); |
| |
| // Add state sets to the list in order. |
| List<Set<Integer>> stateSet = Arrays.asList(dozeLight, dozeDeep, dozeOff); |
| |
| ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| atomTag); |
| |
| // Trigger events in same order. |
| enterDozeModeLight(); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| enterDozeModeDeep(); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| leaveDozeMode(); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| |
| // Sorted list of events in order in which they occurred. |
| List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); |
| |
| // Assert that the events happened in the expected order. |
| AtomTestUtils.assertStatesOccurredInOrder(stateSet, data, AtomTestUtils.WAIT_TIME_SHORT, |
| atom -> atom.getDeviceIdleModeStateChanged().getState().getNumber()); |
| } |
| |
| public void testBatterySaverModeStateChangedAtom() throws Exception { |
| if (DeviceUtils.hasFeature(getDevice(), FEATURE_TWM)) return; |
| if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return; |
| // Setup, turn off battery saver. |
| turnBatterySaverOff(); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| |
| final int atomTag = Atom.BATTERY_SAVER_MODE_STATE_CHANGED_FIELD_NUMBER; |
| |
| Set<Integer> batterySaverOn = new HashSet<>( |
| Arrays.asList(BatterySaverModeStateChanged.State.ON_VALUE)); |
| Set<Integer> batterySaverOff = new HashSet<>( |
| Arrays.asList(BatterySaverModeStateChanged.State.OFF_VALUE)); |
| |
| // Add state sets to the list in order. |
| List<Set<Integer>> stateSet = Arrays.asList(batterySaverOn, batterySaverOff); |
| |
| ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| atomTag); |
| |
| // Trigger events in same order. |
| turnBatterySaverOn(); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| turnBatterySaverOff(); |
| DeviceUtils.flushBatteryStatsHandlers(getDevice()); |
| |
| // Sorted list of events in order in which they occurred. |
| List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); |
| |
| // Assert that the events happened in the expected order. |
| AtomTestUtils.assertStatesOccurredInOrder(stateSet, data, AtomTestUtils.WAIT_TIME_LONG, |
| atom -> atom.getBatterySaverModeStateChanged().getState().getNumber()); |
| } |
| |
| @RestrictedBuildTest |
| public void testRemainingBatteryCapacity() throws Exception { |
| if (DeviceUtils.hasFeature(getDevice(), FEATURE_WATCH)) return; |
| if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return; |
| |
| ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| Atom.REMAINING_BATTERY_CAPACITY_FIELD_NUMBER); |
| |
| AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| |
| List<Atom> data = ReportUtils.getGaugeMetricAtoms(getDevice()); |
| |
| assertThat(data).isNotEmpty(); |
| Atom atom = data.get(0); |
| assertThat(atom.getRemainingBatteryCapacity().hasChargeMicroAmpereHour()).isTrue(); |
| if (DeviceUtils.hasBattery(getDevice())) { |
| assertThat(atom.getRemainingBatteryCapacity().getChargeMicroAmpereHour()) |
| .isGreaterThan(0); |
| } |
| } |
| |
| @RestrictedBuildTest |
| public void testFullBatteryCapacity() throws Exception { |
| if (DeviceUtils.hasFeature(getDevice(), FEATURE_WATCH)) return; |
| if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return; |
| |
| ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| Atom.FULL_BATTERY_CAPACITY_FIELD_NUMBER); |
| |
| AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| |
| List<Atom> data = ReportUtils.getGaugeMetricAtoms(getDevice()); |
| |
| assertThat(data).isNotEmpty(); |
| Atom atom = data.get(0); |
| assertThat(atom.getFullBatteryCapacity().hasCapacityMicroAmpereHour()).isTrue(); |
| if (DeviceUtils.hasBattery(getDevice())) { |
| assertThat(atom.getFullBatteryCapacity().getCapacityMicroAmpereHour()).isGreaterThan(0); |
| } |
| } |
| |
| public void testBatteryVoltage() throws Exception { |
| if (DeviceUtils.hasFeature(getDevice(), FEATURE_WATCH)) return; |
| |
| ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| Atom.BATTERY_VOLTAGE_FIELD_NUMBER); |
| |
| AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| |
| List<Atom> data = ReportUtils.getGaugeMetricAtoms(getDevice()); |
| |
| assertThat(data).isNotEmpty(); |
| Atom atom = data.get(0); |
| assertThat(atom.getBatteryVoltage().hasVoltageMillivolt()).isTrue(); |
| if (DeviceUtils.hasBattery(getDevice())) { |
| assertThat(atom.getBatteryVoltage().getVoltageMillivolt()).isGreaterThan(0); |
| } |
| } |
| |
| // This test is for the pulled battery level atom. |
| public void testBatteryLevel() throws Exception { |
| if (DeviceUtils.hasFeature(getDevice(), FEATURE_WATCH)) return; |
| |
| ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| Atom.BATTERY_LEVEL_FIELD_NUMBER); |
| |
| AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| |
| List<Atom> data = ReportUtils.getGaugeMetricAtoms(getDevice()); |
| |
| assertThat(data).isNotEmpty(); |
| Atom atom = data.get(0); |
| assertThat(atom.getBatteryLevel().hasBatteryLevel()).isTrue(); |
| if (DeviceUtils.hasBattery(getDevice())) { |
| assertThat(atom.getBatteryLevel().getBatteryLevel()).isIn(Range.openClosed(0, 100)); |
| } |
| } |
| |
| public void testKernelWakelock() throws Exception { |
| if (!kernelWakelockStatsExist()) { |
| return; |
| } |
| |
| ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| Atom.KERNEL_WAKELOCK_FIELD_NUMBER); |
| |
| AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| |
| List<Atom> data = ReportUtils.getGaugeMetricAtoms(getDevice()); |
| |
| assertThat(data).isNotEmpty(); |
| for (Atom atom : data) { |
| assertThat(atom.getKernelWakelock().hasName()).isTrue(); |
| assertThat(atom.getKernelWakelock().hasCount()).isTrue(); |
| assertThat(atom.getKernelWakelock().hasVersion()).isTrue(); |
| assertThat(atom.getKernelWakelock().getVersion()).isGreaterThan(0); |
| assertThat(atom.getKernelWakelock().hasTimeMicros()).isTrue(); |
| } |
| } |
| |
| // Returns true iff either |WAKE_LOCK_FILE| or |WAKE_SOURCES_FILE| exists. |
| private boolean kernelWakelockStatsExist() { |
| try { |
| return doesFileExist(WAKE_LOCK_FILE) || doesFileExist(WAKE_SOURCES_FILE); |
| } catch(Exception e) { |
| return false; |
| } |
| } |
| |
| public void testWifiActivityInfo() throws Exception { |
| if (!DeviceUtils.hasFeature(getDevice(), FEATURE_WIFI)) return; |
| if (DeviceUtils.hasFeature(getDevice(), FEATURE_WATCH)) return; |
| if (!DeviceUtils.checkDeviceFor(getDevice(), "checkWifiEnhancedPowerReportingSupported")) { |
| return; |
| } |
| |
| ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| Atom.WIFI_ACTIVITY_INFO_FIELD_NUMBER); |
| |
| AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| |
| List<Atom> dataList = ReportUtils.getGaugeMetricAtoms(getDevice()); |
| |
| for (Atom atom : dataList) { |
| assertThat(atom.getWifiActivityInfo().getTimestampMillis()).isGreaterThan(0L); |
| assertThat(atom.getWifiActivityInfo().getStackState()).isAtLeast(0); |
| assertThat(atom.getWifiActivityInfo().getControllerIdleTimeMillis()).isGreaterThan(0L); |
| assertThat(atom.getWifiActivityInfo().getControllerTxTimeMillis()).isAtLeast(0L); |
| assertThat(atom.getWifiActivityInfo().getControllerRxTimeMillis()).isAtLeast(0L); |
| assertThat(atom.getWifiActivityInfo().getControllerEnergyUsed()).isAtLeast(0L); |
| } |
| } |
| |
| public void testBuildInformation() throws Exception { |
| ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| Atom.BUILD_INFORMATION_FIELD_NUMBER); |
| |
| AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_LONG); |
| |
| List<Atom> data = ReportUtils.getGaugeMetricAtoms(getDevice()); |
| |
| assertThat(data).isNotEmpty(); |
| BuildInformation atom = data.get(0).getBuildInformation(); |
| assertThat(DeviceUtils.getProperty(getDevice(), "ro.product.brand")).isEqualTo( |
| atom.getBrand()); |
| assertThat(DeviceUtils.getProperty(getDevice(), "ro.product.name")).isEqualTo( |
| atom.getProduct()); |
| assertThat(DeviceUtils.getProperty(getDevice(), "ro.product.device")).isEqualTo( |
| atom.getDevice()); |
| assertThat(DeviceUtils.getProperty(getDevice(), |
| "ro.build.version.release_or_codename")).isEqualTo( |
| atom.getVersionRelease()); |
| assertThat(DeviceUtils.getProperty(getDevice(), "ro.build.id")).isEqualTo(atom.getId()); |
| assertThat(DeviceUtils.getProperty(getDevice(), "ro.build.version.incremental")) |
| .isEqualTo(atom.getVersionIncremental()); |
| assertThat(DeviceUtils.getProperty(getDevice(), "ro.build.type")).isEqualTo(atom.getType()); |
| assertThat(DeviceUtils.getProperty(getDevice(), "ro.build.tags")).isEqualTo(atom.getTags()); |
| } |
| |
| // Explicitly tests if the adb command to log a breadcrumb is working. |
| public void testBreadcrumbAdb() throws Exception { |
| final int atomTag = Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER; |
| ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| atomTag); |
| |
| AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| |
| List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); |
| AppBreadcrumbReported atom = data.get(0).getAtom().getAppBreadcrumbReported(); |
| assertThat(atom.getLabel()).isEqualTo(1); |
| assertThat(atom.getState().getNumber()).isEqualTo(AppBreadcrumbReported.State.START_VALUE); |
| } |
| |
| // Test dumpsys stats --proto. |
| public void testDumpsysStats() throws Exception { |
| final int atomTag = Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER; |
| ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| atomTag); |
| |
| AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice()); |
| Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT); |
| |
| // Get the stats incident section. |
| List<ConfigMetricsReportList> listList = getReportsFromStatsDataDumpProto(); |
| assertThat(listList).isNotEmpty(); |
| |
| // Extract the relevant report from the incident section. |
| ConfigMetricsReportList ourList = null; |
| int hostUid = DeviceUtils.getHostUid(getDevice()); |
| for (ConfigMetricsReportList list : listList) { |
| ConfigMetricsReportList.ConfigKey configKey = list.getConfigKey(); |
| if (configKey.getUid() == hostUid && configKey.getId() == ConfigUtils.CONFIG_ID) { |
| ourList = list; |
| break; |
| } |
| } |
| assertWithMessage(String.format("Could not find list for uid=%d id=%d", hostUid, |
| ConfigUtils.CONFIG_ID)) |
| .that(ourList).isNotNull(); |
| |
| // Make sure that the report is correct. |
| List<EventMetricData> data = ReportUtils.getEventMetricDataList(ourList); |
| AppBreadcrumbReported atom = data.get(0).getAtom().getAppBreadcrumbReported(); |
| assertThat(atom.getLabel()).isEqualTo(1); |
| assertThat(atom.getState().getNumber()).isEqualTo(AppBreadcrumbReported.State.START_VALUE); |
| } |
| |
| public void testConnectivityStateChange() throws Exception { |
| if (!DeviceUtils.hasFeature(getDevice(), FEATURE_WIFI)) return; |
| if (DeviceUtils.hasFeature(getDevice(), FEATURE_WATCH)) return; |
| if (DeviceUtils.hasFeature(getDevice(), FEATURE_LEANBACK_ONLY)) return; |
| |
| final int atomTag = Atom.CONNECTIVITY_STATE_CHANGED_FIELD_NUMBER; |
| ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, |
| atomTag); |
| |
| turnOnAirplaneMode(); |
| // wait long enough for airplane mode events to propagate. |
| Thread.sleep(1_200); |
| turnOffAirplaneMode(); |
| // wait long enough for the device to restore connection |
| Thread.sleep(13_000); |
| |
| List<EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice()); |
| // at least 1 disconnect and 1 connect |
| assertThat(data.size()).isAtLeast(2); |
| boolean foundDisconnectEvent = false; |
| boolean foundConnectEvent = false; |
| for (EventMetricData d : data) { |
| ConnectivityStateChanged atom = d.getAtom().getConnectivityStateChanged(); |
| if (atom.getState().getNumber() |
| == ConnectivityStateChanged.State.DISCONNECTED_VALUE) { |
| foundDisconnectEvent = true; |
| } |
| if (atom.getState().getNumber() |
| == ConnectivityStateChanged.State.CONNECTED_VALUE) { |
| foundConnectEvent = true; |
| } |
| } |
| assertThat(foundConnectEvent).isTrue(); |
| assertThat(foundDisconnectEvent).isTrue(); |
| } |
| |
| // Gets whether "Always on Display" setting is enabled. |
| // In rare cases, this is different from whether the device can enter SCREEN_STATE_DOZE. |
| private String getAodState() throws Exception { |
| return getDevice().executeShellCommand("settings get secure doze_always_on"); |
| } |
| |
| private void setAodState(String state) throws Exception { |
| getDevice().executeShellCommand("settings put secure doze_always_on " + state); |
| } |
| |
| private void plugInUsb() throws Exception { |
| getDevice().executeShellCommand("cmd battery set usb 1"); |
| } |
| |
| private void plugInWireless() throws Exception { |
| getDevice().executeShellCommand("cmd battery set wireless 1"); |
| } |
| |
| /** |
| * Determines if the device has |file|. |
| */ |
| private boolean doesFileExist(String file) throws Exception { |
| return getDevice().doesFileExist(file); |
| } |
| |
| private void setBatteryLevel(int level) throws Exception { |
| getDevice().executeShellCommand("cmd battery set level " + level); |
| } |
| |
| private void leaveDozeMode() throws Exception { |
| getDevice().executeShellCommand("dumpsys deviceidle unforce"); |
| getDevice().executeShellCommand("dumpsys deviceidle disable"); |
| getDevice().executeShellCommand("dumpsys deviceidle enable"); |
| } |
| |
| private void enterDozeModeLight() throws Exception { |
| getDevice().executeShellCommand("dumpsys deviceidle force-idle light"); |
| } |
| |
| private void enterDozeModeDeep() throws Exception { |
| getDevice().executeShellCommand("dumpsys deviceidle force-idle deep"); |
| } |
| |
| private void turnBatterySaverOff() throws Exception { |
| getDevice().executeShellCommand("settings put global low_power 0"); |
| getDevice().executeShellCommand("cmd battery reset"); |
| } |
| |
| private void turnBatterySaverOn() throws Exception { |
| DeviceUtils.unplugDevice(getDevice()); |
| getDevice().executeShellCommand("settings put global low_power 1"); |
| } |
| |
| private void turnOnAirplaneMode() throws Exception { |
| getDevice().executeShellCommand("cmd connectivity airplane-mode enable"); |
| } |
| |
| private void turnOffAirplaneMode() throws Exception { |
| getDevice().executeShellCommand("cmd connectivity airplane-mode disable"); |
| } |
| |
| /** Gets reports from the statsd data incident section from the stats dumpsys. */ |
| private List<ConfigMetricsReportList> getReportsFromStatsDataDumpProto() throws Exception { |
| try { |
| StatsDataDumpProto statsProto = DeviceUtils.getShellCommandOutput( |
| getDevice(), |
| StatsDataDumpProto.parser(), |
| String.join(" ", DUMPSYS_STATS_CMD, "--proto")); |
| // statsProto holds repeated bytes, which we must parse into ConfigMetricsReportLists. |
| List<ConfigMetricsReportList> reports |
| = new ArrayList<>(statsProto.getConfigMetricsReportListCount()); |
| for (ByteString reportListBytes : statsProto.getConfigMetricsReportListList()) { |
| reports.add(ConfigMetricsReportList.parseFrom(reportListBytes)); |
| } |
| LogUtil.CLog.d("Got dumpsys stats output:\n " + reports.toString()); |
| return reports; |
| } catch (com.google.protobuf.InvalidProtocolBufferException e) { |
| LogUtil.CLog.e("Failed to dumpsys stats proto"); |
| throw (e); |
| } |
| } |
| } |