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
23namespace android {
24namespace os {
25namespace statsd {
26
27#ifdef __ANDROID__
28namespace {
29
30StatsdConfig 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.
103TEST(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
224TEST(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
346GTEST_LOG_(INFO) << "This test does nothing.\n";
347#endif
348
349}  // namespace statsd
350}  // namespace os
351}  // namespace android
352