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