• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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