1 // Copyright (C) 2017 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <gtest/gtest.h>
16
17 #include "src/StatsLogProcessor.h"
18 #include "src/stats_log_util.h"
19 #include "tests/statsd_test_util.h"
20
21 #include <vector>
22
23 namespace android {
24 namespace os {
25 namespace statsd {
26
27 #ifdef __ANDROID__
28 namespace {
29
CreateStatsdConfig()30 StatsdConfig CreateStatsdConfig() {
31 StatsdConfig config;
32 config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
33
34 *config.add_atom_matcher() = CreateScreenTurnedOnAtomMatcher();
35 *config.add_atom_matcher() = CreateScreenTurnedOffAtomMatcher();
36
37 *config.add_atom_matcher() = CreateSyncStartAtomMatcher();
38 *config.add_atom_matcher() = CreateSyncEndAtomMatcher();
39
40 *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
41 *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
42
43 auto appCrashMatcher = CreateProcessCrashAtomMatcher();
44 *config.add_atom_matcher() = appCrashMatcher;
45
46 auto screenIsOffPredicate = CreateScreenIsOffPredicate();
47
48 auto isSyncingPredicate = CreateIsSyncingPredicate();
49 auto syncDimension = isSyncingPredicate.mutable_simple_predicate()->mutable_dimensions();
50 *syncDimension = CreateAttributionUidDimensions(
51 android::util::SYNC_STATE_CHANGED, {Position::FIRST});
52 syncDimension->add_child()->set_field(2 /* name field*/);
53
54 auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
55 *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
56 CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
57
58 *config.add_predicate() = screenIsOffPredicate;
59 *config.add_predicate() = isSyncingPredicate;
60 *config.add_predicate() = isInBackgroundPredicate;
61
62 auto combinationPredicate = config.add_predicate();
63 combinationPredicate->set_id(StringToId("combinationPredicate"));
64 combinationPredicate->mutable_combination()->set_operation(LogicalOperation::AND);
65 addPredicateToPredicateCombination(screenIsOffPredicate, combinationPredicate);
66 addPredicateToPredicateCombination(isSyncingPredicate, combinationPredicate);
67 addPredicateToPredicateCombination(isInBackgroundPredicate, combinationPredicate);
68
69 auto countMetric = config.add_count_metric();
70 countMetric->set_id(StringToId("AppCrashes"));
71 countMetric->set_what(appCrashMatcher.id());
72 countMetric->set_condition(combinationPredicate->id());
73 // The metric is dimensioning by uid only.
74 *countMetric->mutable_dimensions_in_what() =
75 CreateDimensions(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, {1});
76 countMetric->set_bucket(FIVE_MINUTES);
77
78 // Links between crash atom and condition of app is in syncing.
79 auto links = countMetric->add_links();
80 links->set_condition(isSyncingPredicate.id());
81 auto dimensionWhat = links->mutable_fields_in_what();
82 dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
83 dimensionWhat->add_child()->set_field(1); // uid field.
84 *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
85 android::util::SYNC_STATE_CHANGED, {Position::FIRST});
86
87 // Links between crash atom and condition of app is in background.
88 links = countMetric->add_links();
89 links->set_condition(isInBackgroundPredicate.id());
90 dimensionWhat = links->mutable_fields_in_what();
91 dimensionWhat->set_field(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
92 dimensionWhat->add_child()->set_field(1); // uid field.
93 auto dimensionCondition = links->mutable_fields_in_condition();
94 dimensionCondition->set_field(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
95 dimensionCondition->add_child()->set_field(1); // uid field.
96 return config;
97 }
98 } // namespace
99
100 // If we want to test multiple dump data, we must do it in separate tests, because in the e2e tests,
101 // we should use the real API which will clear the data after dump data is called.
102 // TODO: better refactor the code so that the tests are not so verbose.
TEST(MetricConditionLinkE2eTest,TestMultiplePredicatesAndLinks1)103 TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) {
104 auto config = CreateStatsdConfig();
105 uint64_t bucketStartTimeNs = 10000000000;
106 uint64_t bucketSizeNs =
107 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
108
109 ConfigKey cfgKey;
110 auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
111 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
112 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
113
114 int appUid = 123;
115 auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1);
116 auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201);
117 auto crashEvent3= CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101);
118
119 auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51);
120 auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299);
121 auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001);
122
123 auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16);
124 auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249);
125
126 auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351);
127 auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2);
128
129 auto screenTurnedOnEvent =
130 CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
131 bucketStartTimeNs + 2);
132 auto screenTurnedOffEvent =
133 CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
134 bucketStartTimeNs + 200);
135 auto screenTurnedOnEvent2 =
136 CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
137 bucketStartTimeNs + 2 * bucketSizeNs - 100);
138
139 std::vector<AttributionNodeInternal> attributions = {
140 CreateAttribution(appUid, "App1"), CreateAttribution(appUid + 1, "GMSCoreModule1")};
141 auto syncOnEvent1 =
142 CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50);
143 auto syncOffEvent1 =
144 CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300);
145 auto syncOnEvent2 =
146 CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000);
147
148 auto moveToBackgroundEvent1 =
149 CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15);
150 auto moveToForegroundEvent1 =
151 CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250);
152
153 auto moveToBackgroundEvent2 =
154 CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350);
155 auto moveToForegroundEvent2 =
156 CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1);
157
158 /*
159 bucket #1 bucket #2
160
161
162 | | | | | | | | | | (crashEvents)
163 |-------------------------------------|-----------------------------------|---------
164
165 | | (MoveToBkground)
166
167 | | (MoveToForeground)
168
169 | | (SyncIsOn)
170 | (SyncIsOff)
171 | | (ScreenIsOn)
172 | (ScreenIsOff)
173 */
174 std::vector<std::unique_ptr<LogEvent>> events;
175 events.push_back(std::move(crashEvent1));
176 events.push_back(std::move(crashEvent2));
177 events.push_back(std::move(crashEvent3));
178 events.push_back(std::move(crashEvent4));
179 events.push_back(std::move(crashEvent5));
180 events.push_back(std::move(crashEvent6));
181 events.push_back(std::move(crashEvent7));
182 events.push_back(std::move(crashEvent8));
183 events.push_back(std::move(crashEvent9));
184 events.push_back(std::move(crashEvent10));
185 events.push_back(std::move(screenTurnedOnEvent));
186 events.push_back(std::move(screenTurnedOffEvent));
187 events.push_back(std::move(screenTurnedOnEvent2));
188 events.push_back(std::move(syncOnEvent1));
189 events.push_back(std::move(syncOffEvent1));
190 events.push_back(std::move(syncOnEvent2));
191 events.push_back(std::move(moveToBackgroundEvent1));
192 events.push_back(std::move(moveToForegroundEvent1));
193 events.push_back(std::move(moveToBackgroundEvent2));
194 events.push_back(std::move(moveToForegroundEvent2));
195
196 sortLogEventsByTimestamp(&events);
197
198 for (const auto& event : events) {
199 processor->OnLogEvent(event.get());
200 }
201 ConfigMetricsReportList reports;
202 vector<uint8_t> buffer;
203 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP,
204 &buffer);
205 EXPECT_TRUE(buffer.size() > 0);
206 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
207 backfillDimensionPath(&reports);
208 backfillStringInReport(&reports);
209 backfillStartEndTimestamp(&reports);
210 EXPECT_EQ(reports.reports_size(), 1);
211 EXPECT_EQ(reports.reports(0).metrics_size(), 1);
212 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
213 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
214 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
215 auto data = reports.reports(0).metrics(0).count_metrics().data(0);
216 // Validate dimension value.
217 EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
218 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
219 // Uid field.
220 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
221 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
222 }
223
TEST(MetricConditionLinkE2eTest,TestMultiplePredicatesAndLinks2)224 TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) {
225 auto config = CreateStatsdConfig();
226 uint64_t bucketStartTimeNs = 10000000000;
227 uint64_t bucketSizeNs =
228 TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
229
230 ConfigKey cfgKey;
231 auto processor = CreateStatsLogProcessor(
232 bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
233 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
234 EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
235
236 int appUid = 123;
237 auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1);
238 auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201);
239 auto crashEvent3 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101);
240
241 auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51);
242 auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299);
243 auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001);
244
245 auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16);
246 auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249);
247
248 auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351);
249 auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2);
250
251 auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
252 android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 2);
253 auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
254 android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 200);
255 auto screenTurnedOnEvent2 =
256 CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
257 bucketStartTimeNs + 2 * bucketSizeNs - 100);
258
259 std::vector<AttributionNodeInternal> attributions = {
260 CreateAttribution(appUid, "App1"), CreateAttribution(appUid + 1, "GMSCoreModule1")};
261 auto syncOnEvent1 = CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50);
262 auto syncOffEvent1 =
263 CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300);
264 auto syncOnEvent2 =
265 CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000);
266
267 auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15);
268 auto moveToForegroundEvent1 =
269 CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250);
270
271 auto moveToBackgroundEvent2 =
272 CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350);
273 auto moveToForegroundEvent2 =
274 CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1);
275
276 /*
277 bucket #1 bucket #2
278
279
280 | | | | | | | | | | (crashEvents)
281 |-------------------------------------|-----------------------------------|---------
282
283 | | (MoveToBkground)
284
285 | | (MoveToForeground)
286
287 | | (SyncIsOn)
288 | (SyncIsOff)
289 | | (ScreenIsOn)
290 | (ScreenIsOff)
291 */
292 std::vector<std::unique_ptr<LogEvent>> events;
293 events.push_back(std::move(crashEvent1));
294 events.push_back(std::move(crashEvent2));
295 events.push_back(std::move(crashEvent3));
296 events.push_back(std::move(crashEvent4));
297 events.push_back(std::move(crashEvent5));
298 events.push_back(std::move(crashEvent6));
299 events.push_back(std::move(crashEvent7));
300 events.push_back(std::move(crashEvent8));
301 events.push_back(std::move(crashEvent9));
302 events.push_back(std::move(crashEvent10));
303 events.push_back(std::move(screenTurnedOnEvent));
304 events.push_back(std::move(screenTurnedOffEvent));
305 events.push_back(std::move(screenTurnedOnEvent2));
306 events.push_back(std::move(syncOnEvent1));
307 events.push_back(std::move(syncOffEvent1));
308 events.push_back(std::move(syncOnEvent2));
309 events.push_back(std::move(moveToBackgroundEvent1));
310 events.push_back(std::move(moveToForegroundEvent1));
311 events.push_back(std::move(moveToBackgroundEvent2));
312 events.push_back(std::move(moveToForegroundEvent2));
313
314 sortLogEventsByTimestamp(&events);
315
316 for (const auto& event : events) {
317 processor->OnLogEvent(event.get());
318 }
319 ConfigMetricsReportList reports;
320 vector<uint8_t> buffer;
321
322 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
323 &buffer);
324 EXPECT_TRUE(buffer.size() > 0);
325 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
326 backfillDimensionPath(&reports);
327 backfillStringInReport(&reports);
328 backfillStartEndTimestamp(&reports);
329 EXPECT_EQ(reports.reports_size(), 1);
330 EXPECT_EQ(reports.reports(0).metrics_size(), 1);
331 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
332 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2);
333 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
334 EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3);
335 auto data = reports.reports(0).metrics(0).count_metrics().data(0);
336 // Validate dimension value.
337 EXPECT_EQ(data.dimensions_in_what().field(),
338 android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
339 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
340 // Uid field.
341 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
342 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
343 }
344
345 #else
346 GTEST_LOG_(INFO) << "This test does nothing.\n";
347 #endif
348
349 } // namespace statsd
350 } // namespace os
351 } // namespace android
352