1 /*
2 * Copyright (C) 2019, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <gtest/gtest.h>
18
19 #include "src/StatsLogProcessor.h"
20 #include "src/state/StateManager.h"
21 #include "src/state/StateTracker.h"
22 #include "tests/statsd_test_util.h"
23
24 namespace android {
25 namespace os {
26 namespace statsd {
27
28 #ifdef __ANDROID__
29
30 /**
31 * Tests the initial condition and condition after the first log events for
32 * count metrics with either a combination condition or simple condition.
33 *
34 * Metrics should be initialized with condition kUnknown (given that the
35 * predicate is using the default InitialValue of UNKNOWN). The condition should
36 * be updated to either kFalse or kTrue if a condition event is logged for all
37 * children conditions.
38 */
TEST(CountMetricE2eTest,TestInitialConditionChanges)39 TEST(CountMetricE2eTest, TestInitialConditionChanges) {
40 // Initialize config.
41 StatsdConfig config;
42 config.add_default_pull_packages("AID_ROOT"); // Fake puller is registered with root.
43
44 auto syncStartMatcher = CreateSyncStartAtomMatcher();
45 *config.add_atom_matcher() = syncStartMatcher;
46 *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
47 *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
48 *config.add_atom_matcher() = CreateBatteryStateNoneMatcher();
49 *config.add_atom_matcher() = CreateBatteryStateUsbMatcher();
50
51 auto screenOnPredicate = CreateScreenIsOnPredicate();
52 *config.add_predicate() = screenOnPredicate;
53
54 auto deviceUnpluggedPredicate = CreateDeviceUnpluggedPredicate();
55 *config.add_predicate() = deviceUnpluggedPredicate;
56
57 auto screenOnOnBatteryPredicate = config.add_predicate();
58 screenOnOnBatteryPredicate->set_id(StringToId("screenOnOnBatteryPredicate"));
59 screenOnOnBatteryPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
60 addPredicateToPredicateCombination(screenOnPredicate, screenOnOnBatteryPredicate);
61 addPredicateToPredicateCombination(deviceUnpluggedPredicate, screenOnOnBatteryPredicate);
62
63 // CountSyncStartWhileScreenOnOnBattery (CombinationCondition)
64 CountMetric* countMetric1 = config.add_count_metric();
65 countMetric1->set_id(StringToId("CountSyncStartWhileScreenOnOnBattery"));
66 countMetric1->set_what(syncStartMatcher.id());
67 countMetric1->set_condition(screenOnOnBatteryPredicate->id());
68 countMetric1->set_bucket(FIVE_MINUTES);
69
70 // CountSyncStartWhileOnBattery (SimpleCondition)
71 CountMetric* countMetric2 = config.add_count_metric();
72 countMetric2->set_id(StringToId("CountSyncStartWhileOnBatterySliceScreen"));
73 countMetric2->set_what(syncStartMatcher.id());
74 countMetric2->set_condition(deviceUnpluggedPredicate.id());
75 countMetric2->set_bucket(FIVE_MINUTES);
76
77 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
78 const uint64_t bucketSizeNs =
79 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
80 int uid = 12345;
81 int64_t cfgId = 98765;
82 ConfigKey cfgKey(uid, cfgId);
83 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
84
85 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
86 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
87 EXPECT_TRUE(metricsManager->isConfigValid());
88 EXPECT_EQ(2, metricsManager->mAllMetricProducers.size());
89
90 sp<MetricProducer> metricProducer1 = metricsManager->mAllMetricProducers[0];
91 sp<MetricProducer> metricProducer2 = metricsManager->mAllMetricProducers[1];
92
93 EXPECT_EQ(ConditionState::kUnknown, metricProducer1->mCondition);
94 EXPECT_EQ(ConditionState::kUnknown, metricProducer2->mCondition);
95
96 auto screenOnEvent =
97 CreateScreenStateChangedEvent(bucketStartTimeNs + 30, android::view::DISPLAY_STATE_ON);
98 processor->OnLogEvent(screenOnEvent.get());
99 EXPECT_EQ(ConditionState::kUnknown, metricProducer1->mCondition);
100 EXPECT_EQ(ConditionState::kUnknown, metricProducer2->mCondition);
101
102 auto pluggedUsbEvent = CreateBatteryStateChangedEvent(
103 bucketStartTimeNs + 50, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
104 processor->OnLogEvent(pluggedUsbEvent.get());
105 EXPECT_EQ(ConditionState::kFalse, metricProducer1->mCondition);
106 EXPECT_EQ(ConditionState::kFalse, metricProducer2->mCondition);
107
108 auto pluggedNoneEvent = CreateBatteryStateChangedEvent(
109 bucketStartTimeNs + 70, BatteryPluggedStateEnum::BATTERY_PLUGGED_NONE);
110 processor->OnLogEvent(pluggedNoneEvent.get());
111 EXPECT_EQ(ConditionState::kTrue, metricProducer1->mCondition);
112 EXPECT_EQ(ConditionState::kTrue, metricProducer2->mCondition);
113 }
114
TEST(CountMetricE2eTest,TestConditionTrueNanos)115 TEST(CountMetricE2eTest, TestConditionTrueNanos) {
116 // Initialize config.
117 StatsdConfig config;
118 config.add_default_pull_packages("AID_ROOT"); // Fake puller is registered with root.
119
120 AtomMatcher syncStartMatcher = CreateSyncStartAtomMatcher();
121 *config.add_atom_matcher() = syncStartMatcher;
122 *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
123 *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
124
125 AtomMatcher crashMatcher = CreateProcessCrashAtomMatcher();
126 *config.add_atom_matcher() = crashMatcher;
127
128 Predicate screenOnPredicate = CreateScreenIsOnPredicate();
129 *config.add_predicate() = screenOnPredicate;
130
131 CountMetric* countMetric = config.add_count_metric();
132 int64_t metricId = StringToId("CountSyncStartWhileScreenOn");
133 countMetric->set_id(metricId);
134 countMetric->set_what(syncStartMatcher.id());
135 countMetric->set_condition(screenOnPredicate.id());
136 countMetric->set_bucket(FIVE_MINUTES);
137
138 MetricActivation* metricActivation = config.add_metric_activation();
139 metricActivation->set_metric_id(metricId);
140 EventActivation* eventActivation = metricActivation->add_event_activation();
141 eventActivation->set_atom_matcher_id(crashMatcher.id());
142 eventActivation->set_ttl_seconds(360); // 6 minutes.
143
144 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
145 const uint64_t bucketSizeNs =
146 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
147 const uint64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
148 const uint64_t bucket3StartTimeNs = bucket2StartTimeNs + bucketSizeNs;
149
150 int uid = 12345;
151 int64_t cfgId = 98765;
152 ConfigKey cfgKey(uid, cfgId);
153 sp<StatsLogProcessor> processor =
154 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
155
156 std::vector<int> attributionUids1 = {123};
157 std::vector<string> attributionTags1 = {"App1"};
158 int64_t conditionStart1Ns = bucketStartTimeNs + 50 * NS_PER_SEC;
159 int64_t activationStart1Ns = bucketStartTimeNs + 70 * NS_PER_SEC;
160 int64_t conditionEnd1Ns = bucket2StartTimeNs + 35 * NS_PER_SEC;
161 int64_t conditionStart2Ns = bucket2StartTimeNs + 90 * NS_PER_SEC;
162 int64_t activationEnd1Ns = bucket2StartTimeNs + 140 * NS_PER_SEC;
163 int64_t conditionEnd2Ns = bucket2StartTimeNs + 155 * NS_PER_SEC;
164 int64_t activationStart2Ns = bucket2StartTimeNs + 200 * NS_PER_SEC;
165 int64_t conditionStart3Ns = bucket2StartTimeNs + 240 * NS_PER_SEC;
166 int64_t conditionEnd3Ns = bucket3StartTimeNs + 40 * NS_PER_SEC;
167 int64_t activationEnd2Ns = bucket3StartTimeNs + 270 * NS_PER_SEC;
168
169 std::vector<std::unique_ptr<LogEvent>> events;
170 // Active false, condition becomes true.
171 events.push_back(CreateScreenStateChangedEvent(
172 conditionStart1Ns,
173 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 1:00
174 // Event not counted.
175 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 60 * NS_PER_SEC, attributionUids1,
176 attributionTags1, "sync_name")); // 1:10
177 // Active becomes true, condition true.
178 events.push_back(CreateAppCrashEvent(activationStart1Ns, 111)); // 1:20
179 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 75 * NS_PER_SEC, attributionUids1,
180 attributionTags1, "sync_name")); // 1:25
181
182 // Bucket 2 starts. 5:10
183 events.push_back(CreateSyncStartEvent(bucket2StartTimeNs + 20 * NS_PER_SEC, attributionUids1,
184 attributionTags1, "sync_name")); // 5:30
185 // Active true, condition becomes false.
186 events.push_back(CreateScreenStateChangedEvent(
187 conditionEnd1Ns,
188 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 5:45
189 // Event not counted.
190 events.push_back(CreateSyncStartEvent(bucket2StartTimeNs + 50 * NS_PER_SEC, attributionUids1,
191 attributionTags1, "sync_name")); // 6:00
192 // Active true, condition becomes true.
193 events.push_back(CreateScreenStateChangedEvent(
194 conditionStart2Ns,
195 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 6:40
196 events.push_back(CreateSyncStartEvent(bucket2StartTimeNs + 110 * NS_PER_SEC, attributionUids1,
197 attributionTags1, "sync_name")); // 7:00
198 // Active becomes false, condition true (activation expires).
199 // Event not counted.
200 events.push_back(CreateSyncStartEvent(activationEnd1Ns, attributionUids1, attributionTags1,
201 "sync_name")); // 7:30
202 // Active false, condition becomes false.
203 events.push_back(CreateScreenStateChangedEvent(
204 conditionEnd2Ns,
205 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 7:45
206 // Event not counted.
207 events.push_back(CreateSyncStartEvent(bucket2StartTimeNs + 160 * NS_PER_SEC, attributionUids1,
208 attributionTags1, "sync_name")); // 7:50
209 // Active becomes true, condition false.
210 events.push_back(CreateAppCrashEvent(activationStart2Ns, 111)); // 8:30
211 // Event not counted.
212 events.push_back(CreateSyncStartEvent(bucket2StartTimeNs + 220 * NS_PER_SEC, attributionUids1,
213 attributionTags1, "sync_name")); // 8:50
214 // Active true, condition becomes true.
215 events.push_back(CreateScreenStateChangedEvent(
216 conditionStart3Ns,
217 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 9:10
218 events.push_back(CreateSyncStartEvent(bucket2StartTimeNs + 250 * NS_PER_SEC, attributionUids1,
219 attributionTags1, "sync_name")); // 9:20
220
221 // Bucket 3 starts. 10:10
222 events.push_back(CreateSyncStartEvent(bucket3StartTimeNs + 10 * NS_PER_SEC, attributionUids1,
223 attributionTags1, "sync_name")); // 10:20
224 // Active true, condition becomes false.
225 events.push_back(CreateScreenStateChangedEvent(
226 conditionEnd3Ns,
227 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 10:50
228 // Event not counted.
229 events.push_back(CreateSyncStartEvent(bucket3StartTimeNs + 70 * NS_PER_SEC, attributionUids1,
230 attributionTags1, "sync_name")); // 11:20
231 // Active becomes false, condition false (activation expires).
232 // Event not counted.
233 events.push_back(CreateSyncStartEvent(activationEnd2Ns, attributionUids1, attributionTags1,
234 "sync_name")); // 14:40
235
236 // Send log events to StatsLogProcessor.
237 for (auto& event : events) {
238 processor->OnLogEvent(event.get());
239 }
240
241 // Check dump report.
242 vector<uint8_t> buffer;
243 ConfigMetricsReportList reports;
244 int64_t dumpReportTimeNs = bucket3StartTimeNs + 290 * NS_PER_SEC; // 15:00
245 processor->onDumpReport(cfgKey, dumpReportTimeNs, true, true, ADB_DUMP, FAST, &buffer);
246 ASSERT_GT(buffer.size(), 0);
247 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
248 backfillDimensionPath(&reports);
249 backfillStringInReport(&reports);
250 backfillStartEndTimestamp(&reports);
251
252 ASSERT_EQ(1, reports.reports_size());
253 ASSERT_EQ(1, reports.reports(0).metrics_size());
254 EXPECT_TRUE(reports.reports(0).metrics(0).has_estimated_data_bytes());
255 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
256 StatsLogReport::CountMetricDataWrapper countMetrics;
257 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
258 ASSERT_EQ(1, countMetrics.data_size());
259
260 CountMetricData data = countMetrics.data(0);
261 ASSERT_EQ(4, data.bucket_info_size());
262 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucket2StartTimeNs, 1,
263 bucket2StartTimeNs - activationStart1Ns);
264 ValidateCountBucket(
265 data.bucket_info(1), bucket2StartTimeNs, activationEnd1Ns, 2,
266 (conditionEnd1Ns - bucket2StartTimeNs) + (activationEnd1Ns - conditionStart2Ns));
267 ValidateCountBucket(data.bucket_info(2), activationEnd1Ns, bucket3StartTimeNs, 1,
268 bucket3StartTimeNs - conditionStart3Ns);
269 ValidateCountBucket(data.bucket_info(3), bucket3StartTimeNs, activationEnd2Ns, 1,
270 conditionEnd3Ns - bucket3StartTimeNs);
271 }
272
273 /**
274 * Test a count metric that has one slice_by_state with no primary fields.
275 *
276 * Once the CountMetricProducer is initialized, it has one atom id in
277 * mSlicedStateAtoms and no entries in mStateGroupMap.
278
279 * One StateTracker tracks the state atom, and it has one listener which is the
280 * CountMetricProducer that was initialized.
281 */
TEST(CountMetricE2eTest,TestSlicedState)282 TEST(CountMetricE2eTest, TestSlicedState) {
283 // Initialize config.
284 StatsdConfig config;
285
286 auto syncStartMatcher = CreateSyncStartAtomMatcher();
287 *config.add_atom_matcher() = syncStartMatcher;
288
289 auto state = CreateScreenState();
290 *config.add_state() = state;
291
292 // Create count metric that slices by screen state.
293 int64_t metricId = 123456;
294 auto countMetric = config.add_count_metric();
295 countMetric->set_id(metricId);
296 countMetric->set_what(syncStartMatcher.id());
297 countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
298 countMetric->add_slice_by_state(state.id());
299
300 // Initialize StatsLogProcessor.
301 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
302 const uint64_t bucketSizeNs =
303 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
304 int uid = 12345;
305 int64_t cfgId = 98765;
306 ConfigKey cfgKey(uid, cfgId);
307 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
308
309 // Check that CountMetricProducer was initialized correctly.
310 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
311 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
312 EXPECT_TRUE(metricsManager->isConfigValid());
313 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
314 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
315 ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
316 EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
317 ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
318
319 // Check that StateTrackers were initialized correctly.
320 EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
321 EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
322
323 /*
324 bucket #1 bucket #2
325 | 1 2 3 4 5 6 7 8 9 10 (minutes)
326 |-----------------------------|-----------------------------|--
327 x x x x x x (syncStartEvents)
328 | | (ScreenIsOnEvent)
329 | | (ScreenIsOffEvent)
330 | (ScreenDozeEvent)
331 */
332 // Initialize log events - first bucket.
333 std::vector<int> attributionUids1 = {123};
334 std::vector<string> attributionTags1 = {"App1"};
335
336 std::vector<std::unique_ptr<LogEvent>> events;
337 events.push_back(CreateScreenStateChangedEvent(
338 bucketStartTimeNs + 50 * NS_PER_SEC,
339 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 1:00
340 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 75 * NS_PER_SEC, attributionUids1,
341 attributionTags1, "sync_name")); // 1:25
342 events.push_back(CreateScreenStateChangedEvent(
343 bucketStartTimeNs + 150 * NS_PER_SEC,
344 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 2:40
345 events.push_back(CreateScreenStateChangedEvent(
346 bucketStartTimeNs + 200 * NS_PER_SEC,
347 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 3:30
348 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 250 * NS_PER_SEC, attributionUids1,
349 attributionTags1, "sync_name")); // 4:20
350
351 // Initialize log events - second bucket.
352 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 350 * NS_PER_SEC, attributionUids1,
353 attributionTags1, "sync_name")); // 6:00
354 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 400 * NS_PER_SEC, attributionUids1,
355 attributionTags1, "sync_name")); // 6:50
356 events.push_back(CreateScreenStateChangedEvent(
357 bucketStartTimeNs + 450 * NS_PER_SEC,
358 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 7:40
359 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 475 * NS_PER_SEC, attributionUids1,
360 attributionTags1, "sync_name")); // 8:05
361 events.push_back(CreateScreenStateChangedEvent(
362 bucketStartTimeNs + 500 * NS_PER_SEC,
363 android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN)); // 8:30
364 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 520 * NS_PER_SEC, attributionUids1,
365 attributionTags1, "sync_name")); // 8:50
366
367 // Send log events to StatsLogProcessor.
368 for (auto& event : events) {
369 processor->OnLogEvent(event.get());
370 }
371
372 // Check dump report.
373 vector<uint8_t> buffer;
374 ConfigMetricsReportList reports;
375 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
376 FAST, &buffer);
377 ASSERT_GT(buffer.size(), 0);
378 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
379 backfillDimensionPath(&reports);
380 backfillStringInReport(&reports);
381 backfillStartEndTimestamp(&reports);
382
383 ASSERT_EQ(1, reports.reports_size());
384 ASSERT_EQ(1, reports.reports(0).metrics_size());
385 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
386 StatsLogReport::CountMetricDataWrapper countMetrics;
387 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
388 ASSERT_EQ(3, countMetrics.data_size());
389
390 // For each CountMetricData, check StateValue info is correct and buckets
391 // have correct counts.
392 auto data = countMetrics.data(0);
393 ASSERT_EQ(1, data.slice_by_state_size());
394 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
395 EXPECT_TRUE(data.slice_by_state(0).has_value());
396 EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
397 data.slice_by_state(0).value());
398 ASSERT_EQ(1, data.bucket_info_size());
399 EXPECT_EQ(1, data.bucket_info(0).count());
400
401 data = countMetrics.data(1);
402 ASSERT_EQ(1, data.slice_by_state_size());
403 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
404 EXPECT_TRUE(data.slice_by_state(0).has_value());
405 EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
406 ASSERT_EQ(2, data.bucket_info_size());
407 EXPECT_EQ(1, data.bucket_info(0).count());
408 EXPECT_EQ(2, data.bucket_info(1).count());
409
410 data = countMetrics.data(2);
411 ASSERT_EQ(1, data.slice_by_state_size());
412 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
413 EXPECT_TRUE(data.slice_by_state(0).has_value());
414 EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
415 ASSERT_EQ(2, data.bucket_info_size());
416 EXPECT_EQ(1, data.bucket_info(0).count());
417 EXPECT_EQ(1, data.bucket_info(1).count());
418 }
419
420 /**
421 * Test a count metric that has one slice_by_state with a mapping and no
422 * primary fields.
423 *
424 * Once the CountMetricProducer is initialized, it has one atom id in
425 * mSlicedStateAtoms and has one entry per state value in mStateGroupMap.
426 *
427 * One StateTracker tracks the state atom, and it has one listener which is the
428 * CountMetricProducer that was initialized.
429 */
TEST(CountMetricE2eTest,TestSlicedStateWithMap)430 TEST(CountMetricE2eTest, TestSlicedStateWithMap) {
431 // Initialize config.
432 StatsdConfig config;
433
434 auto syncStartMatcher = CreateSyncStartAtomMatcher();
435 *config.add_atom_matcher() = syncStartMatcher;
436
437 int64_t screenOnId = 4444;
438 int64_t screenOffId = 9876;
439 auto state = CreateScreenStateWithOnOffMap(screenOnId, screenOffId);
440 *config.add_state() = state;
441
442 // Create count metric that slices by screen state with on/off map.
443 int64_t metricId = 123456;
444 auto countMetric = config.add_count_metric();
445 countMetric->set_id(metricId);
446 countMetric->set_what(syncStartMatcher.id());
447 countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
448 countMetric->add_slice_by_state(state.id());
449
450 // Initialize StatsLogProcessor.
451 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
452 const uint64_t bucketSizeNs =
453 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
454 int uid = 12345;
455 int64_t cfgId = 98765;
456 ConfigKey cfgKey(uid, cfgId);
457 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
458
459 // Check that StateTrackers were initialized correctly.
460 EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
461 EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
462
463 // Check that CountMetricProducer was initialized correctly.
464 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
465 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
466 EXPECT_TRUE(metricsManager->isConfigValid());
467 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
468 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
469 ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
470 EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
471 ASSERT_EQ(metricProducer->mStateGroupMap.size(), 1);
472
473 StateMap map = state.map();
474 for (auto group : map.group()) {
475 for (auto value : group.value()) {
476 EXPECT_EQ(metricProducer->mStateGroupMap.at(SCREEN_STATE_ATOM_ID).at(value),
477 group.group_id());
478 }
479 }
480
481 /*
482 bucket #1 bucket #2
483 | 1 2 3 4 5 6 7 8 9 10 (minutes)
484 |-----------------------------|-----------------------------|--
485 x x x x x x x x x (syncStartEvents)
486 -----------------------------------------------------------SCREEN_OFF events
487 | | (ScreenStateOffEvent = 1)
488 | | (ScreenStateDozeEvent = 3)
489 | (ScreenStateDozeSuspendEvent =
490 4)
491 -----------------------------------------------------------SCREEN_ON events
492 | | (ScreenStateOnEvent = 2)
493 | (ScreenStateVrEvent = 5)
494 | (ScreenStateOnSuspendEvent = 6)
495 */
496 // Initialize log events - first bucket.
497 std::vector<int> attributionUids1 = {123};
498 std::vector<string> attributionTags1 = {"App1"};
499
500 std::vector<std::unique_ptr<LogEvent>> events;
501 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 20 * NS_PER_SEC, attributionUids1,
502 attributionTags1, "sync_name")); // 0:30
503 events.push_back(CreateScreenStateChangedEvent(
504 bucketStartTimeNs + 30 * NS_PER_SEC,
505 android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 0:40
506 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 60 * NS_PER_SEC, attributionUids1,
507 attributionTags1, "sync_name")); // 1:10
508 events.push_back(CreateScreenStateChangedEvent(
509 bucketStartTimeNs + 90 * NS_PER_SEC,
510 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 1:40
511 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 120 * NS_PER_SEC, attributionUids1,
512 attributionTags1, "sync_name")); // 2:10
513 events.push_back(CreateScreenStateChangedEvent(
514 bucketStartTimeNs + 150 * NS_PER_SEC,
515 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 2:40
516 events.push_back(CreateScreenStateChangedEvent(
517 bucketStartTimeNs + 180 * NS_PER_SEC,
518 android::view::DisplayStateEnum::DISPLAY_STATE_VR)); // 3:10
519 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 200 * NS_PER_SEC, attributionUids1,
520 attributionTags1, "sync_name")); // 3:30
521 events.push_back(CreateScreenStateChangedEvent(
522 bucketStartTimeNs + 210 * NS_PER_SEC,
523 android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 3:40
524 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 250 * NS_PER_SEC, attributionUids1,
525 attributionTags1, "sync_name")); // 4:20
526 events.push_back(CreateScreenStateChangedEvent(
527 bucketStartTimeNs + 280 * NS_PER_SEC,
528 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 4:50
529 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 285 * NS_PER_SEC, attributionUids1,
530 attributionTags1, "sync_name")); // 4:55
531
532 // Initialize log events - second bucket.
533 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 360 * NS_PER_SEC, attributionUids1,
534 attributionTags1, "sync_name")); // 6:10
535 events.push_back(CreateScreenStateChangedEvent(
536 bucketStartTimeNs + 390 * NS_PER_SEC,
537 android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND)); // 6:40
538 events.push_back(CreateScreenStateChangedEvent(
539 bucketStartTimeNs + 430 * NS_PER_SEC,
540 android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND)); // 7:20
541 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 440 * NS_PER_SEC, attributionUids1,
542 attributionTags1, "sync_name")); // 7:30
543 events.push_back(CreateScreenStateChangedEvent(
544 bucketStartTimeNs + 540 * NS_PER_SEC,
545 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 9:10
546 events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 570 * NS_PER_SEC, attributionUids1,
547 attributionTags1, "sync_name")); // 9:40
548
549 // Send log events to StatsLogProcessor.
550 for (auto& event : events) {
551 processor->OnLogEvent(event.get());
552 }
553
554 // Check dump report.
555 vector<uint8_t> buffer;
556 ConfigMetricsReportList reports;
557 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
558 FAST, &buffer);
559 ASSERT_GT(buffer.size(), 0);
560 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
561 backfillDimensionPath(&reports);
562 backfillStringInReport(&reports);
563 backfillStartEndTimestamp(&reports);
564
565 ASSERT_EQ(1, reports.reports_size());
566 ASSERT_EQ(1, reports.reports(0).metrics_size());
567 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
568 StatsLogReport::CountMetricDataWrapper countMetrics;
569 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
570 ASSERT_EQ(3, countMetrics.data_size());
571
572 // For each CountMetricData, check StateValue info is correct and buckets
573 // have correct counts.
574 auto data = countMetrics.data(0);
575 ASSERT_EQ(1, data.slice_by_state_size());
576 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
577 EXPECT_TRUE(data.slice_by_state(0).has_value());
578 EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
579 ASSERT_EQ(1, data.bucket_info_size());
580 EXPECT_EQ(1, data.bucket_info(0).count());
581
582 data = countMetrics.data(1);
583 ASSERT_EQ(1, data.slice_by_state_size());
584 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
585 EXPECT_TRUE(data.slice_by_state(0).has_group_id());
586 EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id());
587 ASSERT_EQ(2, data.bucket_info_size());
588 EXPECT_EQ(1, data.bucket_info(0).count());
589 EXPECT_EQ(1, data.bucket_info(1).count());
590
591 data = countMetrics.data(2);
592 ASSERT_EQ(1, data.slice_by_state_size());
593 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
594 EXPECT_TRUE(data.slice_by_state(0).has_group_id());
595 EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
596 ASSERT_EQ(2, data.bucket_info_size());
597 EXPECT_EQ(4, data.bucket_info(0).count());
598 EXPECT_EQ(2, data.bucket_info(1).count());
599 }
600
601 /**
602 * Test a count metric that has one slice_by_state with a primary field.
603
604 * Once the CountMetricProducer is initialized, it should have one
605 * MetricStateLink stored. State querying using a non-empty primary key
606 * should also work as intended.
607 */
TEST(CountMetricE2eTest,TestSlicedStateWithPrimaryFields)608 TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) {
609 // Initialize config.
610 StatsdConfig config;
611
612 auto appCrashMatcher =
613 CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED);
614 *config.add_atom_matcher() = appCrashMatcher;
615
616 auto state = CreateUidProcessState();
617 *config.add_state() = state;
618
619 // Create count metric that slices by uid process state.
620 int64_t metricId = 123456;
621 auto countMetric = config.add_count_metric();
622 countMetric->set_id(metricId);
623 countMetric->set_what(appCrashMatcher.id());
624 countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
625 countMetric->add_slice_by_state(state.id());
626 *countMetric->mutable_dimensions_in_what() =
627 CreateDimensions(util::APP_CRASH_OCCURRED, {1 /*uid*/});
628 MetricStateLink* stateLink = countMetric->add_state_link();
629 stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
630 auto fieldsInWhat = stateLink->mutable_fields_in_what();
631 *fieldsInWhat = CreateDimensions(util::APP_CRASH_OCCURRED, {1 /*uid*/});
632 auto fieldsInState = stateLink->mutable_fields_in_state();
633 *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/});
634
635 // Initialize StatsLogProcessor.
636 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
637 const uint64_t bucketSizeNs =
638 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
639 int uid = 12345;
640 int64_t cfgId = 98765;
641 ConfigKey cfgKey(uid, cfgId);
642 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
643
644 // Check that StateTrackers were initialized correctly.
645 EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
646 EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
647
648 // Check that CountMetricProducer was initialized correctly.
649 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
650 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
651 EXPECT_TRUE(metricsManager->isConfigValid());
652 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
653 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
654 ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
655 EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID);
656 ASSERT_EQ(metricProducer->mStateGroupMap.size(), 0);
657 ASSERT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
658
659 /*
660 NOTE: "1" or "2" represents the uid associated with the state/app crash event
661 bucket #1 bucket #2
662 | 1 2 3 4 5 6 7 8 9 10
663 |------------------------|-------------------------|--
664 1 1 1 1 1 2 1 1 2 (AppCrashEvents)
665 -----------------------------------------------------PROCESS STATE events
666 1 2 (TopEvent = 1002)
667 1 1 (ForegroundServiceEvent = 1003)
668 2 (ImportantBackgroundEvent = 1006)
669 1 1 1 (ImportantForegroundEvent = 1005)
670
671 Based on the diagram above, an AppCrashEvent querying for process state value would return:
672 - StateTracker::kStateUnknown
673 - Important foreground
674 - Top
675 - Important foreground
676 - Foreground service
677 - Top (both the app crash and state still have matching uid = 2)
678
679 - Foreground service
680 - Foreground service
681 - Important background
682 */
683 // Initialize log events - first bucket.
684 std::vector<std::unique_ptr<LogEvent>> events;
685 events.push_back(
686 CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /*uid*/)); // 0:30
687 events.push_back(CreateUidProcessStateChangedEvent(
688 bucketStartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/,
689 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 0:40
690 events.push_back(
691 CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, 1 /*uid*/)); // 1:10
692 events.push_back(CreateUidProcessStateChangedEvent(
693 bucketStartTimeNs + 90 * NS_PER_SEC, 1 /*uid*/,
694 android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 1:40
695 events.push_back(
696 CreateAppCrashOccurredEvent(bucketStartTimeNs + 120 * NS_PER_SEC, 1 /*uid*/)); // 2:10
697 events.push_back(CreateUidProcessStateChangedEvent(
698 bucketStartTimeNs + 150 * NS_PER_SEC, 1 /*uid*/,
699 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 2:40
700 events.push_back(
701 CreateAppCrashOccurredEvent(bucketStartTimeNs + 200 * NS_PER_SEC, 1 /*uid*/)); // 3:30
702 events.push_back(CreateUidProcessStateChangedEvent(
703 bucketStartTimeNs + 210 * NS_PER_SEC, 1 /*uid*/,
704 android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE)); // 3:40
705 events.push_back(
706 CreateAppCrashOccurredEvent(bucketStartTimeNs + 250 * NS_PER_SEC, 1 /*uid*/)); // 4:20
707 events.push_back(CreateUidProcessStateChangedEvent(
708 bucketStartTimeNs + 280 * NS_PER_SEC, 2 /*uid*/,
709 android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 4:50
710 events.push_back(
711 CreateAppCrashOccurredEvent(bucketStartTimeNs + 285 * NS_PER_SEC, 2 /*uid*/)); // 4:55
712
713 // Initialize log events - second bucket.
714 events.push_back(
715 CreateAppCrashOccurredEvent(bucketStartTimeNs + 360 * NS_PER_SEC, 1 /*uid*/)); // 6:10
716 events.push_back(CreateUidProcessStateChangedEvent(
717 bucketStartTimeNs + 390 * NS_PER_SEC, 1 /*uid*/,
718 android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE)); // 6:40
719 events.push_back(CreateUidProcessStateChangedEvent(
720 bucketStartTimeNs + 430 * NS_PER_SEC, 2 /*uid*/,
721 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND)); // 7:20
722 events.push_back(
723 CreateAppCrashOccurredEvent(bucketStartTimeNs + 440 * NS_PER_SEC, 1 /*uid*/)); // 7:30
724 events.push_back(CreateUidProcessStateChangedEvent(
725 bucketStartTimeNs + 540 * NS_PER_SEC, 1 /*uid*/,
726 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 9:10
727 events.push_back(
728 CreateAppCrashOccurredEvent(bucketStartTimeNs + 570 * NS_PER_SEC, 2 /*uid*/)); // 9:40
729
730 // Send log events to StatsLogProcessor.
731 for (auto& event : events) {
732 processor->OnLogEvent(event.get());
733 }
734
735 // Check dump report.
736 vector<uint8_t> buffer;
737 ConfigMetricsReportList reports;
738 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
739 FAST, &buffer);
740 ASSERT_GT(buffer.size(), 0);
741 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
742 backfillDimensionPath(&reports);
743 backfillStringInReport(&reports);
744 backfillStartEndTimestamp(&reports);
745
746 ASSERT_EQ(1, reports.reports_size());
747 ASSERT_EQ(1, reports.reports(0).metrics_size());
748 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
749 StatsLogReport::CountMetricDataWrapper countMetrics;
750 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
751 ASSERT_EQ(6, countMetrics.data_size());
752
753 // For each CountMetricData, check StateValue info is correct and buckets
754 // have correct counts.
755 auto data = countMetrics.data(0);
756 ASSERT_EQ(1, data.slice_by_state_size());
757 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
758 EXPECT_TRUE(data.slice_by_state(0).has_value());
759 EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
760 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1);
761 ASSERT_EQ(1, data.bucket_info_size());
762 EXPECT_EQ(1, data.bucket_info(0).count());
763
764 data = countMetrics.data(1);
765 ASSERT_EQ(1, data.slice_by_state_size());
766 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
767 EXPECT_TRUE(data.slice_by_state(0).has_value());
768 EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value());
769 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1);
770 ASSERT_EQ(1, data.bucket_info_size());
771 EXPECT_EQ(1, data.bucket_info(0).count());
772
773 data = countMetrics.data(2);
774 ASSERT_EQ(1, data.slice_by_state_size());
775 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
776 EXPECT_TRUE(data.slice_by_state(0).has_value());
777 EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value());
778 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1);
779 ASSERT_EQ(2, data.bucket_info_size());
780 EXPECT_EQ(1, data.bucket_info(0).count());
781 EXPECT_EQ(2, data.bucket_info(1).count());
782
783 data = countMetrics.data(3);
784 ASSERT_EQ(1, data.slice_by_state_size());
785 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
786 EXPECT_TRUE(data.slice_by_state(0).has_value());
787 EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value());
788 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1);
789 ASSERT_EQ(1, data.bucket_info_size());
790 EXPECT_EQ(2, data.bucket_info(0).count());
791
792 data = countMetrics.data(4);
793 ASSERT_EQ(1, data.slice_by_state_size());
794 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
795 EXPECT_TRUE(data.slice_by_state(0).has_value());
796 EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value());
797 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 2);
798 ASSERT_EQ(1, data.bucket_info_size());
799 EXPECT_EQ(1, data.bucket_info(0).count());
800
801 data = countMetrics.data(5);
802 ASSERT_EQ(1, data.slice_by_state_size());
803 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
804 EXPECT_TRUE(data.slice_by_state(0).has_value());
805 EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value());
806 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 2);
807 ASSERT_EQ(1, data.bucket_info_size());
808 EXPECT_EQ(1, data.bucket_info(0).count());
809 }
810
TEST(CountMetricE2eTest,TestMultipleSlicedStates)811 TEST(CountMetricE2eTest, TestMultipleSlicedStates) {
812 // Initialize config.
813 StatsdConfig config;
814
815 auto appCrashMatcher =
816 CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED);
817 *config.add_atom_matcher() = appCrashMatcher;
818
819 int64_t screenOnId = 4444;
820 int64_t screenOffId = 9876;
821 auto state1 = CreateScreenStateWithOnOffMap(screenOnId, screenOffId);
822 *config.add_state() = state1;
823 auto state2 = CreateUidProcessState();
824 *config.add_state() = state2;
825
826 // Create count metric that slices by screen state with on/off map and
827 // slices by uid process state.
828 int64_t metricId = 123456;
829 auto countMetric = config.add_count_metric();
830 countMetric->set_id(metricId);
831 countMetric->set_what(appCrashMatcher.id());
832 countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
833 countMetric->add_slice_by_state(state1.id());
834 countMetric->add_slice_by_state(state2.id());
835 *countMetric->mutable_dimensions_in_what() =
836 CreateDimensions(util::APP_CRASH_OCCURRED, {1 /*uid*/});
837 MetricStateLink* stateLink = countMetric->add_state_link();
838 stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
839 auto fieldsInWhat = stateLink->mutable_fields_in_what();
840 *fieldsInWhat = CreateDimensions(util::APP_CRASH_OCCURRED, {1 /*uid*/});
841 auto fieldsInState = stateLink->mutable_fields_in_state();
842 *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/});
843
844 // Initialize StatsLogProcessor.
845 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
846 const uint64_t bucketSizeNs =
847 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
848 int uid = 12345;
849 int64_t cfgId = 98765;
850 ConfigKey cfgKey(uid, cfgId);
851 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
852
853 // Check that StateTrackers were properly initialized.
854 EXPECT_EQ(2, StateManager::getInstance().getStateTrackersCount());
855 EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
856 EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
857
858 // Check that CountMetricProducer was initialized correctly.
859 ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
860 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
861 EXPECT_TRUE(metricsManager->isConfigValid());
862 ASSERT_EQ(metricsManager->mAllMetricProducers.size(), 1);
863 sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
864 ASSERT_EQ(metricProducer->mSlicedStateAtoms.size(), 2);
865 EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
866 EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), UID_PROCESS_STATE_ATOM_ID);
867 ASSERT_EQ(metricProducer->mStateGroupMap.size(), 1);
868 ASSERT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
869
870 StateMap map = state1.map();
871 for (auto group : map.group()) {
872 for (auto value : group.value()) {
873 EXPECT_EQ(metricProducer->mStateGroupMap.at(SCREEN_STATE_ATOM_ID).at(value),
874 group.group_id());
875 }
876 }
877
878 /*
879 bucket #1 bucket #2
880 | 1 2 3 4 5 6 7 8 9 10 (minutes)
881 |------------------------|------------------------|--
882 1 1 1 1 1 2 1 1 2 (AppCrashEvents)
883 ---------------------------------------------------SCREEN_OFF events
884 | | (ScreenOffEvent = 1)
885 | | (ScreenDozeEvent = 3)
886 ---------------------------------------------------SCREEN_ON events
887 | | (ScreenOnEvent = 2)
888 | (ScreenOnSuspendEvent = 6)
889 ---------------------------------------------------PROCESS STATE events
890 1 2 (TopEvent = 1002)
891 1 (ForegroundServiceEvent = 1003)
892 2 (ImportantBackgroundEvent = 1006)
893 1 1 1 (ImportantForegroundEvent = 1005)
894
895 Based on the diagram above, Screen State / Process State pairs for each
896 AppCrashEvent are:
897 - StateTracker::kStateUnknown / important foreground
898 - off / important foreground
899 - off / Top
900 - on / important foreground
901 - off / important foreground
902 - off / top
903
904 - off / important foreground
905 - off / foreground service
906 - on / important background
907
908 */
909 // Initialize log events - first bucket.
910 std::vector<std::unique_ptr<LogEvent>> events;
911 events.push_back(CreateUidProcessStateChangedEvent(
912 bucketStartTimeNs + 5 * NS_PER_SEC, 1 /*uid*/,
913 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 0:15
914 events.push_back(
915 CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /*uid*/)); // 0:30
916 events.push_back(CreateScreenStateChangedEvent(
917 bucketStartTimeNs + 30 * NS_PER_SEC,
918 android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 0:40
919 events.push_back(
920 CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, 1 /*uid*/)); // 1:10
921 events.push_back(CreateUidProcessStateChangedEvent(
922 bucketStartTimeNs + 90 * NS_PER_SEC, 1 /*uid*/,
923 android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 1:40
924 events.push_back(CreateScreenStateChangedEvent(
925 bucketStartTimeNs + 90 * NS_PER_SEC,
926 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 1:40
927 events.push_back(
928 CreateAppCrashOccurredEvent(bucketStartTimeNs + 120 * NS_PER_SEC, 1 /*uid*/)); // 2:10
929 events.push_back(CreateUidProcessStateChangedEvent(
930 bucketStartTimeNs + 150 * NS_PER_SEC, 1 /*uid*/,
931 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 2:40
932 events.push_back(CreateScreenStateChangedEvent(
933 bucketStartTimeNs + 160 * NS_PER_SEC,
934 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 2:50
935 events.push_back(
936 CreateAppCrashOccurredEvent(bucketStartTimeNs + 200 * NS_PER_SEC, 1 /*uid*/)); // 3:30
937 events.push_back(CreateScreenStateChangedEvent(
938 bucketStartTimeNs + 210 * NS_PER_SEC,
939 android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 3:40
940 events.push_back(
941 CreateAppCrashOccurredEvent(bucketStartTimeNs + 250 * NS_PER_SEC, 1 /*uid*/)); // 4:20
942 events.push_back(CreateUidProcessStateChangedEvent(
943 bucketStartTimeNs + 280 * NS_PER_SEC, 2 /*uid*/,
944 android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 4:50
945 events.push_back(
946 CreateAppCrashOccurredEvent(bucketStartTimeNs + 285 * NS_PER_SEC, 2 /*uid*/)); // 4:55
947
948 // Initialize log events - second bucket.
949 events.push_back(
950 CreateAppCrashOccurredEvent(bucketStartTimeNs + 360 * NS_PER_SEC, 1 /*uid*/)); // 6:10
951 events.push_back(CreateUidProcessStateChangedEvent(
952 bucketStartTimeNs + 380 * NS_PER_SEC, 1 /*uid*/,
953 android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE)); // 6:30
954 events.push_back(CreateScreenStateChangedEvent(
955 bucketStartTimeNs + 390 * NS_PER_SEC,
956 android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND)); // 6:40
957 events.push_back(CreateUidProcessStateChangedEvent(
958 bucketStartTimeNs + 420 * NS_PER_SEC, 2 /*uid*/,
959 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND)); // 7:10
960 events.push_back(CreateScreenStateChangedEvent(
961 bucketStartTimeNs + 440 * NS_PER_SEC,
962 android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 7:30
963 events.push_back(
964 CreateAppCrashOccurredEvent(bucketStartTimeNs + 450 * NS_PER_SEC, 1 /*uid*/)); // 7:40
965 events.push_back(CreateScreenStateChangedEvent(
966 bucketStartTimeNs + 520 * NS_PER_SEC,
967 android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 8:50
968 events.push_back(CreateUidProcessStateChangedEvent(
969 bucketStartTimeNs + 540 * NS_PER_SEC, 1 /*uid*/,
970 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 9:10
971 events.push_back(
972 CreateAppCrashOccurredEvent(bucketStartTimeNs + 570 * NS_PER_SEC, 2 /*uid*/)); // 9:40
973
974 // Send log events to StatsLogProcessor.
975 for (auto& event : events) {
976 processor->OnLogEvent(event.get());
977 }
978
979 // Check dump report.
980 vector<uint8_t> buffer;
981 ConfigMetricsReportList reports;
982 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
983 FAST, &buffer);
984 ASSERT_GT(buffer.size(), 0);
985 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
986 backfillDimensionPath(&reports);
987 backfillStringInReport(&reports);
988 backfillStartEndTimestamp(&reports);
989
990 ASSERT_EQ(1, reports.reports_size());
991 ASSERT_EQ(1, reports.reports(0).metrics_size());
992 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
993 StatsLogReport::CountMetricDataWrapper countMetrics;
994 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
995 ASSERT_EQ(7, countMetrics.data_size());
996
997 // For each CountMetricData, check StateValue info is correct and buckets
998 // have correct counts.
999 auto data = countMetrics.data(0);
1000 ASSERT_EQ(2, data.slice_by_state_size());
1001 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1002 EXPECT_TRUE(data.slice_by_state(0).has_value());
1003 EXPECT_EQ(-1, data.slice_by_state(0).value());
1004 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
1005 EXPECT_TRUE(data.slice_by_state(1).has_value());
1006 EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
1007 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1);
1008 ASSERT_EQ(1, data.bucket_info_size());
1009 EXPECT_EQ(1, data.bucket_info(0).count());
1010
1011 data = countMetrics.data(1);
1012 ASSERT_EQ(2, data.slice_by_state_size());
1013 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1014 EXPECT_TRUE(data.slice_by_state(0).has_group_id());
1015 EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id());
1016 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
1017 EXPECT_TRUE(data.slice_by_state(1).has_value());
1018 EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
1019 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1);
1020 ASSERT_EQ(1, data.bucket_info_size());
1021 EXPECT_EQ(1, data.bucket_info(0).count());
1022
1023 data = countMetrics.data(2);
1024 ASSERT_EQ(2, data.slice_by_state_size());
1025 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1026 EXPECT_TRUE(data.slice_by_state(0).has_group_id());
1027 EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
1028 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
1029 EXPECT_TRUE(data.slice_by_state(1).has_value());
1030 EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value());
1031 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1);
1032 ASSERT_EQ(1, data.bucket_info_size());
1033 EXPECT_EQ(1, data.bucket_info(0).count());
1034
1035 data = countMetrics.data(3);
1036 ASSERT_EQ(2, data.slice_by_state_size());
1037 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1038 EXPECT_TRUE(data.slice_by_state(0).has_group_id());
1039 EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
1040 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
1041 EXPECT_TRUE(data.slice_by_state(1).has_value());
1042 EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value());
1043 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1);
1044 ASSERT_EQ(1, data.bucket_info_size());
1045 EXPECT_EQ(1, data.bucket_info(0).count());
1046
1047 data = countMetrics.data(4);
1048 ASSERT_EQ(2, data.slice_by_state_size());
1049 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1050 EXPECT_TRUE(data.slice_by_state(0).has_group_id());
1051 EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
1052 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
1053 EXPECT_TRUE(data.slice_by_state(1).has_value());
1054 EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
1055 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 1);
1056 ASSERT_EQ(2, data.bucket_info_size());
1057 EXPECT_EQ(2, data.bucket_info(0).count());
1058 EXPECT_EQ(1, data.bucket_info(1).count());
1059
1060 data = countMetrics.data(5);
1061 ASSERT_EQ(2, data.slice_by_state_size());
1062 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1063 EXPECT_TRUE(data.slice_by_state(0).has_group_id());
1064 EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id());
1065 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
1066 EXPECT_TRUE(data.slice_by_state(1).has_value());
1067 EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value());
1068 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 2);
1069 ASSERT_EQ(1, data.bucket_info_size());
1070 EXPECT_EQ(1, data.bucket_info(0).count());
1071
1072 data = countMetrics.data(6);
1073 ASSERT_EQ(2, data.slice_by_state_size());
1074 EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
1075 EXPECT_TRUE(data.slice_by_state(0).has_group_id());
1076 EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id());
1077 EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
1078 EXPECT_TRUE(data.slice_by_state(1).has_value());
1079 EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value());
1080 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, 2);
1081 ASSERT_EQ(1, data.bucket_info_size());
1082 EXPECT_EQ(1, data.bucket_info(0).count());
1083 }
1084
TEST(CountMetricE2eTest,TestUploadThreshold)1085 TEST(CountMetricE2eTest, TestUploadThreshold) {
1086 // Initialize config.
1087 StatsdConfig config;
1088
1089 auto appCrashMatcher = CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED);
1090 *config.add_atom_matcher() = appCrashMatcher;
1091
1092 int64_t thresholdCount = 2;
1093 UploadThreshold threshold;
1094 threshold.set_gt_int(thresholdCount);
1095
1096 int64_t metricId = 123456;
1097 CountMetric countMetric = createCountMetric("COUNT", appCrashMatcher.id(), nullopt, {});
1098 *countMetric.mutable_dimensions_in_what() =
1099 CreateDimensions(util::APP_CRASH_OCCURRED, {1 /*uid*/});
1100 *countMetric.mutable_threshold() = threshold;
1101 *config.add_count_metric() = countMetric;
1102
1103 // Initialize StatsLogProcessor.
1104 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
1105 const uint64_t bucketSizeNs =
1106 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
1107 int uid = 12345;
1108 int64_t cfgId = 98765;
1109 ConfigKey cfgKey(uid, cfgId);
1110 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
1111
1112 int appUid1 = 1;
1113 int appUid2 = 2;
1114 std::vector<std::unique_ptr<LogEvent>> events;
1115 events.push_back(
1116 CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, appUid1)); // 0:30
1117 events.push_back(
1118 CreateAppCrashOccurredEvent(bucketStartTimeNs + 40 * NS_PER_SEC, appUid2)); // 0:50
1119 events.push_back(
1120 CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, appUid1)); // 1:10
1121 events.push_back(
1122 CreateAppCrashOccurredEvent(bucketStartTimeNs + 65 * NS_PER_SEC, appUid1)); // 1:15
1123
1124 // Send log events to StatsLogProcessor.
1125 for (auto& event : events) {
1126 processor->OnLogEvent(event.get());
1127 }
1128
1129 // Check dump report.
1130 vector<uint8_t> buffer;
1131 ConfigMetricsReportList reports;
1132 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
1133 FAST, &buffer);
1134 ASSERT_GT(buffer.size(), 0);
1135 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1136 backfillDimensionPath(&reports);
1137 backfillStringInReport(&reports);
1138 backfillStartEndTimestamp(&reports);
1139
1140 ASSERT_EQ(1, reports.reports_size());
1141 ASSERT_EQ(1, reports.reports(0).metrics_size());
1142 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
1143 StatsLogReport::CountMetricDataWrapper countMetrics;
1144 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
1145 ASSERT_EQ(1, countMetrics.data_size());
1146
1147 CountMetricData data = countMetrics.data(0);
1148
1149 // Uid 1 reports a count greater than the threshold.
1150 // Uid 2 is dropped because the count was less than the threshold.
1151 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, appUid1);
1152 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1153 3);
1154 }
1155
TEST(CountMetricE2eTest,TestRepeatedFieldsAndEmptyArrays)1156 TEST(CountMetricE2eTest, TestRepeatedFieldsAndEmptyArrays) {
1157 StatsdConfig config;
1158
1159 AtomMatcher testAtomReportedAtomMatcher =
1160 CreateSimpleAtomMatcher("TestAtomReportedMatcher", util::TEST_ATOM_REPORTED);
1161 *config.add_atom_matcher() = testAtomReportedAtomMatcher;
1162
1163 int64_t metricId = 123456;
1164 CountMetric* countMetric = config.add_count_metric();
1165 countMetric->set_id(metricId);
1166 countMetric->set_what(testAtomReportedAtomMatcher.id());
1167 countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
1168
1169 // Initialize StatsLogProcessor.
1170 ConfigKey cfgKey(123, 987);
1171 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
1172 const uint64_t bucketSizeNs =
1173 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
1174 sp<StatsLogProcessor> processor =
1175 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
1176
1177 vector<int> intArray = {3, 6};
1178 vector<int64_t> longArray = {1000L, 10002L};
1179 vector<float> floatArray = {0.3f, 0.09f};
1180 vector<string> stringArray = {"str1", "str2"};
1181 int boolArrayLength = 2;
1182 bool boolArray[boolArrayLength];
1183 boolArray[0] = 1;
1184 boolArray[1] = 0;
1185 vector<int> enumArray = {TestAtomReported::ON, TestAtomReported::OFF};
1186
1187 std::vector<std::unique_ptr<LogEvent>> events;
1188 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1189 bucketStartTimeNs + 10 * NS_PER_SEC, intArray, longArray, floatArray, stringArray,
1190 boolArray, boolArrayLength, enumArray));
1191 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1192 bucketStartTimeNs + 20 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, {}));
1193
1194 // Send log events to StatsLogProcessor.
1195 for (auto& event : events) {
1196 processor->OnLogEvent(event.get());
1197 }
1198
1199 // Check dump report.
1200 vector<uint8_t> buffer;
1201 ConfigMetricsReportList reports;
1202 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
1203 FAST, &buffer);
1204 ASSERT_GT(buffer.size(), 0);
1205 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1206 backfillDimensionPath(&reports);
1207 backfillStringInReport(&reports);
1208 backfillStartEndTimestamp(&reports);
1209
1210 ASSERT_EQ(1, reports.reports_size());
1211 ASSERT_EQ(1, reports.reports(0).metrics_size());
1212 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
1213 StatsLogReport::CountMetricDataWrapper countMetrics;
1214 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
1215 ASSERT_EQ(1, countMetrics.data_size());
1216
1217 CountMetricData data = countMetrics.data(0);
1218 ASSERT_EQ(1, data.bucket_info_size());
1219 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1220 2);
1221 }
1222
TEST(CountMetricE2eTest,TestMatchRepeatedFieldPositionAny)1223 TEST(CountMetricE2eTest, TestMatchRepeatedFieldPositionAny) {
1224 StatsdConfig config;
1225
1226 AtomMatcher testAtomReportedStateAnyOnAtomMatcher =
1227 CreateTestAtomRepeatedStateAnyOnAtomMatcher();
1228 *config.add_atom_matcher() = testAtomReportedStateAnyOnAtomMatcher;
1229
1230 int64_t metricId = 123456;
1231 CountMetric* countMetric = config.add_count_metric();
1232 countMetric->set_id(metricId);
1233 countMetric->set_what(testAtomReportedStateAnyOnAtomMatcher.id());
1234 countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
1235
1236 // Initialize StatsLogProcessor.
1237 ConfigKey cfgKey(123, 987);
1238 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
1239 const uint64_t bucketSizeNs =
1240 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
1241 sp<StatsLogProcessor> processor =
1242 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
1243
1244 vector<int> enumArrayOnFirst = {TestAtomReported::ON, TestAtomReported::OFF};
1245 vector<int> enumArrayOnLast = {TestAtomReported::OFF, TestAtomReported::ON};
1246 vector<int> enumArrayNoOn = {TestAtomReported::OFF, TestAtomReported::OFF};
1247
1248 std::vector<std::unique_ptr<LogEvent>> events;
1249 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1250 bucketStartTimeNs + 20 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOnFirst));
1251 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1252 bucketStartTimeNs + 40 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayNoOn));
1253 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1254 bucketStartTimeNs + 60 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOnLast));
1255 // No matching is done on empty array.
1256 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1257 bucketStartTimeNs + 80 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, {}));
1258
1259 // Send log events to StatsLogProcessor.
1260 for (auto& event : events) {
1261 processor->OnLogEvent(event.get());
1262 }
1263
1264 // Check dump report.
1265 vector<uint8_t> buffer;
1266 ConfigMetricsReportList reports;
1267 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
1268 FAST, &buffer);
1269 ASSERT_GT(buffer.size(), 0);
1270 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1271 backfillDimensionPath(&reports);
1272 backfillStringInReport(&reports);
1273 backfillStartEndTimestamp(&reports);
1274
1275 ASSERT_EQ(1, reports.reports_size());
1276 ASSERT_EQ(1, reports.reports(0).metrics_size());
1277 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
1278 StatsLogReport::CountMetricDataWrapper countMetrics;
1279 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
1280 ASSERT_EQ(1, countMetrics.data_size());
1281
1282 CountMetricData data = countMetrics.data(0);
1283 ASSERT_EQ(1, data.bucket_info_size());
1284 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1285 2);
1286 }
1287
TEST(CountMetricE2eTest,TestRepeatedFieldDimension_PositionFirst)1288 TEST(CountMetricE2eTest, TestRepeatedFieldDimension_PositionFirst) {
1289 StatsdConfig config;
1290
1291 AtomMatcher testAtomReportedAtomMatcher =
1292 CreateSimpleAtomMatcher("TestAtomReportedMatcher", util::TEST_ATOM_REPORTED);
1293 *config.add_atom_matcher() = testAtomReportedAtomMatcher;
1294
1295 int64_t metricId = 123456;
1296 CountMetric* countMetric = config.add_count_metric();
1297 countMetric->set_id(metricId);
1298 countMetric->set_what(testAtomReportedAtomMatcher.id());
1299 countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
1300 *countMetric->mutable_dimensions_in_what() = CreateRepeatedDimensions(
1301 util::TEST_ATOM_REPORTED, {14 /*repeated_enum_field*/}, {Position::FIRST});
1302
1303 // Initialize StatsLogProcessor.
1304 ConfigKey cfgKey(2000, 921);
1305 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
1306 const uint64_t bucketSizeNs =
1307 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
1308 sp<StatsLogProcessor> processor =
1309 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
1310
1311 vector<int> enumArrayOnOff = {TestAtomReported::ON, TestAtomReported::OFF};
1312 vector<int> enumArrayOnOn = {TestAtomReported::ON, TestAtomReported::ON};
1313 vector<int> enumArrayOffOn = {TestAtomReported::OFF, TestAtomReported::ON};
1314
1315 std::vector<std::unique_ptr<LogEvent>> events;
1316 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1317 bucketStartTimeNs + 20 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOnOff));
1318 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1319 bucketStartTimeNs + 40 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOffOn));
1320 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1321 bucketStartTimeNs + 60 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOnOn));
1322 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1323 bucketStartTimeNs + 80 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, {}));
1324
1325 // Send log events to StatsLogProcessor.
1326 for (auto& event : events) {
1327 processor->OnLogEvent(event.get());
1328 }
1329
1330 // Check dump report.
1331 vector<uint8_t> buffer;
1332 ConfigMetricsReportList reports;
1333 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
1334 FAST, &buffer);
1335 ASSERT_GT(buffer.size(), 0);
1336 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1337 backfillStringInReport(&reports);
1338 backfillStartEndTimestamp(&reports);
1339
1340 ASSERT_EQ(1, reports.reports_size());
1341 ASSERT_EQ(1, reports.reports(0).metrics_size());
1342 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
1343 StatsLogReport::CountMetricDataWrapper countMetrics;
1344 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
1345 ASSERT_EQ(3, countMetrics.data_size());
1346
1347 // Empty dimensions case.
1348 CountMetricData data = countMetrics.data(0);
1349 ASSERT_EQ(1, data.bucket_info_size());
1350 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1351 1);
1352 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 0);
1353
1354 data = countMetrics.data(1);
1355 ASSERT_EQ(1, data.bucket_info_size());
1356 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1357 1);
1358 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1359 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
1360 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 14);
1361 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(),
1362 TestAtomReported::OFF);
1363
1364 data = countMetrics.data(2);
1365 ASSERT_EQ(1, data.bucket_info_size());
1366 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1367 2);
1368 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1369 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
1370 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 14);
1371 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(),
1372 TestAtomReported::ON);
1373 }
1374
TEST(CountMetricE2eTest,TestRepeatedFieldDimension_PositionLast)1375 TEST(CountMetricE2eTest, TestRepeatedFieldDimension_PositionLast) {
1376 StatsdConfig config;
1377
1378 AtomMatcher testAtomReportedAtomMatcher =
1379 CreateSimpleAtomMatcher("TestAtomReportedMatcher", util::TEST_ATOM_REPORTED);
1380 *config.add_atom_matcher() = testAtomReportedAtomMatcher;
1381
1382 int64_t metricId = 123456;
1383 CountMetric* countMetric = config.add_count_metric();
1384 countMetric->set_id(metricId);
1385 countMetric->set_what(testAtomReportedAtomMatcher.id());
1386 countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
1387 *countMetric->mutable_dimensions_in_what() = CreateRepeatedDimensions(
1388 util::TEST_ATOM_REPORTED, {14 /*repeated_enum_field*/}, {Position::LAST});
1389
1390 // Initialize StatsLogProcessor.
1391 ConfigKey cfgKey(2000, 921);
1392 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
1393 const uint64_t bucketSizeNs =
1394 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
1395 sp<StatsLogProcessor> processor =
1396 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
1397
1398 vector<int> enumArrayOnOff = {TestAtomReported::ON, TestAtomReported::OFF};
1399 vector<int> enumArrayOffOff = {TestAtomReported::OFF, TestAtomReported::OFF};
1400 vector<int> enumArrayOffOn = {TestAtomReported::OFF, TestAtomReported::ON};
1401
1402 std::vector<std::unique_ptr<LogEvent>> events;
1403 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1404 bucketStartTimeNs + 20 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOnOff));
1405 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1406 bucketStartTimeNs + 40 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOffOff));
1407 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1408 bucketStartTimeNs + 60 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOffOn));
1409
1410 // Send log events to StatsLogProcessor.
1411 for (auto& event : events) {
1412 processor->OnLogEvent(event.get());
1413 }
1414
1415 // Check dump report.
1416 vector<uint8_t> buffer;
1417 ConfigMetricsReportList reports;
1418 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
1419 FAST, &buffer);
1420 ASSERT_GT(buffer.size(), 0);
1421 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1422 backfillStringInReport(&reports);
1423 backfillStartEndTimestamp(&reports);
1424
1425 ASSERT_EQ(1, reports.reports_size());
1426 ASSERT_EQ(1, reports.reports(0).metrics_size());
1427 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
1428 StatsLogReport::CountMetricDataWrapper countMetrics;
1429 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
1430 ASSERT_EQ(2, countMetrics.data_size());
1431
1432 CountMetricData data = countMetrics.data(0);
1433 ASSERT_EQ(1, data.bucket_info_size());
1434 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1435 2);
1436 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1437 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
1438 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 14);
1439 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(),
1440 TestAtomReported::OFF);
1441
1442 data = countMetrics.data(1);
1443 ASSERT_EQ(1, data.bucket_info_size());
1444 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1445 1);
1446 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1447 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
1448 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 14);
1449 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(),
1450 TestAtomReported::ON);
1451 }
1452
TEST(CountMetricE2eTest,TestRepeatedFieldDimension_PositionAll)1453 TEST(CountMetricE2eTest, TestRepeatedFieldDimension_PositionAll) {
1454 StatsdConfig config;
1455
1456 AtomMatcher testAtomReportedAtomMatcher =
1457 CreateSimpleAtomMatcher("TestAtomReportedMatcher", util::TEST_ATOM_REPORTED);
1458 *config.add_atom_matcher() = testAtomReportedAtomMatcher;
1459
1460 int64_t metricId = 123456;
1461 CountMetric* countMetric = config.add_count_metric();
1462 countMetric->set_id(metricId);
1463 countMetric->set_what(testAtomReportedAtomMatcher.id());
1464 countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
1465 *countMetric->mutable_dimensions_in_what() = CreateRepeatedDimensions(
1466 util::TEST_ATOM_REPORTED, {14 /*repeated_enum_field*/}, {Position::ALL});
1467
1468 // Initialize StatsLogProcessor.
1469 ConfigKey cfgKey(2000, 921);
1470 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
1471 const uint64_t bucketSizeNs =
1472 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
1473 sp<StatsLogProcessor> processor =
1474 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
1475
1476 vector<int> enumArrayOnOff = {TestAtomReported::ON, TestAtomReported::OFF};
1477 vector<int> enumArrayOnOn = {TestAtomReported::ON, TestAtomReported::ON};
1478 vector<int> enumArrayOffOn = {TestAtomReported::OFF, TestAtomReported::ON};
1479
1480 std::vector<std::unique_ptr<LogEvent>> events;
1481 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1482 bucketStartTimeNs + 20 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOnOff));
1483 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1484 bucketStartTimeNs + 40 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOffOn));
1485 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1486 bucketStartTimeNs + 60 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOnOn));
1487 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1488 bucketStartTimeNs + 40 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOffOn));
1489 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1490 bucketStartTimeNs + 20 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOnOff));
1491 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1492 bucketStartTimeNs + 40 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOffOn));
1493
1494 // Send log events to StatsLogProcessor.
1495 for (auto& event : events) {
1496 processor->OnLogEvent(event.get());
1497 }
1498
1499 // Check dump report.
1500 vector<uint8_t> buffer;
1501 ConfigMetricsReportList reports;
1502 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
1503 FAST, &buffer);
1504 ASSERT_GT(buffer.size(), 0);
1505 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1506 // Don't need to backfill dimension path because dimensions with position ALL are not encoded
1507 // with the path format.
1508 backfillStringInReport(&reports);
1509 backfillStartEndTimestamp(&reports);
1510
1511 ASSERT_EQ(1, reports.reports_size());
1512 ASSERT_EQ(1, reports.reports(0).metrics_size());
1513 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
1514 StatsLogReport::CountMetricDataWrapper countMetrics;
1515 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
1516 ASSERT_EQ(3, countMetrics.data_size());
1517
1518 CountMetricData data = countMetrics.data(0);
1519 ASSERT_EQ(1, data.bucket_info_size());
1520 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1521 3);
1522 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1523 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 2);
1524 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 14);
1525 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(),
1526 TestAtomReported::OFF);
1527 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).field(), 14);
1528 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).value_int(),
1529 TestAtomReported::ON);
1530
1531 data = countMetrics.data(1);
1532 ASSERT_EQ(1, data.bucket_info_size());
1533 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1534 2);
1535 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1536 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 2);
1537 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 14);
1538 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(),
1539 TestAtomReported::ON);
1540 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).field(), 14);
1541 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).value_int(),
1542 TestAtomReported::OFF);
1543
1544 data = countMetrics.data(2);
1545 ASSERT_EQ(1, data.bucket_info_size());
1546 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1547 1);
1548 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1549 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 2);
1550 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 14);
1551 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(),
1552 TestAtomReported::ON);
1553 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).field(), 14);
1554 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).value_int(),
1555 TestAtomReported::ON);
1556 }
1557
TEST(CountMetricE2eTest,TestMultipleRepeatedFieldDimensions_PositionFirst)1558 TEST(CountMetricE2eTest, TestMultipleRepeatedFieldDimensions_PositionFirst) {
1559 StatsdConfig config;
1560
1561 AtomMatcher testAtomReportedAtomMatcher =
1562 CreateSimpleAtomMatcher("TestAtomReportedMatcher", util::TEST_ATOM_REPORTED);
1563 *config.add_atom_matcher() = testAtomReportedAtomMatcher;
1564
1565 int64_t metricId = 123456;
1566 CountMetric* countMetric = config.add_count_metric();
1567 countMetric->set_id(metricId);
1568 countMetric->set_what(testAtomReportedAtomMatcher.id());
1569 countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
1570 *countMetric->mutable_dimensions_in_what() = CreateRepeatedDimensions(
1571 util::TEST_ATOM_REPORTED, {9 /*repeated_int_field*/, 14 /*repeated_enum_field*/},
1572 {Position::FIRST, Position::FIRST});
1573
1574 // Initialize StatsLogProcessor.
1575 ConfigKey cfgKey(2000, 921);
1576 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
1577 const uint64_t bucketSizeNs =
1578 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
1579 sp<StatsLogProcessor> processor =
1580 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
1581
1582 vector<int> intArrayThree = {3, 6, 9};
1583 vector<int> intArraySix = {6, 9};
1584 vector<int> enumArrayOn = {TestAtomReported::ON, TestAtomReported::OFF};
1585
1586 std::vector<std::unique_ptr<LogEvent>> events;
1587 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1588 bucketStartTimeNs + 20 * NS_PER_SEC, intArrayThree, {}, {}, {}, {}, 0, enumArrayOn));
1589 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1590 bucketStartTimeNs + 40 * NS_PER_SEC, intArraySix, {}, {}, {}, {}, 0, enumArrayOn));
1591 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1592 bucketStartTimeNs + 60 * NS_PER_SEC, intArrayThree, {}, {}, {}, {}, 0, enumArrayOn));
1593 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1594 bucketStartTimeNs + 80 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArrayOn));
1595 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1596 bucketStartTimeNs + 100 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, {}));
1597 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1598 bucketStartTimeNs + 120 * NS_PER_SEC, intArraySix, {}, {}, {}, {}, 0, {}));
1599
1600 // Send log events to StatsLogProcessor.
1601 for (auto& event : events) {
1602 processor->OnLogEvent(event.get());
1603 }
1604
1605 // Check dump report.
1606 vector<uint8_t> buffer;
1607 ConfigMetricsReportList reports;
1608 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
1609 FAST, &buffer);
1610 ASSERT_GT(buffer.size(), 0);
1611 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1612 backfillStringInReport(&reports);
1613 backfillStartEndTimestamp(&reports);
1614
1615 ASSERT_EQ(1, reports.reports_size());
1616 ASSERT_EQ(1, reports.reports(0).metrics_size());
1617 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
1618 StatsLogReport::CountMetricDataWrapper countMetrics;
1619 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
1620 ASSERT_EQ(5, countMetrics.data_size());
1621
1622 CountMetricData data = countMetrics.data(0);
1623 ASSERT_EQ(1, data.bucket_info_size());
1624 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1625 1);
1626 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 0);
1627
1628 data = countMetrics.data(1);
1629 ASSERT_EQ(1, data.bucket_info_size());
1630 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1631 1);
1632 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1633 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
1634 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 9);
1635 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 6);
1636
1637 data = countMetrics.data(2);
1638 ASSERT_EQ(1, data.bucket_info_size());
1639 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1640 1);
1641 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1642 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
1643 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 14);
1644 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(),
1645 TestAtomReported::ON);
1646
1647 data = countMetrics.data(3);
1648 ASSERT_EQ(1, data.bucket_info_size());
1649 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1650 2);
1651 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1652 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 2);
1653 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 9);
1654 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 3);
1655 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).field(), 14);
1656 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).value_int(),
1657 TestAtomReported::ON);
1658
1659 data = countMetrics.data(4);
1660 ASSERT_EQ(1, data.bucket_info_size());
1661 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1662 1);
1663 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1664 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 2);
1665 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 9);
1666 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 6);
1667 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).field(), 14);
1668 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).value_int(),
1669 TestAtomReported::ON);
1670 }
1671
TEST(CountMetricE2eTest,TestMultipleRepeatedFieldDimensions_PositionAll)1672 TEST(CountMetricE2eTest, TestMultipleRepeatedFieldDimensions_PositionAll) {
1673 StatsdConfig config;
1674
1675 AtomMatcher testAtomReportedAtomMatcher =
1676 CreateSimpleAtomMatcher("TestAtomReportedMatcher", util::TEST_ATOM_REPORTED);
1677 *config.add_atom_matcher() = testAtomReportedAtomMatcher;
1678
1679 int64_t metricId = 123456;
1680 CountMetric* countMetric = config.add_count_metric();
1681 countMetric->set_id(metricId);
1682 countMetric->set_what(testAtomReportedAtomMatcher.id());
1683 countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
1684 *countMetric->mutable_dimensions_in_what() = CreateRepeatedDimensions(
1685 util::TEST_ATOM_REPORTED, {9 /*repeated_int_field*/, 14 /*repeated_enum_field*/},
1686 {Position::ALL, Position::ALL});
1687
1688 // Initialize StatsLogProcessor.
1689 ConfigKey cfgKey(2000, 921);
1690 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
1691 const uint64_t bucketSizeNs =
1692 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
1693 sp<StatsLogProcessor> processor =
1694 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
1695
1696 vector<int> intArray1 = {3, 6};
1697 vector<int> intArray2 = {6, 9};
1698 vector<int> enumArray = {TestAtomReported::ON, TestAtomReported::OFF};
1699
1700 std::vector<std::unique_ptr<LogEvent>> events;
1701 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1702 bucketStartTimeNs + 20 * NS_PER_SEC, intArray1, {}, {}, {}, {}, 0, enumArray));
1703 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1704 bucketStartTimeNs + 40 * NS_PER_SEC, intArray2, {}, {}, {}, {}, 0, enumArray));
1705 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1706 bucketStartTimeNs + 80 * NS_PER_SEC, intArray1, {}, {}, {}, {}, 0, enumArray));
1707 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1708 bucketStartTimeNs + 100 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, enumArray));
1709 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1710 bucketStartTimeNs + 120 * NS_PER_SEC, {}, {}, {}, {}, {}, 0, {}));
1711 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1712 bucketStartTimeNs + 140 * NS_PER_SEC, intArray2, {}, {}, {}, {}, 0, {}));
1713
1714 // Send log events to StatsLogProcessor.
1715 for (auto& event : events) {
1716 processor->OnLogEvent(event.get());
1717 }
1718
1719 // Check dump report.
1720 vector<uint8_t> buffer;
1721 ConfigMetricsReportList reports;
1722 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
1723 FAST, &buffer);
1724 ASSERT_GT(buffer.size(), 0);
1725 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1726 backfillStringInReport(&reports);
1727 backfillStartEndTimestamp(&reports);
1728
1729 ASSERT_EQ(1, reports.reports_size());
1730 ASSERT_EQ(1, reports.reports(0).metrics_size());
1731 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
1732 StatsLogReport::CountMetricDataWrapper countMetrics;
1733 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
1734 ASSERT_EQ(5, countMetrics.data_size());
1735
1736 CountMetricData data = countMetrics.data(0);
1737 ASSERT_EQ(1, data.bucket_info_size());
1738 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1739 1);
1740 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 0);
1741
1742 data = countMetrics.data(1);
1743 ASSERT_EQ(1, data.bucket_info_size());
1744 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1745 1);
1746 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1747 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 2);
1748 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 9);
1749 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 6);
1750 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).field(), 9);
1751 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).value_int(), 9);
1752
1753 data = countMetrics.data(2);
1754 ASSERT_EQ(1, data.bucket_info_size());
1755 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1756 1);
1757 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1758 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 2);
1759 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 14);
1760 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(),
1761 TestAtomReported::ON);
1762 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).field(), 14);
1763 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).value_int(),
1764 TestAtomReported::OFF);
1765
1766 data = countMetrics.data(3);
1767 ASSERT_EQ(1, data.bucket_info_size());
1768 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1769 2);
1770 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1771 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 4);
1772 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 9);
1773 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 3);
1774 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).field(), 9);
1775 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).value_int(), 6);
1776 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(2).field(), 14);
1777 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(2).value_int(),
1778 TestAtomReported::ON);
1779 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(3).field(), 14);
1780 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(3).value_int(),
1781 TestAtomReported::OFF);
1782
1783 data = countMetrics.data(4);
1784 ASSERT_EQ(1, data.bucket_info_size());
1785 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1786 1);
1787 EXPECT_EQ(util::TEST_ATOM_REPORTED, data.dimensions_in_what().field());
1788 ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 4);
1789 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 9);
1790 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), 6);
1791 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).field(), 9);
1792 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(1).value_int(), 9);
1793 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(2).field(), 14);
1794 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(2).value_int(),
1795 TestAtomReported::ON);
1796 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(3).field(), 14);
1797 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(3).value_int(),
1798 TestAtomReported::OFF);
1799 }
1800
TEST(CountMetricE2eTest,TestConditionSlicedByRepeatedUidWithUidDimension)1801 TEST(CountMetricE2eTest, TestConditionSlicedByRepeatedUidWithUidDimension) {
1802 StatsdConfig config;
1803
1804 AtomMatcher uidProcessStateChangedAtomMatcher = CreateUidProcessStateChangedAtomMatcher();
1805 AtomMatcher repeatedStateFirstOffAtomMatcher = CreateTestAtomRepeatedStateFirstOffAtomMatcher();
1806 AtomMatcher repeatedStateFirstOnAtomMatcher = CreateTestAtomRepeatedStateFirstOnAtomMatcher();
1807 *config.add_atom_matcher() = uidProcessStateChangedAtomMatcher;
1808 *config.add_atom_matcher() = repeatedStateFirstOffAtomMatcher;
1809 *config.add_atom_matcher() = repeatedStateFirstOnAtomMatcher;
1810
1811 Predicate testAtomRepeatedStateFirstOffPerUidPredicate =
1812 CreateTestAtomRepeatedStateFirstOffPredicate();
1813 FieldMatcher* dimensions =
1814 testAtomRepeatedStateFirstOffPerUidPredicate.mutable_simple_predicate()
1815 ->mutable_dimensions();
1816 *dimensions = CreateRepeatedDimensions(util::TEST_ATOM_REPORTED, {9 /* repeated uid*/},
1817 {Position::FIRST});
1818 *config.add_predicate() = testAtomRepeatedStateFirstOffPerUidPredicate;
1819
1820 int64_t metricId = 123456;
1821 CountMetric* countMetric = config.add_count_metric();
1822 countMetric->set_id(metricId);
1823 countMetric->set_what(uidProcessStateChangedAtomMatcher.id());
1824 countMetric->set_condition(testAtomRepeatedStateFirstOffPerUidPredicate.id());
1825 countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
1826 *countMetric->mutable_dimensions_in_what() =
1827 CreateDimensions(util::UID_PROCESS_STATE_CHANGED, {1 /*uid*/});
1828 MetricConditionLink* links = countMetric->add_links();
1829 links->set_condition(testAtomRepeatedStateFirstOffPerUidPredicate.id());
1830 *links->mutable_fields_in_what() =
1831 CreateDimensions(util::UID_PROCESS_STATE_CHANGED, {1 /* uid*/});
1832 *links->mutable_fields_in_condition() = CreateRepeatedDimensions(
1833 util::TEST_ATOM_REPORTED, {9 /* repeated uid*/}, {Position::FIRST});
1834
1835 // Initialize StatsLogProcessor.
1836 ConfigKey cfgKey(2000, 921);
1837 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
1838 const uint64_t bucketSizeNs =
1839 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
1840 const uint64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
1841 sp<StatsLogProcessor> processor =
1842 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
1843
1844 vector<int> intArray1 = {1, 2};
1845 vector<int> intArray2 = {2, 1};
1846 vector<int> enumArrayOn = {TestAtomReported::ON, TestAtomReported::OFF};
1847 vector<int> enumArrayOff = {TestAtomReported::OFF, TestAtomReported::ON};
1848
1849 std::vector<std::unique_ptr<LogEvent>> events;
1850 // Set condition to true for uid 1.
1851 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1852 bucketStartTimeNs + 20 * NS_PER_SEC, intArray1, {}, {}, {}, {}, 0, enumArrayOff));
1853
1854 // Uid 1 process state changed.
1855 events.push_back(CreateUidProcessStateChangedEvent(
1856 bucketStartTimeNs + 40 * NS_PER_SEC, 1 /*uid*/,
1857 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));
1858 // Uid 2 process state changed. Should not be counted.
1859 events.push_back(CreateUidProcessStateChangedEvent(
1860 bucketStartTimeNs + 60 * NS_PER_SEC, 2 /*uid*/,
1861 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));
1862
1863 // Set condition to true for uid 2.
1864 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1865 bucketStartTimeNs + 80 * NS_PER_SEC, intArray2, {}, {}, {}, {}, 0, enumArrayOff));
1866 // Uid 1 process state changed.
1867 events.push_back(CreateUidProcessStateChangedEvent(
1868 bucketStartTimeNs + 100 * NS_PER_SEC, 1 /*uid*/,
1869 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));
1870 // Uid 2 process state changed.
1871 events.push_back(CreateUidProcessStateChangedEvent(
1872 bucketStartTimeNs + 120 * NS_PER_SEC, 2 /*uid*/,
1873 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));
1874
1875 // Bucket 2
1876 // Set condition to false for uid 1.
1877 events.push_back(CreateTestAtomReportedEventVariableRepeatedFields(
1878 bucket2StartTimeNs + 20 * NS_PER_SEC, intArray1, {}, {}, {}, {}, 0, enumArrayOn));
1879 // Uid 1 process state changed. Should not be counted.
1880 events.push_back(CreateUidProcessStateChangedEvent(
1881 bucket2StartTimeNs + 40 * NS_PER_SEC, 1 /*uid*/,
1882 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));
1883 // Uid 2 process state changed.
1884 events.push_back(CreateUidProcessStateChangedEvent(
1885 bucket2StartTimeNs + 60 * NS_PER_SEC, 2 /*uid*/,
1886 android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));
1887
1888 // Send log events to StatsLogProcessor.
1889 for (auto& event : events) {
1890 processor->OnLogEvent(event.get());
1891 }
1892
1893 // Check dump report.
1894 vector<uint8_t> buffer;
1895 ConfigMetricsReportList reports;
1896 processor->onDumpReport(cfgKey, bucket2StartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
1897 FAST, &buffer);
1898 ASSERT_GT(buffer.size(), 0);
1899 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1900 backfillDimensionPath(&reports);
1901 backfillStringInReport(&reports);
1902 backfillStartEndTimestamp(&reports);
1903
1904 ASSERT_EQ(1, reports.reports_size());
1905 ASSERT_EQ(1, reports.reports(0).metrics_size());
1906 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
1907 StatsLogReport::CountMetricDataWrapper countMetrics;
1908 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
1909 ASSERT_EQ(2, countMetrics.data_size());
1910
1911 CountMetricData data = countMetrics.data(0);
1912 ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
1913 EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value(0).field());
1914 EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
1915 ASSERT_EQ(1, data.bucket_info_size());
1916 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1917 2);
1918
1919 data = countMetrics.data(1);
1920 ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
1921 EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value(0).field());
1922 EXPECT_EQ(2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
1923 ASSERT_EQ(2, data.bucket_info_size());
1924 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
1925 1);
1926 ValidateCountBucket(data.bucket_info(1), bucket2StartTimeNs, bucket2StartTimeNs + bucketSizeNs,
1927 1);
1928 }
1929
TEST(CountMetricE2eTest,TestDimensionalSampling)1930 TEST(CountMetricE2eTest, TestDimensionalSampling) {
1931 ShardOffsetProvider::getInstance().setShardOffset(5);
1932
1933 // Initialize config.
1934 StatsdConfig config;
1935
1936 AtomMatcher appCrashMatcher =
1937 CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED);
1938 *config.add_atom_matcher() = appCrashMatcher;
1939
1940 CountMetric sampledCountMetric =
1941 createCountMetric("CountSampledAppCrashesPerUid", appCrashMatcher.id(), nullopt, {});
1942 *sampledCountMetric.mutable_dimensions_in_what() =
1943 CreateDimensions(util::APP_CRASH_OCCURRED, {1 /*uid*/});
1944 *sampledCountMetric.mutable_dimensional_sampling_info()->mutable_sampled_what_field() =
1945 CreateDimensions(util::APP_CRASH_OCCURRED, {1 /*uid*/});
1946 sampledCountMetric.mutable_dimensional_sampling_info()->set_shard_count(2);
1947 *config.add_count_metric() = sampledCountMetric;
1948
1949 // Initialize StatsLogProcessor.
1950 const uint64_t bucketStartTimeNs = 10000000000; // 0:10
1951 const uint64_t bucketSizeNs =
1952 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
1953 int uid = 12345;
1954 int64_t cfgId = 98765;
1955 ConfigKey cfgKey(uid, cfgId);
1956
1957 sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
1958 bucketStartTimeNs, bucketStartTimeNs, config, cfgKey, nullptr, 0, new UidMap());
1959
1960 int appUid1 = 1001; // odd hash value
1961 int appUid2 = 1002; // even hash value
1962 int appUid3 = 1003; // odd hash value
1963 std::vector<std::unique_ptr<LogEvent>> events;
1964 events.push_back(
1965 CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, appUid1)); // 0:30
1966 events.push_back(
1967 CreateAppCrashOccurredEvent(bucketStartTimeNs + 40 * NS_PER_SEC, appUid2)); // 0:50
1968 events.push_back(
1969 CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, appUid3)); // 1:10
1970 events.push_back(
1971 CreateAppCrashOccurredEvent(bucketStartTimeNs + 80 * NS_PER_SEC, appUid1)); // 1:20
1972 events.push_back(
1973 CreateAppCrashOccurredEvent(bucketStartTimeNs + 90 * NS_PER_SEC, appUid2)); // 1:30
1974 events.push_back(
1975 CreateAppCrashOccurredEvent(bucketStartTimeNs + 100 * NS_PER_SEC, appUid3)); // 1:40
1976
1977 // Send log events to StatsLogProcessor.
1978 for (auto& event : events) {
1979 processor->OnLogEvent(event.get());
1980 }
1981
1982 // Check dump report.
1983 vector<uint8_t> buffer;
1984 ConfigMetricsReportList reports;
1985 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
1986 FAST, &buffer);
1987 ASSERT_GT(buffer.size(), 0);
1988 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
1989 backfillDimensionPath(&reports);
1990 backfillStringInReport(&reports);
1991 backfillStartEndTimestamp(&reports);
1992
1993 ASSERT_EQ(1, reports.reports_size());
1994 ASSERT_EQ(1, reports.reports(0).metrics_size());
1995 EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
1996 StatsLogReport::CountMetricDataWrapper countMetrics;
1997 sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
1998 ASSERT_EQ(2, countMetrics.data_size());
1999
2000 // Only Uid 1 and 3 are logged. (odd hash value) + (offset of 5) % (shard count of 2) = 0
2001 CountMetricData data = countMetrics.data(0);
2002 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, appUid1);
2003 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
2004 2);
2005
2006 data = countMetrics.data(1);
2007 ValidateUidDimension(data.dimensions_in_what(), util::APP_CRASH_OCCURRED, appUid3);
2008 ValidateCountBucket(data.bucket_info(0), bucketStartTimeNs, bucketStartTimeNs + bucketSizeNs,
2009 2);
2010 }
2011
2012 } // namespace statsd
2013 } // namespace os
2014 } // namespace android
2015 #else
2016 GTEST_LOG_(INFO) << "This test does nothing.\n";
2017 #endif
2018