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