1 // Copyright (C) 2017 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <gtest/gtest.h>
16 
17 #include "src/StatsLogProcessor.h"
18 #include "src/stats_log_util.h"
19 #include "tests/statsd_test_util.h"
20 
21 #include <vector>
22 
23 namespace android {
24 namespace os {
25 namespace statsd {
26 
27 #ifdef __ANDROID__
28 
29 namespace {
30 
CreateDurationMetricConfig_NoLink_SimpleCondition(DurationMetric::AggregationType aggregationType,bool addExtraDimensionInCondition)31 StatsdConfig CreateDurationMetricConfig_NoLink_SimpleCondition(
32         DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
33     StatsdConfig config;
34     config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
35     *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
36     *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
37     *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
38     *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
39 
40     auto scheduledJobPredicate = CreateScheduledJobPredicate();
41     auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
42     dimensions->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
43     dimensions->add_child()->set_field(2);  // job name field.
44 
45     auto isSyncingPredicate = CreateIsSyncingPredicate();
46     auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
47     *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
48                                                           {Position::FIRST});
49     if (addExtraDimensionInCondition) {
50         syncDimension->add_child()->set_field(2 /* name field*/);
51     }
52 
53     *config.add_predicate() = scheduledJobPredicate;
54     *config.add_predicate() = isSyncingPredicate;
55 
56     auto metric = config.add_duration_metric();
57     metric->set_bucket(FIVE_MINUTES);
58     metric->set_id(StringToId("scheduledJob"));
59     metric->set_what(scheduledJobPredicate.id());
60     metric->set_condition(isSyncingPredicate.id());
61     metric->set_aggregation_type(aggregationType);
62     auto dimensionWhat = metric->mutable_dimensions_in_what();
63     dimensionWhat->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
64     dimensionWhat->add_child()->set_field(2);  // job name field.
65     *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
66             android::util::SYNC_STATE_CHANGED, {Position::FIRST});
67     return config;
68 }
69 
70 }  // namespace
71 
TEST(DimensionInConditionE2eTest,TestDurationMetric_NoLink_SimpleCondition)72 TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_SimpleCondition) {
73     for (bool isDimensionInConditionSubSetOfConditionTrackerDimension : {true, false}) {
74         for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
75             ConfigKey cfgKey;
76             auto config = CreateDurationMetricConfig_NoLink_SimpleCondition(
77                     aggregationType, isDimensionInConditionSubSetOfConditionTrackerDimension);
78             int64_t bucketStartTimeNs = 10000000000;
79             int64_t bucketSizeNs =
80                     TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
81 
82             auto processor = CreateStatsLogProcessor(
83                     bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
84             EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
85             EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
86 
87             std::vector<AttributionNodeInternal> attributions1 = {
88                     CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
89                     CreateAttribution(222, "GMSCoreModule2")};
90 
91             std::vector<AttributionNodeInternal> attributions2 = {
92                     CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
93                     CreateAttribution(555, "GMSCoreModule2")};
94 
95             std::vector<std::unique_ptr<LogEvent>> events;
96 
97             events.push_back(CreateStartScheduledJobEvent(
98                     {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 1));
99             events.push_back(CreateFinishScheduledJobEvent(
100                     {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
101 
102             events.push_back(CreateStartScheduledJobEvent(
103                     {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
104             events.push_back(CreateFinishScheduledJobEvent(
105                     {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
106 
107             events.push_back(CreateStartScheduledJobEvent(
108                     {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
109             events.push_back(CreateFinishScheduledJobEvent(
110                     {CreateAttribution(8888, "")}, "job2",bucketStartTimeNs + bucketSizeNs + 850));
111 
112             events.push_back(CreateStartScheduledJobEvent(
113                     {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 600));
114             events.push_back(CreateFinishScheduledJobEvent(
115                     {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 900));
116 
117             events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
118                                                   bucketStartTimeNs + 10));
119             events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
120                                                 bucketStartTimeNs + 50));
121 
122             events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
123                                                   bucketStartTimeNs + 200));
124             events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
125                                                 bucketStartTimeNs + bucketSizeNs + 300));
126 
127             events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
128                                                   bucketStartTimeNs + 400));
129             events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
130                                                 bucketStartTimeNs + bucketSizeNs - 1));
131 
132             events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
133                                                   bucketStartTimeNs + 401));
134             events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
135                                                 bucketStartTimeNs + bucketSizeNs + 700));
136 
137             sortLogEventsByTimestamp(&events);
138 
139             for (const auto& event : events) {
140                 processor->OnLogEvent(event.get());
141             }
142 
143             ConfigMetricsReportList reports;
144             vector<uint8_t> buffer;
145             processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
146                                     true, ADB_DUMP, FAST, &buffer);
147             EXPECT_TRUE(buffer.size() > 0);
148             EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
149             backfillDimensionPath(&reports);
150             backfillStringInReport(&reports);
151             backfillStartEndTimestamp(&reports);
152 
153             EXPECT_EQ(reports.reports_size(), 1);
154             EXPECT_EQ(reports.reports(0).metrics_size(), 1);
155             StatsLogReport::DurationMetricDataWrapper metrics;
156             sortMetricDataByDimensionsValue(
157                     reports.reports(0).metrics(0).duration_metrics(), &metrics);
158             if (aggregationType == DurationMetric::SUM) {
159                 EXPECT_EQ(metrics.data_size(), 4);
160                 auto data = metrics.data(0);
161                 EXPECT_EQ(data.dimensions_in_what().field(),
162                           android::util::SCHEDULED_JOB_STATE_CHANGED);
163                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
164                           2);  // job name field
165                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
166                           "job0");  // job name
167                 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
168                                                       android::util::SYNC_STATE_CHANGED, 111, "App1");
169                 EXPECT_EQ(data.bucket_info_size(), 1);
170                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40);
171                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
172                           bucketStartTimeNs);
173                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
174                     bucketStartTimeNs + bucketSizeNs);
175 
176                 data = metrics.data(1);
177                 EXPECT_EQ(data.dimensions_in_what().field(),
178                           android::util::SCHEDULED_JOB_STATE_CHANGED);
179                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
180                           2);  // job name field
181                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
182                           "job1");  // job name
183                 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
184                                                       android::util::SYNC_STATE_CHANGED, 333, "App2");
185                 EXPECT_EQ(data.bucket_info_size(), 1);
186                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
187                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
188                           bucketStartTimeNs + bucketSizeNs);
189                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
190                     bucketStartTimeNs + 2 * bucketSizeNs);
191 
192                 data = metrics.data(2);
193                 EXPECT_EQ(data.dimensions_in_what().field(),
194                           android::util::SCHEDULED_JOB_STATE_CHANGED);
195                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
196                           2);  // job name field
197                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
198                           "job2");  // job name
199                 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
200                                                       android::util::SYNC_STATE_CHANGED, 111, "App1");
201                 EXPECT_EQ(data.bucket_info_size(), 2);
202                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
203                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
204                           bucketStartTimeNs + bucketSizeNs);
205                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201 + bucketSizeNs - 600);
206                 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 300);
207                 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
208                           bucketStartTimeNs + bucketSizeNs);
209                 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
210                           bucketStartTimeNs + 2 * bucketSizeNs);
211 
212                 data = metrics.data(3);
213                 EXPECT_EQ(data.dimensions_in_what().field(),
214                           android::util::SCHEDULED_JOB_STATE_CHANGED);
215                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
216                           2);  // job name field
217                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
218                           "job2");  // job name
219                 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
220                                                       android::util::SYNC_STATE_CHANGED, 333, "App2");
221                 EXPECT_EQ(data.bucket_info_size(), 2);
222                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 + bucketSizeNs - 600);
223                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
224                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
225                           bucketStartTimeNs + bucketSizeNs);
226                 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
227                 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
228                           bucketStartTimeNs + bucketSizeNs);
229                 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
230                           bucketStartTimeNs + 2 * bucketSizeNs);
231             } else {
232                 EXPECT_EQ(metrics.data_size(), 4);
233                 auto data = metrics.data(0);
234                 EXPECT_EQ(data.dimensions_in_what().field(),
235                           android::util::SCHEDULED_JOB_STATE_CHANGED);
236                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
237                           2);  // job name field
238                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
239                           "job0");  // job name
240                 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
241                                                       android::util::SYNC_STATE_CHANGED, 111, "App1");
242                 EXPECT_EQ(data.bucket_info_size(), 1);
243                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40);
244                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
245                           bucketStartTimeNs);
246                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
247                     bucketStartTimeNs + bucketSizeNs);
248 
249                 data = metrics.data(1);
250                 EXPECT_EQ(data.dimensions_in_what().field(),
251                           android::util::SCHEDULED_JOB_STATE_CHANGED);
252                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
253                           2);  // job name field
254                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
255                           "job1");  // job name
256                 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
257                                                       android::util::SYNC_STATE_CHANGED, 333, "App2");
258                 EXPECT_EQ(data.bucket_info_size(), 1);
259                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
260                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
261                           bucketStartTimeNs + bucketSizeNs);
262                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
263                     bucketStartTimeNs + 2 * bucketSizeNs);
264 
265                 data = metrics.data(2);
266                 EXPECT_EQ(data.dimensions_in_what().field(),
267                           android::util::SCHEDULED_JOB_STATE_CHANGED);
268                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
269                           2);  // job name field
270                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
271                           "job2");  // job name
272                 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
273                                                       android::util::SYNC_STATE_CHANGED, 111, "App1");
274                 EXPECT_EQ(data.bucket_info_size(), 2);
275                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
276                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
277                           bucketStartTimeNs + bucketSizeNs);
278                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 201);
279                 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 300);
280                 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
281                           bucketStartTimeNs + bucketSizeNs);
282                 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
283                           bucketStartTimeNs + 2 * bucketSizeNs);
284 
285                 data = metrics.data(3);
286                 EXPECT_EQ(data.dimensions_in_what().field(),
287                           android::util::SCHEDULED_JOB_STATE_CHANGED);
288                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
289                           2);  // job name field
290                 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
291                           "job2");  // job name
292                 ValidateAttributionUidAndTagDimension(data.dimensions_in_condition(),
293                                                       android::util::SYNC_STATE_CHANGED, 333, "App2");
294                 EXPECT_EQ(data.bucket_info_size(), 2);
295                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 401 );
296                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
297                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
298                           bucketStartTimeNs + bucketSizeNs);
299                 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
300                 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
301                           bucketStartTimeNs + bucketSizeNs);
302                 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
303                           bucketStartTimeNs + 2 * bucketSizeNs);
304             }
305         }
306     }
307 }
308 
309 namespace {
310 
createDurationMetric_Link_SimpleConditionConfig(DurationMetric::AggregationType aggregationType,bool addExtraDimensionInCondition)311 StatsdConfig createDurationMetric_Link_SimpleConditionConfig(
312         DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
313     StatsdConfig config;
314     config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
315     *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
316     *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
317     *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
318     *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
319 
320     auto scheduledJobPredicate = CreateScheduledJobPredicate();
321     auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
322     *dimensions = CreateAttributionUidDimensions(
323                 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
324     dimensions->add_child()->set_field(2);  // job name field.
325 
326     auto isSyncingPredicate = CreateIsSyncingPredicate();
327     auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
328     *syncDimension = CreateAttributionUidDimensions(
329             android::util::SYNC_STATE_CHANGED, {Position::FIRST});
330     if (addExtraDimensionInCondition) {
331         syncDimension->add_child()->set_field(2 /* name field*/);
332     }
333 
334     *config.add_predicate() = scheduledJobPredicate;
335     *config.add_predicate() = isSyncingPredicate;
336 
337     auto metric = config.add_duration_metric();
338     metric->set_bucket(FIVE_MINUTES);
339     metric->set_id(StringToId("scheduledJob"));
340     metric->set_what(scheduledJobPredicate.id());
341     metric->set_condition(isSyncingPredicate.id());
342     metric->set_aggregation_type(aggregationType);
343     *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
344             android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
345 
346     auto links = metric->add_links();
347     links->set_condition(isSyncingPredicate.id());
348     *links->mutable_fields_in_what() =
349             CreateAttributionUidDimensions(
350                 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
351     *links->mutable_fields_in_condition() =
352             CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
353     return config;
354 }
355 
356 }  // namespace
357 
TEST(DimensionInConditionE2eTest,TestDurationMetric_Link_SimpleCondition)358 TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_SimpleCondition) {
359     for (bool isFullLink : {true, false}) {
360         for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
361             ConfigKey cfgKey;
362             auto config = createDurationMetric_Link_SimpleConditionConfig(
363                     aggregationType, !isFullLink);
364             int64_t bucketStartTimeNs = 10000000000;
365             int64_t bucketSizeNs =
366                     TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
367 
368             auto processor = CreateStatsLogProcessor(
369                     bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
370             EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
371             EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
372 
373             std::vector<AttributionNodeInternal> attributions1 = {
374                     CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
375                     CreateAttribution(222, "GMSCoreModule2")};
376 
377             std::vector<AttributionNodeInternal> attributions2 = {
378                     CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
379                     CreateAttribution(555, "GMSCoreModule2")};
380 
381             std::vector<AttributionNodeInternal> attributions3 = {
382                     CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
383                     CreateAttribution(555, "GMSCoreModule2")};
384 
385             std::vector<std::unique_ptr<LogEvent>> events;
386 
387             events.push_back(CreateStartScheduledJobEvent(
388                     {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
389             events.push_back(CreateFinishScheduledJobEvent(
390                     {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
391 
392             events.push_back(CreateStartScheduledJobEvent(
393                     {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
394             events.push_back(CreateFinishScheduledJobEvent(
395                     {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
396             events.push_back(CreateStartScheduledJobEvent(
397                     {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
398             events.push_back(
399                 CreateFinishScheduledJobEvent({CreateAttribution(333, "App2")}, "job2",
400                                                bucketStartTimeNs + bucketSizeNs + 850));
401 
402             events.push_back(
403                 CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
404                                              bucketStartTimeNs + bucketSizeNs - 2));
405             events.push_back(
406                 CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
407                                               bucketStartTimeNs + bucketSizeNs + 900));
408 
409             events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
410                                                   bucketStartTimeNs + 50));
411             events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
412                                                 bucketStartTimeNs + 110));
413 
414             events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
415                                                   bucketStartTimeNs + 300));
416             events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
417                                                 bucketStartTimeNs + bucketSizeNs + 700));
418             events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
419                                                   bucketStartTimeNs + 400));
420             events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
421                                                 bucketStartTimeNs + bucketSizeNs - 1));
422 
423             events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
424                                                   bucketStartTimeNs + 550));
425             events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
426                                                 bucketStartTimeNs + 800));
427             events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
428                                                   bucketStartTimeNs + bucketSizeNs - 1));
429             events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
430                                                 bucketStartTimeNs + bucketSizeNs + 700));
431 
432             sortLogEventsByTimestamp(&events);
433 
434             for (const auto& event : events) {
435                 processor->OnLogEvent(event.get());
436             }
437 
438             ConfigMetricsReportList reports;
439             vector<uint8_t> buffer;
440             processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
441                                     true, ADB_DUMP, FAST, &buffer);
442             EXPECT_TRUE(buffer.size() > 0);
443             EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
444             backfillDimensionPath(&reports);
445             backfillStringInReport(&reports);
446             backfillStartEndTimestamp(&reports);
447 
448             EXPECT_EQ(reports.reports_size(), 1);
449             EXPECT_EQ(reports.reports(0).metrics_size(), 1);
450             StatsLogReport::DurationMetricDataWrapper metrics;
451             sortMetricDataByDimensionsValue(
452                     reports.reports(0).metrics(0).duration_metrics(), &metrics);
453 
454             if (aggregationType == DurationMetric::SUM) {
455                 EXPECT_EQ(metrics.data_size(), 3);
456                 auto data = metrics.data(0);
457                 ValidateAttributionUidDimension(
458                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
459                 EXPECT_EQ(data.bucket_info_size(), 1);
460                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
461                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
462                           bucketStartTimeNs);
463                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
464                     bucketStartTimeNs + bucketSizeNs);
465 
466                 data = metrics.data(1);
467                 ValidateAttributionUidDimension(
468                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
469                 EXPECT_EQ(data.bucket_info_size(), 2);
470                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
471                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
472                           bucketStartTimeNs + bucketSizeNs);
473                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300 + bucketSizeNs - 600);
474                 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
475                 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
476                           bucketStartTimeNs + bucketSizeNs);
477                 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
478                           bucketStartTimeNs + 2 * bucketSizeNs);
479 
480                 data = metrics.data(2);
481                 ValidateAttributionUidDimension(
482                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
483                 EXPECT_EQ(data.bucket_info_size(), 2);
484                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
485                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
486                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
487                           bucketStartTimeNs + bucketSizeNs);
488                 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
489                 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
490                           bucketStartTimeNs + bucketSizeNs);
491                 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
492                           bucketStartTimeNs + 2 * bucketSizeNs);
493             } else {
494                 EXPECT_EQ(metrics.data_size(), 3);
495                 auto data = metrics.data(0);
496                 ValidateAttributionUidDimension(
497                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
498                 EXPECT_EQ(data.bucket_info_size(), 1);
499                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
500                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
501                           bucketStartTimeNs);
502                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
503                     bucketStartTimeNs + bucketSizeNs);
504 
505                 data = metrics.data(1);
506                 ValidateAttributionUidDimension(
507                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
508                 EXPECT_EQ(data.bucket_info_size(), 2);
509                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
510                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
511                           bucketStartTimeNs + bucketSizeNs);
512                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300);
513                 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
514                 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
515                           bucketStartTimeNs + bucketSizeNs);
516                 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
517                           bucketStartTimeNs + 2 * bucketSizeNs);
518 
519                 data = metrics.data(2);
520                 ValidateAttributionUidDimension(
521                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
522                 EXPECT_EQ(data.bucket_info_size(), 1);
523                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 701);
524                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
525                           bucketStartTimeNs + bucketSizeNs);
526                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
527                           bucketStartTimeNs + 2 * bucketSizeNs);
528             }
529         }
530     }
531 }
532 
533 namespace {
534 
createDurationMetric_PartialLink_SimpleConditionConfig(DurationMetric::AggregationType aggregationType)535 StatsdConfig createDurationMetric_PartialLink_SimpleConditionConfig(
536         DurationMetric::AggregationType aggregationType) {
537     StatsdConfig config;
538     config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
539     *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
540     *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
541     *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
542     *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
543 
544     auto scheduledJobPredicate = CreateScheduledJobPredicate();
545     auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
546     *dimensions = CreateAttributionUidDimensions(
547                 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
548     dimensions->add_child()->set_field(2);  // job name field.
549 
550     auto isSyncingPredicate = CreateIsSyncingPredicate();
551     auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
552     *syncDimension = CreateAttributionUidDimensions(
553             android::util::SYNC_STATE_CHANGED, {Position::FIRST});
554     syncDimension->add_child()->set_field(2 /* name field*/);
555 
556     *config.add_predicate() = scheduledJobPredicate;
557     *config.add_predicate() = isSyncingPredicate;
558 
559     auto metric = config.add_duration_metric();
560     metric->set_bucket(FIVE_MINUTES);
561     metric->set_id(StringToId("scheduledJob"));
562     metric->set_what(scheduledJobPredicate.id());
563     metric->set_condition(isSyncingPredicate.id());
564     metric->set_aggregation_type(aggregationType);
565     *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
566             android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
567     *metric->mutable_dimensions_in_condition() = *syncDimension;
568 
569     auto links = metric->add_links();
570     links->set_condition(isSyncingPredicate.id());
571     *links->mutable_fields_in_what() =
572             CreateAttributionUidDimensions(
573                 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
574     *links->mutable_fields_in_condition() =
575             CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
576     return config;
577 }
578 
579 }  // namespace
580 
TEST(DimensionInConditionE2eTest,TestDurationMetric_PartialLink_SimpleCondition)581 TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_SimpleCondition) {
582     for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
583         ConfigKey cfgKey;
584         auto config = createDurationMetric_PartialLink_SimpleConditionConfig(
585                 aggregationType);
586         int64_t bucketStartTimeNs = 10000000000;
587         int64_t bucketSizeNs =
588                 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
589 
590         auto processor = CreateStatsLogProcessor(
591                 bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
592         EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
593         EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
594 
595         std::vector<AttributionNodeInternal> attributions1 = {
596                 CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
597                 CreateAttribution(222, "GMSCoreModule2")};
598 
599         std::vector<AttributionNodeInternal> attributions2 = {
600                 CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
601                 CreateAttribution(555, "GMSCoreModule2")};
602 
603         std::vector<AttributionNodeInternal> attributions3 = {
604                 CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
605                 CreateAttribution(555, "GMSCoreModule2")};
606 
607         std::vector<std::unique_ptr<LogEvent>> events;
608 
609         events.push_back(CreateStartScheduledJobEvent(
610                 {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
611         events.push_back(CreateFinishScheduledJobEvent(
612                 {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
613 
614         events.push_back(CreateStartScheduledJobEvent(
615                 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
616         events.push_back(CreateFinishScheduledJobEvent(
617                 {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
618         events.push_back(CreateStartScheduledJobEvent(
619                 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
620         events.push_back(CreateFinishScheduledJobEvent(
621                 {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + bucketSizeNs + 850));
622 
623         events.push_back(
624             CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
625                                          bucketStartTimeNs + bucketSizeNs - 2));
626         events.push_back(
627             CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
628                                           bucketStartTimeNs + bucketSizeNs + 900));
629 
630         events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
631                                               bucketStartTimeNs + 50));
632         events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
633                                             bucketStartTimeNs + 110));
634 
635         events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
636                                               bucketStartTimeNs + 300));
637         events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
638                                             bucketStartTimeNs + bucketSizeNs + 700));
639         events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
640                                               bucketStartTimeNs + 400));
641         events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
642                                             bucketStartTimeNs + bucketSizeNs - 1));
643 
644         events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
645                                               bucketStartTimeNs + 550));
646         events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
647                                             bucketStartTimeNs + 800));
648         events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
649                                               bucketStartTimeNs + bucketSizeNs - 1));
650         events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
651                                             bucketStartTimeNs + bucketSizeNs + 700));
652 
653         sortLogEventsByTimestamp(&events);
654 
655         for (const auto& event : events) {
656             processor->OnLogEvent(event.get());
657         }
658 
659         ConfigMetricsReportList reports;
660         vector<uint8_t> buffer;
661         processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
662                                 ADB_DUMP, FAST, &buffer);
663         EXPECT_TRUE(buffer.size() > 0);
664         EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
665         backfillDimensionPath(&reports);
666         backfillStringInReport(&reports);
667         backfillStartEndTimestamp(&reports);
668 
669         EXPECT_EQ(reports.reports_size(), 1);
670         EXPECT_EQ(reports.reports(0).metrics_size(), 1);
671         StatsLogReport::DurationMetricDataWrapper metrics;
672         sortMetricDataByDimensionsValue(
673                 reports.reports(0).metrics(0).duration_metrics(), &metrics);
674 
675         if (aggregationType == DurationMetric::SUM) {
676             EXPECT_EQ(4, metrics.data_size());
677             auto data = metrics.data(0);
678             ValidateAttributionUidDimension(
679                 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
680             ValidateAttributionUidDimension(
681                 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
682             EXPECT_EQ("ReadEmail",
683                       data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
684             EXPECT_EQ(data.bucket_info_size(), 1);
685             EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
686             EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
687                       bucketStartTimeNs);
688             EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
689                 bucketStartTimeNs + bucketSizeNs);
690 
691             data = metrics.data(1);
692             ValidateAttributionUidDimension(
693                 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
694             ValidateAttributionUidDimension(
695                 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
696             EXPECT_EQ("ReadDoc",
697                       data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
698             EXPECT_EQ(data.bucket_info_size(), 1);
699             EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
700             EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
701                       bucketStartTimeNs + bucketSizeNs);
702             EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 1 - 400 - 100);
703 
704             data = metrics.data(2);
705             ValidateAttributionUidDimension(
706                 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
707             ValidateAttributionUidDimension(
708                 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
709             EXPECT_EQ("ReadEmail",
710                       data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
711             EXPECT_EQ(data.bucket_info_size(), 2);
712             EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
713             EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
714                       bucketStartTimeNs + bucketSizeNs);
715             EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300 + bucketSizeNs - 600);
716             EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
717             EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
718                       bucketStartTimeNs + bucketSizeNs);
719             EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
720                       bucketStartTimeNs + 2 * bucketSizeNs);
721 
722             data = metrics.data(3);
723             ValidateAttributionUidDimension(
724                 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
725             ValidateAttributionUidDimension(
726                 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
727             EXPECT_EQ("ReadDoc",
728                       data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
729             EXPECT_EQ(data.bucket_info_size(), 2);
730             EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
731             EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
732             EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
733                       bucketStartTimeNs + bucketSizeNs);
734             EXPECT_EQ(data.bucket_info(1).duration_nanos(), 700);
735             EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
736                       bucketStartTimeNs + bucketSizeNs);
737             EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
738                       bucketStartTimeNs + 2 * bucketSizeNs);
739         } else {
740             EXPECT_EQ(metrics.data_size(), 4);
741             auto data = metrics.data(0);
742             ValidateAttributionUidDimension(
743                 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
744             ValidateAttributionUidDimension(
745                 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
746             EXPECT_EQ("ReadEmail",
747                       data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
748             EXPECT_EQ(data.bucket_info_size(), 1);
749             EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 50);
750             EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
751                       bucketStartTimeNs);
752             EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
753                 bucketStartTimeNs + bucketSizeNs);
754 
755             data = metrics.data(1);
756             ValidateAttributionUidDimension(
757                 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
758             ValidateAttributionUidDimension(
759                 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
760             EXPECT_EQ("ReadDoc",
761                       data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
762             EXPECT_EQ(data.bucket_info_size(), 2);
763             EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
764             EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
765                       bucketStartTimeNs + bucketSizeNs);
766             EXPECT_EQ(data.bucket_info(0).duration_nanos(), 100);
767             EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
768                       bucketStartTimeNs + bucketSizeNs);
769             EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
770                       bucketStartTimeNs + 2 * bucketSizeNs);
771             EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 1 - 600);
772 
773             data = metrics.data(2);
774             ValidateAttributionUidDimension(
775                 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
776             ValidateAttributionUidDimension(
777                 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
778             EXPECT_EQ("ReadEmail",
779                       data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
780             EXPECT_EQ(data.bucket_info_size(), 2);
781             EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
782             EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
783                       bucketStartTimeNs + bucketSizeNs);
784             EXPECT_EQ(data.bucket_info(0).duration_nanos(), 500 - 300);
785             EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 700);
786             EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
787                       bucketStartTimeNs + bucketSizeNs);
788             EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
789                       bucketStartTimeNs + 2 * bucketSizeNs);
790 
791             data = metrics.data(3);
792             ValidateAttributionUidDimension(
793                 data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
794             ValidateAttributionUidDimension(
795                 data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
796             EXPECT_EQ("ReadDoc",
797                       data.dimensions_in_condition().value_tuple().dimensions_value(1).value_str());
798             EXPECT_EQ(data.bucket_info_size(), 1);
799             EXPECT_EQ(data.bucket_info(0).duration_nanos(), 701);
800             EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
801                       bucketStartTimeNs + bucketSizeNs);
802             EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
803                       bucketStartTimeNs + 2 * bucketSizeNs);
804         }
805     }
806 }
807 
808 #else
809 GTEST_LOG_(INFO) << "This test does nothing.\n";
810 #endif
811 
812 }  // namespace statsd
813 }  // namespace os
814 }  // namespace android
815