• Home
  • History
  • Annotate
  • 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.statsd.atom;
17 
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertTrue;
21 
22 import android.os.WakeLockLevelEnum;
23 import android.platform.test.annotations.RestrictedBuildTest;
24 
25 import com.android.internal.os.StatsdConfigProto.FieldMatcher;
26 import com.android.internal.os.StatsdConfigProto.StatsdConfig;
27 import com.android.os.AtomsProto.AppCrashOccurred;
28 import com.android.os.AtomsProto.AppStartOccurred;
29 import com.android.os.AtomsProto.Atom;
30 import com.android.os.AtomsProto.AudioStateChanged;
31 import com.android.os.AtomsProto.BleScanResultReceived;
32 import com.android.os.AtomsProto.BleScanStateChanged;
33 import com.android.os.AtomsProto.CameraStateChanged;
34 import com.android.os.AtomsProto.CpuActiveTime;
35 import com.android.os.AtomsProto.CpuTimePerUid;
36 import com.android.os.AtomsProto.FlashlightStateChanged;
37 import com.android.os.AtomsProto.ForegroundServiceStateChanged;
38 import com.android.os.AtomsProto.GpsScanStateChanged;
39 import com.android.os.AtomsProto.MediaCodecStateChanged;
40 import com.android.os.AtomsProto.OverlayStateChanged;
41 import com.android.os.AtomsProto.PictureInPictureStateChanged;
42 import com.android.os.AtomsProto.ScheduledJobStateChanged;
43 import com.android.os.AtomsProto.SyncStateChanged;
44 import com.android.os.AtomsProto.WakelockStateChanged;
45 import com.android.os.AtomsProto.WifiLockStateChanged;
46 import com.android.os.AtomsProto.WifiMulticastLockStateChanged;
47 import com.android.os.AtomsProto.WifiScanStateChanged;
48 import com.android.os.StatsLog.EventMetricData;
49 
50 import java.util.Arrays;
51 import java.util.HashSet;
52 import java.util.List;
53 import java.util.Set;
54 
55 /**
56  * Statsd atom tests that are done via app, for atoms that report a uid.
57  */
58 public class UidAtomTests extends DeviceAtomTestCase {
59 
60     private static final String TAG = "Statsd.UidAtomTests";
61 
62     // These constants are those in PackageManager.
63     private static final String FEATURE_BLUETOOTH_LE = "android.hardware.bluetooth_le";
64     private static final String FEATURE_LOCATION_GPS = "android.hardware.location.gps";
65     private static final String FEATURE_WIFI = "android.hardware.wifi";
66     private static final String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
67     private static final String FEATURE_CAMERA = "android.hardware.camera";
68     private static final String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
69     private static final String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output";
70     private static final String FEATURE_WATCH = "android.hardware.type.watch";
71     private static final String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
72 
73     private static final boolean DAVEY_ENABLED = false;
74 
75     @Override
setUp()76     protected void setUp() throws Exception {
77         super.setUp();
78     }
79 
testAppStartOccurred()80     public void testAppStartOccurred() throws Exception {
81         if (statsdDisabled()) {
82             return;
83         }
84         final int atomTag = Atom.APP_START_OCCURRED_FIELD_NUMBER;
85 
86         createAndUploadConfig(atomTag, false);
87         Thread.sleep(WAIT_TIME_SHORT);
88 
89         runActivity("StatsdCtsForegroundActivity", "action", "action.sleep_top");
90 
91         // Sorted list of events in order in which they occurred.
92         List<EventMetricData> data = getEventMetricDataList();
93 
94         AppStartOccurred atom = data.get(0).getAtom().getAppStartOccurred();
95         assertEquals("com.android.server.cts.device.statsd", atom.getPkgName());
96         assertEquals("com.android.server.cts.device.statsd.StatsdCtsForegroundActivity",
97                 atom.getActivityName());
98         assertFalse(atom.getIsInstantApp());
99         assertTrue(atom.getActivityStartMillis() > 0);
100         assertTrue(atom.getTransitionDelayMillis() > 0);
101     }
102 
testBleScan()103     public void testBleScan() throws Exception {
104         if (statsdDisabled()) {
105             return;
106         }
107         if (!hasFeature(FEATURE_BLUETOOTH_LE, true)) return;
108 
109         final int atom = Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER;
110         final int field = BleScanStateChanged.STATE_FIELD_NUMBER;
111         final int stateOn = BleScanStateChanged.State.ON_VALUE;
112         final int stateOff = BleScanStateChanged.State.OFF_VALUE;
113         final int minTimeDiffMillis = 1_500;
114         final int maxTimeDiffMillis = 3_000;
115 
116         List<EventMetricData> data = doDeviceMethodOnOff("testBleScanUnoptimized", atom, field,
117                 stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, true);
118 
119         BleScanStateChanged a0 = data.get(0).getAtom().getBleScanStateChanged();
120         BleScanStateChanged a1 = data.get(1).getAtom().getBleScanStateChanged();
121         assertTrue(a0.getState().getNumber() == stateOn);
122         assertTrue(a1.getState().getNumber() == stateOff);
123     }
124 
testBleUnoptimizedScan()125     public void testBleUnoptimizedScan() throws Exception {
126         if (statsdDisabled()) {
127             return;
128         }
129         if (!hasFeature(FEATURE_BLUETOOTH_LE, true)) return;
130 
131         final int atom = Atom.BLE_SCAN_STATE_CHANGED_FIELD_NUMBER;
132         final int field = BleScanStateChanged.STATE_FIELD_NUMBER;
133         final int stateOn = BleScanStateChanged.State.ON_VALUE;
134         final int stateOff = BleScanStateChanged.State.OFF_VALUE;
135         final int minTimeDiffMillis = 1_500;
136         final int maxTimeDiffMillis = 3_000;
137 
138         List<EventMetricData> data = doDeviceMethodOnOff("testBleScanUnoptimized", atom, field,
139                 stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, true);
140 
141         BleScanStateChanged a0 = data.get(0).getAtom().getBleScanStateChanged();
142         assertTrue(a0.getState().getNumber() == stateOn);
143         assertFalse(a0.getIsFiltered());
144         assertFalse(a0.getIsFirstMatch());
145         assertFalse(a0.getIsOpportunistic());
146         BleScanStateChanged a1 = data.get(1).getAtom().getBleScanStateChanged();
147         assertTrue(a1.getState().getNumber() == stateOff);
148         assertFalse(a1.getIsFiltered());
149         assertFalse(a1.getIsFirstMatch());
150         assertFalse(a1.getIsOpportunistic());
151 
152 
153         // Now repeat the test for opportunistic scanning and make sure it is reported correctly.
154         data = doDeviceMethodOnOff("testBleScanOpportunistic", atom, field,
155                 stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, true);
156 
157         a0 = data.get(0).getAtom().getBleScanStateChanged();
158         assertTrue(a0.getState().getNumber() == stateOn);
159         assertFalse(a0.getIsFiltered());
160         assertFalse(a0.getIsFirstMatch());
161         assertTrue(a0.getIsOpportunistic());  // This scan is opportunistic.
162         a1 = data.get(1).getAtom().getBleScanStateChanged();
163         assertTrue(a1.getState().getNumber() == stateOff);
164         assertFalse(a1.getIsFiltered());
165         assertFalse(a1.getIsFirstMatch());
166         assertTrue(a1.getIsOpportunistic());
167     }
168 
testBleScanResult()169     public void testBleScanResult() throws Exception {
170         if (statsdDisabled()) {
171             return;
172         }
173         if (!hasFeature(FEATURE_BLUETOOTH_LE, true)) return;
174 
175         final int atom = Atom.BLE_SCAN_RESULT_RECEIVED_FIELD_NUMBER;
176         final int field = BleScanResultReceived.NUM_RESULTS_FIELD_NUMBER;
177 
178         StatsdConfig.Builder conf = createConfigBuilder();
179         addAtomEvent(conf, atom, createFvm(field).setGteInt(0));
180         List<EventMetricData> data = doDeviceMethod("testBleScanResult", conf);
181 
182         assertTrue(data.size() >= 1);
183         BleScanResultReceived a0 = data.get(0).getAtom().getBleScanResultReceived();
184         assertTrue(a0.getNumResults() >= 1);
185     }
186 
testCameraState()187     public void testCameraState() throws Exception {
188         if (statsdDisabled()) {
189             return;
190         }
191         if (!hasFeature(FEATURE_CAMERA, true) && !hasFeature(FEATURE_CAMERA_FRONT, true)) return;
192 
193         final int atomTag = Atom.CAMERA_STATE_CHANGED_FIELD_NUMBER;
194         Set<Integer> cameraOn = new HashSet<>(Arrays.asList(CameraStateChanged.State.ON_VALUE));
195         Set<Integer> cameraOff = new HashSet<>(Arrays.asList(CameraStateChanged.State.OFF_VALUE));
196 
197         // Add state sets to the list in order.
198         List<Set<Integer>> stateSet = Arrays.asList(cameraOn, cameraOff);
199 
200         createAndUploadConfig(atomTag, true);  // True: uses attribution.
201         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testCameraState");
202 
203         // Sorted list of events in order in which they occurred.
204         List<EventMetricData> data = getEventMetricDataList();
205 
206         // Assert that the events happened in the expected order.
207         assertStatesOccurred(stateSet, data, WAIT_TIME_LONG,
208                 atom -> atom.getCameraStateChanged().getState().getNumber());
209     }
210 
testCpuTimePerUid()211     public void testCpuTimePerUid() throws Exception {
212         if (statsdDisabled()) {
213             return;
214         }
215         if (!hasFeature(FEATURE_WATCH, false)) return;
216         StatsdConfig.Builder config = getPulledConfig();
217         FieldMatcher.Builder dimension = FieldMatcher.newBuilder()
218                 .setField(Atom.CPU_TIME_PER_UID_FIELD_NUMBER)
219                 .addChild(FieldMatcher.newBuilder()
220                         .setField(CpuTimePerUid.UID_FIELD_NUMBER));
221         addGaugeAtom(config, Atom.CPU_TIME_PER_UID_FIELD_NUMBER, dimension);
222 
223         uploadConfig(config);
224 
225         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu");
226 
227         turnScreenOff();
228         Thread.sleep(WAIT_TIME_SHORT);
229         turnScreenOn();
230         Thread.sleep(WAIT_TIME_SHORT);
231 
232         List<Atom> atomList = getGaugeMetricDataList();
233 
234         // TODO: We don't have atom matching on gauge yet. Let's refactor this after that feature is
235         // implemented.
236         boolean found = false;
237         int uid = getUid();
238         for (Atom atom : atomList) {
239             if (atom.getCpuTimePerUid().getUid() == uid) {
240                 found = true;
241                 assertTrue(atom.getCpuTimePerUid().getUserTimeMillis() > 0);
242                 assertTrue(atom.getCpuTimePerUid().getSysTimeMillis() > 0);
243             }
244         }
245         assertTrue("found uid " + uid, found);
246     }
247 
248     @RestrictedBuildTest
testCpuActiveTime()249     public void testCpuActiveTime() throws Exception {
250         if (statsdDisabled()) {
251             return;
252         }
253         if (!hasFeature(FEATURE_WATCH, false)) return;
254         StatsdConfig.Builder config = getPulledConfig();
255         FieldMatcher.Builder dimension = FieldMatcher.newBuilder()
256                 .setField(Atom.CPU_ACTIVE_TIME_FIELD_NUMBER)
257                 .addChild(FieldMatcher.newBuilder()
258                         .setField(CpuActiveTime.UID_FIELD_NUMBER));
259         addGaugeAtom(config, Atom.CPU_ACTIVE_TIME_FIELD_NUMBER, dimension);
260 
261         uploadConfig(config);
262 
263         turnScreenOn();
264         Thread.sleep(WAIT_TIME_SHORT);
265         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSimpleCpu");
266         Thread.sleep(WAIT_TIME_SHORT);
267         turnScreenOff();
268         Thread.sleep(WAIT_TIME_SHORT);
269         turnScreenOn();
270         Thread.sleep(WAIT_TIME_SHORT);
271 
272         List<Atom> atomList = getGaugeMetricDataList();
273 
274         boolean found = false;
275         int uid = getUid();
276         long timeSpent = 0;
277         for (Atom atom : atomList) {
278             if (atom.getCpuActiveTime().getUid() == uid) {
279                 found = true;
280                 timeSpent += atom.getCpuActiveTime().getTimeMillis();
281             }
282         }
283         assertTrue(timeSpent > 0);
284         assertTrue("found uid " + uid, found);
285     }
286 
testFlashlightState()287     public void testFlashlightState() throws Exception {
288         if (statsdDisabled()) {
289             return;
290         }
291         if (!hasFeature(FEATURE_CAMERA_FLASH, true)) return;
292 
293         final int atomTag = Atom.FLASHLIGHT_STATE_CHANGED_FIELD_NUMBER;
294         final String name = "testFlashlight";
295 
296         Set<Integer> flashlightOn = new HashSet<>(
297             Arrays.asList(FlashlightStateChanged.State.ON_VALUE));
298         Set<Integer> flashlightOff = new HashSet<>(
299             Arrays.asList(FlashlightStateChanged.State.OFF_VALUE));
300 
301         // Add state sets to the list in order.
302         List<Set<Integer>> stateSet = Arrays.asList(flashlightOn, flashlightOff);
303 
304         createAndUploadConfig(atomTag, true);  // True: uses attribution.
305         Thread.sleep(WAIT_TIME_SHORT);
306 
307         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", name);
308 
309         // Sorted list of events in order in which they occurred.
310         List<EventMetricData> data = getEventMetricDataList();
311 
312         // Assert that the events happened in the expected order.
313         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
314                 atom -> atom.getFlashlightStateChanged().getState().getNumber());
315     }
316 
testForegroundServiceState()317     public void testForegroundServiceState() throws Exception {
318         if (statsdDisabled()) {
319             return;
320         }
321         final int atomTag = Atom.FOREGROUND_SERVICE_STATE_CHANGED_FIELD_NUMBER;
322         final String name = "testForegroundService";
323 
324         Set<Integer> enterForeground = new HashSet<>(
325                 Arrays.asList(ForegroundServiceStateChanged.State.ENTER_VALUE));
326         Set<Integer> exitForeground = new HashSet<>(
327                 Arrays.asList(ForegroundServiceStateChanged.State.EXIT_VALUE));
328 
329         // Add state sets to the list in order.
330         List<Set<Integer>> stateSet = Arrays.asList(enterForeground, exitForeground);
331 
332         createAndUploadConfig(atomTag, false);
333         Thread.sleep(WAIT_TIME_SHORT);
334 
335         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", name);
336 
337         // Sorted list of events in order in which they occurred.
338         List<EventMetricData> data = getEventMetricDataList();
339 
340         // Assert that the events happened in the expected order.
341         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
342                 atom -> atom.getForegroundServiceStateChanged().getState().getNumber());
343     }
344 
testGpsScan()345     public void testGpsScan() throws Exception {
346         if (statsdDisabled()) {
347             return;
348         }
349         if (!hasFeature(FEATURE_LOCATION_GPS, true)) return;
350         // Whitelist this app against background location request throttling
351         getDevice().executeShellCommand(String.format(
352                 "settings put global location_background_throttle_package_whitelist %s",
353                 DEVICE_SIDE_TEST_PACKAGE));
354 
355         final int atom = Atom.GPS_SCAN_STATE_CHANGED_FIELD_NUMBER;
356         final int key = GpsScanStateChanged.STATE_FIELD_NUMBER;
357         final int stateOn = GpsScanStateChanged.State.ON_VALUE;
358         final int stateOff = GpsScanStateChanged.State.OFF_VALUE;
359         final int minTimeDiffMillis = 500;
360         final int maxTimeDiffMillis = 60_000;
361 
362         List<EventMetricData> data = doDeviceMethodOnOff("testGpsScan", atom, key,
363                 stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, true);
364 
365         GpsScanStateChanged a0 = data.get(0).getAtom().getGpsScanStateChanged();
366         GpsScanStateChanged a1 = data.get(1).getAtom().getGpsScanStateChanged();
367         assertTrue(a0.getState().getNumber() == stateOn);
368         assertTrue(a1.getState().getNumber() == stateOff);
369     }
370 
testOverlayState()371     public void testOverlayState() throws Exception {
372         if (statsdDisabled()) {
373             return;
374         }
375         final int atomTag = Atom.OVERLAY_STATE_CHANGED_FIELD_NUMBER;
376 
377         Set<Integer> entered = new HashSet<>(
378                 Arrays.asList(OverlayStateChanged.State.ENTERED_VALUE));
379         Set<Integer> exited = new HashSet<>(
380                 Arrays.asList(OverlayStateChanged.State.EXITED_VALUE));
381 
382         // Add state sets to the list in order.
383         List<Set<Integer>> stateSet = Arrays.asList(entered, exited);
384 
385         createAndUploadConfig(atomTag, false);
386 
387         runActivity("StatsdCtsForegroundActivity", "action", "action.show_application_overlay",
388                 3_000);
389 
390         // Sorted list of events in order in which they occurred.
391         List<EventMetricData> data = getEventMetricDataList();
392 
393         // Assert that the events happened in the expected order.
394         // The overlay box should appear about 2sec after the app start
395         assertStatesOccurred(stateSet, data, 0,
396                 atom -> atom.getOverlayStateChanged().getState().getNumber());
397     }
398 
testDavey()399     public void testDavey() throws Exception {
400         if (statsdDisabled()) {
401             return;
402         }
403         if (!DAVEY_ENABLED ) return;
404         long MAX_DURATION = 2000;
405         long MIN_DURATION = 750;
406         final int atomTag = Atom.DAVEY_OCCURRED_FIELD_NUMBER;
407         createAndUploadConfig(atomTag, false); // UID is logged without attribution node
408 
409         runActivity("DaveyActivity", null, null);
410 
411         List<EventMetricData> data = getEventMetricDataList();
412         assertTrue(data.size() == 1);
413         long duration = data.get(0).getAtom().getDaveyOccurred().getJankDurationMillis();
414         assertTrue("Jank duration of " + duration + "ms was less than " + MIN_DURATION + "ms",
415                 duration >= MIN_DURATION);
416         assertTrue("Jank duration of " + duration + "ms was longer than " + MAX_DURATION + "ms",
417                 duration <= MAX_DURATION);
418     }
419 
testScheduledJobState()420     public void testScheduledJobState() throws Exception {
421         if (statsdDisabled()) {
422             return;
423         }
424         String expectedName = "com.android.server.cts.device.statsd/.StatsdJobService";
425         final int atomTag = Atom.SCHEDULED_JOB_STATE_CHANGED_FIELD_NUMBER;
426         Set<Integer> jobSchedule = new HashSet<>(
427                 Arrays.asList(ScheduledJobStateChanged.State.SCHEDULED_VALUE));
428         Set<Integer> jobOn = new HashSet<>(
429                 Arrays.asList(ScheduledJobStateChanged.State.STARTED_VALUE));
430         Set<Integer> jobOff = new HashSet<>(
431                 Arrays.asList(ScheduledJobStateChanged.State.FINISHED_VALUE));
432 
433         // Add state sets to the list in order.
434         List<Set<Integer>> stateSet = Arrays.asList(jobSchedule, jobOn, jobOff);
435 
436         createAndUploadConfig(atomTag, true);  // True: uses attribution.
437         allowImmediateSyncs();
438         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testScheduledJob");
439 
440         // Sorted list of events in order in which they occurred.
441         List<EventMetricData> data = getEventMetricDataList();
442 
443         assertStatesOccurred(stateSet, data, 0,
444                 atom -> atom.getScheduledJobStateChanged().getState().getNumber());
445 
446         for (EventMetricData e : data) {
447             assertTrue(e.getAtom().getScheduledJobStateChanged().getJobName().equals(expectedName));
448         }
449     }
450 
451     //Note: this test does not have uid, but must run on the device
testScreenBrightness()452     public void testScreenBrightness() throws Exception {
453         if (statsdDisabled()) {
454             return;
455         }
456         int initialBrightness = getScreenBrightness();
457         boolean isInitialManual = isScreenBrightnessModeManual();
458         setScreenBrightnessMode(true);
459         setScreenBrightness(200);
460         Thread.sleep(WAIT_TIME_LONG);
461 
462         final int atomTag = Atom.SCREEN_BRIGHTNESS_CHANGED_FIELD_NUMBER;
463 
464         Set<Integer> screenMin = new HashSet<>(Arrays.asList(47));
465         Set<Integer> screen100 = new HashSet<>(Arrays.asList(100));
466         Set<Integer> screen200 = new HashSet<>(Arrays.asList(198));
467         // Set<Integer> screenMax = new HashSet<>(Arrays.asList(255));
468 
469         // Add state sets to the list in order.
470         List<Set<Integer>> stateSet = Arrays.asList(screenMin, screen100, screen200);
471 
472         createAndUploadConfig(atomTag);
473         Thread.sleep(WAIT_TIME_SHORT);
474         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testScreenBrightness");
475 
476         // Sorted list of events in order in which they occurred.
477         List<EventMetricData> data = getEventMetricDataList();
478 
479         // Restore initial screen brightness
480         setScreenBrightness(initialBrightness);
481         setScreenBrightnessMode(isInitialManual);
482 
483         popUntilFind(data, screenMin, atom->atom.getScreenBrightnessChanged().getLevel());
484         popUntilFindFromEnd(data, screen200, atom->atom.getScreenBrightnessChanged().getLevel());
485         // Assert that the events happened in the expected order.
486         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
487             atom -> atom.getScreenBrightnessChanged().getLevel());
488     }
testSyncState()489     public void testSyncState() throws Exception {
490         if (statsdDisabled()) {
491             return;
492         }
493         final int atomTag = Atom.SYNC_STATE_CHANGED_FIELD_NUMBER;
494         Set<Integer> syncOn = new HashSet<>(Arrays.asList(SyncStateChanged.State.ON_VALUE));
495         Set<Integer> syncOff = new HashSet<>(Arrays.asList(SyncStateChanged.State.OFF_VALUE));
496 
497         // Add state sets to the list in order.
498         List<Set<Integer>> stateSet = Arrays.asList(syncOn, syncOff, syncOn, syncOff);
499 
500         createAndUploadConfig(atomTag, true);
501         allowImmediateSyncs();
502         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testSyncState");
503 
504         // Sorted list of events in order in which they occurred.
505         List<EventMetricData> data = getEventMetricDataList();
506 
507         // Assert that the events happened in the expected order.
508         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
509                 atom -> atom.getSyncStateChanged().getState().getNumber());
510     }
511 
testWakelockState()512     public void testWakelockState() throws Exception {
513         if (statsdDisabled()) {
514             return;
515         }
516         final int atomTag = Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER;
517         Set<Integer> wakelockOn = new HashSet<>(Arrays.asList(
518                 WakelockStateChanged.State.ACQUIRE_VALUE,
519                 WakelockStateChanged.State.CHANGE_ACQUIRE_VALUE));
520         Set<Integer> wakelockOff = new HashSet<>(Arrays.asList(
521                 WakelockStateChanged.State.RELEASE_VALUE,
522                 WakelockStateChanged.State.CHANGE_RELEASE_VALUE));
523 
524         final String EXPECTED_TAG = "StatsdPartialWakelock";
525         final WakeLockLevelEnum EXPECTED_LEVEL = WakeLockLevelEnum.PARTIAL_WAKE_LOCK;
526 
527         // Add state sets to the list in order.
528         List<Set<Integer>> stateSet = Arrays.asList(wakelockOn, wakelockOff);
529 
530         createAndUploadConfig(atomTag, true);  // True: uses attribution.
531         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWakelockState");
532 
533         // Sorted list of events in order in which they occurred.
534         List<EventMetricData> data = getEventMetricDataList();
535 
536         // Assert that the events happened in the expected order.
537         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
538             atom -> atom.getWakelockStateChanged().getState().getNumber());
539 
540         for (EventMetricData event: data) {
541             String tag = event.getAtom().getWakelockStateChanged().getTag();
542             WakeLockLevelEnum type = event.getAtom().getWakelockStateChanged().getLevel();
543             assertTrue("Expected tag: " + EXPECTED_TAG + ", but got tag: " + tag,
544                     tag.equals(EXPECTED_TAG));
545             assertTrue("Expected wakelock level: " + EXPECTED_LEVEL  + ", but got level: " + type,
546                     type == EXPECTED_LEVEL);
547         }
548     }
549 
testWakeupAlarm()550     public void testWakeupAlarm() throws Exception {
551         if (statsdDisabled()) {
552             return;
553         }
554         final int atomTag = Atom.WAKEUP_ALARM_OCCURRED_FIELD_NUMBER;
555 
556         StatsdConfig.Builder config = createConfigBuilder();
557         addAtomEvent(config, atomTag, true);  // True: uses attribution.
558 
559         List<EventMetricData> data = doDeviceMethod("testWakeupAlarm", config);
560         assertTrue(data.size() >= 1);
561         for (int i = 0; i < data.size(); i++) {
562             String tag = data.get(i).getAtom().getWakeupAlarmOccurred().getTag();
563             assertTrue(tag.equals("*walarm*:android.cts.statsd.testWakeupAlarm"));
564         }
565     }
566 
testWifiLock()567     public void testWifiLock() throws Exception {
568         if (statsdDisabled()) {
569             return;
570         }
571         if (!hasFeature(FEATURE_WIFI, true)) return;
572 
573         final int atomTag = Atom.WIFI_LOCK_STATE_CHANGED_FIELD_NUMBER;
574         Set<Integer> lockOn = new HashSet<>(Arrays.asList(WifiLockStateChanged.State.ON_VALUE));
575         Set<Integer> lockOff = new HashSet<>(Arrays.asList(WifiLockStateChanged.State.OFF_VALUE));
576 
577         // Add state sets to the list in order.
578         List<Set<Integer>> stateSet = Arrays.asList(lockOn, lockOff);
579 
580         createAndUploadConfig(atomTag, true);  // True: uses attribution.
581         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWifiLock");
582 
583         // Sorted list of events in order in which they occurred.
584         List<EventMetricData> data = getEventMetricDataList();
585 
586         // Assert that the events happened in the expected order.
587         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
588                 atom -> atom.getWifiLockStateChanged().getState().getNumber());
589     }
590 
testWifiMulticastLock()591     public void testWifiMulticastLock() throws Exception {
592         if (statsdDisabled()) {
593             return;
594         }
595         if (!hasFeature(FEATURE_WIFI, true)) return;
596 
597         final int atomTag = Atom.WIFI_MULTICAST_LOCK_STATE_CHANGED_FIELD_NUMBER;
598         Set<Integer> lockOn = new HashSet<>(
599                 Arrays.asList(WifiMulticastLockStateChanged.State.ON_VALUE));
600         Set<Integer> lockOff = new HashSet<>(
601                 Arrays.asList(WifiMulticastLockStateChanged.State.OFF_VALUE));
602 
603         // Add state sets to the list in order.
604         List<Set<Integer>> stateSet = Arrays.asList(lockOn, lockOff);
605 
606         createAndUploadConfig(atomTag, true);
607         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWifiMulticastLock");
608 
609         // Sorted list of events in order in which they occurred.
610         List<EventMetricData> data = getEventMetricDataList();
611 
612         // Assert that the events happened in the expected order.
613         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
614                 atom -> atom.getWifiMulticastLockStateChanged().getState().getNumber());
615     }
616 
testWifiScan()617     public void testWifiScan() throws Exception {
618         if (statsdDisabled()) {
619             return;
620         }
621         if (!hasFeature(FEATURE_WIFI, true)) return;
622 
623         final int atom = Atom.WIFI_SCAN_STATE_CHANGED_FIELD_NUMBER;
624         final int key = WifiScanStateChanged.STATE_FIELD_NUMBER;
625         final int stateOn = WifiScanStateChanged.State.ON_VALUE;
626         final int stateOff = WifiScanStateChanged.State.OFF_VALUE;
627         final int minTimeDiffMillis = 250;
628         final int maxTimeDiffMillis = 60_000;
629         final boolean demandExactlyTwo = false; // Two scans are performed, so up to 4 atoms logged.
630 
631         List<EventMetricData> data = doDeviceMethodOnOff("testWifiScan", atom, key,
632                 stateOn, stateOff, minTimeDiffMillis, maxTimeDiffMillis, demandExactlyTwo);
633 
634         assertTrue(data.size() >= 2);
635         assertTrue(data.size() <= 4);
636         WifiScanStateChanged a0 = data.get(0).getAtom().getWifiScanStateChanged();
637         WifiScanStateChanged a1 = data.get(1).getAtom().getWifiScanStateChanged();
638         assertTrue(a0.getState().getNumber() == stateOn);
639         assertTrue(a1.getState().getNumber() == stateOff);
640     }
641 
testAudioState()642     public void testAudioState() throws Exception {
643         if (statsdDisabled()) {
644             return;
645         }
646         if (!hasFeature(FEATURE_AUDIO_OUTPUT, true)) return;
647 
648         final int atomTag = Atom.AUDIO_STATE_CHANGED_FIELD_NUMBER;
649         final String name = "testAudioState";
650 
651         Set<Integer> onState = new HashSet<>(
652                 Arrays.asList(AudioStateChanged.State.ON_VALUE));
653         Set<Integer> offState = new HashSet<>(
654                 Arrays.asList(AudioStateChanged.State.OFF_VALUE));
655 
656         // Add state sets to the list in order.
657         List<Set<Integer>> stateSet = Arrays.asList(onState, offState);
658 
659         createAndUploadConfig(atomTag, true);  // True: uses attribution.
660         Thread.sleep(WAIT_TIME_SHORT);
661 
662         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", name);
663 
664         Thread.sleep(WAIT_TIME_SHORT);
665         // Sorted list of events in order in which they occurred.
666         List<EventMetricData> data = getEventMetricDataList();
667 
668         // AudioStateChanged timestamp is fuzzed to 5min buckets
669         assertStatesOccurred(stateSet, data, 0,
670                 atom -> atom.getAudioStateChanged().getState().getNumber());
671     }
672 
testMediaCodecActivity()673     public void testMediaCodecActivity() throws Exception {
674         if (statsdDisabled()) {
675             return;
676         }
677         if (!hasFeature(FEATURE_WATCH, false)) return;
678         final int atomTag = Atom.MEDIA_CODEC_STATE_CHANGED_FIELD_NUMBER;
679 
680         Set<Integer> onState = new HashSet<>(
681                 Arrays.asList(MediaCodecStateChanged.State.ON_VALUE));
682         Set<Integer> offState = new HashSet<>(
683                 Arrays.asList(MediaCodecStateChanged.State.OFF_VALUE));
684 
685         // Add state sets to the list in order.
686         List<Set<Integer>> stateSet = Arrays.asList(onState, offState);
687 
688         createAndUploadConfig(atomTag, true);  // True: uses attribution.
689         Thread.sleep(WAIT_TIME_SHORT);
690 
691         runActivity("VideoPlayerActivity", "action", "action.play_video");
692 
693         // Sorted list of events in order in which they occurred.
694         List<EventMetricData> data = getEventMetricDataList();
695 
696         // Assert that the events happened in the expected order.
697         assertStatesOccurred(stateSet, data, WAIT_TIME_LONG,
698                 atom -> atom.getMediaCodecStateChanged().getState().getNumber());
699     }
700 
testPictureInPictureState()701     public void testPictureInPictureState() throws Exception {
702         if (statsdDisabled()) {
703             return;
704         }
705         if (!hasFeature(FEATURE_WATCH, false) ||
706             !hasFeature(FEATURE_PICTURE_IN_PICTURE, true)) return;
707         final int atomTag = Atom.PICTURE_IN_PICTURE_STATE_CHANGED_FIELD_NUMBER;
708 
709         Set<Integer> entered = new HashSet<>(
710                 Arrays.asList(PictureInPictureStateChanged.State.ENTERED_VALUE));
711 
712         // Add state sets to the list in order.
713         List<Set<Integer>> stateSet = Arrays.asList(entered);
714 
715         createAndUploadConfig(atomTag, false);
716 
717         runActivity("VideoPlayerActivity", "action", "action.play_video_picture_in_picture_mode");
718 
719         // Sorted list of events in order in which they occurred.
720         List<EventMetricData> data = getEventMetricDataList();
721 
722         // Assert that the events happened in the expected order.
723         assertStatesOccurred(stateSet, data, WAIT_TIME_LONG,
724                 atom -> atom.getPictureInPictureStateChanged().getState().getNumber());
725     }
726 
testAppCrashOccurred()727     public void testAppCrashOccurred() throws Exception {
728         if (statsdDisabled()) {
729             return;
730         }
731         final int atomTag = Atom.APP_CRASH_OCCURRED_FIELD_NUMBER;
732         createAndUploadConfig(atomTag, false);
733         Thread.sleep(WAIT_TIME_SHORT);
734 
735         runActivity("StatsdCtsForegroundActivity", "action", "action.crash");
736 
737         Thread.sleep(WAIT_TIME_SHORT);
738         // Sorted list of events in order in which they occurred.
739         List<EventMetricData> data = getEventMetricDataList();
740 
741         AppCrashOccurred atom = data.get(0).getAtom().getAppCrashOccurred();
742         assertEquals("crash", atom.getEventType());
743         assertEquals(AppCrashOccurred.InstantApp.FALSE_VALUE, atom.getIsInstantApp().getNumber());
744         assertEquals(AppCrashOccurred.ForegroundState.FOREGROUND_VALUE,
745                 atom.getForegroundState().getNumber());
746         assertEquals("com.android.server.cts.device.statsd", atom.getPackageName());
747     }
748 }
749