• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.metric;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 
20 import android.cts.statsdatom.lib.AtomTestUtils;
21 import android.cts.statsdatom.lib.ConfigUtils;
22 import android.cts.statsdatom.lib.ReportUtils;
23 
24 import com.android.internal.os.StatsdConfigProto.ActivationType;
25 import com.android.internal.os.StatsdConfigProto.AtomMatcher;
26 import com.android.internal.os.StatsdConfigProto.EventActivation;
27 import com.android.internal.os.StatsdConfigProto.FieldMatcher;
28 import com.android.internal.os.StatsdConfigProto.MetricActivation;
29 import com.android.internal.os.StatsdConfigProto.Predicate;
30 import com.android.internal.os.StatsdConfigProto.SimpleAtomMatcher;
31 import com.android.internal.os.StatsdConfigProto.SimplePredicate;
32 import com.android.internal.os.StatsdConfigProto.StatsdConfig;
33 import com.android.internal.os.StatsdConfigProto.TimeUnit;
34 import com.android.internal.os.StatsdConfigProto.ValueMetric;
35 
36 import com.android.os.AtomsProto.AppBreadcrumbReported;
37 import com.android.os.AtomsProto.Atom;
38 import com.android.os.AtomsProto.SystemElapsedRealtime;
39 import com.android.os.StatsLog.StatsLogReport;
40 import com.android.os.StatsLog.ValueBucketInfo;
41 import com.android.os.StatsLog.ValueMetricData;
42 
43 import com.android.tradefed.log.LogUtil;
44 import com.android.tradefed.testtype.DeviceTestCase;
45 import com.android.tradefed.util.RunUtil;
46 
47 import com.google.protobuf.ExtensionRegistry;
48 
49 public class ValueMetricsTests extends DeviceTestCase {
50     private static final int APP_BREADCRUMB_REPORTED_A_MATCH_START_ID = 0;
51     private static final int APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID = 1;
52     private static final int APP_BREADCRUMB_REPORTED_B_MATCH_START_ID = 2;
53 
54     @Override
setUp()55     protected void setUp() throws Exception {
56         super.setUp();
57         ConfigUtils.removeConfig(getDevice());
58         ReportUtils.clearReports(getDevice());
59         RunUtil.getDefault().sleep(1000);
60     }
61 
62     @Override
tearDown()63     protected void tearDown() throws Exception {
64         ConfigUtils.removeConfig(getDevice());
65         ReportUtils.clearReports(getDevice());
66         super.tearDown();
67     }
68 
69 
testValueMetric()70     public void testValueMetric() throws Exception {
71         // Add AtomMatcher's.
72         AtomMatcher startAtomMatcher =
73                 MetricsUtils.startAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID);
74         AtomMatcher stopAtomMatcher =
75                 MetricsUtils.stopAtomMatcher(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID);
76         AtomMatcher atomMatcher =
77                 MetricsUtils.simpleAtomMatcher(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID);
78 
79         StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
80                 MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
81         builder.addAtomMatcher(startAtomMatcher);
82         builder.addAtomMatcher(stopAtomMatcher);
83         builder.addAtomMatcher(atomMatcher);
84 
85         // Add ValueMetric.
86         builder.addValueMetric(ValueMetric.newBuilder()
87                 .setId(MetricsUtils.VALUE_METRIC_ID)
88                 .setWhat(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
89                 .setBucket(TimeUnit.CTS)
90                 .setValueField(FieldMatcher.newBuilder()
91                         .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
92                         .addChild(FieldMatcher.newBuilder().setField(
93                                 AppBreadcrumbReported.LABEL_FIELD_NUMBER)))
94                 .setDimensionsInWhat(FieldMatcher.newBuilder()
95                         .setField(APP_BREADCRUMB_REPORTED_B_MATCH_START_ID)
96                         .build())
97                 .build());
98 
99         // Upload config.
100         ConfigUtils.uploadConfig(getDevice(), builder);
101 
102         // Create AppBreadcrumbReported Start/Stop events.
103         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
104                 AppBreadcrumbReported.State.START.getNumber(), 1);
105         RunUtil.getDefault().sleep(1000);
106         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
107                 AppBreadcrumbReported.State.STOP.getNumber(), 1);
108         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
109                 AppBreadcrumbReported.State.START.getNumber(), 3);
110         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
111                 AppBreadcrumbReported.State.STOP.getNumber(), 3);
112 
113         // Wait for the metrics to propagate to statsd.
114         RunUtil.getDefault().sleep(1000);
115 
116         StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
117                 ExtensionRegistry.getEmptyRegistry());
118         LogUtil.CLog.d("Got the following value metric data: " + metricReport.toString());
119         assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
120         assertThat(metricReport.hasValueMetrics()).isTrue();
121         StatsLogReport.ValueMetricDataWrapper valueData = metricReport.getValueMetrics();
122         assertThat(valueData.getDataCount()).isEqualTo(1);
123 
124         int bucketCount = valueData.getData(0).getBucketInfoCount();
125         assertThat(bucketCount).isGreaterThan(1);
126         ValueMetricData data = valueData.getData(0);
127         int totalValue = 0;
128         for (ValueBucketInfo bucketInfo : data.getBucketInfoList()) {
129             MetricsUtils.assertBucketTimePresent(bucketInfo);
130             assertThat(bucketInfo.getValuesCount()).isEqualTo(1);
131             assertThat(bucketInfo.getValues(0).getIndex()).isEqualTo(0);
132             totalValue += (int) bucketInfo.getValues(0).getValueLong();
133         }
134         assertThat(totalValue).isEqualTo(8);
135     }
136 
137     // Test value metric with pulled atoms and across multiple buckets
testPullerAcrossBuckets()138     public void testPullerAcrossBuckets() throws Exception {
139         // Add AtomMatcher's.
140         final String predicateTrueName = "APP_BREADCRUMB_REPORTED_START";
141         final String predicateFalseName = "APP_BREADCRUMB_REPORTED_STOP";
142         final String predicateName = "APP_BREADCRUMB_REPORTED_IS_STOP";
143 
144         AtomMatcher startAtomMatcher =
145                 MetricsUtils.startAtomMatcher(predicateTrueName.hashCode());
146         AtomMatcher stopAtomMatcher =
147                 MetricsUtils.stopAtomMatcher(predicateFalseName.hashCode());
148 
149         StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
150                 MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
151         builder.addAtomMatcher(startAtomMatcher);
152         builder.addAtomMatcher(stopAtomMatcher);
153         builder.addPredicate(Predicate.newBuilder()
154                 .setId(predicateName.hashCode())
155                 .setSimplePredicate(SimplePredicate.newBuilder()
156                         .setStart(predicateTrueName.hashCode())
157                         .setStop(predicateFalseName.hashCode())
158                         .setCountNesting(false)
159                 )
160         );
161 
162         final String atomName = "SYSTEM_ELAPSED_REALTIME";
163         SimpleAtomMatcher.Builder sam = SimpleAtomMatcher.newBuilder().setAtomId(
164                 Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER);
165         builder.addAtomMatcher(AtomMatcher.newBuilder()
166                 .setId(atomName.hashCode())
167                 .setSimpleAtomMatcher(sam));
168 
169         // Add ValueMetric.
170         builder.addValueMetric(ValueMetric.newBuilder()
171                 .setId(MetricsUtils.VALUE_METRIC_ID)
172                 .setWhat(atomName.hashCode())
173                 .setBucket(TimeUnit.ONE_MINUTE)
174                 .setValueField(FieldMatcher.newBuilder()
175                         .setField(Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER)
176                         .addChild(FieldMatcher.newBuilder().setField(
177                                 SystemElapsedRealtime.TIME_MILLIS_FIELD_NUMBER)))
178                 .setCondition(predicateName.hashCode())
179                 .build());
180 
181         // Upload config.
182         ConfigUtils.uploadConfig(getDevice(), builder);
183 
184         // Create AppBreadcrumbReported Start/Stop events.
185         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
186                 AppBreadcrumbReported.State.START.getNumber(), 1);
187         // Wait for 2 min and 1 sec to capture at least 2 buckets
188         RunUtil.getDefault().sleep(2 * 60_000 + 10_000);
189         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
190                 AppBreadcrumbReported.State.STOP.getNumber(), 1);
191 
192         // Wait for the metrics to propagate to statsd.
193         RunUtil.getDefault().sleep(1_000);
194 
195         StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
196                 ExtensionRegistry.getEmptyRegistry());
197         LogUtil.CLog.d("Got the following value metric data: " + metricReport.toString());
198         assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
199         assertThat(metricReport.hasValueMetrics()).isTrue();
200         StatsLogReport.ValueMetricDataWrapper valueData = metricReport.getValueMetrics();
201         assertThat(valueData.getDataCount()).isEqualTo(1);
202 
203         int bucketCount = valueData.getData(0).getBucketInfoCount();
204         // should have at least 2 buckets
205         assertThat(bucketCount).isAtLeast(2);
206         ValueMetricData data = valueData.getData(0);
207         int totalValue = 0;
208         for (ValueBucketInfo bucketInfo : data.getBucketInfoList()) {
209             MetricsUtils.assertBucketTimePresent(bucketInfo);
210             assertThat(bucketInfo.getValuesCount()).isEqualTo(1);
211             assertThat(bucketInfo.getValues(0).getIndex()).isEqualTo(0);
212             totalValue += (int) bucketInfo.getValues(0).getValueLong();
213         }
214         // At most we lose one full min bucket
215         assertThat(totalValue).isGreaterThan(130_000 - 60_000);
216     }
217 
218     // Test value metric with pulled atoms and across multiple buckets
testMultipleEventsPerBucket()219     public void testMultipleEventsPerBucket() throws Exception {
220         // Add AtomMatcher's.
221         final String predicateTrueName = "APP_BREADCRUMB_REPORTED_START";
222         final String predicateFalseName = "APP_BREADCRUMB_REPORTED_STOP";
223         final String predicateName = "APP_BREADCRUMB_REPORTED_IS_STOP";
224 
225         AtomMatcher startAtomMatcher =
226                 MetricsUtils.startAtomMatcher(predicateTrueName.hashCode());
227         AtomMatcher stopAtomMatcher =
228                 MetricsUtils.stopAtomMatcher(predicateFalseName.hashCode());
229 
230         StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
231                 MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
232         builder.addAtomMatcher(startAtomMatcher);
233         builder.addAtomMatcher(stopAtomMatcher);
234         builder.addPredicate(Predicate.newBuilder()
235                 .setId(predicateName.hashCode())
236                 .setSimplePredicate(SimplePredicate.newBuilder()
237                         .setStart(predicateTrueName.hashCode())
238                         .setStop(predicateFalseName.hashCode())
239                         .setCountNesting(false)
240                 )
241         );
242 
243         final String atomName = "SYSTEM_ELAPSED_REALTIME";
244         SimpleAtomMatcher.Builder sam = SimpleAtomMatcher.newBuilder().setAtomId(
245                 Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER);
246         builder.addAtomMatcher(AtomMatcher.newBuilder()
247                 .setId(atomName.hashCode())
248                 .setSimpleAtomMatcher(sam));
249 
250         // Add ValueMetric.
251         builder.addValueMetric(ValueMetric.newBuilder()
252                 .setId(MetricsUtils.VALUE_METRIC_ID)
253                 .setWhat(atomName.hashCode())
254                 .setBucket(TimeUnit.ONE_MINUTE)
255                 .setValueField(FieldMatcher.newBuilder()
256                         .setField(Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER)
257                         .addChild(FieldMatcher.newBuilder().setField(
258                                 SystemElapsedRealtime.TIME_MILLIS_FIELD_NUMBER)))
259                 .setCondition(predicateName.hashCode())
260                 .build());
261 
262         // Upload config.
263         ConfigUtils.uploadConfig(getDevice(), builder);
264 
265         final int NUM_EVENTS = 10;
266         final long GAP_INTERVAL = 10_000;
267         // Create AppBreadcrumbReported Start/Stop events.
268         for (int i = 0; i < NUM_EVENTS; i++) {
269             AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
270                     AppBreadcrumbReported.State.START.getNumber(), 1);
271             RunUtil.getDefault().sleep(GAP_INTERVAL);
272             AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
273                     AppBreadcrumbReported.State.STOP.getNumber(), 1);
274             RunUtil.getDefault().sleep(GAP_INTERVAL);
275         }
276 
277         // Wait for the metrics to propagate to statsd.
278         RunUtil.getDefault().sleep(1_000);
279 
280         StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
281                 ExtensionRegistry.getEmptyRegistry());
282         LogUtil.CLog.d("Got the following value metric data: " + metricReport.toString());
283         assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
284         assertThat(metricReport.hasValueMetrics()).isTrue();
285         StatsLogReport.ValueMetricDataWrapper valueData = metricReport.getValueMetrics();
286         assertThat(valueData.getDataCount()).isEqualTo(1);
287 
288         int bucketCount = valueData.getData(0).getBucketInfoCount();
289         // should have at least 2 buckets
290         assertThat(bucketCount).isAtLeast(2);
291         ValueMetricData data = valueData.getData(0);
292         int totalValue = 0;
293         for (ValueBucketInfo bucketInfo : data.getBucketInfoList()) {
294             MetricsUtils.assertBucketTimePresent(bucketInfo);
295             assertThat(bucketInfo.getValuesCount()).isEqualTo(1);
296             assertThat(bucketInfo.getValues(0).getIndex()).isEqualTo(0);
297             totalValue += (int) bucketInfo.getValues(0).getValueLong();
298         }
299         // At most we lose one full min bucket
300         assertThat((long) totalValue).isGreaterThan(GAP_INTERVAL * NUM_EVENTS - 60_000);
301     }
302 
303     // Test value metric with pulled atoms and across multiple buckets
testPullerAcrossBucketsWithActivation()304     public void testPullerAcrossBucketsWithActivation() throws Exception {
305         StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
306                 MetricsUtils.DEVICE_SIDE_TEST_PACKAGE);
307 
308         // Add AtomMatcher's.
309         int activationAtomMatcherId = 1;
310         int activationAtomMatcherLabel = 1;
311         AtomMatcher activationAtomMatcher =
312                 MetricsUtils.appBreadcrumbMatcherWithLabel(
313                         activationAtomMatcherId, activationAtomMatcherLabel);
314         final String atomName = "SYSTEM_ELAPSED_REALTIME";
315         SimpleAtomMatcher.Builder sam = SimpleAtomMatcher.newBuilder()
316                 .setAtomId(Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER);
317         builder.addAtomMatcher(activationAtomMatcher)
318                 .addAtomMatcher(AtomMatcher.newBuilder()
319                         .setId(atomName.hashCode())
320                         .setSimpleAtomMatcher(sam));
321 
322         // Add ValueMetric.
323         builder.addValueMetric(ValueMetric.newBuilder()
324                 .setId(MetricsUtils.VALUE_METRIC_ID)
325                 .setWhat(atomName.hashCode())
326                 .setBucket(TimeUnit.ONE_MINUTE)
327                 .setValueField(FieldMatcher.newBuilder()
328                         .setField(Atom.SYSTEM_ELAPSED_REALTIME_FIELD_NUMBER)
329                         .addChild(FieldMatcher.newBuilder().setField(
330                                 SystemElapsedRealtime.TIME_MILLIS_FIELD_NUMBER)))
331                 .build());
332         // Add activation.
333         builder.addMetricActivation(MetricActivation.newBuilder()
334                 .setMetricId(MetricsUtils.VALUE_METRIC_ID)
335                 .setActivationType(ActivationType.ACTIVATE_IMMEDIATELY)
336                 .addEventActivation(EventActivation.newBuilder()
337                         .setAtomMatcherId(activationAtomMatcherId)
338                         .setTtlSeconds(5)));
339 
340 
341         // Upload config.
342         ConfigUtils.uploadConfig(getDevice(), builder);
343 
344         // Wait for 1 min and 10 sec to capture at least 1 bucket
345         RunUtil.getDefault().sleep(60_000 + 10_000);
346 
347         // Wait for the metrics to propagate to statsd.
348         RunUtil.getDefault().sleep(1_000);
349 
350         StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
351                 ExtensionRegistry.getEmptyRegistry());
352         LogUtil.CLog.d("Got the following value metric data: " + metricReport.toString());
353         assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
354         assertThat(metricReport.getValueMetrics().getDataList()).isEmpty();
355         // Skipped buckets are not added when metric is empty.
356         assertThat(metricReport.getValueMetrics().getSkippedList()).isEmpty();
357     }
358 
testValueMetricWithConditionAndActivation()359     public void testValueMetricWithConditionAndActivation() throws Exception {
360         final int conditionLabel = 2;
361         final int activationMatcherId = 5;
362         final int activationMatcherLabel = 5;
363         final int whatMatcherId = 8;
364         final int ttlSec = 5;
365 
366         // Add AtomMatchers.
367         AtomMatcher conditionStartAtomMatcher = MetricsUtils.startAtomMatcherWithLabel(
368                 APP_BREADCRUMB_REPORTED_A_MATCH_START_ID, conditionLabel);
369         AtomMatcher conditionStopAtomMatcher = MetricsUtils.stopAtomMatcherWithLabel(
370                 APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID, conditionLabel);
371         AtomMatcher activationMatcher =
372                 MetricsUtils.startAtomMatcherWithLabel(
373                         activationMatcherId, activationMatcherLabel);
374         AtomMatcher whatMatcher =
375                 MetricsUtils.unspecifiedAtomMatcher(whatMatcherId);
376 
377         StatsdConfig.Builder builder = ConfigUtils.createConfigBuilder(
378                         MetricsUtils.DEVICE_SIDE_TEST_PACKAGE)
379                 .addAtomMatcher(conditionStartAtomMatcher)
380                 .addAtomMatcher(conditionStopAtomMatcher)
381                 .addAtomMatcher(whatMatcher)
382                 .addAtomMatcher(activationMatcher);
383 
384         // Add Predicates.
385         SimplePredicate simplePredicate = SimplePredicate.newBuilder()
386                 .setStart(APP_BREADCRUMB_REPORTED_A_MATCH_START_ID)
387                 .setStop(APP_BREADCRUMB_REPORTED_A_MATCH_STOP_ID)
388                 .build();
389         Predicate predicate = Predicate.newBuilder()
390                 .setId(MetricsUtils.StringToId("Predicate"))
391                 .setSimplePredicate(simplePredicate)
392                 .build();
393         builder.addPredicate(predicate);
394 
395         // Add ValueMetric.
396         builder.addValueMetric(ValueMetric.newBuilder()
397                         .setId(MetricsUtils.VALUE_METRIC_ID)
398                         .setWhat(whatMatcher.getId())
399                         .setBucket(TimeUnit.ONE_MINUTE)
400                         .setCondition(predicate.getId())
401                         .setValueField(FieldMatcher.newBuilder()
402                                 .setField(Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER)
403                                 .addChild(FieldMatcher.newBuilder()
404                                         .setField(AppBreadcrumbReported.LABEL_FIELD_NUMBER))
405                         )
406                         .setDimensionsInWhat(FieldMatcher.newBuilder().setField(whatMatcherId))
407                 )
408                 .addMetricActivation(MetricActivation.newBuilder()
409                         .setMetricId(MetricsUtils.VALUE_METRIC_ID)
410                         .addEventActivation(EventActivation.newBuilder()
411                                 .setAtomMatcherId(activationMatcherId)
412                                 .setActivationType(ActivationType.ACTIVATE_IMMEDIATELY)
413                                 .setTtlSeconds(ttlSec)
414                         )
415                 );
416 
417         ConfigUtils.uploadConfig(getDevice(), builder);
418 
419         // Activate the metric.
420         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
421                 AppBreadcrumbReported.State.START.getNumber(), activationMatcherLabel);
422         RunUtil.getDefault().sleep(10);
423 
424         // Set the condition to true.
425         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
426                 AppBreadcrumbReported.State.START.getNumber(), conditionLabel);
427         RunUtil.getDefault().sleep(10);
428 
429         // Skipped due to unknown condition at start of bucket.
430         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
431                 AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 10);
432         RunUtil.getDefault().sleep(10);
433 
434         // Skipped due to unknown condition at start of bucket.
435         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
436                 AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 200);
437         RunUtil.getDefault().sleep(10);
438 
439         // Set the condition to false.
440         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
441                 AppBreadcrumbReported.State.STOP.getNumber(), conditionLabel);
442         RunUtil.getDefault().sleep(10);
443 
444         // Log an event that should not be counted because condition is false.
445         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
446                 AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 3_000);
447         RunUtil.getDefault().sleep(10);
448 
449         // Let the metric deactivate.
450         RunUtil.getDefault().sleep(ttlSec * 1000);
451 
452         // Log an event that should not be counted.
453         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
454                 AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 40_000);
455         RunUtil.getDefault().sleep(10);
456 
457         // Condition to true again.
458         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
459                 AppBreadcrumbReported.State.START.getNumber(), conditionLabel);
460         RunUtil.getDefault().sleep(10);
461 
462         // Event should not be counted, metric is still not active.
463         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
464                 AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 500_000);
465         RunUtil.getDefault().sleep(10);
466 
467         // Activate the metric.
468         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
469                 AppBreadcrumbReported.State.START.getNumber(), activationMatcherLabel);
470         RunUtil.getDefault().sleep(10);
471 
472         //  Log an event that should be counted.
473         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
474                 AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 6_000_000);
475         RunUtil.getDefault().sleep(10);
476 
477         // Let the metric deactivate.
478         RunUtil.getDefault().sleep(ttlSec * 1000);
479 
480         // Log an event that should not be counted.
481         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice(),
482                 AppBreadcrumbReported.State.UNSPECIFIED.getNumber(), 70_000_000);
483         RunUtil.getDefault().sleep(10);
484 
485         // Wait for the metrics to propagate to statsd.
486         RunUtil.getDefault().sleep(2000);
487 
488         StatsLogReport metricReport = ReportUtils.getStatsLogReport(getDevice(),
489                 ExtensionRegistry.getEmptyRegistry());
490         LogUtil.CLog.d("Received the following data: " + metricReport.toString());
491         assertThat(metricReport.getMetricId()).isEqualTo(MetricsUtils.VALUE_METRIC_ID);
492         assertThat(metricReport.hasValueMetrics()).isTrue();
493         assertThat(metricReport.getIsActive()).isFalse();
494 
495         StatsLogReport.ValueMetricDataWrapper valueData = metricReport.getValueMetrics();
496         assertThat(valueData.getDataCount()).isEqualTo(1);
497         assertThat(valueData.getData(0).getBucketInfoCount()).isEqualTo(1);
498         long totalValue = valueData.getData(0).getBucketInfoList().stream()
499                 .peek(MetricsUtils::assertBucketTimePresent)
500                 .peek(bucketInfo -> assertThat(bucketInfo.getValuesCount()).isEqualTo(1))
501                 .map(bucketInfo -> bucketInfo.getValues(0))
502                 .peek(value -> assertThat(value.getIndex()).isEqualTo(0))
503                 .mapToLong(value -> value.getValueLong())
504                 .sum();
505         assertThat(totalValue).isEqualTo(6_000_000);
506     }
507 
508 }
509