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 <vector>
18 
19 #include "src/StatsLogProcessor.h"
20 #include "src/stats_log_util.h"
21 #include "stats_event.h"
22 #include "tests/statsd_test_util.h"
23 
24 namespace android {
25 namespace os {
26 namespace statsd {
27 
28 #ifdef __ANDROID__
29 
30 namespace {
31 
CreateStatsdConfigForPushedEvent(const GaugeMetric::SamplingType sampling_type)32 StatsdConfig CreateStatsdConfigForPushedEvent(const GaugeMetric::SamplingType sampling_type) {
33     StatsdConfig config;
34     config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
35     *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
36     *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
37 
38     auto atomMatcher = CreateSimpleAtomMatcher("", util::APP_START_OCCURRED);
39     *config.add_atom_matcher() = atomMatcher;
40 
41     auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
42     *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
43         CreateDimensions(util::ACTIVITY_FOREGROUND_STATE_CHANGED, {1 /* uid field */ });
44     *config.add_predicate() = isInBackgroundPredicate;
45 
46     auto gaugeMetric = config.add_gauge_metric();
47     gaugeMetric->set_id(123456);
48     gaugeMetric->set_what(atomMatcher.id());
49     gaugeMetric->set_condition(isInBackgroundPredicate.id());
50     gaugeMetric->mutable_gauge_fields_filter()->set_include_all(false);
51     gaugeMetric->set_sampling_type(sampling_type);
52     auto fieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields();
53     fieldMatcher->set_field(util::APP_START_OCCURRED);
54     fieldMatcher->add_child()->set_field(3);  // type (enum)
55     fieldMatcher->add_child()->set_field(4);  // activity_name(str)
56     fieldMatcher->add_child()->set_field(7);  // activity_start_msec(int64)
57     *gaugeMetric->mutable_dimensions_in_what() =
58         CreateDimensions(util::APP_START_OCCURRED, {1 /* uid field */ });
59     gaugeMetric->set_bucket(FIVE_MINUTES);
60 
61     auto links = gaugeMetric->add_links();
62     links->set_condition(isInBackgroundPredicate.id());
63     auto dimensionWhat = links->mutable_fields_in_what();
64     dimensionWhat->set_field(util::APP_START_OCCURRED);
65     dimensionWhat->add_child()->set_field(1);  // uid field.
66     auto dimensionCondition = links->mutable_fields_in_condition();
67     dimensionCondition->set_field(util::ACTIVITY_FOREGROUND_STATE_CHANGED);
68     dimensionCondition->add_child()->set_field(1);  // uid field.
69     return config;
70 }
71 
CreateAppStartOccurredEvent(uint64_t timestampNs,const int uid,const string & pkg_name,AppStartOccurred::TransitionType type,const string & activity_name,const string & calling_pkg_name,const bool is_instant_app,int64_t activity_start_msec)72 std::unique_ptr<LogEvent> CreateAppStartOccurredEvent(
73         uint64_t timestampNs, const int uid, const string& pkg_name,
74         AppStartOccurred::TransitionType type, const string& activity_name,
75         const string& calling_pkg_name, const bool is_instant_app, int64_t activity_start_msec) {
76     AStatsEvent* statsEvent = AStatsEvent_obtain();
77     AStatsEvent_setAtomId(statsEvent, util::APP_START_OCCURRED);
78     AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
79 
80     AStatsEvent_writeInt32(statsEvent, uid);
81     AStatsEvent_writeString(statsEvent, pkg_name.c_str());
82     AStatsEvent_writeInt32(statsEvent, type);
83     AStatsEvent_writeString(statsEvent, activity_name.c_str());
84     AStatsEvent_writeString(statsEvent, calling_pkg_name.c_str());
85     AStatsEvent_writeInt32(statsEvent, is_instant_app);
86     AStatsEvent_writeInt32(statsEvent, activity_start_msec);
87 
88     std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
89     parseStatsEventToLogEvent(statsEvent, logEvent.get());
90     return logEvent;
91 }
92 
93 }  // namespace
94 
TEST(GaugeMetricE2eTest,TestMultipleFieldsForPushedEvent)95 TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) {
96     for (const auto& sampling_type :
97          {GaugeMetric::FIRST_N_SAMPLES, GaugeMetric::RANDOM_ONE_SAMPLE}) {
98         auto config = CreateStatsdConfigForPushedEvent(sampling_type);
99         int64_t bucketStartTimeNs = 10000000000;
100         int64_t bucketSizeNs =
101                 TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
102 
103         ConfigKey cfgKey;
104         auto processor =
105                 CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
106         ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
107         EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
108 
109         int appUid1 = 123;
110         int appUid2 = 456;
111         std::vector<std::unique_ptr<LogEvent>> events;
112         events.push_back(CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid1));
113         events.push_back(
114                 CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid1));
115         events.push_back(
116                 CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid1));
117         events.push_back(
118                 CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100, appUid1));
119 
120         events.push_back(CreateAppStartOccurredEvent(
121                 bucketStartTimeNs + 10, appUid1, "app1", AppStartOccurred::WARM, "activity_name1",
122                 "calling_pkg_name1", true /*is_instant_app*/, 101 /*activity_start_msec*/));
123         events.push_back(CreateAppStartOccurredEvent(
124                 bucketStartTimeNs + 20, appUid1, "app1", AppStartOccurred::HOT, "activity_name2",
125                 "calling_pkg_name2", true /*is_instant_app*/, 102 /*activity_start_msec*/));
126         events.push_back(CreateAppStartOccurredEvent(
127                 bucketStartTimeNs + 30, appUid1, "app1", AppStartOccurred::COLD, "activity_name3",
128                 "calling_pkg_name3", true /*is_instant_app*/, 103 /*activity_start_msec*/));
129         events.push_back(CreateAppStartOccurredEvent(
130                 bucketStartTimeNs + bucketSizeNs + 30, appUid1, "app1", AppStartOccurred::WARM,
131                 "activity_name4", "calling_pkg_name4", true /*is_instant_app*/,
132                 104 /*activity_start_msec*/));
133         events.push_back(CreateAppStartOccurredEvent(
134                 bucketStartTimeNs + 2 * bucketSizeNs, appUid1, "app1", AppStartOccurred::COLD,
135                 "activity_name5", "calling_pkg_name5", true /*is_instant_app*/,
136                 105 /*activity_start_msec*/));
137         events.push_back(CreateAppStartOccurredEvent(
138                 bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid1, "app1", AppStartOccurred::HOT,
139                 "activity_name6", "calling_pkg_name6", false /*is_instant_app*/,
140                 106 /*activity_start_msec*/));
141 
142         events.push_back(
143                 CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 10, appUid2));
144         events.push_back(CreateAppStartOccurredEvent(
145                 bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid2, "app2", AppStartOccurred::COLD,
146                 "activity_name7", "calling_pkg_name7", true /*is_instant_app*/,
147                 201 /*activity_start_msec*/));
148 
149         sortLogEventsByTimestamp(&events);
150 
151         for (const auto& event : events) {
152             processor->OnLogEvent(event.get());
153         }
154         ConfigMetricsReportList reports;
155         vector<uint8_t> buffer;
156         processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true, ADB_DUMP,
157                                 FAST, &buffer);
158         EXPECT_TRUE(buffer.size() > 0);
159         EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
160         backfillDimensionPath(&reports);
161         backfillStringInReport(&reports);
162         backfillStartEndTimestamp(&reports);
163         ASSERT_EQ(1, reports.reports_size());
164         ASSERT_EQ(1, reports.reports(0).metrics_size());
165         StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
166         sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(),
167                                         &gaugeMetrics);
168         ASSERT_EQ(2, gaugeMetrics.data_size());
169 
170         auto data = gaugeMetrics.data(0);
171         EXPECT_EQ(util::APP_START_OCCURRED, data.dimensions_in_what().field());
172         ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
173         EXPECT_EQ(1 /* uid field */,
174                   data.dimensions_in_what().value_tuple().dimensions_value(0).field());
175         EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
176         ASSERT_EQ(3, data.bucket_info_size());
177         if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) {
178             ASSERT_EQ(2, data.bucket_info(0).atom_size());
179             ASSERT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
180             ASSERT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
181             EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
182             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
183                       data.bucket_info(0).end_bucket_elapsed_nanos());
184             EXPECT_EQ(AppStartOccurred::HOT,
185                       data.bucket_info(0).atom(0).app_start_occurred().type());
186             EXPECT_EQ("activity_name2",
187                       data.bucket_info(0).atom(0).app_start_occurred().activity_name());
188             EXPECT_EQ(102L,
189                       data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
190             EXPECT_EQ(AppStartOccurred::COLD,
191                       data.bucket_info(0).atom(1).app_start_occurred().type());
192             EXPECT_EQ("activity_name3",
193                       data.bucket_info(0).atom(1).app_start_occurred().activity_name());
194             EXPECT_EQ(103L,
195                       data.bucket_info(0).atom(1).app_start_occurred().activity_start_millis());
196 
197             ASSERT_EQ(1, data.bucket_info(1).atom_size());
198             ASSERT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
199             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
200                       data.bucket_info(1).start_bucket_elapsed_nanos());
201             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
202                       data.bucket_info(1).end_bucket_elapsed_nanos());
203             EXPECT_EQ(AppStartOccurred::WARM,
204                       data.bucket_info(1).atom(0).app_start_occurred().type());
205             EXPECT_EQ("activity_name4",
206                       data.bucket_info(1).atom(0).app_start_occurred().activity_name());
207             EXPECT_EQ(104L,
208                       data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
209 
210             ASSERT_EQ(2, data.bucket_info(2).atom_size());
211             ASSERT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
212             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
213                       data.bucket_info(2).start_bucket_elapsed_nanos());
214             EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
215                       data.bucket_info(2).end_bucket_elapsed_nanos());
216             EXPECT_EQ(AppStartOccurred::COLD,
217                       data.bucket_info(2).atom(0).app_start_occurred().type());
218             EXPECT_EQ("activity_name5",
219                       data.bucket_info(2).atom(0).app_start_occurred().activity_name());
220             EXPECT_EQ(105L,
221                       data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
222             EXPECT_EQ(AppStartOccurred::HOT,
223                       data.bucket_info(2).atom(1).app_start_occurred().type());
224             EXPECT_EQ("activity_name6",
225                       data.bucket_info(2).atom(1).app_start_occurred().activity_name());
226             EXPECT_EQ(106L,
227                       data.bucket_info(2).atom(1).app_start_occurred().activity_start_millis());
228         } else {
229             ASSERT_EQ(1, data.bucket_info(0).atom_size());
230             ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
231             EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
232             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
233                       data.bucket_info(0).end_bucket_elapsed_nanos());
234             EXPECT_EQ(AppStartOccurred::HOT,
235                       data.bucket_info(0).atom(0).app_start_occurred().type());
236             EXPECT_EQ("activity_name2",
237                       data.bucket_info(0).atom(0).app_start_occurred().activity_name());
238             EXPECT_EQ(102L,
239                       data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
240 
241             ASSERT_EQ(1, data.bucket_info(1).atom_size());
242             ASSERT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
243             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
244                       data.bucket_info(1).start_bucket_elapsed_nanos());
245             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
246                       data.bucket_info(1).end_bucket_elapsed_nanos());
247             EXPECT_EQ(AppStartOccurred::WARM,
248                       data.bucket_info(1).atom(0).app_start_occurred().type());
249             EXPECT_EQ("activity_name4",
250                       data.bucket_info(1).atom(0).app_start_occurred().activity_name());
251             EXPECT_EQ(104L,
252                       data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
253 
254             ASSERT_EQ(1, data.bucket_info(2).atom_size());
255             ASSERT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
256             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
257                       data.bucket_info(2).start_bucket_elapsed_nanos());
258             EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
259                       data.bucket_info(2).end_bucket_elapsed_nanos());
260             EXPECT_EQ(AppStartOccurred::COLD,
261                       data.bucket_info(2).atom(0).app_start_occurred().type());
262             EXPECT_EQ("activity_name5",
263                       data.bucket_info(2).atom(0).app_start_occurred().activity_name());
264             EXPECT_EQ(105L,
265                       data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
266         }
267 
268         data = gaugeMetrics.data(1);
269 
270         EXPECT_EQ(data.dimensions_in_what().field(), util::APP_START_OCCURRED);
271         ASSERT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
272         EXPECT_EQ(1 /* uid field */,
273                   data.dimensions_in_what().value_tuple().dimensions_value(0).field());
274         EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
275         ASSERT_EQ(1, data.bucket_info_size());
276         ASSERT_EQ(1, data.bucket_info(0).atom_size());
277         ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
278         EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
279                   data.bucket_info(0).start_bucket_elapsed_nanos());
280         EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
281                   data.bucket_info(0).end_bucket_elapsed_nanos());
282         EXPECT_EQ(AppStartOccurred::COLD, data.bucket_info(0).atom(0).app_start_occurred().type());
283         EXPECT_EQ("activity_name7",
284                   data.bucket_info(0).atom(0).app_start_occurred().activity_name());
285         EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
286     }
287 }
288 
289 #else
290 GTEST_LOG_(INFO) << "This test does nothing.\n";
291 #endif
292 
293 }  // namespace statsd
294 }  // namespace os
295 }  // namespace android
296