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