1 /*
2  * Copyright (C) 2018 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.validation;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 import static com.google.common.truth.Truth.assertWithMessage;
20 
21 import android.cts.statsd.atom.DeviceAtomTestCase;
22 import android.os.BatteryPluggedStateEnum;
23 import android.os.BatteryStatsProto;
24 import android.os.UidProto;
25 import android.os.UidProto.Wakelock;
26 import android.os.WakeLockLevelEnum;
27 import android.platform.test.annotations.RestrictedBuildTest;
28 import android.view.DisplayStateEnum;
29 
30 import com.android.internal.os.StatsdConfigProto.AtomMatcher;
31 import com.android.internal.os.StatsdConfigProto.DurationMetric;
32 import com.android.internal.os.StatsdConfigProto.FieldMatcher;
33 import com.android.internal.os.StatsdConfigProto.FieldValueMatcher;
34 import com.android.internal.os.StatsdConfigProto.LogicalOperation;
35 import com.android.internal.os.StatsdConfigProto.Position;
36 import com.android.internal.os.StatsdConfigProto.Predicate;
37 import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
38 import com.android.internal.os.StatsdConfigProto.SimplePredicate;
39 import com.android.internal.os.StatsdConfigProto.StatsdConfig;
40 import com.android.internal.os.StatsdConfigProto.TimeUnit;
41 import com.android.os.AtomsProto.Atom;
42 import com.android.os.AtomsProto.PluggedStateChanged;
43 import com.android.os.AtomsProto.ScreenStateChanged;
44 import com.android.os.AtomsProto.WakelockStateChanged;
45 import com.android.os.StatsLog.DimensionsValue;
46 import com.android.os.StatsLog.DurationBucketInfo;
47 import com.android.os.StatsLog.DurationMetricData;
48 import com.android.os.StatsLog.EventMetricData;
49 import com.android.os.StatsLog.StatsLogReport;
50 import com.android.tradefed.log.LogUtil.CLog;
51 
52 import com.google.common.collect.Range;
53 
54 import java.util.Arrays;
55 import java.util.HashMap;
56 import java.util.HashSet;
57 import java.util.List;
58 import java.util.Set;
59 
60 /**
61  * Side-by-side comparison between statsd and batterystats.
62  */
63 public class ValidationTests extends DeviceAtomTestCase {
64 
65     private static final String TAG = "Statsd.ValidationTests";
66     private static final String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
67     private static final boolean ENABLE_LOAD_TEST = false;
68 
69     @Override
70     protected void setUp() throws Exception {
71         super.setUp();
72         turnBatteryStatsAutoResetOff(); // Turn off Battery Stats auto resetting
73     }
74 
75     @Override
76     protected void tearDown() throws Exception {
77         resetBatteryStatus(); // Undo any unplugDevice().
78         turnScreenOn(); // Reset screen to on state
79         turnBatteryStatsAutoResetOn(); // Turn Battery Stats auto resetting back on
80         super.tearDown();
81     }
82 
83     public void testPartialWakelock() throws Exception {
84         if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return;
85         resetBatteryStats();
86         unplugDevice();
87         flushBatteryStatsHandlers();
88         // AoD needs to be turned off because the screen should go into an off state. But, if AoD is
89         // on and the device doesn't support STATE_DOZE, the screen sadly goes back to STATE_ON.
90         String aodState = getAodState();
91         setAodState("0");
92         turnScreenOff();
93 
94         final int atomTag = Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER;
95         Set<Integer> wakelockOn = new HashSet<>(Arrays.asList(
96                 WakelockStateChanged.State.ACQUIRE_VALUE,
97                 WakelockStateChanged.State.CHANGE_ACQUIRE_VALUE));
98         Set<Integer> wakelockOff = new HashSet<>(Arrays.asList(
99                 WakelockStateChanged.State.RELEASE_VALUE,
100                 WakelockStateChanged.State.CHANGE_RELEASE_VALUE));
101 
102         final String EXPECTED_TAG = "StatsdPartialWakelock";
103         final WakeLockLevelEnum EXPECTED_LEVEL = WakeLockLevelEnum.PARTIAL_WAKE_LOCK;
104 
105         // Add state sets to the list in order.
106         List<Set<Integer>> stateSet = Arrays.asList(wakelockOn, wakelockOff);
107 
108         createAndUploadConfig(atomTag, true);  // True: uses attribution.
109         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWakelockState");
110 
111         // Sorted list of events in order in which they occurred.
112         List<EventMetricData> data = getEventMetricDataList();
113 
114         //=================== verify that statsd is correct ===============//
115         // Assert that the events happened in the expected order.
116         assertStatesOccurred(stateSet, data, WAIT_TIME_SHORT,
117                 atom -> atom.getWakelockStateChanged().getState().getNumber());
118 
119         for (EventMetricData event : data) {
120             String tag = event.getAtom().getWakelockStateChanged().getTag();
121             WakeLockLevelEnum type = event.getAtom().getWakelockStateChanged().getType();
122             assertThat(tag).isEqualTo(EXPECTED_TAG);
123             assertThat(type).isEqualTo(EXPECTED_LEVEL);
124         }
125     }
126 
127     @RestrictedBuildTest
128     public void testPartialWakelockDuration() throws Exception {
129         if (!hasFeature(FEATURE_AUTOMOTIVE, false)) return;
130 
131         // getUid() needs shell command via ADB. turnScreenOff() sometimes let system go to suspend.
132         // ADB disconnection causes failure of getUid(). Move up here before turnScreenOff().
133         final int EXPECTED_UID = getUid();
134 
135         turnScreenOn(); // To ensure that the ScreenOff later gets logged.
136         // AoD needs to be turned off because the screen should go into an off state. But, if AoD is
137         // on and the device doesn't support STATE_DOZE, the screen sadly goes back to STATE_ON.
138         String aodState = getAodState();
139         setAodState("0");
140         uploadWakelockDurationBatteryStatsConfig(TimeUnit.CTS);
141         Thread.sleep(WAIT_TIME_SHORT);
142         resetBatteryStats();
143         unplugDevice();
144         turnScreenOff();
145 
146         Thread.sleep(WAIT_TIME_SHORT);
147 
148         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWakelockState");
149         Thread.sleep(WAIT_TIME_LONG); // Make sure the one second bucket has ended.
150 
151 
152         final String EXPECTED_TAG = "StatsdPartialWakelock";
153         final long EXPECTED_TAG_HASH = Long.parseUnsignedLong("15814523794762874414");
154         final int MIN_DURATION = 350;
155         final int MAX_DURATION = 700;
156 
157         HashMap<Integer, HashMap<Long, Long>> statsdWakelockData = getStatsdWakelockData();
158 
159         // Get the statsd wakelock time and make sure it's reasonable.
160         assertWithMessage("No wakelocks with uid %s in statsd", EXPECTED_UID)
161                 .that(statsdWakelockData).containsKey(EXPECTED_UID);
162         assertWithMessage("No wakelocks with tag %s in statsd", EXPECTED_TAG)
163                 .that(statsdWakelockData.get(EXPECTED_UID)).containsKey(EXPECTED_TAG_HASH);
164         long statsdDurationMs = statsdWakelockData.get(EXPECTED_UID)
165                 .get(EXPECTED_TAG_HASH) / 1_000_000;
166         assertWithMessage(
167                 "Wakelock in statsd with uid %s and tag %s was too short or too long",
168                 EXPECTED_UID, EXPECTED_TAG
169         ).that(statsdDurationMs).isIn(Range.closed((long) MIN_DURATION, (long) MAX_DURATION));
170 
171         setAodState(aodState); // restores AOD to initial state.
172     }
173 
174     public void testPartialWakelockLoad() throws Exception {
175         if (!ENABLE_LOAD_TEST) return;
176         turnScreenOn(); // To ensure that the ScreenOff later gets logged.
177         uploadWakelockDurationBatteryStatsConfig(TimeUnit.CTS);
178         Thread.sleep(WAIT_TIME_SHORT);
179         resetBatteryStats();
180         unplugDevice();
181         turnScreenOff();
182 
183         runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".AtomTests", "testWakelockLoad");
184         // Give time for stuck wakelocks to increase duration.
185         Thread.sleep(10_000);
186 
187 
188         final String EXPECTED_TAG = "StatsdPartialWakelock";
189         final int EXPECTED_UID = getUid();
190         final int NUM_THREADS = 16;
191         final int NUM_COUNT_PER_THREAD = 1000;
192         final int MAX_DURATION_MS = 15_000;
193         final int MIN_DURATION_MS = 1_000;
194 
195 
196         BatteryStatsProto batterystatsProto = getBatteryStatsProto();
197         HashMap<Integer, HashMap<Long, Long>> statsdWakelockData = getStatsdWakelockData();
198 
199         // TODO: this fails because we only have the hashes of the wakelock tags in statsd.
200         // If we want to run this test, we need to fix this.
201 
202         // Verify batterystats output is reasonable.
203         // boolean foundUid = false;
204         // for (UidProto uidProto : batterystatsProto.getUidsList()) {
205         //     if (uidProto.getUid() == EXPECTED_UID) {
206         //         foundUid = true;
207         //         CLog.d("Battery stats has the following wakelocks: \n" +
208         //                 uidProto.getWakelocksList());
209         //         assertTrue("UidProto has size "  + uidProto.getWakelocksList().size() +
210         //                 " wakelocks in it. Expected " + NUM_THREADS + " wakelocks.",
211         //                 uidProto.getWakelocksList().size() == NUM_THREADS);
212         //
213         //         for (Wakelock wl : uidProto.getWakelocksList()) {
214         //             String tag = wl.getName();
215         //             assertTrue("Wakelock tag in batterystats " + tag + " does not contain "
216         //                     + "expected tag " + EXPECTED_TAG, tag.contains(EXPECTED_TAG));
217         //             assertTrue("Wakelock in batterystats with tag " + tag + " does not have any "
218         //                             + "partial wakelock data.", wl.hasPartial());
219         //             assertTrue("Wakelock in batterystats with tag " + tag + " tag has count " +
220         //                     wl.getPartial().getCount() + " Expected " + NUM_COUNT_PER_THREAD,
221         //                     wl.getPartial().getCount() == NUM_COUNT_PER_THREAD);
222         //             long bsDurationMs = wl.getPartial().getTotalDurationMs();
223         //             assertTrue("Wakelock in batterystats with uid " + EXPECTED_UID + " and tag "
224         //                     + EXPECTED_TAG + "was too short. Expected " + MIN_DURATION_MS +
225         //                     ", received " + bsDurationMs, bsDurationMs >= MIN_DURATION_MS);
226         //             assertTrue("Wakelock in batterystats with uid " + EXPECTED_UID + " and tag "
227         //                     + EXPECTED_TAG + "was too long. Expected " + MAX_DURATION_MS +
228         //                     ", received " + bsDurationMs, bsDurationMs <= MAX_DURATION_MS);
229         //
230         //             // Validate statsd.
231         //             long statsdDurationNs = statsdWakelockData.get(EXPECTED_UID).get(tag);
232         //             long statsdDurationMs = statsdDurationNs / 1_000_000;
233         //             long difference = Math.abs(statsdDurationMs - bsDurationMs);
234         //             assertTrue("Unusually large difference in wakelock duration for tag: " +
235         // tag +
236         //                         ". Statsd had duration " + statsdDurationMs +
237         //                         " and batterystats had duration " + bsDurationMs,
238         //                         difference <= bsDurationMs / 10);
239         //
240         //         }
241         //     }
242         // }
243         // assertTrue("Did not find uid " + EXPECTED_UID + " in batterystats.", foundUid);
244         //
245         // // Assert that the wakelock appears in statsd and is correct.
246         // assertTrue("Could not find any wakelocks with uid " + EXPECTED_UID + " in statsd",
247         //         statsdWakelockData.containsKey(EXPECTED_UID));
248         // HashMap<String, Long> expectedWakelocks = statsdWakelockData.get(EXPECTED_UID);
249         // assertEquals("Expected " + NUM_THREADS + " wakelocks in statsd with UID " +
250         // EXPECTED_UID +
251         //         ". Received " + expectedWakelocks.size(), expectedWakelocks.size(), NUM_THREADS);
252     }
253 
254     // Helper functions
255     // TODO: Refactor these into some utils class.
256 
257     public HashMap<Integer, HashMap<Long, Long>> getStatsdWakelockData() throws Exception {
258         StatsLogReport report = getStatsLogReport();
259         CLog.d("Received the following stats log report: \n" + report.toString());
260 
261         // Stores total duration of each wakelock across buckets.
262         HashMap<Integer, HashMap<Long, Long>> statsdWakelockData = new HashMap<>();
263 
264         for (DurationMetricData data : report.getDurationMetrics().getDataList()) {
265             // Gets tag and uid.
266             List<DimensionsValue> dims = data.getDimensionLeafValuesInWhatList();
267             assertThat(dims).hasSize(2);
268             boolean hasTag = false;
269             long tag = 0;
270             int uid = -1;
271             long duration = 0;
272             for (DimensionsValue dim : dims) {
273                 if (dim.hasValueInt()) {
274                     uid = dim.getValueInt();
275                 } else if (dim.hasValueStrHash()) {
276                     hasTag = true;
277                     tag = dim.getValueStrHash();
278                 }
279             }
280             assertWithMessage("Did not receive a tag for the wakelock").that(hasTag).isTrue();
281             assertWithMessage("Did not receive a uid for the wakelock").that(uid).isNotEqualTo(-1);
282 
283             // Gets duration.
284             for (DurationBucketInfo bucketInfo : data.getBucketInfoList()) {
285                 duration += bucketInfo.getDurationNanos();
286             }
287 
288             // Store the info.
289             if (statsdWakelockData.containsKey(uid)) {
290                 HashMap<Long, Long> tagToDuration = statsdWakelockData.get(uid);
291                 tagToDuration.put(tag, duration);
292             } else {
293                 HashMap<Long, Long> tagToDuration = new HashMap<>();
294                 tagToDuration.put(tag, duration);
295                 statsdWakelockData.put(uid, tagToDuration);
296             }
297         }
298         CLog.d("follow: statsdwakelockdata is: " + statsdWakelockData);
299         return statsdWakelockData;
300     }
301 
302     private android.os.TimerProto getBatteryStatsPartialWakelock(BatteryStatsProto proto,
303             long uid, String tag) {
304         if (proto.getUidsList().size() < 1) {
305             CLog.w("Batterystats proto contains no uids");
306             return null;
307         }
308         boolean hadUid = false;
309         for (UidProto uidProto : proto.getUidsList()) {
310             if (uidProto.getUid() == uid) {
311                 hadUid = true;
312                 for (Wakelock wl : uidProto.getWakelocksList()) {
313                     if (tag.equals(wl.getName())) {
314                         if (wl.hasPartial()) {
315                             return wl.getPartial();
316                         }
317                         CLog.w("Batterystats had wakelock for uid (" + uid + ") "
318                                 + "with tag (" + tag + ") "
319                                 + "but it didn't have a partial wakelock");
320                     }
321                 }
322                 CLog.w("Batterystats didn't have a partial wakelock for uid " + uid
323                         + " with tag " + tag);
324             }
325         }
326         if (!hadUid) CLog.w("Batterystats didn't have uid " + uid);
327         return null;
328     }
329 
330     public void uploadWakelockDurationBatteryStatsConfig(TimeUnit bucketsize) throws Exception {
331         final int atomTag = Atom.WAKELOCK_STATE_CHANGED_FIELD_NUMBER;
332         String metricName = "DURATION_PARTIAL_WAKELOCK_PER_TAG_UID_WHILE_SCREEN_OFF_ON_BATTERY";
333         int metricId = metricName.hashCode();
334 
335         String partialWakelockIsOnName = "PARTIAL_WAKELOCK_IS_ON";
336         int partialWakelockIsOnId = partialWakelockIsOnName.hashCode();
337 
338         String partialWakelockOnName = "PARTIAL_WAKELOCK_ON";
339         int partialWakelockOnId = partialWakelockOnName.hashCode();
340         String partialWakelockOffName = "PARTIAL_WAKELOCK_OFF";
341         int partialWakelockOffId = partialWakelockOffName.hashCode();
342 
343         String partialWakelockAcquireName = "PARTIAL_WAKELOCK_ACQUIRE";
344         int partialWakelockAcquireId = partialWakelockAcquireName.hashCode();
345         String partialWakelockChangeAcquireName = "PARTIAL_WAKELOCK_CHANGE_ACQUIRE";
346         int partialWakelockChangeAcquireId = partialWakelockChangeAcquireName.hashCode();
347 
348         String partialWakelockReleaseName = "PARTIAL_WAKELOCK_RELEASE";
349         int partialWakelockReleaseId = partialWakelockReleaseName.hashCode();
350         String partialWakelockChangeReleaseName = "PARTIAL_WAKELOCK_CHANGE_RELEASE";
351         int partialWakelockChangeReleaseId = partialWakelockChangeReleaseName.hashCode();
352 
353 
354         String screenOffBatteryOnName = "SCREEN_IS_OFF_ON_BATTERY";
355         int screenOffBatteryOnId = screenOffBatteryOnName.hashCode();
356 
357         String screenStateUnknownName = "SCREEN_STATE_UNKNOWN";
358         int screenStateUnknownId = screenStateUnknownName.hashCode();
359         String screenStateOffName = "SCREEN_STATE_OFF";
360         int screenStateOffId = screenStateOffName.hashCode();
361         String screenStateOnName = "SCREEN_STATE_ON";
362         int screenStateOnId = screenStateOnName.hashCode();
363         String screenStateDozeName = "SCREEN_STATE_DOZE";
364         int screenStateDozeId = screenStateDozeName.hashCode();
365         String screenStateDozeSuspendName = "SCREEN_STATE_DOZE_SUSPEND";
366         int screenStateDozeSuspendId = screenStateDozeSuspendName.hashCode();
367         String screenStateVrName = "SCREEN_STATE_VR";
368         int screenStateVrId = screenStateVrName.hashCode();
369         String screenStateOnSuspendName = "SCREEN_STATE_ON_SUSPEND";
370         int screenStateOnSuspendId = screenStateOnSuspendName.hashCode();
371 
372         String screenTurnedOnName = "SCREEN_TURNED_ON";
373         int screenTurnedOnId = screenTurnedOnName.hashCode();
374         String screenTurnedOffName = "SCREEN_TURNED_OFF";
375         int screenTurnedOffId = screenTurnedOffName.hashCode();
376 
377         String screenIsOffName = "SCREEN_IS_OFF";
378         int screenIsOffId = screenIsOffName.hashCode();
379 
380         String pluggedStateBatteryPluggedNoneName = "PLUGGED_STATE_BATTERY_PLUGGED_NONE";
381         int pluggedStateBatteryPluggedNoneId = pluggedStateBatteryPluggedNoneName.hashCode();
382         String pluggedStateBatteryPluggedAcName = "PLUGGED_STATE_BATTERY_PLUGGED_AC";
383         int pluggedStateBatteryPluggedAcId = pluggedStateBatteryPluggedAcName.hashCode();
384         String pluggedStateBatteryPluggedUsbName = "PLUGGED_STATE_BATTERY_PLUGGED_USB";
385         int pluggedStateBatteryPluggedUsbId = pluggedStateBatteryPluggedUsbName.hashCode();
386         String pluggedStateBatteryPluggedWlName = "PLUGGED_STATE_BATTERY_PLUGGED_WIRELESS";
387         int pluggedStateBatteryPluggedWirelessId = pluggedStateBatteryPluggedWlName.hashCode();
388 
389         String pluggedStateBatteryPluggedName = "PLUGGED_STATE_BATTERY_PLUGGED";
390         int pluggedStateBatteryPluggedId = pluggedStateBatteryPluggedName.hashCode();
391 
392         String deviceIsUnpluggedName = "DEVICE_IS_UNPLUGGED";
393         int deviceIsUnpluggedId = deviceIsUnpluggedName.hashCode();
394 
395 
396         FieldMatcher.Builder dimensions = FieldMatcher.newBuilder()
397                 .setField(atomTag)
398                 .addChild(FieldMatcher.newBuilder()
399                         .setField(WakelockStateChanged.TAG_FIELD_NUMBER))
400                 .addChild(FieldMatcher.newBuilder()
401                         .setField(1)
402                         .setPosition(Position.FIRST)
403                         .addChild(FieldMatcher.newBuilder()
404                                 .setField(1)));
405 
406         AtomMatcher.Builder wakelockAcquire = AtomMatcher.newBuilder()
407                 .setId(partialWakelockAcquireId)
408                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
409                         .setAtomId(atomTag)
410                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
411                                 .setField(WakelockStateChanged.TYPE_FIELD_NUMBER)
412                                 .setEqInt(WakeLockLevelEnum.PARTIAL_WAKE_LOCK_VALUE))
413                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
414                                 .setField(WakelockStateChanged.STATE_FIELD_NUMBER)
415                                 .setEqInt(WakelockStateChanged.State.ACQUIRE_VALUE)));
416 
417         AtomMatcher.Builder wakelockChangeAcquire = AtomMatcher.newBuilder()
418                 .setId(partialWakelockChangeAcquireId)
419                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
420                         .setAtomId(atomTag)
421                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
422                                 .setField(WakelockStateChanged.TYPE_FIELD_NUMBER)
423                                 .setEqInt(WakeLockLevelEnum.PARTIAL_WAKE_LOCK_VALUE))
424                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
425                                 .setField(WakelockStateChanged.STATE_FIELD_NUMBER)
426                                 .setEqInt(WakelockStateChanged.State.CHANGE_ACQUIRE_VALUE)));
427 
428         AtomMatcher.Builder wakelockRelease = AtomMatcher.newBuilder()
429                 .setId(partialWakelockReleaseId)
430                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
431                         .setAtomId(atomTag)
432                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
433                                 .setField(WakelockStateChanged.TYPE_FIELD_NUMBER)
434                                 .setEqInt(WakeLockLevelEnum.PARTIAL_WAKE_LOCK_VALUE))
435                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
436                                 .setField(WakelockStateChanged.STATE_FIELD_NUMBER)
437                                 .setEqInt(WakelockStateChanged.State.RELEASE_VALUE)));
438 
439         AtomMatcher.Builder wakelockChangeRelease = AtomMatcher.newBuilder()
440                 .setId(partialWakelockChangeReleaseId)
441                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
442                         .setAtomId(atomTag)
443                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
444                                 .setField(WakelockStateChanged.TYPE_FIELD_NUMBER)
445                                 .setEqInt(WakeLockLevelEnum.PARTIAL_WAKE_LOCK_VALUE))
446                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
447                                 .setField(WakelockStateChanged.STATE_FIELD_NUMBER)
448                                 .setEqInt(WakelockStateChanged.State.CHANGE_RELEASE_VALUE)));
449 
450         AtomMatcher.Builder wakelockOn = AtomMatcher.newBuilder()
451                 .setId(partialWakelockOnId)
452                 .setCombination(AtomMatcher.Combination.newBuilder()
453                         .setOperation(LogicalOperation.OR)
454                         .addMatcher(partialWakelockAcquireId)
455                         .addMatcher(partialWakelockChangeAcquireId));
456 
457         AtomMatcher.Builder wakelockOff = AtomMatcher.newBuilder()
458                 .setId(partialWakelockOffId)
459                 .setCombination(AtomMatcher.Combination.newBuilder()
460                         .setOperation(LogicalOperation.OR)
461                         .addMatcher(partialWakelockReleaseId)
462                         .addMatcher(partialWakelockChangeReleaseId));
463 
464 
465         Predicate.Builder wakelockPredicate = Predicate.newBuilder()
466                 .setId(partialWakelockIsOnId)
467                 .setSimplePredicate(SimplePredicate.newBuilder()
468                         .setStart(partialWakelockOnId)
469                         .setStop(partialWakelockOffId)
470                         .setCountNesting(true)
471                         .setDimensions(dimensions));
472 
473         AtomMatcher.Builder pluggedStateBatteryPluggedNone = AtomMatcher.newBuilder()
474                 .setId(pluggedStateBatteryPluggedNoneId)
475                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
476                         .setAtomId(Atom.PLUGGED_STATE_CHANGED_FIELD_NUMBER)
477                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
478                                 .setField(PluggedStateChanged.STATE_FIELD_NUMBER)
479                                 .setEqInt(BatteryPluggedStateEnum.BATTERY_PLUGGED_NONE_VALUE)));
480 
481         AtomMatcher.Builder pluggedStateBatteryPluggedAc = AtomMatcher.newBuilder()
482                 .setId(pluggedStateBatteryPluggedAcId)
483                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
484                         .setAtomId(Atom.PLUGGED_STATE_CHANGED_FIELD_NUMBER)
485                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
486                                 .setField(PluggedStateChanged.STATE_FIELD_NUMBER)
487                                 .setEqInt(BatteryPluggedStateEnum.BATTERY_PLUGGED_AC_VALUE)));
488 
489         AtomMatcher.Builder pluggedStateBatteryPluggedUsb = AtomMatcher.newBuilder()
490                 .setId(pluggedStateBatteryPluggedUsbId)
491                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
492                         .setAtomId(Atom.PLUGGED_STATE_CHANGED_FIELD_NUMBER)
493                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
494                                 .setField(PluggedStateChanged.STATE_FIELD_NUMBER)
495                                 .setEqInt(BatteryPluggedStateEnum.BATTERY_PLUGGED_USB_VALUE)));
496 
497         AtomMatcher.Builder pluggedStateBatteryPluggedWireless = AtomMatcher.newBuilder()
498                 .setId(pluggedStateBatteryPluggedWirelessId)
499                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
500                         .setAtomId(Atom.PLUGGED_STATE_CHANGED_FIELD_NUMBER)
501                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
502                                 .setField(PluggedStateChanged.STATE_FIELD_NUMBER)
503                                 .setEqInt(BatteryPluggedStateEnum.BATTERY_PLUGGED_WIRELESS_VALUE)));
504 
505         AtomMatcher.Builder pluggedStateBatteryPlugged = AtomMatcher.newBuilder()
506                 .setId(pluggedStateBatteryPluggedId)
507                 .setCombination(AtomMatcher.Combination.newBuilder()
508                         .setOperation(LogicalOperation.OR)
509                         .addMatcher(pluggedStateBatteryPluggedAcId)
510                         .addMatcher(pluggedStateBatteryPluggedUsbId)
511                         .addMatcher(pluggedStateBatteryPluggedWirelessId));
512 
513         Predicate.Builder deviceIsUnplugged = Predicate.newBuilder()
514                 .setId(deviceIsUnpluggedId)
515                 .setSimplePredicate(SimplePredicate.newBuilder()
516                         .setStart(pluggedStateBatteryPluggedNoneId)
517                         .setStop(pluggedStateBatteryPluggedId)
518                         .setCountNesting(false));
519 
520         AtomMatcher.Builder screenStateUnknown = AtomMatcher.newBuilder()
521                 .setId(screenStateUnknownId)
522                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
523                         .setAtomId(Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER)
524                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
525                                 .setField(ScreenStateChanged.STATE_FIELD_NUMBER)
526                                 .setEqInt(DisplayStateEnum.DISPLAY_STATE_UNKNOWN_VALUE)));
527 
528         AtomMatcher.Builder screenStateOff = AtomMatcher.newBuilder()
529                 .setId(screenStateOffId)
530                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
531                         .setAtomId(Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER)
532                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
533                                 .setField(ScreenStateChanged.STATE_FIELD_NUMBER)
534                                 .setEqInt(DisplayStateEnum.DISPLAY_STATE_OFF_VALUE)));
535 
536         AtomMatcher.Builder screenStateOn = AtomMatcher.newBuilder()
537                 .setId(screenStateOnId)
538                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
539                         .setAtomId(Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER)
540                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
541                                 .setField(ScreenStateChanged.STATE_FIELD_NUMBER)
542                                 .setEqInt(DisplayStateEnum.DISPLAY_STATE_ON_VALUE)));
543 
544         AtomMatcher.Builder screenStateDoze = AtomMatcher.newBuilder()
545                 .setId(screenStateDozeId)
546                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
547                         .setAtomId(Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER)
548                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
549                                 .setField(ScreenStateChanged.STATE_FIELD_NUMBER)
550                                 .setEqInt(DisplayStateEnum.DISPLAY_STATE_DOZE_VALUE)));
551 
552         AtomMatcher.Builder screenStateDozeSuspend = AtomMatcher.newBuilder()
553                 .setId(screenStateDozeSuspendId)
554                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
555                         .setAtomId(Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER)
556                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
557                                 .setField(ScreenStateChanged.STATE_FIELD_NUMBER)
558                                 .setEqInt(DisplayStateEnum.DISPLAY_STATE_DOZE_SUSPEND_VALUE)));
559 
560         AtomMatcher.Builder screenStateVr = AtomMatcher.newBuilder()
561                 .setId(screenStateVrId)
562                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
563                         .setAtomId(Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER)
564                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
565                                 .setField(ScreenStateChanged.STATE_FIELD_NUMBER)
566                                 .setEqInt(DisplayStateEnum.DISPLAY_STATE_VR_VALUE)));
567 
568         AtomMatcher.Builder screenStateOnSuspend = AtomMatcher.newBuilder()
569                 .setId(screenStateOnSuspendId)
570                 .setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder()
571                         .setAtomId(Atom.SCREEN_STATE_CHANGED_FIELD_NUMBER)
572                         .addFieldValueMatcher(FieldValueMatcher.newBuilder()
573                                 .setField(ScreenStateChanged.STATE_FIELD_NUMBER)
574                                 .setEqInt(DisplayStateEnum.DISPLAY_STATE_ON_SUSPEND_VALUE)));
575 
576 
577         AtomMatcher.Builder screenTurnedOff = AtomMatcher.newBuilder()
578                 .setId(screenTurnedOffId)
579                 .setCombination(AtomMatcher.Combination.newBuilder()
580                         .setOperation(LogicalOperation.OR)
581                         .addMatcher(screenStateOffId)
582                         .addMatcher(screenStateDozeId)
583                         .addMatcher(screenStateDozeSuspendId)
584                         .addMatcher(screenStateUnknownId));
585 
586         AtomMatcher.Builder screenTurnedOn = AtomMatcher.newBuilder()
587                 .setId(screenTurnedOnId)
588                 .setCombination(AtomMatcher.Combination.newBuilder()
589                         .setOperation(LogicalOperation.OR)
590                         .addMatcher(screenStateOnId)
591                         .addMatcher(screenStateOnSuspendId)
592                         .addMatcher(screenStateVrId));
593 
594         Predicate.Builder screenIsOff = Predicate.newBuilder()
595                 .setId(screenIsOffId)
596                 .setSimplePredicate(SimplePredicate.newBuilder()
597                         .setStart(screenTurnedOffId)
598                         .setStop(screenTurnedOnId)
599                         .setCountNesting(false));
600 
601 
602         Predicate.Builder screenOffBatteryOn = Predicate.newBuilder()
603                 .setId(screenOffBatteryOnId)
604                 .setCombination(Predicate.Combination.newBuilder()
605                         .setOperation(LogicalOperation.AND)
606                         .addPredicate(screenIsOffId)
607                         .addPredicate(deviceIsUnpluggedId));
608 
609         StatsdConfig.Builder builder = createConfigBuilder();
610         builder.addDurationMetric(DurationMetric.newBuilder()
611                 .setId(metricId)
612                 .setWhat(partialWakelockIsOnId)
613                 .setCondition(screenOffBatteryOnId)
614                 .setDimensionsInWhat(dimensions)
615                 .setBucket(bucketsize))
616                 .addAtomMatcher(wakelockAcquire)
617                 .addAtomMatcher(wakelockChangeAcquire)
618                 .addAtomMatcher(wakelockRelease)
619                 .addAtomMatcher(wakelockChangeRelease)
620                 .addAtomMatcher(wakelockOn)
621                 .addAtomMatcher(wakelockOff)
622                 .addAtomMatcher(pluggedStateBatteryPluggedNone)
623                 .addAtomMatcher(pluggedStateBatteryPluggedAc)
624                 .addAtomMatcher(pluggedStateBatteryPluggedUsb)
625                 .addAtomMatcher(pluggedStateBatteryPluggedWireless)
626                 .addAtomMatcher(pluggedStateBatteryPlugged)
627                 .addAtomMatcher(screenStateUnknown)
628                 .addAtomMatcher(screenStateOff)
629                 .addAtomMatcher(screenStateOn)
630                 .addAtomMatcher(screenStateDoze)
631                 .addAtomMatcher(screenStateDozeSuspend)
632                 .addAtomMatcher(screenStateVr)
633                 .addAtomMatcher(screenStateOnSuspend)
634                 .addAtomMatcher(screenTurnedOff)
635                 .addAtomMatcher(screenTurnedOn)
636                 .addPredicate(wakelockPredicate)
637                 .addPredicate(deviceIsUnplugged)
638                 .addPredicate(screenIsOff)
639                 .addPredicate(screenOffBatteryOn);
640 
641         uploadConfig(builder);
642     }
643 }
644