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         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(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(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(util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
83     dimensionWhat->add_child()->set_field(1);  // uid field.
84     *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
85             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(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(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.
TEST(MetricConditionLinkE2eTest,TestMultiplePredicatesAndLinks1)102 TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) {
103     auto config = CreateStatsdConfig();
104     uint64_t bucketStartTimeNs = 10000000000;
105     uint64_t bucketSizeNs =
106             TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
107 
108     ConfigKey cfgKey;
109     auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
110     ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
111     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
112 
113     int appUid = 123;
114     auto crashEvent1 = CreateAppCrashEvent(bucketStartTimeNs + 1, appUid);
115     auto crashEvent2 = CreateAppCrashEvent(bucketStartTimeNs + 201, appUid);
116     auto crashEvent3 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 101, appUid);
117 
118     auto crashEvent4 = CreateAppCrashEvent(bucketStartTimeNs + 51, appUid);
119     auto crashEvent5 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 299, appUid);
120     auto crashEvent6 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 2001, appUid);
121 
122     auto crashEvent7 = CreateAppCrashEvent(bucketStartTimeNs + 16, appUid);
123     auto crashEvent8 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 249, appUid);
124 
125     auto crashEvent9 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 351, appUid);
126     auto crashEvent10 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 2, appUid);
127 
128     auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
129             bucketStartTimeNs + 2, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
130     auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
131             bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
132     auto screenTurnedOnEvent2 =
133             CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
134                                           android::view::DisplayStateEnum::DISPLAY_STATE_ON);
135 
136     std::vector<int> attributionUids = {appUid, appUid + 1};
137     std::vector<string> attributionTags = {"App1", "GMSCoreModule1"};
138 
139     auto syncOnEvent1 = CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids,
140                                              attributionTags, "ReadEmail");
141     auto syncOffEvent1 = CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids,
142                                             attributionTags, "ReadEmail");
143     auto syncOnEvent2 = CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs + 2000,
144                                              attributionUids, attributionTags, "ReadDoc");
145 
146     auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid);
147     auto moveToForegroundEvent1 =
148             CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid);
149 
150     auto moveToBackgroundEvent2 =
151             CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid);
152     auto moveToForegroundEvent2 =
153             CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs - 1, appUid);
154 
155     /*
156                     bucket #1                               bucket #2
157 
158 
159        |      |   |  |                      |   |          |        |   |   |     (crashEvents)
160     |-------------------------------------|-----------------------------------|---------
161 
162              |                                           |                        (MoveToBkground)
163 
164                                              |                               |    (MoveToForeground)
165 
166                 |                                                 |                (SyncIsOn)
167                                                   |                                (SyncIsOff)
168           |                                                               |        (ScreenIsOn)
169                    |                                                               (ScreenIsOff)
170     */
171     std::vector<std::unique_ptr<LogEvent>> events;
172     events.push_back(std::move(crashEvent1));
173     events.push_back(std::move(crashEvent2));
174     events.push_back(std::move(crashEvent3));
175     events.push_back(std::move(crashEvent4));
176     events.push_back(std::move(crashEvent5));
177     events.push_back(std::move(crashEvent6));
178     events.push_back(std::move(crashEvent7));
179     events.push_back(std::move(crashEvent8));
180     events.push_back(std::move(crashEvent9));
181     events.push_back(std::move(crashEvent10));
182     events.push_back(std::move(screenTurnedOnEvent));
183     events.push_back(std::move(screenTurnedOffEvent));
184     events.push_back(std::move(screenTurnedOnEvent2));
185     events.push_back(std::move(syncOnEvent1));
186     events.push_back(std::move(syncOffEvent1));
187     events.push_back(std::move(syncOnEvent2));
188     events.push_back(std::move(moveToBackgroundEvent1));
189     events.push_back(std::move(moveToForegroundEvent1));
190     events.push_back(std::move(moveToBackgroundEvent2));
191     events.push_back(std::move(moveToForegroundEvent2));
192 
193     sortLogEventsByTimestamp(&events);
194 
195     for (const auto& event : events) {
196         processor->OnLogEvent(event.get());
197     }
198     ConfigMetricsReportList reports;
199     vector<uint8_t> buffer;
200     processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, ADB_DUMP,
201                             FAST, &buffer);
202     EXPECT_TRUE(buffer.size() > 0);
203     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
204     backfillDimensionPath(&reports);
205     backfillStringInReport(&reports);
206     backfillStartEndTimestamp(&reports);
207     ASSERT_EQ(reports.reports_size(), 1);
208     ASSERT_EQ(reports.reports(0).metrics_size(), 1);
209     ASSERT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
210     ASSERT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
211     EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
212     auto data = reports.reports(0).metrics(0).count_metrics().data(0);
213     // Validate dimension value.
214     EXPECT_EQ(data.dimensions_in_what().field(), util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
215     ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
216     // Uid field.
217     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
218     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
219 }
220 
TEST(MetricConditionLinkE2eTest,TestMultiplePredicatesAndLinks2)221 TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) {
222     auto config = CreateStatsdConfig();
223     uint64_t bucketStartTimeNs = 10000000000;
224     uint64_t bucketSizeNs =
225             TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
226 
227     ConfigKey cfgKey;
228     auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
229     ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
230     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
231 
232     int appUid = 123;
233     auto crashEvent1 = CreateAppCrashEvent(bucketStartTimeNs + 1, appUid);
234     auto crashEvent2 = CreateAppCrashEvent(bucketStartTimeNs + 201, appUid);
235     auto crashEvent3 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 101, appUid);
236 
237     auto crashEvent4 = CreateAppCrashEvent(bucketStartTimeNs + 51, appUid);
238     auto crashEvent5 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 299, appUid);
239     auto crashEvent6 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 2001, appUid);
240 
241     auto crashEvent7 = CreateAppCrashEvent(bucketStartTimeNs + 16, appUid);
242     auto crashEvent8 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 249, appUid);
243 
244     auto crashEvent9 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 351, appUid);
245     auto crashEvent10 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 2, appUid);
246 
247     auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
248             bucketStartTimeNs + 2, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
249     auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
250             bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
251     auto screenTurnedOnEvent2 =
252             CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
253                                           android::view::DisplayStateEnum::DISPLAY_STATE_ON);
254 
255     std::vector<int> attributionUids = {appUid, appUid + 1};
256     std::vector<string> attributionTags = {"App1", "GMSCoreModule1"};
257 
258     auto syncOnEvent1 = CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids,
259                                              attributionTags, "ReadEmail");
260     auto syncOffEvent1 = CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids,
261                                             attributionTags, "ReadEmail");
262     auto syncOnEvent2 = CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs + 2000,
263                                              attributionUids, attributionTags, "ReadDoc");
264 
265     auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid);
266     auto moveToForegroundEvent1 =
267             CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid);
268 
269     auto moveToBackgroundEvent2 =
270             CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid);
271     auto moveToForegroundEvent2 =
272             CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs - 1, appUid);
273 
274     /*
275                     bucket #1                               bucket #2
276 
277 
278        |      |   |  |                      |   |          |        |   |   |     (crashEvents)
279     |-------------------------------------|-----------------------------------|---------
280 
281              |                                           |                        (MoveToBkground)
282 
283                                              |                               |    (MoveToForeground)
284 
285                 |                                                 |                (SyncIsOn)
286                                                   |                                (SyncIsOff)
287           |                                                               |        (ScreenIsOn)
288                    |                                                               (ScreenIsOff)
289     */
290     std::vector<std::unique_ptr<LogEvent>> events;
291     events.push_back(std::move(crashEvent1));
292     events.push_back(std::move(crashEvent2));
293     events.push_back(std::move(crashEvent3));
294     events.push_back(std::move(crashEvent4));
295     events.push_back(std::move(crashEvent5));
296     events.push_back(std::move(crashEvent6));
297     events.push_back(std::move(crashEvent7));
298     events.push_back(std::move(crashEvent8));
299     events.push_back(std::move(crashEvent9));
300     events.push_back(std::move(crashEvent10));
301     events.push_back(std::move(screenTurnedOnEvent));
302     events.push_back(std::move(screenTurnedOffEvent));
303     events.push_back(std::move(screenTurnedOnEvent2));
304     events.push_back(std::move(syncOnEvent1));
305     events.push_back(std::move(syncOffEvent1));
306     events.push_back(std::move(syncOnEvent2));
307     events.push_back(std::move(moveToBackgroundEvent1));
308     events.push_back(std::move(moveToForegroundEvent1));
309     events.push_back(std::move(moveToBackgroundEvent2));
310     events.push_back(std::move(moveToForegroundEvent2));
311 
312     sortLogEventsByTimestamp(&events);
313 
314     for (const auto& event : events) {
315         processor->OnLogEvent(event.get());
316     }
317     ConfigMetricsReportList reports;
318     vector<uint8_t> buffer;
319 
320     processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, ADB_DUMP,
321                             FAST, &buffer);
322     EXPECT_TRUE(buffer.size() > 0);
323     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
324     backfillDimensionPath(&reports);
325     backfillStringInReport(&reports);
326     backfillStartEndTimestamp(&reports);
327     ASSERT_EQ(reports.reports_size(), 1);
328     ASSERT_EQ(reports.reports(0).metrics_size(), 1);
329     ASSERT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
330     ASSERT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2);
331     EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
332     EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3);
333     auto data = reports.reports(0).metrics(0).count_metrics().data(0);
334     // Validate dimension value.
335     EXPECT_EQ(data.dimensions_in_what().field(), util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
336     ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
337     // Uid field.
338     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
339     EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
340 }
341 
342 #else
343 GTEST_LOG_(INFO) << "This test does nothing.\n";
344 #endif
345 
346 }  // namespace statsd
347 }  // namespace os
348 }  // namespace android
349