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