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