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