1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.cts.statsd.atom;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 
20 import android.os.BatteryPluggedStateEnum;
21 import android.os.BatteryStatusEnum;
22 import android.platform.test.annotations.RestrictedBuildTest;
23 import android.server.DeviceIdleModeEnum;
24 import android.view.DisplayStateEnum;
25 
26 import com.android.internal.os.StatsdConfigProto.StatsdConfig;
27 import com.android.os.AtomsProto.AppBreadcrumbReported;
28 import com.android.os.AtomsProto.Atom;
29 import com.android.os.AtomsProto.BatterySaverModeStateChanged;
30 import com.android.os.AtomsProto.BuildInformation;
31 import com.android.os.AtomsProto.ConnectivityStateChanged;
32 import com.android.os.StatsLog.ConfigMetricsReportList;
33 import com.android.os.StatsLog.EventMetricData;
34 
35 import java.util.Arrays;
36 import java.util.HashSet;
37 import java.util.List;
38 import java.util.Set;
39 
40 /**
41  * Statsd atom tests that are done via adb (hostside).
42  */
43 public class HostAtomTests extends AtomTestCase {
44 
45     private static final String TAG = "Statsd.HostAtomTests";
46 
47     // Either file must exist to read kernel wake lock stats.
48     private static final String WAKE_LOCK_FILE = "/proc/wakelocks";
49     private static final String WAKE_SOURCES_FILE = "/d/wakeup_sources";
50 
51     @Override
setUp()52     protected void setUp() throws Exception {
53         super.setUp();
54     }
55 
testScreenStateChangedAtom()56     public void testScreenStateChangedAtom() throws Exception {
57         if (statsdDisabled()) {
58             return;
59         }
60         // Setup, make sure the screen is off and turn off AoD if it is on.
61         // AoD needs to be turned off because the screen should go into an off state. But, if AoD is
62         // on and the device doesn't support STATE_DOZE, the screen sadly goes back to STATE_ON.
63         String aodState = getAodState();
64         setAodState("0");
65         turnScreenOn();
66         Thread.sleep(WAIT_TIME_SHORT);
67         turnScreenOff();
68         Thread.sleep(WAIT_TIME_SHORT);
69 
70         final int atomTag = Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER;
71 
72         Set<Integer> screenOnStates = new HashSet<>(
73                 Arrays.asList(DisplayStateEnum.DISPLAY_STATE_ON_VALUE,
74                         DisplayStateEnum.DISPLAY_STATE_ON_SUSPEND_VALUE,
75                         DisplayStateEnum.DISPLAY_STATE_VR_VALUE));
76         Set<Integer> screenOffStates = new HashSet<>(
77                 Arrays.asList(DisplayStateEnum.DISPLAY_STATE_OFF_VALUE,
78                         DisplayStateEnum.DISPLAY_STATE_DOZE_VALUE,
79                         DisplayStateEnum.DISPLAY_STATE_DOZE_SUSPEND_VALUE,
80                         DisplayStateEnum.DISPLAY_STATE_UNKNOWN_VALUE));
81 
82         // Add state sets to the list in order.
83         List<Set<Integer>> stateSet = Arrays.asList(screenOnStates, screenOffStates);
84 
85         createAndUploadConfig(atomTag);
86         Thread.sleep(WAIT_TIME_SHORT);
87 
88         // Trigger events in same order.
89         turnScreenOn();
90         Thread.sleep(WAIT_TIME_LONG);
91         turnScreenOff();
92         Thread.sleep(WAIT_TIME_LONG);
93 
94         // Sorted list of events in order in which they occurred.
95         List<EventMetricData> data = getEventMetricDataList();
96         // reset screen to on
97         turnScreenOn();
98         // Restores AoD to initial state.
99         setAodState(aodState);
100         // Assert that the events happened in the expected order.
101         assertStatesOccurred(stateSet, data, WAIT_TIME_LONG,
102                 atom -> atom.getScreenStateChanged().getState().getNumber());
103     }
104 
testChargingStateChangedAtom()105     public void testChargingStateChangedAtom() throws Exception {
106         if (statsdDisabled()) {
107             return;
108         }
109         if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return;
110         // Setup, set charging state to full.
111         setChargingState(5);
112         Thread.sleep(WAIT_TIME_SHORT);
113 
114         final int atomTag = Atom.CHARGING_STATE_CHANGED_FIELD_NUMBER;
115 
116         Set<Integer> batteryUnknownStates = new HashSet<>(
117                 Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_UNKNOWN_VALUE));
118         Set<Integer> batteryChargingStates = new HashSet<>(
119                 Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_CHARGING_VALUE));
120         Set<Integer> batteryDischargingStates = new HashSet<>(
121                 Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_DISCHARGING_VALUE));
122         Set<Integer> batteryNotChargingStates = new HashSet<>(
123                 Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_NOT_CHARGING_VALUE));
124         Set<Integer> batteryFullStates = new HashSet<>(
125                 Arrays.asList(BatteryStatusEnum.BATTERY_STATUS_FULL_VALUE));
126 
127         // Add state sets to the list in order.
128         List<Set<Integer>> stateSet = Arrays.asList(batteryUnknownStates, batteryChargingStates,
129                 batteryDischargingStates, batteryNotChargingStates, batteryFullStates);
130 
131         createAndUploadConfig(atomTag);
132         Thread.sleep(WAIT_TIME_SHORT);
133 
134         // Trigger events in same order.
135         setChargingState(1);
136         Thread.sleep(WAIT_TIME_SHORT);
137         setChargingState(2);
138         Thread.sleep(WAIT_TIME_SHORT);
139         setChargingState(3);
140         Thread.sleep(WAIT_TIME_SHORT);
141         setChargingState(4);
142         Thread.sleep(WAIT_TIME_SHORT);
143         setChargingState(5);
144         Thread.sleep(WAIT_TIME_SHORT);
145 
146         // Sorted list of events in order in which they occurred.
147         List<EventMetricData> data = getEventMetricDataList();
148 
149         // Unfreeze battery state after test
150         resetBatteryStatus();
151         Thread.sleep(WAIT_TIME_SHORT);
152 
153         // Assert that the events happened in the expected order.
154         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
155                 atom -> atom.getChargingStateChanged().getState().getNumber());
156     }
157 
testPluggedStateChangedAtom()158     public void testPluggedStateChangedAtom() throws Exception {
159         if (statsdDisabled()) {
160             return;
161         }
162         if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return;
163         // Setup, unplug device.
164         unplugDevice();
165         Thread.sleep(WAIT_TIME_SHORT);
166 
167         final int atomTag = Atom.PLUGGED_STATE_CHANGED_FIELD_NUMBER;
168 
169         Set<Integer> unpluggedStates = new HashSet<>(
170                 Arrays.asList(BatteryPluggedStateEnum.BATTERY_PLUGGED_NONE_VALUE));
171         Set<Integer> acStates = new HashSet<>(
172                 Arrays.asList(BatteryPluggedStateEnum.BATTERY_PLUGGED_AC_VALUE));
173         Set<Integer> usbStates = new HashSet<>(
174                 Arrays.asList(BatteryPluggedStateEnum.BATTERY_PLUGGED_USB_VALUE));
175         Set<Integer> wirelessStates = new HashSet<>(
176                 Arrays.asList(BatteryPluggedStateEnum.BATTERY_PLUGGED_WIRELESS_VALUE));
177 
178         // Add state sets to the list in order.
179         List<Set<Integer>> stateSet = Arrays.asList(acStates, unpluggedStates, usbStates,
180                 unpluggedStates, wirelessStates, unpluggedStates);
181 
182         createAndUploadConfig(atomTag);
183         Thread.sleep(WAIT_TIME_SHORT);
184 
185         // Trigger events in same order.
186         plugInAc();
187         Thread.sleep(WAIT_TIME_SHORT);
188         unplugDevice();
189         Thread.sleep(WAIT_TIME_SHORT);
190         plugInUsb();
191         Thread.sleep(WAIT_TIME_SHORT);
192         unplugDevice();
193         Thread.sleep(WAIT_TIME_SHORT);
194         plugInWireless();
195         Thread.sleep(WAIT_TIME_SHORT);
196         unplugDevice();
197         Thread.sleep(WAIT_TIME_SHORT);
198 
199         // Sorted list of events in order in which they occurred.
200         List<EventMetricData> data = getEventMetricDataList();
201 
202         // Unfreeze battery state after test
203         resetBatteryStatus();
204         Thread.sleep(WAIT_TIME_SHORT);
205 
206         // Assert that the events happened in the expected order.
207         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
208                 atom -> atom.getPluggedStateChanged().getState().getNumber());
209     }
210 
testBatteryLevelChangedAtom()211     public void testBatteryLevelChangedAtom() throws Exception {
212         if (statsdDisabled()) {
213             return;
214         }
215         if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return;
216         // Setup, set battery level to full.
217         setBatteryLevel(100);
218         Thread.sleep(WAIT_TIME_SHORT);
219 
220         final int atomTag = Atom.BATTERY_LEVEL_CHANGED_FIELD_NUMBER;
221 
222         Set<Integer> batteryLow = new HashSet<>(Arrays.asList(2));
223         Set<Integer> battery25p = new HashSet<>(Arrays.asList(25));
224         Set<Integer> battery50p = new HashSet<>(Arrays.asList(50));
225         Set<Integer> battery75p = new HashSet<>(Arrays.asList(75));
226         Set<Integer> batteryFull = new HashSet<>(Arrays.asList(100));
227 
228         // Add state sets to the list in order.
229         List<Set<Integer>> stateSet = Arrays.asList(batteryLow, battery25p, battery50p,
230                 battery75p, batteryFull);
231 
232         createAndUploadConfig(atomTag);
233         Thread.sleep(WAIT_TIME_SHORT);
234 
235         // Trigger events in same order.
236         setBatteryLevel(2);
237         Thread.sleep(WAIT_TIME_SHORT);
238         setBatteryLevel(25);
239         Thread.sleep(WAIT_TIME_SHORT);
240         setBatteryLevel(50);
241         Thread.sleep(WAIT_TIME_SHORT);
242         setBatteryLevel(75);
243         Thread.sleep(WAIT_TIME_SHORT);
244         setBatteryLevel(100);
245         Thread.sleep(WAIT_TIME_SHORT);
246 
247         // Sorted list of events in order in which they occurred.
248         List<EventMetricData> data = getEventMetricDataList();
249 
250         // Unfreeze battery state after test
251         resetBatteryStatus();
252         Thread.sleep(WAIT_TIME_SHORT);
253 
254         // Assert that the events happened in the expected order.
255         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
256                 atom -> atom.getBatteryLevelChanged().getBatteryLevel());
257     }
258 
testDeviceIdleModeStateChangedAtom()259     public void testDeviceIdleModeStateChangedAtom() throws Exception {
260         if (statsdDisabled()) {
261             return;
262         }
263         // Setup, leave doze mode.
264         leaveDozeMode();
265         Thread.sleep(WAIT_TIME_SHORT);
266 
267         final int atomTag = Atom.DEVICE_IDLE_MODE_STATE_CHANGED_FIELD_NUMBER;
268 
269         Set<Integer> dozeOff = new HashSet<>(
270                 Arrays.asList(DeviceIdleModeEnum.DEVICE_IDLE_MODE_OFF_VALUE));
271         Set<Integer> dozeLight = new HashSet<>(
272                 Arrays.asList(DeviceIdleModeEnum.DEVICE_IDLE_MODE_LIGHT_VALUE));
273         Set<Integer> dozeDeep = new HashSet<>(
274                 Arrays.asList(DeviceIdleModeEnum.DEVICE_IDLE_MODE_DEEP_VALUE));
275 
276         // Add state sets to the list in order.
277         List<Set<Integer>> stateSet = Arrays.asList(dozeLight, dozeDeep, dozeOff);
278 
279         createAndUploadConfig(atomTag);
280         Thread.sleep(WAIT_TIME_SHORT);
281 
282         // Trigger events in same order.
283         enterDozeModeLight();
284         Thread.sleep(WAIT_TIME_SHORT);
285         enterDozeModeDeep();
286         Thread.sleep(WAIT_TIME_SHORT);
287         leaveDozeMode();
288         Thread.sleep(WAIT_TIME_SHORT);
289 
290         // Sorted list of events in order in which they occurred.
291         List<EventMetricData> data = getEventMetricDataList();;
292 
293         // Assert that the events happened in the expected order.
294         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
295                 atom -> atom.getDeviceIdleModeStateChanged().getState().getNumber());
296     }
297 
testBatterySaverModeStateChangedAtom()298     public void testBatterySaverModeStateChangedAtom() throws Exception {
299         if (statsdDisabled()) {
300             return;
301         }
302         if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return;
303         // Setup, turn off battery saver.
304         turnBatterySaverOff();
305         Thread.sleep(WAIT_TIME_SHORT);
306 
307         final int atomTag = Atom.BATTERY_SAVER_MODE_STATE_CHANGED_FIELD_NUMBER;
308 
309         Set<Integer> batterySaverOn = new HashSet<>(
310                 Arrays.asList(BatterySaverModeStateChanged.State.ON_VALUE));
311         Set<Integer> batterySaverOff = new HashSet<>(
312                 Arrays.asList(BatterySaverModeStateChanged.State.OFF_VALUE));
313 
314         // Add state sets to the list in order.
315         List<Set<Integer>> stateSet = Arrays.asList(batterySaverOn, batterySaverOff);
316 
317         createAndUploadConfig(atomTag);
318         Thread.sleep(WAIT_TIME_SHORT);
319 
320         // Trigger events in same order.
321         turnBatterySaverOn();
322         Thread.sleep(WAIT_TIME_LONG);
323         turnBatterySaverOff();
324         Thread.sleep(WAIT_TIME_LONG);
325 
326         // Sorted list of events in order in which they occurred.
327         List<EventMetricData> data = getEventMetricDataList();
328 
329         // Assert that the events happened in the expected order.
330         assertStatesOccurred(stateSet, data, WAIT_TIME_LONG,
331                 atom -> atom.getBatterySaverModeStateChanged().getState().getNumber());
332     }
333 
334     @RestrictedBuildTest
testRemainingBatteryCapacity()335     public void testRemainingBatteryCapacity() throws Exception {
336         if (statsdDisabled()) {
337             return;
338         }
339         if (!hasFeature(FEATURE_WATCH, false)) return;
340         if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return;
341         StatsdConfig.Builder config = getPulledConfig();
342         addGaugeAtomWithDimensions(config, Atom.REMAINING_BATTERY_CAPACITY_FIELD_NUMBER, null);
343 
344         uploadConfig(config);
345 
346         Thread.sleep(WAIT_TIME_LONG);
347         setAppBreadcrumbPredicate();
348         Thread.sleep(WAIT_TIME_LONG);
349 
350         List<Atom> data = getGaugeMetricDataList();
351 
352         assertTrue(data.size() > 0);
353         Atom atom = data.get(0);
354         assertTrue(atom.getRemainingBatteryCapacity().hasChargeMicroAmpereHour());
355         if (hasBattery()) {
356             assertTrue(atom.getRemainingBatteryCapacity().getChargeMicroAmpereHour() > 0);
357         }
358     }
359 
360     @RestrictedBuildTest
testFullBatteryCapacity()361     public void testFullBatteryCapacity() throws Exception {
362         if (statsdDisabled()) {
363             return;
364         }
365         if (!hasFeature(FEATURE_WATCH, false)) return;
366         if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return;
367         StatsdConfig.Builder config = getPulledConfig();
368         addGaugeAtomWithDimensions(config, Atom.FULL_BATTERY_CAPACITY_FIELD_NUMBER, null);
369 
370         uploadConfig(config);
371 
372         Thread.sleep(WAIT_TIME_LONG);
373         setAppBreadcrumbPredicate();
374         Thread.sleep(WAIT_TIME_LONG);
375 
376         List<Atom> data = getGaugeMetricDataList();
377 
378         assertTrue(data.size() > 0);
379         Atom atom = data.get(0);
380         assertTrue(atom.getFullBatteryCapacity().hasCapacityMicroAmpereHour());
381         if (hasBattery()) {
382             assertTrue(atom.getFullBatteryCapacity().getCapacityMicroAmpereHour() > 0);
383         }
384     }
385 
testBatteryVoltage()386     public void testBatteryVoltage() throws Exception {
387         if (statsdDisabled()) {
388             return;
389         }
390         if (!hasFeature(FEATURE_WATCH, false)) return;
391         StatsdConfig.Builder config = getPulledConfig();
392         addGaugeAtomWithDimensions(config, Atom.BATTERY_VOLTAGE_FIELD_NUMBER, null);
393 
394         uploadConfig(config);
395 
396         Thread.sleep(WAIT_TIME_LONG);
397         setAppBreadcrumbPredicate();
398         Thread.sleep(WAIT_TIME_LONG);
399 
400         List<Atom> data = getGaugeMetricDataList();
401 
402         assertTrue(data.size() > 0);
403         Atom atom = data.get(0);
404         assertTrue(atom.getBatteryVoltage().hasVoltageMillivolt());
405         if (hasBattery()) {
406             assertTrue(atom.getBatteryVoltage().getVoltageMillivolt() > 0);
407         }
408     }
409 
410     // This test is for the pulled battery level atom.
testBatteryLevel()411     public void testBatteryLevel() throws Exception {
412         if (statsdDisabled()) {
413             return;
414         }
415         if (!hasFeature(FEATURE_WATCH, false)) return;
416         StatsdConfig.Builder config = getPulledConfig();
417         addGaugeAtomWithDimensions(config, Atom.BATTERY_LEVEL_FIELD_NUMBER, null);
418 
419         uploadConfig(config);
420 
421         Thread.sleep(WAIT_TIME_LONG);
422         setAppBreadcrumbPredicate();
423         Thread.sleep(WAIT_TIME_LONG);
424 
425         List<Atom> data = getGaugeMetricDataList();
426 
427         assertTrue(data.size() > 0);
428         Atom atom = data.get(0);
429         assertTrue(atom.getBatteryLevel().hasBatteryLevel());
430         if (hasBattery()) {
431             assertTrue(atom.getBatteryLevel().getBatteryLevel() > 0);
432             assertTrue(atom.getBatteryLevel().getBatteryLevel() <= 100);
433         }
434     }
435 
436     // This test is for the pulled battery charge count atom.
testBatteryCycleCount()437     public void testBatteryCycleCount() throws Exception {
438         if (statsdDisabled()) {
439             return;
440         }
441         if (!hasFeature(FEATURE_WATCH, false)) return;
442         StatsdConfig.Builder config = getPulledConfig();
443         addGaugeAtomWithDimensions(config, Atom.BATTERY_CYCLE_COUNT_FIELD_NUMBER, null);
444 
445         uploadConfig(config);
446 
447         Thread.sleep(WAIT_TIME_LONG);
448         setAppBreadcrumbPredicate();
449         Thread.sleep(WAIT_TIME_LONG);
450 
451         List<Atom> data = getGaugeMetricDataList();
452 
453         assertTrue(data.size() > 0);
454         Atom atom = data.get(0);
455         assertTrue(atom.getBatteryCycleCount().hasCycleCount());
456         if (hasBattery()) {
457             assertTrue(atom.getBatteryCycleCount().getCycleCount() >= 0);
458         }
459     }
460 
testKernelWakelock()461     public void testKernelWakelock() throws Exception {
462         if (statsdDisabled() || !kernelWakelockStatsExist()) {
463             return;
464         }
465         StatsdConfig.Builder config = getPulledConfig();
466         addGaugeAtomWithDimensions(config, Atom.KERNEL_WAKELOCK_FIELD_NUMBER, null);
467 
468         uploadConfig(config);
469 
470         Thread.sleep(WAIT_TIME_LONG);
471         setAppBreadcrumbPredicate();
472         Thread.sleep(WAIT_TIME_LONG);
473 
474         List<Atom> data = getGaugeMetricDataList();
475 
476         Atom atom = data.get(0);
477         assertTrue(!atom.getKernelWakelock().getName().equals(""));
478         assertTrue(atom.getKernelWakelock().hasCount());
479         assertTrue(atom.getKernelWakelock().hasVersion());
480         assertTrue(atom.getKernelWakelock().getVersion() > 0);
481         assertTrue(atom.getKernelWakelock().hasTimeMicros());
482     }
483 
484     // Returns true iff either |WAKE_LOCK_FILE| or |WAKE_SOURCES_FILE| exists.
kernelWakelockStatsExist()485     private boolean kernelWakelockStatsExist() {
486       try {
487         return doesFileExist(WAKE_LOCK_FILE) || doesFileExist(WAKE_SOURCES_FILE);
488       } catch(Exception e) {
489         return false;
490       }
491     }
492 
testWifiActivityInfo()493     public void testWifiActivityInfo() throws Exception {
494         if (statsdDisabled()) {
495             return;
496         }
497         if (!hasFeature(FEATURE_WIFI, true)) return;
498         if (!hasFeature(FEATURE_WATCH, false)) return;
499         if (!checkDeviceFor("checkWifiEnhancedPowerReportingSupported")) return;
500 
501         StatsdConfig.Builder config = getPulledConfig();
502         addGaugeAtomWithDimensions(config, Atom.WIFI_ACTIVITY_INFO_FIELD_NUMBER, null);
503 
504         uploadConfig(config);
505 
506         Thread.sleep(WAIT_TIME_LONG);
507         setAppBreadcrumbPredicate();
508         Thread.sleep(WAIT_TIME_LONG);
509 
510         List<Atom> dataList = getGaugeMetricDataList();
511 
512         for (Atom atom: dataList) {
513             assertTrue(atom.getWifiActivityInfo().getTimestampMillis() > 0);
514             assertTrue(atom.getWifiActivityInfo().getStackState() >= 0);
515             assertTrue(atom.getWifiActivityInfo().getControllerIdleTimeMillis() > 0);
516             assertTrue(atom.getWifiActivityInfo().getControllerTxTimeMillis() >= 0);
517             assertTrue(atom.getWifiActivityInfo().getControllerRxTimeMillis() >= 0);
518             assertTrue(atom.getWifiActivityInfo().getControllerEnergyUsed() >= 0);
519         }
520     }
521 
testBuildInformation()522     public void testBuildInformation() throws Exception {
523         if (statsdDisabled()) {
524             return;
525         }
526 
527         StatsdConfig.Builder config = getPulledConfig();
528         addGaugeAtomWithDimensions(config, Atom.BUILD_INFORMATION_FIELD_NUMBER, null);
529         uploadConfig(config);
530 
531         Thread.sleep(WAIT_TIME_LONG);
532         setAppBreadcrumbPredicate();
533         Thread.sleep(WAIT_TIME_LONG);
534 
535         List<Atom> data = getGaugeMetricDataList();
536         assertTrue(data.size() > 0);
537         BuildInformation atom = data.get(0).getBuildInformation();
538         assertEquals(getProperty("ro.product.brand"),             atom.getBrand());
539         assertEquals(getProperty("ro.product.name"),              atom.getProduct());
540         assertEquals(getProperty("ro.product.device"),            atom.getDevice());
541         assertEquals(getProperty("ro.build.version.release"),     atom.getVersionRelease());
542         assertEquals(getProperty("ro.build.id"),                  atom.getId());
543         assertEquals(getProperty("ro.build.version.incremental"), atom.getVersionIncremental());
544         assertEquals(getProperty("ro.build.type"),                atom.getType());
545         assertEquals(getProperty("ro.build.tags"),                atom.getTags());
546     }
547 
testOnDevicePowerMeasurement()548     public void testOnDevicePowerMeasurement() throws Exception {
549         if (!OPTIONAL_TESTS_ENABLED) return;
550         if (statsdDisabled()) {
551             return;
552         }
553 
554         StatsdConfig.Builder config = getPulledConfig();
555         addGaugeAtomWithDimensions(config, Atom.ON_DEVICE_POWER_MEASUREMENT_FIELD_NUMBER, null);
556 
557         uploadConfig(config);
558 
559         Thread.sleep(WAIT_TIME_LONG);
560         setAppBreadcrumbPredicate();
561         Thread.sleep(WAIT_TIME_LONG);
562 
563         List<Atom> dataList = getGaugeMetricDataList();
564 
565         for (Atom atom: dataList) {
566             assertTrue(atom.getOnDevicePowerMeasurement().getMeasurementTimestampMillis() >= 0);
567             assertTrue(atom.getOnDevicePowerMeasurement().getEnergyMicrowattSecs() >= 0);
568         }
569     }
570 
571     // Explicitly tests if the adb command to log a breadcrumb is working.
testBreadcrumbAdb()572     public void testBreadcrumbAdb() throws Exception {
573         if (statsdDisabled()) {
574             return;
575         }
576         final int atomTag = Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER;
577         createAndUploadConfig(atomTag);
578         Thread.sleep(WAIT_TIME_SHORT);
579 
580         doAppBreadcrumbReportedStart(1);
581         Thread.sleep(WAIT_TIME_SHORT);
582 
583         List<EventMetricData> data = getEventMetricDataList();
584         AppBreadcrumbReported atom = data.get(0).getAtom().getAppBreadcrumbReported();
585         assertTrue(atom.getLabel() == 1);
586         assertTrue(atom.getState().getNumber() == AppBreadcrumbReported.State.START_VALUE);
587     }
588 
589     // Test dumpsys stats --proto.
testDumpsysStats()590     public void testDumpsysStats() throws Exception {
591         if (statsdDisabled()) {
592             return;
593         }
594         final int atomTag = Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER;
595         createAndUploadConfig(atomTag);
596         Thread.sleep(WAIT_TIME_SHORT);
597 
598         doAppBreadcrumbReportedStart(1);
599         Thread.sleep(WAIT_TIME_SHORT);
600 
601         // Get the stats incident section.
602         List<ConfigMetricsReportList> listList = getReportsFromStatsDataDumpProto();
603         assertTrue(listList.size() > 0);
604 
605         // Extract the relevent report from the incident section.
606         ConfigMetricsReportList ourList = null;
607         int hostUid = getHostUid();
608         for (ConfigMetricsReportList list : listList) {
609             ConfigMetricsReportList.ConfigKey configKey = list.getConfigKey();
610             if (configKey.getUid() == hostUid && configKey.getId() == CONFIG_ID) {
611                 ourList = list;
612                 break;
613             }
614         }
615         assertNotNull("Could not find list for uid=" + hostUid
616                 + " id=" + CONFIG_ID, ourList);
617 
618         // Make sure that the report is correct.
619         List<EventMetricData> data = getEventMetricDataList(ourList);
620         AppBreadcrumbReported atom = data.get(0).getAtom().getAppBreadcrumbReported();
621         assertTrue(atom.getLabel() == 1);
622         assertTrue(atom.getState().getNumber() == AppBreadcrumbReported.State.START_VALUE);
623     }
624 
testConnectivityStateChange()625     public void testConnectivityStateChange() throws Exception {
626         if (statsdDisabled()) {
627             return;
628         }
629         if (!hasFeature(FEATURE_WIFI, true)) return;
630         if (!hasFeature(FEATURE_WATCH, false)) return;
631         if (!hasFeature(FEATURE_LEANBACK_ONLY, false)) return;
632 
633         final int atomTag = Atom.CONNECTIVITY_STATE_CHANGED_FIELD_NUMBER;
634         createAndUploadConfig(atomTag);
635         Thread.sleep(WAIT_TIME_SHORT);
636 
637         turnOnAirplaneMode();
638         // wait long enough for airplane mode events to propagate.
639         Thread.sleep(1_200);
640         turnOffAirplaneMode();
641         // wait long enough for the device to restore connection
642         Thread.sleep(13_000);
643 
644         List<EventMetricData> data = getEventMetricDataList();
645         // at least 1 disconnect and 1 connect
646         assertThat(data.size()).isAtLeast(2);
647         boolean foundDisconnectEvent = false;
648         boolean foundConnectEvent = false;
649         for (EventMetricData d : data) {
650             ConnectivityStateChanged atom = d.getAtom().getConnectivityStateChanged();
651             if(atom.getState().getNumber()
652                     == ConnectivityStateChanged.State.DISCONNECTED_VALUE) {
653                 foundDisconnectEvent = true;
654             }
655             if(atom.getState().getNumber()
656                     == ConnectivityStateChanged.State.CONNECTED_VALUE) {
657                 foundConnectEvent = true;
658             }
659         }
660         assertTrue(foundConnectEvent && foundDisconnectEvent);
661     }
662 }
663