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