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/flags.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 vector<int32_t> uids({1000});
63 vector<int64_t> versions({1});
64 vector<String16> apps({String16("app1")});
65 vector<String16> versionStrings({String16("v1")});
66 vector<String16> installers({String16("installer1")});
67 uidMap->updateMap(1, uids, versions, versionStrings, apps, installers);
68
69 StatsdConfig config = CreateSimpleConfig();
70 config.set_version_strings_in_metric_report(true);
71 config.set_installer_in_metric_report(false);
72 int64_t baseTimeNs = getElapsedRealtimeNs();
73
74 ConfigKey cfgKey(0, 12345);
75 sp<StatsLogProcessor> processor =
76 CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey, nullptr, 0, uidMap);
77 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
78 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
79 EXPECT_TRUE(metricsManager->isConfigValid());
80
81 // Now update.
82 config.set_version_strings_in_metric_report(false);
83 config.set_installer_in_metric_report(true);
84 processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, GetParam());
85 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
86 EXPECT_EQ(metricsManager == processor->mMetricsManagers.begin()->second, GetParam());
87 EXPECT_TRUE(metricsManager->isConfigValid());
88
89 ConfigMetricsReportList reports;
90 vector<uint8_t> buffer;
91 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
92 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
93 // First report is written to disk when the update happens.
94 ASSERT_EQ(reports.reports_size(), 2);
95 UidMapping uidMapping = reports.reports(1).uid_map();
96 ASSERT_EQ(uidMapping.snapshots_size(), 1);
97 ASSERT_EQ(uidMapping.snapshots(0).package_info_size(), 1);
98 EXPECT_FALSE(uidMapping.snapshots(0).package_info(0).has_version_string());
99 EXPECT_EQ(uidMapping.snapshots(0).package_info(0).installer(), "installer1");
100 }
101
TEST_P(ConfigUpdateE2eAbTest,TestHashStrings)102 TEST_P(ConfigUpdateE2eAbTest, TestHashStrings) {
103 sp<UidMap> uidMap = new UidMap();
104 vector<int32_t> uids({1000});
105 vector<int64_t> versions({1});
106 vector<String16> apps({String16("app1")});
107 vector<String16> versionStrings({String16("v1")});
108 vector<String16> installers({String16("installer1")});
109 uidMap->updateMap(1, uids, versions, versionStrings, apps, installers);
110
111 StatsdConfig config = CreateSimpleConfig();
112 config.set_version_strings_in_metric_report(true);
113 config.set_hash_strings_in_metric_report(true);
114 int64_t baseTimeNs = getElapsedRealtimeNs();
115
116 ConfigKey cfgKey(0, 12345);
117 sp<StatsLogProcessor> processor =
118 CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey, nullptr, 0, uidMap);
119 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
120 sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
121 EXPECT_TRUE(metricsManager->isConfigValid());
122
123 // Now update.
124 config.set_hash_strings_in_metric_report(false);
125 processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, GetParam());
126 EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
127 EXPECT_EQ(metricsManager == processor->mMetricsManagers.begin()->second, GetParam());
128 EXPECT_TRUE(metricsManager->isConfigValid());
129
130 ConfigMetricsReportList reports;
131 vector<uint8_t> buffer;
132 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
133 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
134 // First report is written to disk when the update happens.
135 ASSERT_EQ(reports.reports_size(), 2);
136 UidMapping uidMapping = reports.reports(1).uid_map();
137 ASSERT_EQ(uidMapping.snapshots_size(), 1);
138 ASSERT_EQ(uidMapping.snapshots(0).package_info_size(), 1);
139 EXPECT_TRUE(uidMapping.snapshots(0).package_info(0).has_version_string());
140 EXPECT_FALSE(uidMapping.snapshots(0).package_info(0).has_version_string_hash());
141 }
142
TEST_P(ConfigUpdateE2eAbTest,TestAnnotations)143 TEST_P(ConfigUpdateE2eAbTest, TestAnnotations) {
144 StatsdConfig config = CreateSimpleConfig();
145 StatsdConfig_Annotation* annotation = config.add_annotation();
146 annotation->set_field_int64(11);
147 annotation->set_field_int32(1);
148 int64_t baseTimeNs = getElapsedRealtimeNs();
149 ConfigKey cfgKey(0, 12345);
150 sp<StatsLogProcessor> processor =
151 CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
152
153 // Now update
154 config.clear_annotation();
155 annotation = config.add_annotation();
156 annotation->set_field_int64(22);
157 annotation->set_field_int32(2);
158 processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, GetParam());
159
160 ConfigMetricsReportList reports;
161 vector<uint8_t> buffer;
162 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
163 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
164 // First report is written to disk when the update happens.
165 ASSERT_EQ(reports.reports_size(), 2);
166 ConfigMetricsReport report = reports.reports(1);
167 EXPECT_EQ(report.annotation_size(), 1);
168 EXPECT_EQ(report.annotation(0).field_int64(), 22);
169 EXPECT_EQ(report.annotation(0).field_int32(), 2);
170 }
171
TEST_P(ConfigUpdateE2eAbTest,TestPersistLocally)172 TEST_P(ConfigUpdateE2eAbTest, TestPersistLocally) {
173 StatsdConfig config = CreateSimpleConfig();
174 config.set_persist_locally(false);
175 int64_t baseTimeNs = getElapsedRealtimeNs();
176 ConfigKey cfgKey(0, 12345);
177 sp<StatsLogProcessor> processor =
178 CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
179 ConfigMetricsReportList reports;
180 vector<uint8_t> buffer;
181 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
182 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
183 ASSERT_EQ(reports.reports_size(), 1);
184 // Number of reports should still be 1 since persist_locally is false.
185 reports.Clear();
186 buffer.clear();
187 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
188 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
189 ASSERT_EQ(reports.reports_size(), 1);
190
191 // Now update.
192 config.set_persist_locally(true);
193 processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, GetParam());
194
195 // Should get 2: 1 in memory + 1 on disk. Both should be saved on disk.
196 reports.Clear();
197 buffer.clear();
198 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
199 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
200 ASSERT_EQ(reports.reports_size(), 2);
201 // Should get 3, 2 on disk + 1 in memory.
202 reports.Clear();
203 buffer.clear();
204 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
205 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
206 ASSERT_EQ(reports.reports_size(), 3);
207 string suffix = StringPrintf("%d_%lld", cfgKey.GetUid(), (long long)cfgKey.GetId());
208 StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, suffix.c_str());
209 string historySuffix =
210 StringPrintf("%d_%lld_history", cfgKey.GetUid(), (long long)cfgKey.GetId());
211 StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, historySuffix.c_str());
212 }
213
TEST_P(ConfigUpdateE2eAbTest,TestNoReportMetrics)214 TEST_P(ConfigUpdateE2eAbTest, TestNoReportMetrics) {
215 StatsdConfig config = CreateSimpleConfig();
216 // Second simple count metric.
217 CountMetric* countMetric = config.add_count_metric();
218 countMetric->set_id(StringToId("Count2"));
219 countMetric->set_what(config.atom_matcher(0).id());
220 countMetric->set_bucket(FIVE_MINUTES);
221 config.add_no_report_metric(config.count_metric(0).id());
222 int64_t baseTimeNs = getElapsedRealtimeNs();
223 ConfigKey cfgKey(0, 12345);
224 sp<StatsLogProcessor> processor =
225 CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
226
227 // Now update.
228 config.clear_no_report_metric();
229 config.add_no_report_metric(config.count_metric(1).id());
230 processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, GetParam());
231
232 ConfigMetricsReportList reports;
233 vector<uint8_t> buffer;
234 processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer);
235 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
236 // First report is written to disk when the update happens.
237 ASSERT_EQ(reports.reports_size(), 2);
238 // First report (before update) has the first count metric.
239 ASSERT_EQ(reports.reports(0).metrics_size(), 1);
240 EXPECT_EQ(reports.reports(0).metrics(0).metric_id(), config.count_metric(1).id());
241 // Second report (after update) has the first count metric.
242 ASSERT_EQ(reports.reports(1).metrics_size(), 1);
243 EXPECT_EQ(reports.reports(1).metrics(0).metric_id(), config.count_metric(0).id());
244 }
245
TEST_P(ConfigUpdateE2eAbTest,TestAtomsAllowedFromAnyUid)246 TEST_P(ConfigUpdateE2eAbTest, TestAtomsAllowedFromAnyUid) {
247 StatsdConfig config = CreateSimpleConfig();
248 int64_t baseTimeNs = getElapsedRealtimeNs();
249 ConfigKey cfgKey(0, 12345);
250 sp<StatsLogProcessor> processor =
251 CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey);
252 // Uses AID_ROOT, which isn't in allowed log sources.
253 unique_ptr<LogEvent> event = CreateBatteryStateChangedEvent(
254 baseTimeNs + 2, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB);
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_allowed_log_source("AID_ROOT");
309 config.add_default_pull_packages("AID_ROOT"); // Fake puller is registered with root.
310
311 AtomMatcher subsystemSleepMatcher =
312 CreateSimpleAtomMatcher("SubsystemSleep", util::SUBSYSTEM_SLEEP_STATE);
313 *config.add_atom_matcher() = subsystemSleepMatcher;
314
315 GaugeMetric metric = createGaugeMetric("GaugeSubsystemSleep", subsystemSleepMatcher.id(),
316 GaugeMetric::RANDOM_ONE_SAMPLE, nullopt, nullopt);
317 *metric.mutable_dimensions_in_what() =
318 CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {1 /* subsystem name */});
319 *config.add_gauge_metric() = metric;
320
321 ConfigKey key(123, 987);
322 uint64_t bucketStartTimeNs = getElapsedRealtimeNs();
323 uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(TEN_MINUTES) * 1000000LL;
324 sp<StatsLogProcessor> processor = CreateStatsLogProcessor(
325 bucketStartTimeNs, bucketStartTimeNs, config, key,
326 SharedRefBase::make<FakeSubsystemSleepCallback>(), util::SUBSYSTEM_SLEEP_STATE);
327
328 uint64_t updateTimeNs = bucketStartTimeNs + 60 * NS_PER_SEC;
329 processor->OnConfigUpdated(updateTimeNs, key, config, GetParam());
330 uint64_t dumpTimeNs = bucketStartTimeNs + 90 * NS_PER_SEC;
331 ConfigMetricsReportList reports;
332 vector<uint8_t> buffer;
333 processor->onDumpReport(key, dumpTimeNs, true, true, ADB_DUMP, NO_TIME_CONSTRAINTS, &buffer);
334 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
335 backfillDimensionPath(&reports);
336 backfillStringInReport(&reports);
337 backfillStartEndTimestamp(&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