1 // Copyright (C) 2019 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 <vector>
18
19 #include "src/StatsLogProcessor.h"
20 #include "src/state/StateTracker.h"
21 #include "src/stats_log_util.h"
22 #include "tests/statsd_test_util.h"
23
24 namespace android {
25 namespace os {
26 namespace statsd {
27
28 #ifdef __ANDROID__
29
TEST(DurationMetricE2eTest,TestOneBucket)30 TEST(DurationMetricE2eTest, TestOneBucket) {
31 StatsdConfig config;
32
33 auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
34 auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
35 *config.add_atom_matcher() = screenOnMatcher;
36 *config.add_atom_matcher() = screenOffMatcher;
37
38 auto durationPredicate = CreateScreenIsOnPredicate();
39 *config.add_predicate() = durationPredicate;
40
41 int64_t metricId = 123456;
42 auto durationMetric = config.add_duration_metric();
43 durationMetric->set_id(metricId);
44 durationMetric->set_what(durationPredicate.id());
45 durationMetric->set_bucket(FIVE_MINUTES);
46 durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
47
48 const int64_t baseTimeNs = 0; // 0:00
49 const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
50 const int64_t bucketSizeNs =
51 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
52
53 int uid = 12345;
54 int64_t cfgId = 98765;
55 ConfigKey cfgKey(uid, cfgId);
56
57 auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
58
59 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
60 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
61 EXPECT_TRUE(metricsManager->isConfigValid());
62 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
63 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
64 EXPECT_TRUE(metricsManager->isActive());
65 EXPECT_TRUE(metricProducer->mIsActive);
66
67 std::unique_ptr<LogEvent> event;
68
69 // Screen is off at start of bucket.
70 event = CreateScreenStateChangedEvent(configAddedTimeNs,
71 android::view::DISPLAY_STATE_OFF); // 0:01
72 processor->OnLogEvent(event.get());
73
74 // Turn screen on.
75 const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11
76 event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
77 processor->OnLogEvent(event.get());
78
79 // Turn off screen 30 seconds after turning on.
80 const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41
81 event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
82 processor->OnLogEvent(event.get());
83
84 event = CreateScreenBrightnessChangedEvent(durationEndNs + 1 * NS_PER_SEC, 64); // 0:42
85 processor->OnLogEvent(event.get());
86
87 ConfigMetricsReportList reports;
88 vector<uint8_t> buffer;
89 processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
90 ADB_DUMP, FAST, &buffer); // 5:01
91 EXPECT_TRUE(buffer.size() > 0);
92 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
93 backfillDimensionPath(&reports);
94 backfillStartEndTimestamp(&reports);
95 ASSERT_EQ(1, reports.reports_size());
96 ASSERT_EQ(1, reports.reports(0).metrics_size());
97 EXPECT_TRUE(reports.reports(0).metrics(0).has_estimated_data_bytes());
98 EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
99 EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
100
101 StatsLogReport::DurationMetricDataWrapper durationMetrics;
102 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
103 &durationMetrics);
104 ASSERT_EQ(1, durationMetrics.data_size());
105
106 DurationMetricData data = durationMetrics.data(0);
107 ASSERT_EQ(1, data.bucket_info_size());
108 EXPECT_EQ(durationEndNs - durationStartNs, data.bucket_info(0).duration_nanos());
109 EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
110 EXPECT_EQ(baseTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
111 }
112
TEST(DurationMetricE2eTest,TestTwoBuckets)113 TEST(DurationMetricE2eTest, TestTwoBuckets) {
114 StatsdConfig config;
115
116 auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
117 auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
118 *config.add_atom_matcher() = screenOnMatcher;
119 *config.add_atom_matcher() = screenOffMatcher;
120
121 auto durationPredicate = CreateScreenIsOnPredicate();
122 *config.add_predicate() = durationPredicate;
123
124 int64_t metricId = 123456;
125 auto durationMetric = config.add_duration_metric();
126 durationMetric->set_id(metricId);
127 durationMetric->set_what(durationPredicate.id());
128 durationMetric->set_bucket(FIVE_MINUTES);
129 durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
130
131 const int64_t baseTimeNs = 0; // 0:00
132 const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
133 const int64_t bucketSizeNs =
134 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
135
136 int uid = 12345;
137 int64_t cfgId = 98765;
138 ConfigKey cfgKey(uid, cfgId);
139
140 auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
141
142 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
143 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
144 EXPECT_TRUE(metricsManager->isConfigValid());
145 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
146 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
147 EXPECT_TRUE(metricsManager->isActive());
148 EXPECT_TRUE(metricProducer->mIsActive);
149
150 std::unique_ptr<LogEvent> event;
151
152 // Screen is off at start of bucket.
153 event = CreateScreenStateChangedEvent(configAddedTimeNs,
154 android::view::DISPLAY_STATE_OFF); // 0:01
155 processor->OnLogEvent(event.get());
156
157 // Turn screen on.
158 const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11
159 event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
160 processor->OnLogEvent(event.get());
161
162 // Turn off screen 30 seconds after turning on.
163 const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41
164 event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
165 processor->OnLogEvent(event.get());
166
167 event = CreateScreenBrightnessChangedEvent(durationEndNs + 1 * NS_PER_SEC, 64); // 0:42
168 processor->OnLogEvent(event.get());
169
170 ConfigMetricsReportList reports;
171 vector<uint8_t> buffer;
172 processor->onDumpReport(cfgKey, configAddedTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC, false,
173 true, ADB_DUMP, FAST, &buffer); // 10:01
174 EXPECT_TRUE(buffer.size() > 0);
175 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
176 backfillDimensionPath(&reports);
177 backfillStartEndTimestamp(&reports);
178 ASSERT_EQ(1, reports.reports_size());
179 ASSERT_EQ(1, reports.reports(0).metrics_size());
180 EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
181 EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
182
183 StatsLogReport::DurationMetricDataWrapper durationMetrics;
184 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
185 &durationMetrics);
186 ASSERT_EQ(1, durationMetrics.data_size());
187
188 DurationMetricData data = durationMetrics.data(0);
189 ASSERT_EQ(1, data.bucket_info_size());
190
191 auto bucketInfo = data.bucket_info(0);
192 EXPECT_EQ(0, bucketInfo.bucket_num());
193 EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
194 EXPECT_EQ(configAddedTimeNs, bucketInfo.start_bucket_elapsed_nanos());
195 EXPECT_EQ(baseTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
196 }
197
TEST(DurationMetricE2eTest,TestWithActivation)198 TEST(DurationMetricE2eTest, TestWithActivation) {
199 StatsdConfig config;
200
201 auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
202 auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
203 auto crashMatcher = CreateProcessCrashAtomMatcher();
204 *config.add_atom_matcher() = screenOnMatcher;
205 *config.add_atom_matcher() = screenOffMatcher;
206 *config.add_atom_matcher() = crashMatcher;
207
208 auto durationPredicate = CreateScreenIsOnPredicate();
209 *config.add_predicate() = durationPredicate;
210
211 int64_t metricId = 123456;
212 auto durationMetric = config.add_duration_metric();
213 durationMetric->set_id(metricId);
214 durationMetric->set_what(durationPredicate.id());
215 durationMetric->set_bucket(FIVE_MINUTES);
216 durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
217
218 auto metric_activation1 = config.add_metric_activation();
219 metric_activation1->set_metric_id(metricId);
220 auto event_activation1 = metric_activation1->add_event_activation();
221 event_activation1->set_atom_matcher_id(crashMatcher.id());
222 event_activation1->set_ttl_seconds(30); // 30 secs.
223
224 const int64_t bucketStartTimeNs = 10000000000;
225 const int64_t bucketSizeNs =
226 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
227
228 int uid = 12345;
229 int64_t cfgId = 98765;
230 ConfigKey cfgKey(uid, cfgId);
231
232 sp<UidMap> m = new UidMap();
233 sp<StatsPullerManager> pullerManager = new StatsPullerManager();
234 sp<AlarmMonitor> anomalyAlarmMonitor;
235 sp<AlarmMonitor> subscriberAlarmMonitor;
236 vector<int64_t> activeConfigsBroadcast;
237
238 std::shared_ptr<MockLogEventFilter> mockLogEventFilter = std::make_shared<MockLogEventFilter>();
239 EXPECT_CALL(*mockLogEventFilter, setAtomIds(StatsLogProcessor::getDefaultAtomIdSet(), _))
240 .Times(1);
241
242 int broadcastCount = 0;
243 StatsLogProcessor processor(
244 m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
245 [](const ConfigKey& key) { return true; },
246 [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
247 const vector<int64_t>& activeConfigs) {
248 broadcastCount++;
249 EXPECT_EQ(broadcastUid, uid);
250 activeConfigsBroadcast.clear();
251 activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
252 activeConfigs.end());
253 return true;
254 },
255 [](const ConfigKey&, const string&, const vector<int64_t>&) {}, mockLogEventFilter);
256
257 EXPECT_CALL(*mockLogEventFilter, setAtomIds(CreateAtomIdSetFromConfig(config), &processor))
258 .Times(1);
259
260 processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); // 0:00
261
262 ASSERT_EQ(processor.mMetricsManagers.size(), 1u);
263 sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
264 EXPECT_TRUE(metricsManager->isConfigValid());
265 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
266 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
267 auto& eventActivationMap = metricProducer->mEventActivationMap;
268
269 EXPECT_FALSE(metricsManager->isActive());
270 EXPECT_FALSE(metricProducer->mIsActive);
271 ASSERT_EQ(eventActivationMap.size(), 1u);
272 EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
273 EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
274 EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
275 EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
276
277 std::unique_ptr<LogEvent> event;
278
279 // Turn screen off.
280 event = CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * NS_PER_SEC,
281 android::view::DISPLAY_STATE_OFF); // 0:02
282 processor.OnLogEvent(event.get(), bucketStartTimeNs + 2 * NS_PER_SEC);
283
284 // Turn screen on.
285 const int64_t durationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:05
286 event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
287 processor.OnLogEvent(event.get(), durationStartNs);
288
289 // Activate metric.
290 const int64_t activationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:10
291 const int64_t activationEndNs =
292 activationStartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 0:40
293 event = CreateAppCrashEvent(activationStartNs, 111);
294 processor.OnLogEvent(event.get(), activationStartNs);
295 EXPECT_TRUE(metricsManager->isActive());
296 EXPECT_TRUE(metricProducer->mIsActive);
297 EXPECT_EQ(broadcastCount, 1);
298 ASSERT_EQ(activeConfigsBroadcast.size(), 1);
299 EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
300 EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
301 EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
302 EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
303
304 // Expire activation.
305 const int64_t expirationNs = activationEndNs + 7 * NS_PER_SEC;
306 event = CreateScreenBrightnessChangedEvent(expirationNs, 64); // 0:47
307 processor.OnLogEvent(event.get(), expirationNs);
308 EXPECT_FALSE(metricsManager->isActive());
309 EXPECT_FALSE(metricProducer->mIsActive);
310 EXPECT_EQ(broadcastCount, 2);
311 ASSERT_EQ(activeConfigsBroadcast.size(), 0);
312 ASSERT_EQ(eventActivationMap.size(), 1u);
313 EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
314 EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
315 EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
316 EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
317
318 // Turn off screen 10 seconds after activation expiration.
319 const int64_t durationEndNs = activationEndNs + 10 * NS_PER_SEC; // 0:50
320 event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
321 processor.OnLogEvent(event.get(), durationEndNs);
322
323 // Turn screen on.
324 const int64_t duration2StartNs = durationEndNs + 5 * NS_PER_SEC; // 0:55
325 event = CreateScreenStateChangedEvent(duration2StartNs, android::view::DISPLAY_STATE_ON);
326 processor.OnLogEvent(event.get(), duration2StartNs);
327
328 // Turn off screen.
329 const int64_t duration2EndNs = duration2StartNs + 10 * NS_PER_SEC; // 1:05
330 event = CreateScreenStateChangedEvent(duration2EndNs, android::view::DISPLAY_STATE_OFF);
331 processor.OnLogEvent(event.get(), duration2EndNs);
332
333 // Activate metric.
334 const int64_t activation2StartNs = duration2EndNs + 5 * NS_PER_SEC; // 1:10
335 const int64_t activation2EndNs =
336 activation2StartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 1:40
337 event = CreateAppCrashEvent(activation2StartNs, 211);
338 processor.OnLogEvent(event.get(), activation2StartNs);
339 EXPECT_TRUE(metricsManager->isActive());
340 EXPECT_TRUE(metricProducer->mIsActive);
341 EXPECT_EQ(broadcastCount, 3);
342 ASSERT_EQ(activeConfigsBroadcast.size(), 1);
343 EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
344 EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
345 EXPECT_EQ(eventActivationMap[2]->start_ns, activation2StartNs);
346 EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
347
348 ConfigMetricsReportList reports;
349 vector<uint8_t> buffer;
350 processor.onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
351 ADB_DUMP, FAST, &buffer); // 5:01
352 EXPECT_TRUE(buffer.size() > 0);
353 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
354 backfillDimensionPath(&reports);
355 backfillStartEndTimestamp(&reports);
356 ASSERT_EQ(1, reports.reports_size());
357 ASSERT_EQ(1, reports.reports(0).metrics_size());
358 EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
359 EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
360
361 StatsLogReport::DurationMetricDataWrapper durationMetrics;
362 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
363 &durationMetrics);
364 ASSERT_EQ(1, durationMetrics.data_size());
365
366 DurationMetricData data = durationMetrics.data(0);
367 ASSERT_EQ(1, data.bucket_info_size());
368
369 auto bucketInfo = data.bucket_info(0);
370 EXPECT_EQ(0, bucketInfo.bucket_num());
371 EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
372 EXPECT_EQ(expirationNs, bucketInfo.end_bucket_elapsed_nanos());
373 EXPECT_EQ(expirationNs - durationStartNs, bucketInfo.duration_nanos());
374 }
375
TEST(DurationMetricE2eTest,TestWithCondition)376 TEST(DurationMetricE2eTest, TestWithCondition) {
377 StatsdConfig config;
378 *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
379 *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
380 *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
381 *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
382
383 auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
384 *config.add_predicate() = holdingWakelockPredicate;
385
386 auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
387 *config.add_predicate() = isInBackgroundPredicate;
388
389 auto durationMetric = config.add_duration_metric();
390 durationMetric->set_id(StringToId("WakelockDuration"));
391 durationMetric->set_what(holdingWakelockPredicate.id());
392 durationMetric->set_condition(isInBackgroundPredicate.id());
393 durationMetric->set_aggregation_type(DurationMetric::SUM);
394 durationMetric->set_bucket(FIVE_MINUTES);
395
396 ConfigKey cfgKey;
397 uint64_t bucketStartTimeNs = 10000000000;
398 uint64_t bucketSizeNs =
399 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
400 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
401 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
402 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
403 EXPECT_TRUE(metricsManager->isConfigValid());
404 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
405 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
406 auto& eventActivationMap = metricProducer->mEventActivationMap;
407 EXPECT_TRUE(metricsManager->isActive());
408 EXPECT_TRUE(metricProducer->mIsActive);
409 EXPECT_TRUE(eventActivationMap.empty());
410
411 int appUid = 123;
412 vector<int> attributionUids1 = {appUid};
413 vector<string> attributionTags1 = {"App1"};
414 int64_t conditionStartTime1Ns = bucketStartTimeNs + 22 * NS_PER_SEC;
415 int64_t conditionEndTimeNs = bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC;
416 int64_t conditionStartTime2Ns = bucketStartTimeNs + (4 * 60 + 20) * NS_PER_SEC;
417 int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
418
419 std::vector<std::unique_ptr<LogEvent>> events;
420 events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
421 attributionUids1, attributionTags1,
422 "wl1")); // 0:10
423 events.push_back(CreateMoveToBackgroundEvent(conditionStartTime1Ns, appUid)); // 0:22
424 events.push_back(CreateMoveToForegroundEvent(conditionEndTimeNs,
425 appUid)); // 3:15
426 events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 4 * 60 * NS_PER_SEC,
427 attributionUids1, attributionTags1,
428 "wl1")); // 4:00
429 events.push_back(CreateMoveToBackgroundEvent(conditionStartTime2Ns, appUid)); // 4:20
430
431 // Bucket 2.
432 events.push_back(CreateAcquireWakelockEvent(bucket2StartTimeNs + 10 * NS_PER_SEC,
433 attributionUids1, attributionTags1,
434 "wl1")); // 5:10
435 // Send log events to StatsLogProcessor.
436 for (auto& event : events) {
437 processor->OnLogEvent(event.get());
438 }
439
440 vector<uint8_t> buffer;
441 ConfigMetricsReportList reports;
442 int64_t dumpReportTimeNs = bucket2StartTimeNs + 40 * NS_PER_SEC;
443 processor->onDumpReport(cfgKey, dumpReportTimeNs, true, true, ADB_DUMP, FAST, &buffer); // 5:40
444 ASSERT_GT(buffer.size(), 0);
445 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
446 backfillDimensionPath(&reports);
447 backfillStringInReport(&reports);
448 backfillStartEndTimestamp(&reports);
449
450 ASSERT_EQ(1, reports.reports_size());
451 ASSERT_EQ(1, reports.reports(0).metrics_size());
452 StatsLogReport::DurationMetricDataWrapper durationMetrics;
453 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
454 &durationMetrics);
455 ASSERT_EQ(1, durationMetrics.data_size());
456
457 // Validate bucket info.
458 ASSERT_EQ(2, durationMetrics.data(0).bucket_info_size());
459 ValidateDurationBucket(durationMetrics.data(0).bucket_info(0), bucketStartTimeNs,
460 bucket2StartTimeNs, conditionEndTimeNs - conditionStartTime1Ns,
461 (conditionEndTimeNs - conditionStartTime1Ns) +
462 (bucket2StartTimeNs - conditionStartTime2Ns));
463 ValidateDurationBucket(durationMetrics.data(0).bucket_info(1), bucket2StartTimeNs,
464 dumpReportTimeNs, 30 * NS_PER_SEC,
465 dumpReportTimeNs - bucket2StartTimeNs);
466 }
467
TEST(DurationMetricE2eTest,TestWithSlicedCondition)468 TEST(DurationMetricE2eTest, TestWithSlicedCondition) {
469 StatsdConfig config;
470 *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
471 *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
472 *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
473 *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
474
475 auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
476 // The predicate is dimensioning by first attribution node by uid.
477 FieldMatcher dimensions = CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED,
478 {Position::FIRST});
479 *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
480 *config.add_predicate() = holdingWakelockPredicate;
481
482 auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
483 *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
484 CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
485 *config.add_predicate() = isInBackgroundPredicate;
486
487 auto durationMetric = config.add_duration_metric();
488 durationMetric->set_id(StringToId("WakelockDuration"));
489 durationMetric->set_what(holdingWakelockPredicate.id());
490 durationMetric->set_condition(isInBackgroundPredicate.id());
491 durationMetric->set_aggregation_type(DurationMetric::SUM);
492 // The metric is dimensioning by first attribution node and only by uid.
493 *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
494 util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
495 durationMetric->set_bucket(FIVE_MINUTES);
496
497 // Links between wakelock state atom and condition of app is in background.
498 auto links = durationMetric->add_links();
499 links->set_condition(isInBackgroundPredicate.id());
500 *links->mutable_fields_in_what() =
501 CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
502 auto dimensionCondition = links->mutable_fields_in_condition();
503 dimensionCondition->set_field(util::ACTIVITY_FOREGROUND_STATE_CHANGED);
504 dimensionCondition->add_child()->set_field(1); // uid field.
505
506 ConfigKey cfgKey;
507 uint64_t bucketStartTimeNs = 10000000000;
508 uint64_t bucketSizeNs =
509 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
510 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
511 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
512 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
513 EXPECT_TRUE(metricsManager->isConfigValid());
514 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
515 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
516 auto& eventActivationMap = metricProducer->mEventActivationMap;
517 EXPECT_TRUE(metricsManager->isActive());
518 EXPECT_TRUE(metricProducer->mIsActive);
519 EXPECT_TRUE(eventActivationMap.empty());
520
521 int appUid = 123;
522 std::vector<int> attributionUids1 = {appUid};
523 std::vector<string> attributionTags1 = {"App1"};
524
525 auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1,
526 attributionTags1, "wl1"); // 0:10
527 processor->OnLogEvent(event.get());
528
529 event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid); // 0:22
530 processor->OnLogEvent(event.get());
531
532 event = CreateReleaseWakelockEvent(bucketStartTimeNs + 60 * NS_PER_SEC, attributionUids1,
533 attributionTags1, "wl1"); // 1:00
534 processor->OnLogEvent(event.get());
535
536 event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC,
537 appUid); // 3:15
538 processor->OnLogEvent(event.get());
539
540 vector<uint8_t> buffer;
541 ConfigMetricsReportList reports;
542 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
543 FAST, &buffer);
544 ASSERT_GT(buffer.size(), 0);
545 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
546 backfillDimensionPath(&reports);
547 backfillStringInReport(&reports);
548 backfillStartEndTimestamp(&reports);
549
550 ASSERT_EQ(1, reports.reports_size());
551 ASSERT_EQ(1, reports.reports(0).metrics_size());
552 StatsLogReport::DurationMetricDataWrapper durationMetrics;
553 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
554 &durationMetrics);
555 ASSERT_EQ(1, durationMetrics.data_size());
556
557 DurationMetricData data = durationMetrics.data(0);
558 // Validate dimension value.
559 ValidateAttributionUidDimension(data.dimensions_in_what(),
560 util::WAKELOCK_STATE_CHANGED, appUid);
561 // Validate bucket info.
562 ASSERT_EQ(1, data.bucket_info_size());
563
564 auto bucketInfo = data.bucket_info(0);
565 EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
566 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
567 EXPECT_EQ(38 * NS_PER_SEC, bucketInfo.duration_nanos());
568 }
569
TEST(DurationMetricE2eTest,TestWithActivationAndSlicedCondition)570 TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition) {
571 StatsdConfig config;
572 auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
573 *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
574 *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
575 *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
576 *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
577 *config.add_atom_matcher() = screenOnMatcher;
578
579 auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
580 // The predicate is dimensioning by first attribution node by uid.
581 FieldMatcher dimensions = CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED,
582 {Position::FIRST});
583 *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
584 *config.add_predicate() = holdingWakelockPredicate;
585
586 auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
587 *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
588 CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
589 *config.add_predicate() = isInBackgroundPredicate;
590
591 auto durationMetric = config.add_duration_metric();
592 durationMetric->set_id(StringToId("WakelockDuration"));
593 durationMetric->set_what(holdingWakelockPredicate.id());
594 durationMetric->set_condition(isInBackgroundPredicate.id());
595 durationMetric->set_aggregation_type(DurationMetric::SUM);
596 // The metric is dimensioning by first attribution node and only by uid.
597 *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
598 util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
599 durationMetric->set_bucket(FIVE_MINUTES);
600
601 // Links between wakelock state atom and condition of app is in background.
602 auto links = durationMetric->add_links();
603 links->set_condition(isInBackgroundPredicate.id());
604 *links->mutable_fields_in_what() =
605 CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
606 auto dimensionCondition = links->mutable_fields_in_condition();
607 dimensionCondition->set_field(util::ACTIVITY_FOREGROUND_STATE_CHANGED);
608 dimensionCondition->add_child()->set_field(1); // uid field.
609
610 auto metric_activation1 = config.add_metric_activation();
611 metric_activation1->set_metric_id(durationMetric->id());
612 auto event_activation1 = metric_activation1->add_event_activation();
613 event_activation1->set_atom_matcher_id(screenOnMatcher.id());
614 event_activation1->set_ttl_seconds(60 * 2); // 2 minutes.
615
616 ConfigKey cfgKey;
617 uint64_t bucketStartTimeNs = 10000000000;
618 uint64_t bucketSizeNs =
619 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
620 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
621 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
622 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
623 EXPECT_TRUE(metricsManager->isConfigValid());
624 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
625 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
626 auto& eventActivationMap = metricProducer->mEventActivationMap;
627 EXPECT_FALSE(metricsManager->isActive());
628 EXPECT_FALSE(metricProducer->mIsActive);
629 ASSERT_EQ(eventActivationMap.size(), 1u);
630 EXPECT_TRUE(eventActivationMap.find(4) != eventActivationMap.end());
631 EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
632 EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
633 EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
634
635 int appUid = 123;
636 std::vector<int> attributionUids1 = {appUid};
637 std::vector<string> attributionTags1 = {"App1"};
638
639 auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1,
640 attributionTags1, "wl1"); // 0:10
641 processor->OnLogEvent(event.get());
642 EXPECT_FALSE(metricsManager->isActive());
643 EXPECT_FALSE(metricProducer->mIsActive);
644 EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
645 EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
646 EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
647
648 event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid); // 0:22
649 processor->OnLogEvent(event.get());
650 EXPECT_FALSE(metricsManager->isActive());
651 EXPECT_FALSE(metricProducer->mIsActive);
652 EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
653 EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
654 EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
655
656 const int64_t durationStartNs = bucketStartTimeNs + 30 * NS_PER_SEC; // 0:30
657 event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
658 processor->OnLogEvent(event.get());
659 EXPECT_TRUE(metricsManager->isActive());
660 EXPECT_TRUE(metricProducer->mIsActive);
661 EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
662 EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
663 EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
664
665 const int64_t durationEndNs =
666 durationStartNs + (event_activation1->ttl_seconds() + 30) * NS_PER_SEC; // 3:00
667 event = CreateAppCrashEvent(durationEndNs, 333);
668 processor->OnLogEvent(event.get());
669 EXPECT_FALSE(metricsManager->isActive());
670 EXPECT_FALSE(metricProducer->mIsActive);
671 EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
672 EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
673 EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
674
675 event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC,
676 appUid); // 3:15
677 processor->OnLogEvent(event.get());
678
679 event = CreateReleaseWakelockEvent(bucketStartTimeNs + (4 * 60 + 17) * NS_PER_SEC,
680 attributionUids1, attributionTags1, "wl1"); // 4:17
681 processor->OnLogEvent(event.get());
682
683 event = CreateMoveToBackgroundEvent(bucketStartTimeNs + (4 * 60 + 20) * NS_PER_SEC,
684 appUid); // 4:20
685 processor->OnLogEvent(event.get());
686
687 event = CreateAcquireWakelockEvent(bucketStartTimeNs + (4 * 60 + 25) * NS_PER_SEC,
688 attributionUids1, attributionTags1, "wl1"); // 4:25
689 processor->OnLogEvent(event.get());
690
691 const int64_t duration2StartNs = bucketStartTimeNs + (4 * 60 + 30) * NS_PER_SEC; // 4:30
692 event = CreateScreenStateChangedEvent(duration2StartNs, android::view::DISPLAY_STATE_ON);
693 processor->OnLogEvent(event.get());
694 EXPECT_TRUE(metricsManager->isActive());
695 EXPECT_TRUE(metricProducer->mIsActive);
696 EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
697 EXPECT_EQ(eventActivationMap[4]->start_ns, duration2StartNs);
698 EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
699
700 vector<uint8_t> buffer;
701 ConfigMetricsReportList reports;
702 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
703 FAST, &buffer);
704 ASSERT_GT(buffer.size(), 0);
705 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
706 backfillDimensionPath(&reports);
707 backfillStringInReport(&reports);
708 backfillStartEndTimestamp(&reports);
709
710 ASSERT_EQ(1, reports.reports_size());
711 ASSERT_EQ(1, reports.reports(0).metrics_size());
712 StatsLogReport::DurationMetricDataWrapper durationMetrics;
713 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
714 &durationMetrics);
715 ASSERT_EQ(1, durationMetrics.data_size());
716
717 DurationMetricData data = durationMetrics.data(0);
718 // Validate dimension value.
719 ValidateAttributionUidDimension(data.dimensions_in_what(),
720 util::WAKELOCK_STATE_CHANGED, appUid);
721 // Validate bucket info.
722 ASSERT_EQ(2, data.bucket_info_size());
723
724 auto bucketInfo = data.bucket_info(0);
725 EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
726 EXPECT_EQ(durationEndNs, bucketInfo.end_bucket_elapsed_nanos());
727 EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
728
729 bucketInfo = data.bucket_info(1);
730 EXPECT_EQ(durationEndNs, bucketInfo.start_bucket_elapsed_nanos());
731 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
732 EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - duration2StartNs, bucketInfo.duration_nanos());
733 }
734
TEST(DurationMetricE2eTest,TestWithSlicedState)735 TEST(DurationMetricE2eTest, TestWithSlicedState) {
736 // Initialize config.
737 StatsdConfig config;
738
739 *config.add_atom_matcher() = CreateBatterySaverModeStartAtomMatcher();
740 *config.add_atom_matcher() = CreateBatterySaverModeStopAtomMatcher();
741
742 auto batterySaverModePredicate = CreateBatterySaverModePredicate();
743 *config.add_predicate() = batterySaverModePredicate;
744
745 auto screenState = CreateScreenState();
746 *config.add_state() = screenState;
747
748 // Create duration metric that slices by screen state.
749 auto durationMetric = config.add_duration_metric();
750 durationMetric->set_id(StringToId("DurationBatterySaverModeSliceScreen"));
751 durationMetric->set_what(batterySaverModePredicate.id());
752 durationMetric->add_slice_by_state(screenState.id());
753 durationMetric->set_aggregation_type(DurationMetric::SUM);
754 durationMetric->set_bucket(FIVE_MINUTES);
755
756 // Initialize StatsLogProcessor.
757 int uid = 12345;
758 int64_t cfgId = 98765;
759 ConfigKey cfgKey(uid, cfgId);
760 uint64_t bucketStartTimeNs = 10000000000; // 0:10
761 uint64_t bucketSizeNs =
762 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
763 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
764
765 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
766 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
767 EXPECT_TRUE(metricsManager->isConfigValid());
768 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
769 EXPECT_TRUE(metricsManager->isActive());
770 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
771 EXPECT_TRUE(metricProducer->mIsActive);
772 ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
773 EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
774 ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
775
776 // Check that StateTrackers were initialized correctly.
777 EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
778 EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
779
780 /*
781 bucket #1 bucket #2
782 | 1 2 3 4 5 6 7 8 9 10 (minutes)
783 |-----------------------------|-----------------------------|--
784 ON OFF ON (BatterySaverMode)
785 | | | (ScreenIsOnEvent)
786 | | (ScreenIsOffEvent)
787 | (ScreenDozeEvent)
788 */
789 // Initialize log events.
790 std::vector<std::unique_ptr<LogEvent>> events;
791 events.push_back(CreateScreenStateChangedEvent(
792 bucketStartTimeNs + 10 * NS_PER_SEC,
793 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 0:20
794 events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30
795 events.push_back(CreateScreenStateChangedEvent(
796 bucketStartTimeNs + 50 * NS_PER_SEC,
797 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 1:00
798 events.push_back(CreateScreenStateChangedEvent(
799 bucketStartTimeNs + 80 * NS_PER_SEC,
800 android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 1:30
801 events.push_back(CreateScreenStateChangedEvent(
802 bucketStartTimeNs + 120 * NS_PER_SEC,
803 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 2:10
804 events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30
805 events.push_back(CreateScreenStateChangedEvent(
806 bucketStartTimeNs + 250 * NS_PER_SEC,
807 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 4:20
808 events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50
809
810 // Bucket boundary.
811 events.push_back(CreateScreenStateChangedEvent(
812 bucketStartTimeNs + 310 * NS_PER_SEC,
813 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 5:20
814
815 // Send log events to StatsLogProcessor.
816 for (auto& event : events) {
817 processor->OnLogEvent(event.get());
818 }
819
820 // Check dump report.
821 vector<uint8_t> buffer;
822 ConfigMetricsReportList reports;
823 processor->onDumpReport(cfgKey, bucketStartTimeNs + 360 * NS_PER_SEC,
824 true /* include current partial bucket */, true, ADB_DUMP, FAST,
825 &buffer); // 6:10
826 ASSERT_GT(buffer.size(), 0);
827 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
828 backfillDimensionPath(&reports);
829 backfillStringInReport(&reports);
830 backfillStartEndTimestamp(&reports);
831
832 ASSERT_EQ(1, reports.reports_size());
833 ASSERT_EQ(1, reports.reports(0).metrics_size());
834 EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
835 StatsLogReport::DurationMetricDataWrapper durationMetrics;
836 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
837 &durationMetrics);
838 ASSERT_EQ(3, durationMetrics.data_size());
839
840 DurationMetricData data = durationMetrics.data(0);
841 ASSERT_EQ(1, data.slice_by_state_size());
842 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
843 EXPECT_TRUE(data.slice_by_state(0).has_value());
844 EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
845 ASSERT_EQ(2, data.bucket_info_size());
846 EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
847 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
848 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
849 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
850 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
851 EXPECT_EQ(370 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
852
853 data = durationMetrics.data(1);
854 ASSERT_EQ(1, data.slice_by_state_size());
855 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
856 EXPECT_TRUE(data.slice_by_state(0).has_value());
857 EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
858 ASSERT_EQ(2, data.bucket_info_size());
859 EXPECT_EQ(110 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
860 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
861 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
862 EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
863 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
864 EXPECT_EQ(370 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
865
866 data = durationMetrics.data(2);
867 ASSERT_EQ(1, data.slice_by_state_size());
868 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
869 EXPECT_TRUE(data.slice_by_state(0).has_value());
870 EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE, data.slice_by_state(0).value());
871 ASSERT_EQ(1, data.bucket_info_size());
872 EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
873 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
874 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
875 }
876
TEST(DurationMetricE2eTest,TestWithConditionAndSlicedState)877 TEST(DurationMetricE2eTest, TestWithConditionAndSlicedState) {
878 // Initialize config.
879 StatsdConfig config;
880
881 *config.add_atom_matcher() = CreateBatterySaverModeStartAtomMatcher();
882 *config.add_atom_matcher() = CreateBatterySaverModeStopAtomMatcher();
883 *config.add_atom_matcher() = CreateBatteryStateNoneMatcher();
884 *config.add_atom_matcher() = CreateBatteryStateUsbMatcher();
885
886 auto batterySaverModePredicate = CreateBatterySaverModePredicate();
887 *config.add_predicate() = batterySaverModePredicate;
888
889 auto deviceUnpluggedPredicate = CreateDeviceUnpluggedPredicate();
890 *config.add_predicate() = deviceUnpluggedPredicate;
891
892 auto screenState = CreateScreenState();
893 *config.add_state() = screenState;
894
895 // Create duration metric that has a condition and slices by screen state.
896 auto durationMetric = config.add_duration_metric();
897 durationMetric->set_id(StringToId("DurationBatterySaverModeOnBatterySliceScreen"));
898 durationMetric->set_what(batterySaverModePredicate.id());
899 durationMetric->set_condition(deviceUnpluggedPredicate.id());
900 durationMetric->add_slice_by_state(screenState.id());
901 durationMetric->set_aggregation_type(DurationMetric::SUM);
902 durationMetric->set_bucket(FIVE_MINUTES);
903
904 // Initialize StatsLogProcessor.
905 int uid = 12345;
906 int64_t cfgId = 98765;
907 ConfigKey cfgKey(uid, cfgId);
908 uint64_t bucketStartTimeNs = 10000000000; // 0:10
909 uint64_t bucketSizeNs =
910 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
911 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
912
913 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
914 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
915 EXPECT_TRUE(metricsManager->isConfigValid());
916 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
917 EXPECT_TRUE(metricsManager->isActive());
918 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
919 EXPECT_TRUE(metricProducer->mIsActive);
920 ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
921 EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
922 ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
923
924 // Check that StateTrackers were initialized correctly.
925 EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
926 EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
927
928 /*
929 bucket #1 bucket #2
930 | 1 2 3 4 5 6 7 8 (minutes)
931 |---------------------------------------|------------------
932 ON OFF ON (BatterySaverMode)
933 T F T (DeviceUnpluggedPredicate)
934 | | | (ScreenIsOnEvent)
935 | | | (ScreenIsOffEvent)
936 | (ScreenDozeEvent)
937 */
938 // Initialize log events.
939 std::vector<std::unique_ptr<LogEvent>> events;
940 events.push_back(CreateScreenStateChangedEvent(
941 bucketStartTimeNs + 20 * NS_PER_SEC,
942 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 0:30
943 events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10
944 events.push_back(CreateScreenStateChangedEvent(
945 bucketStartTimeNs + 80 * NS_PER_SEC,
946 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 1:30
947 events.push_back(
948 CreateBatteryStateChangedEvent(bucketStartTimeNs + 110 * NS_PER_SEC,
949 BatteryPluggedStateEnum::BATTERY_PLUGGED_NONE)); // 2:00
950 events.push_back(CreateScreenStateChangedEvent(
951 bucketStartTimeNs + 145 * NS_PER_SEC,
952 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 2:35
953 events.push_back(CreateScreenStateChangedEvent(
954 bucketStartTimeNs + 170 * NS_PER_SEC,
955 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 3:00
956 events.push_back(
957 CreateBatteryStateChangedEvent(bucketStartTimeNs + 180 * NS_PER_SEC,
958 BatteryPluggedStateEnum::BATTERY_PLUGGED_USB)); // 3:10
959 events.push_back(CreateScreenStateChangedEvent(
960 bucketStartTimeNs + 200 * NS_PER_SEC,
961 android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 3:30
962 events.push_back(
963 CreateBatteryStateChangedEvent(bucketStartTimeNs + 230 * NS_PER_SEC,
964 BatteryPluggedStateEnum::BATTERY_PLUGGED_NONE)); // 4:00
965 events.push_back(CreateScreenStateChangedEvent(
966 bucketStartTimeNs + 260 * NS_PER_SEC,
967 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 4:30
968 events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50
969
970 // Bucket boundary.
971 events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 320 * NS_PER_SEC)); // 5:30
972 events.push_back(CreateScreenStateChangedEvent(
973 bucketStartTimeNs + 380 * NS_PER_SEC,
974 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 6:30
975
976 // Send log events to StatsLogProcessor.
977 for (auto& event : events) {
978 processor->OnLogEvent(event.get());
979 }
980
981 // Check dump report.
982 vector<uint8_t> buffer;
983 ConfigMetricsReportList reports;
984 processor->onDumpReport(cfgKey, bucketStartTimeNs + 410 * NS_PER_SEC,
985 true /* include current partial bucket */, true, ADB_DUMP, FAST,
986 &buffer);
987 ASSERT_GT(buffer.size(), 0);
988 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
989 backfillDimensionPath(&reports);
990 backfillStringInReport(&reports);
991 backfillStartEndTimestamp(&reports);
992
993 ASSERT_EQ(1, reports.reports_size());
994 ASSERT_EQ(1, reports.reports(0).metrics_size());
995 EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
996 StatsLogReport::DurationMetricDataWrapper durationMetrics;
997 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
998 &durationMetrics);
999 ASSERT_EQ(3, durationMetrics.data_size());
1000
1001 DurationMetricData data = durationMetrics.data(0);
1002 ASSERT_EQ(1, data.slice_by_state_size());
1003 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1004 EXPECT_TRUE(data.slice_by_state(0).has_value());
1005 EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
1006 ASSERT_EQ(2, data.bucket_info_size());
1007 EXPECT_EQ(45 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
1008 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
1009 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
1010 EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
1011 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
1012 EXPECT_EQ(420 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
1013
1014 data = durationMetrics.data(1);
1015 ASSERT_EQ(1, data.slice_by_state_size());
1016 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1017 EXPECT_TRUE(data.slice_by_state(0).has_value());
1018 EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
1019 ASSERT_EQ(2, data.bucket_info_size());
1020 EXPECT_EQ(45 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
1021 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
1022 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
1023 EXPECT_EQ(60 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
1024 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
1025 EXPECT_EQ(420 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
1026
1027 data = durationMetrics.data(2);
1028 ASSERT_EQ(1, data.slice_by_state_size());
1029 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1030 EXPECT_TRUE(data.slice_by_state(0).has_value());
1031 EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE, data.slice_by_state(0).value());
1032 ASSERT_EQ(1, data.bucket_info_size());
1033 EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
1034 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
1035 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
1036 }
1037
TEST(DurationMetricE2eTest,TestWithSlicedStateMapped)1038 TEST(DurationMetricE2eTest, TestWithSlicedStateMapped) {
1039 // Initialize config.
1040 StatsdConfig config;
1041
1042 *config.add_atom_matcher() = CreateBatterySaverModeStartAtomMatcher();
1043 *config.add_atom_matcher() = CreateBatterySaverModeStopAtomMatcher();
1044
1045 auto batterySaverModePredicate = CreateBatterySaverModePredicate();
1046 *config.add_predicate() = batterySaverModePredicate;
1047
1048 int64_t screenOnId = 4444;
1049 int64_t screenOffId = 9876;
1050 auto screenStateWithMap = CreateScreenStateWithOnOffMap(screenOnId, screenOffId);
1051 *config.add_state() = screenStateWithMap;
1052
1053 // Create duration metric that slices by mapped screen state.
1054 auto durationMetric = config.add_duration_metric();
1055 durationMetric->set_id(StringToId("DurationBatterySaverModeSliceScreenMapped"));
1056 durationMetric->set_what(batterySaverModePredicate.id());
1057 durationMetric->add_slice_by_state(screenStateWithMap.id());
1058 durationMetric->set_aggregation_type(DurationMetric::SUM);
1059 durationMetric->set_bucket(FIVE_MINUTES);
1060
1061 // Initialize StatsLogProcessor.
1062 int uid = 12345;
1063 int64_t cfgId = 98765;
1064 ConfigKey cfgKey(uid, cfgId);
1065 uint64_t bucketStartTimeNs = 10000000000; // 0:10
1066 uint64_t bucketSizeNs =
1067 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
1068 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
1069
1070 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
1071 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
1072 EXPECT_TRUE(metricsManager->isConfigValid());
1073 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
1074 EXPECT_TRUE(metricsManager->isActive());
1075 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
1076 EXPECT_TRUE(metricProducer->mIsActive);
1077 ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
1078 EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
1079 ASSERT_EQ(metricProducer->mStateGroupMap.size(), 1);
1080
1081 // Check that StateTrackers were initialized correctly.
1082 EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
1083 EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
1084
1085 /*
1086 bucket #1 bucket #2
1087 | 1 2 3 4 5 6 7 8 9 10 (minutes)
1088 |-----------------------------|-----------------------------|--
1089 ON OFF ON (BatterySaverMode)
1090 ---------------------------------------------------------SCREEN_OFF events
1091 | | (ScreenStateOffEvent = 1)
1092 | (ScreenStateDozeEvent = 3)
1093 | (ScreenStateDozeSuspendEvent = 4)
1094 ---------------------------------------------------------SCREEN_ON events
1095 | | | (ScreenStateOnEvent = 2)
1096 | (ScreenStateVrEvent = 5)
1097 | (ScreenStateOnSuspendEvent = 6)
1098 */
1099 // Initialize log events.
1100 std::vector<std::unique_ptr<LogEvent>> events;
1101 events.push_back(CreateScreenStateChangedEvent(
1102 bucketStartTimeNs + 10 * NS_PER_SEC,
1103 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 0:20
1104 events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30
1105 events.push_back(CreateScreenStateChangedEvent(
1106 bucketStartTimeNs + 70 * NS_PER_SEC,
1107 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 1:20
1108 events.push_back(CreateScreenStateChangedEvent(
1109 bucketStartTimeNs + 100 * NS_PER_SEC,
1110 android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 1:50
1111 events.push_back(CreateScreenStateChangedEvent(
1112 bucketStartTimeNs + 120 * NS_PER_SEC,
1113 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 2:10
1114 events.push_back(CreateScreenStateChangedEvent(
1115 bucketStartTimeNs + 170 * NS_PER_SEC,
1116 android::view::DisplayStateEnum::DISPLAY_STATE_VR)); // 3:00
1117 events.push_back(CreateBatterySaverOffEvent(bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30
1118 events.push_back(CreateScreenStateChangedEvent(
1119 bucketStartTimeNs + 250 * NS_PER_SEC,
1120 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 4:20
1121 events.push_back(CreateBatterySaverOnEvent(bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50
1122
1123 // Bucket boundary 5:10.
1124 events.push_back(CreateScreenStateChangedEvent(
1125 bucketStartTimeNs + 320 * NS_PER_SEC,
1126 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 5:30
1127 events.push_back(CreateScreenStateChangedEvent(
1128 bucketStartTimeNs + 390 * NS_PER_SEC,
1129 android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND)); // 6:40
1130 events.push_back(CreateScreenStateChangedEvent(
1131 bucketStartTimeNs + 430 * NS_PER_SEC,
1132 android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND)); // 7:20
1133 // Send log events to StatsLogProcessor.
1134 for (auto& event : events) {
1135 processor->OnLogEvent(event.get());
1136 }
1137
1138 // Check dump report.
1139 vector<uint8_t> buffer;
1140 ConfigMetricsReportList reports;
1141 processor->onDumpReport(cfgKey, bucketStartTimeNs + 490 * NS_PER_SEC,
1142 true /* include current partial bucket */, true, ADB_DUMP, FAST,
1143 &buffer);
1144 ASSERT_GT(buffer.size(), 0);
1145 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1146 backfillDimensionPath(&reports);
1147 backfillStringInReport(&reports);
1148 backfillStartEndTimestamp(&reports);
1149
1150 ASSERT_EQ(1, reports.reports_size());
1151 ASSERT_EQ(1, reports.reports(0).metrics_size());
1152 EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
1153 StatsLogReport::DurationMetricDataWrapper durationMetrics;
1154 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
1155 &durationMetrics);
1156 ASSERT_EQ(2, durationMetrics.data_size());
1157
1158 DurationMetricData data = durationMetrics.data(0);
1159 ASSERT_EQ(1, data.slice_by_state_size());
1160 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1161 EXPECT_TRUE(data.slice_by_state(0).has_group_id());
1162 EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id());
1163 ASSERT_EQ(2, data.bucket_info_size());
1164 EXPECT_EQ(130 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
1165 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
1166 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
1167 EXPECT_EQ(110 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
1168 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
1169 EXPECT_EQ(500 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
1170
1171 data = durationMetrics.data(1);
1172 ASSERT_EQ(1, data.slice_by_state_size());
1173 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1174 EXPECT_TRUE(data.slice_by_state(0).has_group_id());
1175 EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
1176 ASSERT_EQ(2, data.bucket_info_size());
1177 EXPECT_EQ(70 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
1178 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
1179 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
1180 EXPECT_EQ(80 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
1181 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
1182 EXPECT_EQ(500 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
1183 }
1184
TEST(DurationMetricE2eTest,TestSlicedStatePrimaryFieldsNotSubsetDimInWhat)1185 TEST(DurationMetricE2eTest, TestSlicedStatePrimaryFieldsNotSubsetDimInWhat) {
1186 // Initialize config.
1187 StatsdConfig config;
1188
1189 *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
1190 *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
1191
1192 auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
1193 *config.add_predicate() = holdingWakelockPredicate;
1194
1195 auto uidProcessState = CreateUidProcessState();
1196 *config.add_state() = uidProcessState;
1197
1198 // Create duration metric that slices by uid process state.
1199 auto durationMetric = config.add_duration_metric();
1200 durationMetric->set_id(StringToId("DurationHoldingWakelockSliceUidProcessState"));
1201 durationMetric->set_what(holdingWakelockPredicate.id());
1202 durationMetric->add_slice_by_state(uidProcessState.id());
1203 durationMetric->set_aggregation_type(DurationMetric::SUM);
1204 durationMetric->set_bucket(FIVE_MINUTES);
1205
1206 // The state has only one primary field (uid).
1207 auto stateLink = durationMetric->add_state_link();
1208 stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
1209 auto fieldsInWhat = stateLink->mutable_fields_in_what();
1210 *fieldsInWhat = CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
1211 auto fieldsInState = stateLink->mutable_fields_in_state();
1212 *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
1213
1214 // Initialize StatsLogProcessor.
1215 int uid = 12345;
1216 int64_t cfgId = 98765;
1217 ConfigKey cfgKey(uid, cfgId);
1218 uint64_t bucketStartTimeNs = 10000000000; // 0:10
1219 uint64_t bucketSizeNs =
1220 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
1221 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
1222
1223 // This config is rejected because the dimension in what fields are not a superset of the sliced
1224 // state primary fields.
1225 ASSERT_EQ(processor->mMetricsManagers.size(), 0);
1226 }
1227
TEST(DurationMetricE2eTest,TestWithSlicedStatePrimaryFieldsSubset)1228 TEST(DurationMetricE2eTest, TestWithSlicedStatePrimaryFieldsSubset) {
1229 // Initialize config.
1230 StatsdConfig config;
1231
1232 *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
1233 *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
1234
1235 auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
1236 *(holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions()) =
1237 CreateAttributionUidAndOtherDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST},
1238 {3 /* tag */});
1239 *config.add_predicate() = holdingWakelockPredicate;
1240
1241 auto uidProcessState = CreateUidProcessState();
1242 *config.add_state() = uidProcessState;
1243
1244 // Create duration metric that slices by uid process state.
1245 auto durationMetric = config.add_duration_metric();
1246 durationMetric->set_id(StringToId("DurationPartialWakelockPerTagUidSliceProcessState"));
1247 durationMetric->set_what(holdingWakelockPredicate.id());
1248 durationMetric->add_slice_by_state(uidProcessState.id());
1249 durationMetric->set_aggregation_type(DurationMetric::SUM);
1250 durationMetric->set_bucket(FIVE_MINUTES);
1251
1252 // The metric is dimensioning by first uid of attribution node and tag.
1253 *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidAndOtherDimensions(
1254 util::WAKELOCK_STATE_CHANGED, {Position::FIRST}, {3 /* tag */});
1255 // The state has only one primary field (uid).
1256 auto stateLink = durationMetric->add_state_link();
1257 stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
1258 auto fieldsInWhat = stateLink->mutable_fields_in_what();
1259 *fieldsInWhat = CreateAttributionUidDimensions(util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
1260 auto fieldsInState = stateLink->mutable_fields_in_state();
1261 *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
1262
1263 // Initialize StatsLogProcessor.
1264 int uid = 12345;
1265 int64_t cfgId = 98765;
1266 ConfigKey cfgKey(uid, cfgId);
1267 uint64_t bucketStartTimeNs = 10000000000; // 0:10
1268 uint64_t bucketSizeNs =
1269 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
1270 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
1271
1272 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
1273 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
1274 EXPECT_TRUE(metricsManager->isConfigValid());
1275 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
1276 EXPECT_TRUE(metricsManager->isActive());
1277 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
1278 EXPECT_TRUE(metricProducer->mIsActive);
1279 ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
1280 EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID);
1281 ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
1282
1283 // Check that StateTrackers were initialized correctly.
1284 EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
1285 EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
1286
1287 // Initialize log events.
1288 int appUid1 = 1001;
1289 int appUid2 = 1002;
1290 std::vector<int> attributionUids1 = {appUid1};
1291 std::vector<string> attributionTags1 = {"App1"};
1292
1293 std::vector<int> attributionUids2 = {appUid2};
1294 std::vector<string> attributionTags2 = {"App2"};
1295
1296 std::vector<std::unique_ptr<LogEvent>> events;
1297 events.push_back(CreateUidProcessStateChangedEvent(
1298 bucketStartTimeNs + 10 * NS_PER_SEC, appUid1,
1299 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 0:20
1300 events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 20 * NS_PER_SEC,
1301 attributionUids1, attributionTags1,
1302 "wakelock1")); // 0:30
1303 events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 25 * NS_PER_SEC,
1304 attributionUids1, attributionTags1,
1305 "wakelock2")); // 0:35
1306 events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 30 * NS_PER_SEC,
1307 attributionUids2, attributionTags2,
1308 "wakelock1")); // 0:40
1309 events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 35 * NS_PER_SEC,
1310 attributionUids2, attributionTags2,
1311 "wakelock2")); // 0:45
1312 events.push_back(CreateUidProcessStateChangedEvent(
1313 bucketStartTimeNs + 50 * NS_PER_SEC, appUid2,
1314 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND)); // 1:00
1315 events.push_back(CreateUidProcessStateChangedEvent(
1316 bucketStartTimeNs + 60 * NS_PER_SEC, appUid1,
1317 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND)); // 1:10
1318 events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 100 * NS_PER_SEC,
1319 attributionUids2, attributionTags2,
1320 "wakelock1")); // 1:50
1321 events.push_back(CreateUidProcessStateChangedEvent(
1322 bucketStartTimeNs + 120 * NS_PER_SEC, appUid2,
1323 android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE)); // 2:10
1324 events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 200 * NS_PER_SEC,
1325 attributionUids1, attributionTags1,
1326 "wakelock2")); // 3:30
1327
1328 // Send log events to StatsLogProcessor.
1329 for (auto& event : events) {
1330 processor->OnLogEvent(event.get());
1331 }
1332
1333 // Check dump report.
1334 vector<uint8_t> buffer;
1335 ConfigMetricsReportList reports;
1336 processor->onDumpReport(cfgKey, bucketStartTimeNs + 320 * NS_PER_SEC,
1337 true /* include current partial bucket */, true, ADB_DUMP, FAST,
1338 &buffer);
1339 ASSERT_GT(buffer.size(), 0);
1340 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1341 backfillDimensionPath(&reports);
1342 backfillStringInReport(&reports);
1343 backfillStartEndTimestamp(&reports);
1344
1345 ASSERT_EQ(1, reports.reports_size());
1346 ASSERT_EQ(1, reports.reports(0).metrics_size());
1347 EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
1348 StatsLogReport::DurationMetricDataWrapper durationMetrics;
1349 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
1350 &durationMetrics);
1351 ASSERT_EQ(9, durationMetrics.data_size());
1352
1353 DurationMetricData data = durationMetrics.data(0);
1354 ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1,
1355 "wakelock1");
1356 ASSERT_EQ(1, data.slice_by_state_size());
1357 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1358 EXPECT_TRUE(data.slice_by_state(0).has_value());
1359 EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
1360 data.slice_by_state(0).value());
1361 ASSERT_EQ(1, data.bucket_info_size());
1362 EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
1363 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
1364 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
1365
1366 data = durationMetrics.data(1);
1367 ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1,
1368 "wakelock1");
1369 ASSERT_EQ(1, data.slice_by_state_size());
1370 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1371 EXPECT_TRUE(data.slice_by_state(0).has_value());
1372 EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
1373 data.slice_by_state(0).value());
1374 ASSERT_EQ(2, data.bucket_info_size());
1375 EXPECT_EQ(240 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
1376 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
1377 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
1378 EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
1379 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
1380 EXPECT_EQ(330 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
1381
1382 data = durationMetrics.data(2);
1383 ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1,
1384 "wakelock2");
1385 ASSERT_EQ(1, data.slice_by_state_size());
1386 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1387 EXPECT_TRUE(data.slice_by_state(0).has_value());
1388 EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
1389 data.slice_by_state(0).value());
1390 ASSERT_EQ(1, data.bucket_info_size());
1391 EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
1392 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
1393 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
1394
1395 data = durationMetrics.data(3);
1396 ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1,
1397 "wakelock2");
1398 ASSERT_EQ(1, data.slice_by_state_size());
1399 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1400 EXPECT_TRUE(data.slice_by_state(0).has_value());
1401 EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
1402 data.slice_by_state(0).value());
1403 ASSERT_EQ(1, data.bucket_info_size());
1404 EXPECT_EQ(140 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
1405 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
1406 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
1407
1408 data = durationMetrics.data(4);
1409 ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
1410 "wakelock1");
1411 ASSERT_EQ(1, data.slice_by_state_size());
1412 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1413 EXPECT_TRUE(data.slice_by_state(0).has_value());
1414 EXPECT_EQ(-1 /* StateTracker:: kStateUnknown */, data.slice_by_state(0).value());
1415 ASSERT_EQ(1, data.bucket_info_size());
1416 EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
1417 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
1418 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
1419
1420 data = durationMetrics.data(5);
1421 ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
1422 "wakelock1");
1423 ASSERT_EQ(1, data.slice_by_state_size());
1424 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1425 EXPECT_TRUE(data.slice_by_state(0).has_value());
1426 EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
1427 data.slice_by_state(0).value());
1428 ASSERT_EQ(1, data.bucket_info_size());
1429 EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
1430 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
1431 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
1432
1433 data = durationMetrics.data(6);
1434 ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
1435 "wakelock2");
1436 ASSERT_EQ(1, data.slice_by_state_size());
1437 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1438 EXPECT_TRUE(data.slice_by_state(0).has_value());
1439 EXPECT_EQ(-1 /* StateTracker:: kStateUnknown */, data.slice_by_state(0).value());
1440 ASSERT_EQ(1, data.bucket_info_size());
1441 EXPECT_EQ(15 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
1442 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
1443 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
1444
1445 data = durationMetrics.data(7);
1446 ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
1447 "wakelock2");
1448 ASSERT_EQ(1, data.slice_by_state_size());
1449 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1450 EXPECT_TRUE(data.slice_by_state(0).has_value());
1451 EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
1452 data.slice_by_state(0).value());
1453 ASSERT_EQ(2, data.bucket_info_size());
1454 EXPECT_EQ(180 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
1455 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
1456 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
1457 EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).duration_nanos());
1458 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos());
1459 EXPECT_EQ(330 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos());
1460
1461 data = durationMetrics.data(8);
1462 ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
1463 "wakelock2");
1464 ASSERT_EQ(1, data.slice_by_state_size());
1465 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1466 EXPECT_TRUE(data.slice_by_state(0).has_value());
1467 EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
1468 data.slice_by_state(0).value());
1469 ASSERT_EQ(1, data.bucket_info_size());
1470 EXPECT_EQ(70 * NS_PER_SEC, data.bucket_info(0).duration_nanos());
1471 EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos());
1472 EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos());
1473 }
1474
TEST(DurationMetricE2eTest,TestUploadThreshold)1475 TEST(DurationMetricE2eTest, TestUploadThreshold) {
1476 StatsdConfig config;
1477
1478 auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
1479 auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
1480 *config.add_atom_matcher() = screenOnMatcher;
1481 *config.add_atom_matcher() = screenOffMatcher;
1482
1483 auto durationPredicate = CreateScreenIsOnPredicate();
1484 *config.add_predicate() = durationPredicate;
1485
1486 int64_t thresholdDurationNs = 30 * 1000 * 1000 * 1000LL; // 30 seconds
1487 UploadThreshold threshold;
1488 threshold.set_gt_int(thresholdDurationNs);
1489
1490 int64_t metricId = 123456;
1491 auto durationMetric = config.add_duration_metric();
1492 durationMetric->set_id(metricId);
1493 durationMetric->set_what(durationPredicate.id());
1494 durationMetric->set_bucket(FIVE_MINUTES);
1495 durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
1496 *durationMetric->mutable_threshold() = threshold;
1497
1498 const int64_t baseTimeNs = 0; // 0:00
1499 const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
1500 const int64_t bucketSizeNs =
1501 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
1502
1503 int uid = 12345;
1504 int64_t cfgId = 98765;
1505 ConfigKey cfgKey(uid, cfgId);
1506
1507 auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
1508
1509 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
1510 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
1511 EXPECT_TRUE(metricsManager->isConfigValid());
1512 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
1513 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
1514 EXPECT_TRUE(metricsManager->isActive());
1515 EXPECT_TRUE(metricProducer->mIsActive);
1516
1517 std::unique_ptr<LogEvent> event;
1518
1519 // Screen is off at start of first bucket.
1520 event = CreateScreenStateChangedEvent(configAddedTimeNs,
1521 android::view::DISPLAY_STATE_OFF); // 0:01
1522 processor->OnLogEvent(event.get());
1523
1524 // Turn screen on.
1525 const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11
1526 event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
1527 processor->OnLogEvent(event.get());
1528
1529 // Turn off screen 30 seconds after turning on.
1530 const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41
1531 event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
1532 processor->OnLogEvent(event.get());
1533
1534 // Turn screen on in second bucket.
1535 const int64_t duration2StartNs = configAddedTimeNs + bucketSizeNs + 10 * NS_PER_SEC; // 5:11
1536 event = CreateScreenStateChangedEvent(duration2StartNs, android::view::DISPLAY_STATE_ON);
1537 processor->OnLogEvent(event.get());
1538
1539 // Turn off screen 31 seconds after turning on.
1540 const int64_t duration2EndNs = duration2StartNs + 31 * NS_PER_SEC; // 5:42
1541 event = CreateScreenStateChangedEvent(duration2EndNs, android::view::DISPLAY_STATE_OFF);
1542 processor->OnLogEvent(event.get());
1543
1544 ConfigMetricsReportList reports;
1545 vector<uint8_t> buffer;
1546 processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs * 2 + 1 * NS_PER_SEC, false,
1547 true, ADB_DUMP, FAST, &buffer); // 10:01
1548 EXPECT_TRUE(buffer.size() > 0);
1549 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1550 backfillDimensionPath(&reports);
1551 backfillStartEndTimestamp(&reports);
1552 ASSERT_EQ(1, reports.reports_size());
1553 ASSERT_EQ(1, reports.reports(0).metrics_size());
1554 EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
1555 EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
1556
1557 StatsLogReport::DurationMetricDataWrapper durationMetrics;
1558 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
1559 &durationMetrics);
1560 ASSERT_EQ(1, durationMetrics.data_size());
1561
1562 DurationMetricData data = durationMetrics.data(0);
1563 ASSERT_EQ(1, data.bucket_info_size());
1564 EXPECT_EQ(duration2EndNs - duration2StartNs, data.bucket_info(0).duration_nanos());
1565 EXPECT_EQ(baseTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
1566 EXPECT_EQ(baseTimeNs + bucketSizeNs * 2, data.bucket_info(0).end_bucket_elapsed_nanos());
1567 }
1568
TEST(DurationMetricE2eTest,TestConditionOnRepeatedEnumField)1569 TEST(DurationMetricE2eTest, TestConditionOnRepeatedEnumField) {
1570 StatsdConfig config;
1571
1572 AtomMatcher repeatedStateFirstOffAtomMatcher = CreateTestAtomRepeatedStateFirstOffAtomMatcher();
1573 AtomMatcher repeatedStateFirstOnAtomMatcher = CreateTestAtomRepeatedStateFirstOnAtomMatcher();
1574 *config.add_atom_matcher() = repeatedStateFirstOffAtomMatcher;
1575 *config.add_atom_matcher() = repeatedStateFirstOnAtomMatcher;
1576
1577 Predicate durationPredicate = CreateTestAtomRepeatedStateFirstOffPredicate();
1578 *config.add_predicate() = durationPredicate;
1579
1580 int64_t metricId = 123456;
1581 DurationMetric* durationMetric = config.add_duration_metric();
1582 durationMetric->set_id(metricId);
1583 durationMetric->set_what(durationPredicate.id());
1584 durationMetric->set_bucket(FIVE_MINUTES);
1585 durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
1586
1587 const int64_t baseTimeNs = 0; // 0:00
1588 const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
1589 const int64_t bucketSizeNs =
1590 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
1591
1592 int uid = 12345;
1593 int64_t cfgId = 98765;
1594 ConfigKey cfgKey(uid, cfgId);
1595
1596 sp<StatsLogProcessor> processor =
1597 CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
1598
1599 vector<int> intArray = {3, 6};
1600 vector<int64_t> longArray = {1000L, 10002L};
1601 vector<float> floatArray = {0.3f, 0.09f};
1602 vector<string> stringArray = {"str1", "str2"};
1603 int boolArrayLength = 2;
1604 bool boolArray[boolArrayLength];
1605 boolArray[0] = 1;
1606 boolArray[1] = 0;
1607 vector<int> enumArrayOff = {TestAtomReported::OFF, TestAtomReported::ON};
1608 vector<int> enumArrayOn = {TestAtomReported::ON, TestAtomReported::OFF};
1609
1610 std::vector<std::unique_ptr<LogEvent>> events;
1611 uint64_t falseDurationStartNs = configAddedTimeNs + 10 * NS_PER_SEC;
1612 uint64_t durationStartNs = configAddedTimeNs + 20 * NS_PER_SEC;
1613 uint64_t durationEndNs = durationStartNs + 50 * NS_PER_SEC;
1614
1615 // Condition false
1616 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(falseDurationStartNs, {}, {},
1617 {}, {}, {}, 0, enumArrayOn));
1618 // Condition true - start collecting duration.
1619 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(durationStartNs, {}, {}, {},
1620 {}, {}, 0, enumArrayOff));
1621 // Condition false - stop collecting duration.
1622 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(durationEndNs, {}, {}, {},
1623 {}, {}, 0, enumArrayOn));
1624
1625 // Send log events to StatsLogProcessor.
1626 for (auto& event : events) {
1627 processor->OnLogEvent(event.get());
1628 }
1629
1630 ConfigMetricsReportList reports;
1631 vector<uint8_t> buffer;
1632 processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
1633 ADB_DUMP, FAST, &buffer); // 10:01
1634 EXPECT_TRUE(buffer.size() > 0);
1635 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1636 backfillDimensionPath(&reports);
1637 backfillStartEndTimestamp(&reports);
1638 ASSERT_EQ(1, reports.reports_size());
1639 ASSERT_EQ(1, reports.reports(0).metrics_size());
1640 EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
1641 EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
1642
1643 StatsLogReport::DurationMetricDataWrapper durationMetrics;
1644 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
1645 &durationMetrics);
1646 ASSERT_EQ(1, durationMetrics.data_size());
1647
1648 DurationMetricData data = durationMetrics.data(0);
1649 ASSERT_EQ(1, data.bucket_info_size());
1650 EXPECT_EQ(durationEndNs - durationStartNs, data.bucket_info(0).duration_nanos());
1651 EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
1652 EXPECT_EQ(baseTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
1653 }
1654
TEST(DurationMetricE2eTest,TestDimensionalSampling)1655 TEST(DurationMetricE2eTest, TestDimensionalSampling) {
1656 ShardOffsetProvider::getInstance().setShardOffset(5);
1657
1658 StatsdConfig config;
1659
1660 *config.add_atom_matcher() = CreateStartScheduledJobAtomMatcher();
1661 *config.add_atom_matcher() = CreateFinishScheduledJobAtomMatcher();
1662 AtomMatcher stopAllMatcher = CreateScheduleScheduledJobAtomMatcher();
1663 *config.add_atom_matcher() = stopAllMatcher;
1664
1665 Predicate scheduledJobPredicate = CreateScheduledJobPredicate();
1666 *scheduledJobPredicate.mutable_simple_predicate()->mutable_dimensions() =
1667 CreateAttributionUidDimensions(util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
1668 SimplePredicate* simplePredicate = scheduledJobPredicate.mutable_simple_predicate();
1669 simplePredicate->set_stop_all(stopAllMatcher.id());
1670 *config.add_predicate() = scheduledJobPredicate;
1671
1672 DurationMetric sampledDurationMetric = createDurationMetric(
1673 "DurationSampledScheduledJobPerUid", scheduledJobPredicate.id(), nullopt, {});
1674 sampledDurationMetric.set_aggregation_type(DurationMetric::SUM);
1675 *sampledDurationMetric.mutable_dimensions_in_what() =
1676 CreateAttributionUidDimensions(util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
1677 *sampledDurationMetric.mutable_dimensional_sampling_info()->mutable_sampled_what_field() =
1678 CreateAttributionUidDimensions(util::SCHEDULED_JOB_STATE_CHANGED, {Position::FIRST});
1679 sampledDurationMetric.mutable_dimensional_sampling_info()->set_shard_count(2);
1680 *config.add_duration_metric() = sampledDurationMetric;
1681
1682 const int64_t configAddedTimeNs = 1 * NS_PER_SEC; // 0:01
1683 const int64_t bucketSizeNs =
1684 TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
1685
1686 int uid = 12345;
1687 int64_t cfgId = 98765;
1688 ConfigKey cfgKey(uid, cfgId);
1689
1690 sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
1691 configAddedTimeNs, configAddedTimeNs, config, cfgKey, nullptr, 0, new UidMap());
1692
1693 int uid1 = 1001; // odd hash value
1694 int uid2 = 1002; // even hash value
1695 int uid3 = 1003; // odd hash value
1696
1697 const int64_t durationStartNs1 = 20 * NS_PER_SEC;
1698 const int64_t durationStartNs2 = 40 * NS_PER_SEC;
1699 const int64_t durationStartNs3 = 60 * NS_PER_SEC;
1700 const int64_t durationStartNs4 = 80 * NS_PER_SEC;
1701 const int64_t durationEndNs1 = 100 * NS_PER_SEC;
1702 const int64_t durationEndNs2 = 110 * NS_PER_SEC;
1703 const int64_t stopAllNs = 130 * NS_PER_SEC;
1704 const int64_t durationEndNs3 = 150 * NS_PER_SEC;
1705 const int64_t durationEndNs4 = 200 * NS_PER_SEC;
1706
1707 std::vector<std::unique_ptr<LogEvent>> events;
1708 events.push_back(CreateStartScheduledJobEvent(durationStartNs1, {uid1}, {"App1"}, "job1"));
1709 events.push_back(CreateStartScheduledJobEvent(durationStartNs2, {uid2}, {"App2"}, "job2"));
1710 events.push_back(CreateStartScheduledJobEvent(durationStartNs3, {uid3}, {"App3"}, "job3"));
1711 events.push_back(CreateFinishScheduledJobEvent(durationEndNs1, {uid1}, {"App1"}, "job1"));
1712 events.push_back(CreateFinishScheduledJobEvent(durationEndNs2, {uid2}, {"App2"}, "job2"));
1713 // This event should pass the sample check regardless of the uid.
1714 events.push_back(CreateScheduleScheduledJobEvent(stopAllNs, {uid2}, {"App2"}, "job2"));
1715 // These events shouldn't do anything since all jobs were stopped with the cancel event.
1716 events.push_back(CreateFinishScheduledJobEvent(durationEndNs3, {uid3}, {"App3"}, "job3"));
1717
1718 // Send log events to StatsLogProcessor.
1719 for (auto& event : events) {
1720 processor->OnLogEvent(event.get());
1721 }
1722
1723 ConfigMetricsReportList reports;
1724 vector<uint8_t> buffer;
1725 processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
1726 FAST, &buffer);
1727 EXPECT_TRUE(buffer.size() > 0);
1728 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1729 backfillDimensionPath(&reports);
1730 backfillStartEndTimestamp(&reports);
1731
1732 ASSERT_EQ(1, reports.reports_size());
1733 ASSERT_EQ(1, reports.reports(0).metrics_size());
1734 EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
1735 StatsLogReport::DurationMetricDataWrapper durationMetrics;
1736 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(),
1737 &durationMetrics);
1738 ASSERT_EQ(2, durationMetrics.data_size());
1739
1740 // Only Uid 1 and 3 are logged. (odd hash value) + (offset of 5) % (shard count of 2) = 0
1741 DurationMetricData data = durationMetrics.data(0);
1742 ValidateAttributionUidDimension(data.dimensions_in_what(), util::SCHEDULED_JOB_STATE_CHANGED,
1743 uid1);
1744 ValidateDurationBucket(data.bucket_info(0), configAddedTimeNs, configAddedTimeNs + bucketSizeNs,
1745 durationEndNs1 - durationStartNs1);
1746
1747 data = durationMetrics.data(1);
1748 ValidateAttributionUidDimension(data.dimensions_in_what(), util::SCHEDULED_JOB_STATE_CHANGED,
1749 uid3);
1750 ValidateDurationBucket(data.bucket_info(0), configAddedTimeNs, configAddedTimeNs + bucketSizeNs,
1751 stopAllNs - durationStartNs3);
1752 }
1753
1754 #else
1755 GTEST_LOG_(INFO) << "This test does nothing.\n";
1756 #endif
1757
1758 } // namespace statsd
1759 } // namespace os
1760 } // namespace android
1761