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
23namespace android {
24namespace os {
25namespace statsd {
26
27#ifdef __ANDROID__
28
29namespace {
30
31StatsdConfig 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
84TEST(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
367namespace {
368
369StatsdConfig 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
426TEST(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
615namespace {
616
617StatsdConfig 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
675TEST(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
928GTEST_LOG_(INFO) << "This test does nothing.\n";
929#endif
930
931}  // namespace statsd
932}  // namespace os
933}  // namespace android
934