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_AND_CombinationCondition(DurationMetric::AggregationType aggregationType,bool addExtraDimensionInCondition,bool hashStringInReport)31 StatsdConfig CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
32         DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition,
33         bool hashStringInReport) {
34     StatsdConfig config;
35     config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
36     *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
37     *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
38     *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
39     *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
40     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
41     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
42 
43     auto scheduledJobPredicate = CreateScheduledJobPredicate();
44     auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
45     dimensions->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
46     dimensions->add_child()->set_field(2);  // job name field.
47 
48     auto screenIsOffPredicate = CreateScreenIsOffPredicate();
49 
50     auto isSyncingPredicate = CreateIsSyncingPredicate();
51     auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
52     *syncDimension = CreateAttributionUidAndTagDimensions(android::util::SYNC_STATE_CHANGED,
53                                                           {Position::FIRST});
54     if (addExtraDimensionInCondition) {
55         syncDimension->add_child()->set_field(2 /* name field*/);
56     }
57 
58     config.set_hash_strings_in_metric_report(hashStringInReport);
59     *config.add_predicate() = scheduledJobPredicate;
60     *config.add_predicate() = screenIsOffPredicate;
61     *config.add_predicate() = isSyncingPredicate;
62     auto combinationPredicate = config.add_predicate();
63     combinationPredicate->set_id(StringToId("CombinationPredicate"));
64     combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
65     addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
66     addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
67 
68     auto metric = config.add_duration_metric();
69     metric->set_bucket(FIVE_MINUTES);
70     metric->set_id(StringToId("scheduledJob"));
71     metric->set_what(scheduledJobPredicate.id());
72     metric->set_condition(combinationPredicate->id());
73     metric->set_aggregation_type(aggregationType);
74     auto dimensionWhat = metric->mutable_dimensions_in_what();
75     dimensionWhat->set_field(android::util::SCHEDULED_JOB_STATE_CHANGED);
76     dimensionWhat->add_child()->set_field(2);  // job name field.
77     *metric->mutable_dimensions_in_condition() = CreateAttributionUidAndTagDimensions(
78             android::util::SYNC_STATE_CHANGED, {Position::FIRST});
79     return config;
80 }
81 
82 }  // namespace
83 
84 /*
85  The following test has the following input.
86 
87 { 10000000002 10000000002 (8)9999[I], [S], job0[S], 1[I],  }
88 { 10000000010 10000000010 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 1[I],  }
89 { 10000000011 10000000011 (29)1[I],  }
90 { 10000000040 10000000040 (29)2[I],  }
91 { 10000000050 10000000050 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 0[I],  }
92 { 10000000101 10000000101 (8)9999[I], [S], job0[S], 0[I],  }
93 { 10000000102 10000000102 (29)1[I],  }
94 { 10000000200 10000000200 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 1[I],  }
95 { 10000000201 10000000201 (8)9999[I], [S], job2[S], 1[I],  }
96 { 10000000400 10000000400 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadDoc[S], 1[I],  }
97 { 10000000401 10000000401 (7)333[I], App2[S], 222[I], GMSCoreModule1[S], 555[I], GMSCoreModule2[S], ReadEmail[S], 1[I],  }
98 { 10000000450 10000000450 (29)2[I],  }
99 { 10000000500 10000000500 (8)9999[I], [S], job2[S], 0[I],  }
100 { 10000000600 10000000600 (8)8888[I], [S], job2[S], 1[I],  }
101 { 10000000650 10000000650 (29)1[I],  }
102 { 309999999999 309999999999 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadDoc[S], 0[I],  }
103 { 310000000100 310000000100 (29)2[I],  }
104 { 310000000300 310000000300 (7)111[I], App1[S], 222[I], GMSCoreModule1[S], 222[I], GMSCoreModule2[S], ReadEmail[S], 0[I],  }
105 { 310000000600 310000000600 (8)8888[I], [S], job1[S], 1[I],  }
106 { 310000000640 310000000640 (29)1[I],  }
107 { 310000000650 310000000650 (29)2[I],  }
108 { 310000000700 310000000700 (7)333[I], App2[S], 222[I], GMSCoreModule1[S], 555[I], GMSCoreModule2[S], ReadEmail[S], 0[I],  }
109 { 310000000850 310000000850 (8)8888[I], [S], job2[S], 0[I],  }
110 { 310000000900 310000000900 (8)8888[I], [S], job1[S], 0[I],  }
111 */
TEST(DimensionInConditionE2eTest,TestDurationMetric_NoLink_AND_CombinationCondition)112 TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition) {
113     for (const bool hashStringInReport : { true, false }) {
114         for (bool isDimensionInConditionSubSetOfConditionTrackerDimension : { true, false }) {
115             for (auto aggregationType : {DurationMetric::MAX_SPARSE, DurationMetric::SUM}) {
116                 ConfigKey cfgKey;
117                 auto config = CreateDurationMetricConfig_NoLink_AND_CombinationCondition(
118                         aggregationType, isDimensionInConditionSubSetOfConditionTrackerDimension,
119                         hashStringInReport);
120                 int64_t bucketStartTimeNs = 10000000000;
121                 int64_t bucketSizeNs =
122                         TimeUnitToBucketSizeInMillis(
123                             config.duration_metric(0).bucket()) * 1000000LL;
124 
125                 auto processor = CreateStatsLogProcessor(
126                         bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
127                 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
128                 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
129 
130                 std::vector<AttributionNodeInternal> attributions1 = {
131                         CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
132                         CreateAttribution(222, "GMSCoreModule2")};
133 
134                 std::vector<AttributionNodeInternal> attributions2 = {
135                         CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
136                         CreateAttribution(555, "GMSCoreModule2")};
137 
138                 std::vector<std::unique_ptr<LogEvent>> events;
139 
140                 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
141                                                                bucketStartTimeNs + 11));
142                 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
143                                                                bucketStartTimeNs + 40));
144 
145                 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
146                                                                bucketStartTimeNs + 102));
147                 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
148                                                                bucketStartTimeNs + 450));
149 
150                 events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
151                                                                bucketStartTimeNs + 650));
152                 events.push_back(CreateScreenStateChangedEvent(
153                                     android::view::DISPLAY_STATE_ON,
154                                     bucketStartTimeNs + bucketSizeNs + 100));
155 
156                 events.push_back(CreateScreenStateChangedEvent(
157                                     android::view::DISPLAY_STATE_OFF,
158                                     bucketStartTimeNs + bucketSizeNs + 640));
159                 events.push_back(CreateScreenStateChangedEvent(
160                                     android::view::DISPLAY_STATE_ON,
161                                     bucketStartTimeNs + bucketSizeNs + 650));
162 
163                 events.push_back(CreateStartScheduledJobEvent(
164                         {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 2));
165                 events.push_back(CreateFinishScheduledJobEvent(
166                         {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
167 
168                 events.push_back(CreateStartScheduledJobEvent(
169                         {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
170                 events.push_back(CreateFinishScheduledJobEvent(
171                         {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
172 
173                 events.push_back(CreateStartScheduledJobEvent(
174                         {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
175                 events.push_back(CreateFinishScheduledJobEvent(
176                         {CreateAttribution(8888, "")}, "job2",
177                         bucketStartTimeNs + bucketSizeNs + 850));
178 
179                 events.push_back(CreateStartScheduledJobEvent(
180                         {CreateAttribution(8888, "")}, "job1",
181                         bucketStartTimeNs + bucketSizeNs + 600));
182                 events.push_back(CreateFinishScheduledJobEvent(
183                         {CreateAttribution(8888, "")}, "job1",
184                         bucketStartTimeNs + bucketSizeNs + 900));
185 
186                 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
187                                                       bucketStartTimeNs + 10));
188                 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
189                                                     bucketStartTimeNs + 50));
190 
191                 events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
192                                                       bucketStartTimeNs + 200));
193                 events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
194                                                     bucketStartTimeNs + bucketSizeNs + 300));
195 
196                 events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
197                                                       bucketStartTimeNs + 400));
198                 events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
199                                                     bucketStartTimeNs + bucketSizeNs - 1));
200 
201                 events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
202                                                       bucketStartTimeNs + 401));
203                 events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
204                                                     bucketStartTimeNs + bucketSizeNs + 700));
205 
206                 sortLogEventsByTimestamp(&events);
207 
208                 for (const auto& event : events) {
209                     processor->OnLogEvent(event.get());
210                 }
211 
212                 ConfigMetricsReportList reports;
213                 vector<uint8_t> buffer;
214                 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
215                                         true, ADB_DUMP, FAST, &buffer);
216                 EXPECT_TRUE(buffer.size() > 0);
217                 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
218                 backfillDimensionPath(&reports);
219                 backfillStringInReport(&reports);
220                 backfillStartEndTimestamp(&reports);
221 
222                 EXPECT_EQ(reports.reports_size(), 1);
223                 EXPECT_EQ(reports.reports(0).metrics_size(), 1);
224                 StatsLogReport::DurationMetricDataWrapper metrics;
225                 sortMetricDataByDimensionsValue(
226                         reports.reports(0).metrics(0).duration_metrics(), &metrics);
227                 if (aggregationType == DurationMetric::SUM) {
228                     EXPECT_EQ(metrics.data_size(), 4);
229                     auto data = metrics.data(0);
230                     EXPECT_EQ(data.dimensions_in_what().field(),
231                               android::util::SCHEDULED_JOB_STATE_CHANGED);
232                     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
233                               2);  // job name field
234                     EXPECT_EQ(data.dimensions_in_what().value_tuple().
235                                     dimensions_value(0).value_str(),
236                               "job0");  // job name
237                     ValidateAttributionUidAndTagDimension(
238                             data.dimensions_in_condition(),
239                             android::util::SYNC_STATE_CHANGED, 111, "App1");
240                     EXPECT_EQ(data.bucket_info_size(), 1);
241                     EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40 - 11);
242                     EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
243                               bucketStartTimeNs);
244                     EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
245                         bucketStartTimeNs + bucketSizeNs);
246 
247 
248                     data = metrics.data(1);
249                     EXPECT_EQ(data.dimensions_in_what().field(),
250                               android::util::SCHEDULED_JOB_STATE_CHANGED);
251                     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
252                               2);  // job name field
253                     EXPECT_EQ(data.dimensions_in_what().value_tuple().
254                                     dimensions_value(0).value_str(),
255                               "job1");  // job name
256                     ValidateAttributionUidAndTagDimension(
257                             data.dimensions_in_condition(),
258                             android::util::SYNC_STATE_CHANGED, 333, "App2");
259                     EXPECT_EQ(data.bucket_info_size(), 1);
260                     EXPECT_EQ(data.bucket_info(0).duration_nanos(), 10);
261                     EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
262                               bucketStartTimeNs + bucketSizeNs);
263                     EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
264                         bucketStartTimeNs + 2 * bucketSizeNs);
265 
266                     data = metrics.data(2);
267                     EXPECT_EQ(data.dimensions_in_what().field(),
268                               android::util::SCHEDULED_JOB_STATE_CHANGED);
269                     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
270                               2);  // job name field
271                     EXPECT_EQ(data.dimensions_in_what().value_tuple().
272                                     dimensions_value(0).value_str(),
273                               "job2");  // job name
274                     ValidateAttributionUidAndTagDimension(
275                             data.dimensions_in_condition(),
276                             android::util::SYNC_STATE_CHANGED, 111, "App1");
277                     EXPECT_EQ(data.bucket_info_size(), 2);
278                     EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
279                     EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
280                               bucketStartTimeNs + bucketSizeNs);
281                     EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201 + bucketSizeNs - 650);
282                     EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
283                     EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
284                               bucketStartTimeNs + bucketSizeNs);
285                     EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
286                               bucketStartTimeNs + 2 * bucketSizeNs);
287 
288                     data = metrics.data(3);
289                     EXPECT_EQ(data.dimensions_in_what().field(),
290                               android::util::SCHEDULED_JOB_STATE_CHANGED);
291                     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
292                               2);  // job name field
293                     EXPECT_EQ(data.dimensions_in_what().value_tuple().
294                                     dimensions_value(0).value_str(),
295                               "job2");  // job name
296                     ValidateAttributionUidAndTagDimension(
297                             data.dimensions_in_condition(),
298                             android::util::SYNC_STATE_CHANGED, 333, "App2");
299                     EXPECT_EQ(data.bucket_info_size(), 2);
300                     EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401 + bucketSizeNs - 650);
301                     EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
302                     EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
303                               bucketStartTimeNs + bucketSizeNs);
304                     EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100 + 650 - 640);
305                     EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
306                               bucketStartTimeNs + bucketSizeNs);
307                     EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
308                               bucketStartTimeNs + 2 * bucketSizeNs);
309                 } else {
310                     EXPECT_EQ(metrics.data_size(), 4);
311                     auto data = metrics.data(0);
312                     EXPECT_EQ(data.dimensions_in_what().field(),
313                               android::util::SCHEDULED_JOB_STATE_CHANGED);
314                     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
315                               2);  // job name field
316                     EXPECT_EQ(data.dimensions_in_what().value_tuple().
317                                     dimensions_value(0).value_str(),
318                               "job0");  // job name
319                     ValidateAttributionUidAndTagDimension(
320                             data.dimensions_in_condition(),
321                             android::util::SYNC_STATE_CHANGED, 111, "App1");
322                     EXPECT_EQ(data.bucket_info_size(), 1);
323                     EXPECT_EQ(data.bucket_info(0).duration_nanos(), 40 - 11);
324                     EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
325                               bucketStartTimeNs);
326                     EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
327                         bucketStartTimeNs + bucketSizeNs);
328 
329                     data = metrics.data(1);
330                     EXPECT_EQ(data.dimensions_in_what().field(),
331                               android::util::SCHEDULED_JOB_STATE_CHANGED);
332                     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
333                               2);  // job name field
334                     EXPECT_EQ(data.dimensions_in_what().value_tuple().
335                                     dimensions_value(0).value_str(),
336                               "job1");  // job name
337                     ValidateAttributionUidAndTagDimension(
338                             data.dimensions_in_condition(),
339                             android::util::SYNC_STATE_CHANGED, 333, "App2");
340                     EXPECT_EQ(data.bucket_info_size(), 1);
341                     EXPECT_EQ(data.bucket_info(0).duration_nanos(), 10);
342                     EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
343                               bucketStartTimeNs + bucketSizeNs);
344                     EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
345                         bucketStartTimeNs + 2 * bucketSizeNs);
346 
347                     data = metrics.data(2);
348                     EXPECT_EQ(data.dimensions_in_what().field(),
349                               android::util::SCHEDULED_JOB_STATE_CHANGED);
350                     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
351                               2);  // job name field
352                     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
353                               "job2");  // job name
354                     ValidateAttributionUidAndTagDimension(
355                             data.dimensions_in_condition(),
356                             android::util::SYNC_STATE_CHANGED, 111, "App1");
357                     EXPECT_EQ(data.bucket_info_size(), 2);
358                     EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
359                     EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
360                               bucketStartTimeNs + bucketSizeNs);
361                     EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 201);
362                     EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 650 + 100);
363                     EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
364                               bucketStartTimeNs + bucketSizeNs);
365                     EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
366                               bucketStartTimeNs + 2 * bucketSizeNs);
367 
368                     data = metrics.data(3);
369                     EXPECT_EQ(data.dimensions_in_what().field(),
370                               android::util::SCHEDULED_JOB_STATE_CHANGED);
371                     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(),
372                               2);  // job name field
373                     EXPECT_EQ(data.dimensions_in_what().value_tuple().
374                                     dimensions_value(0).value_str(),
375                               "job2");  // job name
376                     ValidateAttributionUidAndTagDimension(
377                             data.dimensions_in_condition(),
378                             android::util::SYNC_STATE_CHANGED, 333, "App2");
379                     EXPECT_EQ(data.bucket_info_size(), 2);
380                     EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 401);
381                     EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
382                     EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
383                               bucketStartTimeNs + bucketSizeNs);
384                     EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 650 + 110);
385                     EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
386                               bucketStartTimeNs + bucketSizeNs);
387                     EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
388                               bucketStartTimeNs + 2 * bucketSizeNs);
389                 }
390             }
391         }
392     }
393 }
394 
395 namespace {
396 
CreateDurationMetricConfig_Link_AND_CombinationCondition(DurationMetric::AggregationType aggregationType,bool addExtraDimensionInCondition)397 StatsdConfig CreateDurationMetricConfig_Link_AND_CombinationCondition(
398         DurationMetric::AggregationType aggregationType, bool addExtraDimensionInCondition) {
399     StatsdConfig config;
400     config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
401     *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
402     *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
403     *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
404     *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
405     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
406     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
407 
408     auto scheduledJobPredicate = CreateScheduledJobPredicate();
409     auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
410     *dimensions = CreateAttributionUidDimensions(
411                 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
412     dimensions->add_child()->set_field(2);  // job name field.
413 
414     auto isSyncingPredicate = CreateIsSyncingPredicate();
415     auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
416     *syncDimension = CreateAttributionUidDimensions(
417             android::util::SYNC_STATE_CHANGED, {Position::FIRST});
418     if (addExtraDimensionInCondition) {
419         syncDimension->add_child()->set_field(2 /* name field*/);
420     }
421 
422     auto screenIsOffPredicate = CreateScreenIsOffPredicate();
423 
424     *config.add_predicate() = scheduledJobPredicate;
425     *config.add_predicate() = screenIsOffPredicate;
426     *config.add_predicate() = isSyncingPredicate;
427     auto combinationPredicate = config.add_predicate();
428     combinationPredicate->set_id(StringToId("CombinationPredicate"));
429     combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
430     addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
431     addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
432 
433     auto metric = config.add_duration_metric();
434     metric->set_bucket(FIVE_MINUTES);
435     metric->set_id(StringToId("scheduledJob"));
436     metric->set_what(scheduledJobPredicate.id());
437     metric->set_condition(combinationPredicate->id());
438     metric->set_aggregation_type(aggregationType);
439     *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
440             android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
441 
442     auto links = metric->add_links();
443     links->set_condition(isSyncingPredicate.id());
444     *links->mutable_fields_in_what() =
445             CreateAttributionUidDimensions(
446                 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
447     *links->mutable_fields_in_condition() =
448             CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
449     return config;
450 }
451 
452 }  // namespace
453 
TEST(DimensionInConditionE2eTest,TestDurationMetric_Link_AND_CombinationCondition)454 TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition) {
455     for (bool isFullLink : {true, false}) {
456         for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
457             ConfigKey cfgKey;
458             auto config = CreateDurationMetricConfig_Link_AND_CombinationCondition(
459                 aggregationType, !isFullLink);
460             int64_t bucketStartTimeNs = 10000000000;
461             int64_t bucketSizeNs =
462                     TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
463 
464             auto processor = CreateStatsLogProcessor(
465                     bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
466             EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
467             EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
468 
469             std::vector<AttributionNodeInternal> attributions1 = {
470                     CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
471                     CreateAttribution(222, "GMSCoreModule2")};
472 
473             std::vector<AttributionNodeInternal> attributions2 = {
474                     CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
475                     CreateAttribution(555, "GMSCoreModule2")};
476 
477             std::vector<AttributionNodeInternal> attributions3 = {
478                     CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
479                     CreateAttribution(555, "GMSCoreModule2")};
480 
481             std::vector<std::unique_ptr<LogEvent>> events;
482 
483             events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
484                                                            bucketStartTimeNs + 55));
485             events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
486                                                            bucketStartTimeNs + 120));
487             events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
488                                                            bucketStartTimeNs + 121));
489             events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
490                                                            bucketStartTimeNs + 450));
491 
492             events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
493                                                            bucketStartTimeNs + 501));
494             events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
495                                                            bucketStartTimeNs + bucketSizeNs + 100));
496 
497             events.push_back(CreateStartScheduledJobEvent(
498                     {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
499             events.push_back(CreateFinishScheduledJobEvent(
500                     {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
501 
502             events.push_back(CreateStartScheduledJobEvent(
503                     {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
504             events.push_back(CreateFinishScheduledJobEvent(
505                     {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
506             events.push_back(CreateStartScheduledJobEvent(
507                     {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
508             events.push_back(CreateFinishScheduledJobEvent(
509                     {CreateAttribution(333, "App2")}, "job2",
510                     bucketStartTimeNs + bucketSizeNs + 850));
511 
512             events.push_back(
513                 CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
514                                              bucketStartTimeNs + bucketSizeNs - 2));
515             events.push_back(
516                 CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
517                                               bucketStartTimeNs + bucketSizeNs + 900));
518 
519             events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
520                                                   bucketStartTimeNs + 50));
521             events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
522                                                 bucketStartTimeNs + 110));
523 
524             events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
525                                                   bucketStartTimeNs + 300));
526             events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
527                                                 bucketStartTimeNs + bucketSizeNs + 700));
528             events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
529                                                   bucketStartTimeNs + 400));
530             events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
531                                                 bucketStartTimeNs + bucketSizeNs - 1));
532 
533             events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
534                                                   bucketStartTimeNs + 550));
535             events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
536                                                 bucketStartTimeNs + 800));
537             events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
538                                                   bucketStartTimeNs + bucketSizeNs - 1));
539             events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
540                                                 bucketStartTimeNs + bucketSizeNs + 700));
541 
542             sortLogEventsByTimestamp(&events);
543 
544             for (const auto& event : events) {
545                 processor->OnLogEvent(event.get());
546             }
547 
548             ConfigMetricsReportList reports;
549             vector<uint8_t> buffer;
550             processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
551                                     true, ADB_DUMP, FAST, &buffer);
552             EXPECT_TRUE(buffer.size() > 0);
553             EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
554             backfillDimensionPath(&reports);
555             backfillStringInReport(&reports);
556             backfillStartEndTimestamp(&reports);
557 
558             EXPECT_EQ(reports.reports_size(), 1);
559             EXPECT_EQ(reports.reports(0).metrics_size(), 1);
560             StatsLogReport::DurationMetricDataWrapper metrics;
561             sortMetricDataByDimensionsValue(
562                     reports.reports(0).metrics(0).duration_metrics(), &metrics);
563 
564             if (aggregationType == DurationMetric::SUM) {
565                 EXPECT_EQ(metrics.data_size(), 3);
566                 auto data = metrics.data(0);
567                 ValidateAttributionUidDimension(
568                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
569                 EXPECT_EQ(data.bucket_info_size(), 1);
570                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
571                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
572                           bucketStartTimeNs);
573                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
574                     bucketStartTimeNs + bucketSizeNs);
575 
576                 data = metrics.data(1);
577                 ValidateAttributionUidDimension(
578                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
579                 EXPECT_EQ(data.bucket_info_size(), 2);
580                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
581                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
582                           bucketStartTimeNs + bucketSizeNs);
583                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300 + bucketSizeNs - 600);
584                 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
585                 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
586                           bucketStartTimeNs + bucketSizeNs);
587                 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
588                           bucketStartTimeNs + 2 * bucketSizeNs);
589 
590                 data = metrics.data(2);
591                 ValidateAttributionUidDimension(
592                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
593                 EXPECT_EQ(data.bucket_info_size(), 2);
594                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
595                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
596                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
597                           bucketStartTimeNs + bucketSizeNs);
598                 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
599                 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
600                           bucketStartTimeNs + bucketSizeNs);
601                 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
602                           bucketStartTimeNs + 2 * bucketSizeNs);
603             } else {
604                 EXPECT_EQ(metrics.data_size(), 3);
605                 auto data = metrics.data(0);
606                 ValidateAttributionUidDimension(
607                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
608                 EXPECT_EQ(data.bucket_info_size(), 1);
609                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
610                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
611                           bucketStartTimeNs);
612                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
613                     bucketStartTimeNs + bucketSizeNs);
614 
615                 data = metrics.data(1);
616                 ValidateAttributionUidDimension(
617                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
618                 EXPECT_EQ(data.bucket_info_size(), 2);
619                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
620                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
621                           bucketStartTimeNs + bucketSizeNs);
622                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300);
623                 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100);
624                 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
625                           bucketStartTimeNs + bucketSizeNs);
626                 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
627                           bucketStartTimeNs + 2 * bucketSizeNs);
628 
629                 data = metrics.data(2);
630                 ValidateAttributionUidDimension(
631                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
632                 EXPECT_EQ(data.bucket_info_size(), 1);
633                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101);
634                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
635                           bucketStartTimeNs + bucketSizeNs);
636                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
637                           bucketStartTimeNs + 2 * bucketSizeNs);
638             }
639         }
640     }
641 }
642 
643 namespace {
644 
CreateDurationMetricConfig_PartialLink_AND_CombinationCondition(DurationMetric::AggregationType aggregationType,bool hashStringInReport)645 StatsdConfig CreateDurationMetricConfig_PartialLink_AND_CombinationCondition(
646         DurationMetric::AggregationType aggregationType, bool hashStringInReport) {
647     StatsdConfig config;
648     config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
649     *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
650     *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
651     *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
652     *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
653     *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
654     *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
655 
656     auto scheduledJobPredicate = CreateScheduledJobPredicate();
657     auto dimensions = scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions();
658     *dimensions = CreateAttributionUidDimensions(
659                 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
660     dimensions->add_child()->set_field(2);  // job name field.
661 
662     auto isSyncingPredicate = CreateIsSyncingPredicate();
663     auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
664     *syncDimension = CreateAttributionUidDimensions(
665             android::util::SYNC_STATE_CHANGED, {Position::FIRST});
666     syncDimension->add_child()->set_field(2 /* name field*/);
667 
668     auto screenIsOffPredicate = CreateScreenIsOffPredicate();
669 
670     config.set_hash_strings_in_metric_report(hashStringInReport);
671     *config.add_predicate() = scheduledJobPredicate;
672     *config.add_predicate() = screenIsOffPredicate;
673     *config.add_predicate() = isSyncingPredicate;
674     auto combinationPredicate = config.add_predicate();
675     combinationPredicate->set_id(StringToId("CombinationPredicate"));
676     combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
677     addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
678     addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
679 
680     auto metric = config.add_duration_metric();
681     metric->set_bucket(FIVE_MINUTES);
682     metric->set_id(StringToId("scheduledJob"));
683     metric->set_what(scheduledJobPredicate.id());
684     metric->set_condition(combinationPredicate->id());
685     metric->set_aggregation_type(aggregationType);
686     *metric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
687             android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
688     *metric->mutable_dimensions_in_condition() = *syncDimension;
689 
690 
691     auto links = metric->add_links();
692     links->set_condition(isSyncingPredicate.id());
693     *links->mutable_fields_in_what() =
694             CreateAttributionUidDimensions(
695                 android::util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
696     *links->mutable_fields_in_condition() =
697             CreateAttributionUidDimensions(android::util::SYNC_STATE_CHANGED, {Position::FIRST});
698     return config;
699 }
700 
701 }  // namespace
702 
TEST(DimensionInConditionE2eTest,TestDurationMetric_PartialLink_AND_CombinationCondition)703 TEST(DimensionInConditionE2eTest, TestDurationMetric_PartialLink_AND_CombinationCondition) {
704     for (const bool hashStringInReport : {true, false}) {
705         for (auto aggregationType : {DurationMetric::SUM, DurationMetric::MAX_SPARSE}) {
706             ConfigKey cfgKey;
707             auto config =
708                     CreateDurationMetricConfig_PartialLink_AND_CombinationCondition(
709                             aggregationType, hashStringInReport);
710             int64_t bucketStartTimeNs = 10000000000;
711             int64_t bucketSizeNs =
712                     TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
713 
714             auto processor = CreateStatsLogProcessor(
715                     bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
716             EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
717             EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
718 
719             std::vector<AttributionNodeInternal> attributions1 = {
720                     CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
721                     CreateAttribution(222, "GMSCoreModule2")};
722 
723             std::vector<AttributionNodeInternal> attributions2 = {
724                     CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
725                     CreateAttribution(555, "GMSCoreModule2")};
726 
727             std::vector<AttributionNodeInternal> attributions3 = {
728                     CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
729                     CreateAttribution(555, "GMSCoreModule2")};
730 
731             std::vector<std::unique_ptr<LogEvent>> events;
732 
733             events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
734                                                            bucketStartTimeNs + 55));
735             events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
736                                                            bucketStartTimeNs + 120));
737             events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
738                                                            bucketStartTimeNs + 121));
739             events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
740                                                            bucketStartTimeNs + 450));
741 
742             events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
743                                                            bucketStartTimeNs + 501));
744             events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
745                                                            bucketStartTimeNs + bucketSizeNs + 100));
746 
747             events.push_back(CreateStartScheduledJobEvent(
748                     {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
749             events.push_back(CreateFinishScheduledJobEvent(
750                     {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
751 
752             events.push_back(CreateStartScheduledJobEvent(
753                     {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
754             events.push_back(CreateFinishScheduledJobEvent(
755                     {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
756             events.push_back(CreateStartScheduledJobEvent(
757                     {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
758             events.push_back(CreateFinishScheduledJobEvent(
759                     {CreateAttribution(333, "App2")}, "job2",
760                     bucketStartTimeNs + bucketSizeNs + 850));
761 
762             events.push_back(
763                 CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
764                                              bucketStartTimeNs + bucketSizeNs - 2));
765             events.push_back(
766                 CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
767                                               bucketStartTimeNs + bucketSizeNs + 900));
768 
769             events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
770                                                   bucketStartTimeNs + 50));
771             events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
772                                                 bucketStartTimeNs + 110));
773 
774             events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
775                                                   bucketStartTimeNs + 300));
776             events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
777                                                 bucketStartTimeNs + bucketSizeNs + 700));
778             events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
779                                                   bucketStartTimeNs + 400));
780             events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
781                                                 bucketStartTimeNs + bucketSizeNs - 1));
782 
783             events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
784                                                   bucketStartTimeNs + 550));
785             events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
786                                                 bucketStartTimeNs + 800));
787             events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
788                                                   bucketStartTimeNs + bucketSizeNs - 1));
789             events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
790                                                 bucketStartTimeNs + bucketSizeNs + 700));
791 
792             sortLogEventsByTimestamp(&events);
793 
794             for (const auto& event : events) {
795                 processor->OnLogEvent(event.get());
796             }
797 
798             ConfigMetricsReportList reports;
799             vector<uint8_t> buffer;
800             processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
801                                     true, ADB_DUMP, FAST, &buffer);
802             EXPECT_TRUE(buffer.size() > 0);
803             EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
804             backfillDimensionPath(&reports);
805             backfillStringInReport(&reports);
806             backfillStartEndTimestamp(&reports);
807 
808             EXPECT_EQ(reports.reports_size(), 1);
809             EXPECT_EQ(reports.reports(0).metrics_size(), 1);
810             StatsLogReport::DurationMetricDataWrapper metrics;
811             sortMetricDataByDimensionsValue(
812                     reports.reports(0).metrics(0).duration_metrics(), &metrics);
813             if (aggregationType == DurationMetric::SUM) {
814                 EXPECT_EQ(metrics.data_size(), 4);
815                 auto data = metrics.data(0);
816                 ValidateAttributionUidDimension(
817                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
818                 ValidateAttributionUidDimension(
819                     data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
820                 EXPECT_EQ("ReadEmail",
821                           data.dimensions_in_condition().value_tuple().
822                                 dimensions_value(1).value_str());
823                 EXPECT_EQ(data.bucket_info_size(), 1);
824                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
825                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
826                           bucketStartTimeNs);
827                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
828                           bucketStartTimeNs + bucketSizeNs);
829 
830                 data = metrics.data(1);
831                 ValidateAttributionUidDimension(
832                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
833                 ValidateAttributionUidDimension(
834                     data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
835                 EXPECT_EQ("ReadDoc",
836                           data.dimensions_in_condition().value_tuple().
837                                 dimensions_value(1).value_str());
838                 EXPECT_EQ(data.bucket_info_size(), 1);
839                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
840                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
841                           bucketStartTimeNs + bucketSizeNs);
842                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), bucketSizeNs - 1 - 600 + 50);
843 
844                 data = metrics.data(2);
845                 ValidateAttributionUidDimension(
846                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
847                 ValidateAttributionUidDimension(
848                     data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
849                 EXPECT_EQ("ReadEmail",
850                           data.dimensions_in_condition().value_tuple().
851                                 dimensions_value(1).value_str());
852                 EXPECT_EQ(data.bucket_info_size(), 2);
853                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
854                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
855                           bucketStartTimeNs + bucketSizeNs);
856                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300 + bucketSizeNs - 600);
857                 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
858                 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
859                           bucketStartTimeNs + bucketSizeNs);
860                 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
861                           bucketStartTimeNs + 2 * bucketSizeNs);
862 
863                 data = metrics.data(3);
864                 ValidateAttributionUidDimension(
865                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
866                 ValidateAttributionUidDimension(
867                     data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
868                 EXPECT_EQ("ReadDoc",
869                           data.dimensions_in_condition().value_tuple().
870                                 dimensions_value(1).value_str());
871                 EXPECT_EQ(data.bucket_info_size(), 2);
872                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 1);
873                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
874                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
875                           bucketStartTimeNs + bucketSizeNs);
876                 EXPECT_EQ(data.bucket_info(1).duration_nanos(), 100);
877                 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
878                           bucketStartTimeNs + bucketSizeNs);
879                 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
880                           bucketStartTimeNs + 2 * bucketSizeNs);
881             } else {
882                 EXPECT_EQ(metrics.data_size(), 4);
883                 auto data = metrics.data(0);
884                 ValidateAttributionUidDimension(
885                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 111);
886                 ValidateAttributionUidDimension(
887                     data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 111);
888                 EXPECT_EQ("ReadEmail",
889                           data.dimensions_in_condition().value_tuple().
890                                 dimensions_value(1).value_str());
891                 EXPECT_EQ(data.bucket_info_size(), 1);
892                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101 - 55);
893                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
894                           bucketStartTimeNs);
895                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
896                     bucketStartTimeNs + bucketSizeNs);
897 
898                 data = metrics.data(1);
899                 ValidateAttributionUidDimension(
900                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
901                 ValidateAttributionUidDimension(
902                     data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
903                 EXPECT_EQ("ReadDoc",
904                           data.dimensions_in_condition().value_tuple().
905                                 dimensions_value(1).value_str());
906                 EXPECT_EQ(data.bucket_info_size(), 2);
907                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
908                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
909                           bucketStartTimeNs + bucketSizeNs);
910                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 50);
911                 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 1 - 600);
912                 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
913                           bucketStartTimeNs + bucketSizeNs);
914                 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
915                           bucketStartTimeNs + 2 * bucketSizeNs);
916 
917                 data = metrics.data(2);
918                 ValidateAttributionUidDimension(
919                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 333);
920                 ValidateAttributionUidDimension(
921                     data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 333);
922                 EXPECT_EQ("ReadEmail",
923                           data.dimensions_in_condition().value_tuple().
924                                 dimensions_value(1).value_str());
925                 EXPECT_EQ(data.bucket_info_size(), 2);
926                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
927                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
928                           bucketStartTimeNs + bucketSizeNs);
929                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 450 - 300);
930                 EXPECT_EQ(data.bucket_info(1).duration_nanos(), bucketSizeNs - 600 + 100);
931                 EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
932                           bucketStartTimeNs + bucketSizeNs);
933                 EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(),
934                           bucketStartTimeNs + 2 * bucketSizeNs);
935 
936                 data = metrics.data(3);
937                 ValidateAttributionUidDimension(
938                     data.dimensions_in_what(), android::util::SCHEDULED_JOB_STATE_CHANGED, 444);
939                 ValidateAttributionUidDimension(
940                     data.dimensions_in_condition(), android::util::SYNC_STATE_CHANGED, 444);
941                 EXPECT_EQ("ReadDoc",
942                           data.dimensions_in_condition().value_tuple().
943                                 dimensions_value(1).value_str());
944                 EXPECT_EQ(data.bucket_info_size(), 1);
945                 EXPECT_EQ(data.bucket_info(0).duration_nanos(), 101);
946                 EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
947                           bucketStartTimeNs + bucketSizeNs);
948                 EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(),
949                           bucketStartTimeNs + 2 * bucketSizeNs);
950             }
951         }
952     }
953 }
954 
955 #else
956 GTEST_LOG_(INFO) << "This test does nothing.\n";
957 #endif
958 
959 }  // namespace statsd
960 }  // namespace os
961 }  // namespace android
962