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