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