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
968 } // namespace statsd
969 } // namespace os
970 } // namespace android
971 #else
972 GTEST_LOG_(INFO) << "This test does nothing.\n";
973 #endif
974