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