1 // Copyright (C) 2020 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 <android-base/properties.h>
16 #include <android-base/stringprintf.h>
17 #include <android/binder_interface_utils.h>
18 #include <gtest/gtest.h>
19
20 #include "flags/FlagProvider.h"
21 #include "src/StatsLogProcessor.h"
22 #include "src/storage/StorageManager.h"
23 #include "tests/statsd_test_util.h"
24
25 namespace android {
26 namespace os {
27 namespace statsd {
28
29 #ifdef __ANDROID__
30 #define STATS_DATA_DIR "/data/misc/stats-data"
31
32 using android::base::SetProperty;
33 using android::base::StringPrintf;
34 using ::ndk::SharedRefBase;
35 using namespace std;
36
37 namespace {
38
CreateSimpleConfig()39 StatsdConfig CreateSimpleConfig() {
40 StatsdConfig config;
41 config.add_allowed_log_source("AID_STATSD");
42 config.set_hash_strings_in_metric_report(false);
43
44 *config.add_atom_matcher() = CreateBatteryStateUsbMatcher();
45 // Simple count metric so the config isn't empty.
46 CountMetric* countMetric1 = config.add_count_metric();
47 countMetric1->set_id(StringToId("Count1"));
48 countMetric1->set_what(config.atom_matcher(0).id());
49 countMetric1->set_bucket(FIVE_MINUTES);
50 return config;
51 }
52 } // namespace
53
54 // Setup for parameterized tests.
55 class ConfigUpdateE2eAbTest : public TestWithParam<bool> {
56 };
57
58 INSTANTIATE_TEST_SUITE_P(ConfigUpdateE2eAbTest, ConfigUpdateE2eAbTest, testing::Bool());
59
TEST_P(ConfigUpdateE2eAbTest,TestUidMapVersionStringInstaller)60 TEST_P(ConfigUpdateE2eAbTest, TestUidMapVersionStringInstaller) {
61 sp<UidMap> uidMap = new UidMap();
62 UidData uidData;
63 ApplicationInfo appInfo = createApplicationInfo(/*uid*/ 1000, /*version*/ 1, "v1", "app1");
64 appInfo.set_installer("installer1");
65 *uidData.add_app_info() = appInfo;
66 uidMap->updateMap(1 /* timestamp */, uidData);
67
68 StatsdConfig config = CreateSimpleConfig();
69 config.set_version_strings_in_metric_report(true);
70 config.set_installer_in_metric_report(false);
71 int64_t baseTimeNs = getElapsedRealtimeNs();
72
73 ConfigKey cfgKey(0, 12345);
74 sp<StatsLogProcessor> processor =
75 CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey, nullptr, 0, uidMap);
76 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
77 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
78 EXPECT_TRUE(metricsManager->isConfigValid());
79
80 // Now update.
81 config.set_version_strings_in_metric_report(false);
82 config.set_installer_in_metric_report(true);
83 processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, GetParam());
84 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
85 EXPECT_EQ(metricsManager == processor->mMetricsManagers.begin()->second, GetParam());
86 EXPECT_TRUE(metricsManager->isConfigValid());
87
88 ConfigMetricsReportList reports;
89 vector<uint8_t> buffer;
90 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
91 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
92 // First report is written to disk when the update happens.
93 ASSERT_EQ(reports.reports_size(), 2);
94 UidMapping uidMapping = reports.reports(1).uid_map();
95 ASSERT_EQ(uidMapping.snapshots_size(), 1);
96 ASSERT_EQ(uidMapping.snapshots(0).package_info_size(), 1);
97 EXPECT_FALSE(uidMapping.snapshots(0).package_info(0).has_version_string());
98 EXPECT_EQ(uidMapping.snapshots(0).package_info(0).installer_index(), 0);
99 EXPECT_THAT(uidMapping.installer_name(), ElementsAre("installer1"));
100 }
101
TEST_P(ConfigUpdateE2eAbTest,TestHashStrings)102 TEST_P(ConfigUpdateE2eAbTest, TestHashStrings) {
103 sp<UidMap> uidMap = new UidMap();
104 UidData uidData;
105 ApplicationInfo appInfo = createApplicationInfo(/*uid*/ 1000, /*version*/ 1, "v1", "app1");
106 appInfo.set_installer("installer1");
107 *uidData.add_app_info() = appInfo;
108 uidMap->updateMap(1 /* timestamp */, uidData);
109
110 StatsdConfig config = CreateSimpleConfig();
111 config.set_version_strings_in_metric_report(true);
112 config.set_hash_strings_in_metric_report(true);
113 int64_t baseTimeNs = getElapsedRealtimeNs();
114
115 ConfigKey cfgKey(0, 12345);
116 sp<StatsLogProcessor> processor =
117 CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey, nullptr, 0, uidMap);
118 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
119 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
120 EXPECT_TRUE(metricsManager->isConfigValid());
121
122 // Now update.
123 config.set_hash_strings_in_metric_report(false);
124 processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, GetParam());
125 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
126 EXPECT_EQ(metricsManager == processor->mMetricsManagers.begin()->second, GetParam());
127 EXPECT_TRUE(metricsManager->isConfigValid());
128
129 ConfigMetricsReportList reports;
130 vector<uint8_t> buffer;
131 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
132 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
133 // First report is written to disk when the update happens.
134 ASSERT_EQ(reports.reports_size(), 2);
135 UidMapping uidMapping = reports.reports(1).uid_map();
136 ASSERT_EQ(uidMapping.snapshots_size(), 1);
137 ASSERT_EQ(uidMapping.snapshots(0).package_info_size(), 1);
138 EXPECT_TRUE(uidMapping.snapshots(0).package_info(0).has_version_string());
139 EXPECT_FALSE(uidMapping.snapshots(0).package_info(0).has_version_string_hash());
140 }
141
TEST_P(ConfigUpdateE2eAbTest,TestAnnotations)142 TEST_P(ConfigUpdateE2eAbTest, TestAnnotations) {
143 StatsdConfig config = CreateSimpleConfig();
144 StatsdConfig_Annotation* annotation = config.add_annotation();
145 annotation->set_field_int64(11);
146 annotation->set_field_int32(1);
147 int64_t baseTimeNs = getElapsedRealtimeNs();
148 ConfigKey cfgKey(0, 12345);
149 sp<StatsLogProcessor> processor =
150 CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
151
152 // Now update
153 config.clear_annotation();
154 annotation = config.add_annotation();
155 annotation->set_field_int64(22);
156 annotation->set_field_int32(2);
157 processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, GetParam());
158
159 ConfigMetricsReportList reports;
160 vector<uint8_t> buffer;
161 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
162 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
163 // First report is written to disk when the update happens.
164 ASSERT_EQ(reports.reports_size(), 2);
165 ConfigMetricsReport report = reports.reports(1);
166 EXPECT_EQ(report.annotation_size(), 1);
167 EXPECT_EQ(report.annotation(0).field_int64(), 22);
168 EXPECT_EQ(report.annotation(0).field_int32(), 2);
169 }
170
TEST_P(ConfigUpdateE2eAbTest,TestPersistLocally)171 TEST_P(ConfigUpdateE2eAbTest, TestPersistLocally) {
172 StatsdConfig config = CreateSimpleConfig();
173 config.set_persist_locally(false);
174 int64_t baseTimeNs = getElapsedRealtimeNs();
175 ConfigKey cfgKey(0, 12345);
176 sp<StatsLogProcessor> processor =
177 CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
178 ConfigMetricsReportList reports;
179 vector<uint8_t> buffer;
180 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
181 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
182 ASSERT_EQ(reports.reports_size(), 1);
183 // Number of reports should still be 1 since persist_locally is false.
184 reports.Clear();
185 buffer.clear();
186 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
187 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
188 ASSERT_EQ(reports.reports_size(), 1);
189
190 // Now update.
191 config.set_persist_locally(true);
192 processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, GetParam());
193
194 // Should get 2: 1 in memory + 1 on disk. Both should be saved on disk.
195 reports.Clear();
196 buffer.clear();
197 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
198 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
199 ASSERT_EQ(reports.reports_size(), 2);
200 // Should get 3, 2 on disk + 1 in memory.
201 reports.Clear();
202 buffer.clear();
203 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
204 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
205 ASSERT_EQ(reports.reports_size(), 3);
206 string suffix = StringPrintf("%d_%lld", cfgKey.GetUid(), (long long)cfgKey.GetId());
207 StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, suffix.c_str());
208 string historySuffix =
209 StringPrintf("%d_%lld_history", cfgKey.GetUid(), (long long)cfgKey.GetId());
210 StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, historySuffix.c_str());
211 }
212
TEST_P(ConfigUpdateE2eAbTest,TestNoReportMetrics)213 TEST_P(ConfigUpdateE2eAbTest, TestNoReportMetrics) {
214 StatsdConfig config = CreateSimpleConfig();
215 // Second simple count metric.
216 CountMetric* countMetric = config.add_count_metric();
217 countMetric->set_id(StringToId("Count2"));
218 countMetric->set_what(config.atom_matcher(0).id());
219 countMetric->set_bucket(FIVE_MINUTES);
220 config.add_no_report_metric(config.count_metric(0).id());
221 int64_t baseTimeNs = getElapsedRealtimeNs();
222 ConfigKey cfgKey(0, 12345);
223 sp<StatsLogProcessor> processor =
224 CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
225
226 // Now update.
227 config.clear_no_report_metric();
228 config.add_no_report_metric(config.count_metric(1).id());
229 processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, GetParam());
230
231 ConfigMetricsReportList reports;
232 vector<uint8_t> buffer;
233 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
234 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
235 // First report is written to disk when the update happens.
236 ASSERT_EQ(reports.reports_size(), 2);
237 // First report (before update) has the first count metric.
238 ASSERT_EQ(reports.reports(0).metrics_size(), 1);
239 EXPECT_EQ(reports.reports(0).metrics(0).metric_id(), config.count_metric(1).id());
240 // Second report (after update) has the first count metric.
241 ASSERT_EQ(reports.reports(1).metrics_size(), 1);
242 EXPECT_EQ(reports.reports(1).metrics(0).metric_id(), config.count_metric(0).id());
243 }
244
TEST_P(ConfigUpdateE2eAbTest,TestAtomsAllowedFromAnyUid)245 TEST_P(ConfigUpdateE2eAbTest, TestAtomsAllowedFromAnyUid) {
246 StatsdConfig config = CreateSimpleConfig();
247 int64_t baseTimeNs = getElapsedRealtimeNs();
248 ConfigKey cfgKey(0, 12345);
249 sp<StatsLogProcessor> processor =
250 CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
251 const int32_t customAppUid = AID_APP_START + 1;
252 // override default uid (which is user running the test)
253 unique_ptr<LogEvent> event = CreateBatteryStateChangedEvent(
254 baseTimeNs + 2, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB, customAppUid);
255 processor->OnLogEvent(event.get());
256 ConfigMetricsReportList reports;
257 vector<uint8_t> buffer;
258 processor->onDumpReport(cfgKey, baseTimeNs + 1001, true, true, ADB_DUMP, FAST, &buffer);
259 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
260 ASSERT_EQ(reports.reports_size(), 1);
261 // Check the metric and make sure it has 0 count.
262 ASSERT_EQ(reports.reports(0).metrics_size(), 1);
263 EXPECT_FALSE(reports.reports(0).metrics(0).has_count_metrics());
264
265 // Now update. Allow plugged state to be logged from any uid, so the atom will be counted.
266 config.add_whitelisted_atom_ids(util::PLUGGED_STATE_CHANGED);
267 processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, GetParam());
268 unique_ptr<LogEvent> event2 = CreateBatteryStateChangedEvent(
269 baseTimeNs + 2000, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
270 processor->OnLogEvent(event.get());
271 reports.Clear();
272 buffer.clear();
273 processor->onDumpReport(cfgKey, baseTimeNs + 3000, true, true, ADB_DUMP, FAST, &buffer);
274 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
275 ASSERT_EQ(reports.reports_size(), 2);
276 // Check the metric and make sure it has 0 count.
277 ASSERT_EQ(reports.reports(1).metrics_size(), 1);
278 EXPECT_TRUE(reports.reports(1).metrics(0).has_count_metrics());
279 ASSERT_EQ(reports.reports(1).metrics(0).count_metrics().data_size(), 1);
280 ASSERT_EQ(reports.reports(1).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
281 EXPECT_EQ(reports.reports(1).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
282 }
283
TEST_P(ConfigUpdateE2eAbTest,TestConfigTtl)284 TEST_P(ConfigUpdateE2eAbTest, TestConfigTtl) {
285 StatsdConfig config = CreateSimpleConfig();
286 config.set_ttl_in_seconds(1);
287 int64_t baseTimeNs = getElapsedRealtimeNs();
288 ConfigKey cfgKey(0, 12345);
289 sp<StatsLogProcessor> processor =
290 CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
291 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
292 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
293 EXPECT_EQ(metricsManager->getTtlEndNs(), baseTimeNs + NS_PER_SEC);
294
295 config.set_ttl_in_seconds(5);
296 processor->OnConfigUpdated(baseTimeNs + 2 * NS_PER_SEC, cfgKey, config, GetParam());
297 metricsManager = processor->mMetricsManagers.begin()->second;
298 EXPECT_EQ(metricsManager->getTtlEndNs(), baseTimeNs + 7 * NS_PER_SEC);
299
300 // Clear the data stored on disk as a result of the update.
301 vector<uint8_t> buffer;
302 processor->onDumpReport(cfgKey, baseTimeNs + 3 * NS_PER_SEC, false, true, ADB_DUMP, FAST,
303 &buffer);
304 }
305
TEST_P(ConfigUpdateE2eAbTest,TestExistingGaugePullRandomOneSample)306 TEST_P(ConfigUpdateE2eAbTest, TestExistingGaugePullRandomOneSample) {
307 StatsdConfig config;
308 config.add_default_pull_packages("AID_ROOT"); // Fake puller is registered with root.
309
310 AtomMatcher subsystemSleepMatcher =
311 CreateSimpleAtomMatcher("SubsystemSleep", util::SUBSYSTEM_SLEEP_STATE);
312 *config.add_atom_matcher() = subsystemSleepMatcher;
313
314 GaugeMetric metric = createGaugeMetric("GaugeSubsystemSleep", subsystemSleepMatcher.id(),
315 GaugeMetric::RANDOM_ONE_SAMPLE, nullopt, nullopt);
316 *metric.mutable_dimensions_in_what() =
317 CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */});
318 *config.add_gauge_metric() = metric;
319
320 ConfigKey key(123, 987);
321 uint64_t bucketStartTimeNs = getElapsedRealtimeNs();
322 uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(TEN_MINUTES) * 1000000LL;
323 sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
324 bucketStartTimeNs, bucketStartTimeNs, config, key,
325 SharedRefBase::make<FakeSubsystemSleepCallback>(), util::SUBSYSTEM_SLEEP_STATE);
326
327 uint64_t updateTimeNs = bucketStartTimeNs + 60 * NS_PER_SEC;
328 processor->OnConfigUpdated(updateTimeNs, key, config, GetParam());
329 uint64_t dumpTimeNs = bucketStartTimeNs + 90 * NS_PER_SEC;
330 ConfigMetricsReportList reports;
331 vector<uint8_t> buffer;
332 processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, NO_TIME_CONSTRAINTS, &buffer);
333 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
334 backfillDimensionPath(&reports);
335 backfillStringInReport(&reports);
336 backfillStartEndTimestamp(&reports);
337 backfillAggregatedAtoms(&reports);
338 ASSERT_EQ(reports.reports_size(), 2);
339
340 // From after the update
341 ConfigMetricsReport report = reports.reports(1);
342 ASSERT_EQ(report.metrics_size(), 1);
343 // Count screen on while screen is on. There was 1 after the update.
344 StatsLogReport metricData = report.metrics(0);
345 EXPECT_EQ(metricData.metric_id(), metric.id());
346 EXPECT_TRUE(metricData.has_gauge_metrics());
347 StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
348 sortMetricDataByDimensionsValue(metricData.gauge_metrics(), &gaugeMetrics);
349 ASSERT_EQ(gaugeMetrics.data_size(), 2);
350
351 GaugeMetricData data = metricData.gauge_metrics().data(0);
352 EXPECT_EQ(util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
353 ASSERT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
354 EXPECT_EQ(1 /* subsystem name field */,
355 data.dimensions_in_what().value_tuple().dimensions_value(0).field());
356 EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str(),
357 "subsystem_name_1");
358 ASSERT_EQ(data.bucket_info_size(), 1);
359 ASSERT_EQ(1, data.bucket_info(0).atom_size());
360 ASSERT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
361 EXPECT_EQ(updateTimeNs, data.bucket_info(0).elapsed_timestamp_nanos(0));
362 EXPECT_EQ(MillisToNano(NanoToMillis(updateTimeNs)),
363 data.bucket_info(0).start_bucket_elapsed_nanos());
364 EXPECT_EQ(MillisToNano(NanoToMillis(dumpTimeNs)),
365 data.bucket_info(0).end_bucket_elapsed_nanos());
366 EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
367 EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
368 }
369
370 #else
371 GTEST_LOG_(INFO) << "This test does nothing.\n";
372 #endif
373
374 } // namespace statsd
375 } // namespace os
376 } // namespace android
377