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