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