diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 012450d732664..d225f966c39d3 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -294,6 +294,7 @@ cc_test { "tests/e2e/Anomaly_duration_sum_e2e_test.cpp", "tests/e2e/Attribution_e2e_test.cpp", "tests/e2e/ConfigTtl_e2e_test.cpp", + "tests/e2e/ConfigUpdate_e2e_test.cpp", "tests/e2e/CountMetric_e2e_test.cpp", "tests/e2e/DurationMetric_e2e_test.cpp", "tests/e2e/GaugeMetric_e2e_pull_test.cpp", diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index 7bee4e2d1a368..ae1ef21e553cb 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -520,10 +520,10 @@ void StatsLogProcessor::GetActiveConfigsLocked(const int uid, vector& o } void StatsLogProcessor::OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key, - const StatsdConfig& config) { + const StatsdConfig& config, bool modularUpdate) { std::lock_guard lock(mMetricsMutex); WriteDataToDiskLocked(key, timestampNs, CONFIG_UPDATED, NO_TIME_CONSTRAINTS); - OnConfigUpdatedLocked(timestampNs, key, config); + OnConfigUpdatedLocked(timestampNs, key, config, modularUpdate); } void StatsLogProcessor::OnConfigUpdatedLocked(const int64_t timestampNs, const ConfigKey& key, @@ -720,7 +720,8 @@ void StatsLogProcessor::resetConfigsLocked(const int64_t timestampNs, for (const auto& key : configs) { StatsdConfig config; if (StorageManager::readConfigFromDisk(key, &config)) { - OnConfigUpdatedLocked(timestampNs, key, config); + // Force a full update when resetting a config. + OnConfigUpdatedLocked(timestampNs, key, config, /*modularUpdate=*/false); StatsdStats::getInstance().noteConfigReset(key); } else { ALOGE("Failed to read backup config from disk for : %s", key.ToString().c_str()); diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 383dbd9db2c18..2af277ad1e5b9 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -48,7 +48,7 @@ public: void OnLogEvent(LogEvent* event); void OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key, - const StatsdConfig& config); + const StatsdConfig& config, bool modularUpdate = false); void OnConfigRemoved(const ConfigKey& key); size_t GetMetricsSize(const ConfigKey& key) const; @@ -188,7 +188,7 @@ private: void resetIfConfigTtlExpiredLocked(const int64_t timestampNs); void OnConfigUpdatedLocked(const int64_t currentTimestampNs, const ConfigKey& key, - const StatsdConfig& config, bool modularUpdate = false); + const StatsdConfig& config, bool modularUpdate); void GetActiveConfigsLocked(const int uid, vector& outActiveConfigs); @@ -338,6 +338,10 @@ private: FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation); FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations); + FRIEND_TEST(ConfigUpdateE2eTest, TestHashStrings); + FRIEND_TEST(ConfigUpdateE2eTest, TestUidMapVersionStringInstaller); + FRIEND_TEST(ConfigUpdateE2eTest, TestConfigTtl); + FRIEND_TEST(CountMetricE2eTest, TestInitialConditionChanges); FRIEND_TEST(CountMetricE2eTest, TestSlicedState); FRIEND_TEST(CountMetricE2eTest, TestSlicedStateWithMap); diff --git a/cmds/statsd/src/config/ConfigListener.h b/cmds/statsd/src/config/ConfigListener.h index dcd5e52feefd5..3d301379f3590 100644 --- a/cmds/statsd/src/config/ConfigListener.h +++ b/cmds/statsd/src/config/ConfigListener.h @@ -39,7 +39,7 @@ public: * A configuration was added or updated. */ virtual void OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key, - const StatsdConfig& config) = 0; + const StatsdConfig& config, bool modularUpdate = false) = 0; /** * A configuration was removed. diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index acc12aa884aae..3b6e10b030fb9 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -188,6 +188,23 @@ bool MetricsManager::updateConfig(const StatsdConfig& config, const int64_t time mAlertTrackerMap = newAlertTrackerMap; mAllPeriodicAlarmTrackers = newPeriodicAlarmTrackers; + mTtlNs = config.has_ttl_in_seconds() ? config.ttl_in_seconds() * NS_PER_SEC : -1; + refreshTtl(currentTimeNs); + + mHashStringsInReport = config.hash_strings_in_metric_report(); + mVersionStringsInReport = config.version_strings_in_metric_report(); + mInstallerInReport = config.installer_in_metric_report(); + mWhitelistedAtomIds.clear(); + mWhitelistedAtomIds.insert(config.whitelisted_atom_ids().begin(), + config.whitelisted_atom_ids().end()); + mShouldPersistHistory = config.persist_locally(); + + // Store the sub-configs used. + mAnnotations.clear(); + for (const auto& annotation : config.annotation()) { + mAnnotations.emplace_back(annotation.field_int64(), annotation.field_int32()); + } + mAllowedUid.clear(); mAllowedPkg.clear(); mDefaultPullUids.clear(); diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index 23048ae2d40a8..98d4bff1cd76a 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -172,7 +172,7 @@ private: bool mVersionStringsInReport = false; bool mInstallerInReport = false; - const int64_t mTtlNs; + int64_t mTtlNs; int64_t mTtlEndNs; int64_t mLastReportTimeNs; @@ -193,7 +193,7 @@ private: // To guard access to mAllowedLogSources mutable std::mutex mAllowedLogSourcesMutex; - const std::set mWhitelistedAtomIds; + std::set mWhitelistedAtomIds; // We can pull any atom from these uids. std::set mDefaultPullUids; @@ -211,8 +211,7 @@ private: // Contains the annotations passed in with StatsdConfig. std::list> mAnnotations; - const bool mShouldPersistHistory; - + bool mShouldPersistHistory; // All event tags that are interesting to my metrics. std::set mTagIds; @@ -327,6 +326,7 @@ private: FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms); FRIEND_TEST(ConfigTtlE2eTest, TestCountMetric); + FRIEND_TEST(ConfigUpdateE2eTest, TestConfigTtl); FRIEND_TEST(MetricActivationE2eTest, TestCountMetric); FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation); FRIEND_TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations); diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp index 637236145bf5a..af9606bc15f93 100644 --- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp +++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp @@ -869,6 +869,14 @@ bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64 newMetricProducers.push_back(producer.value()); } + for (int i = 0; i < config.no_report_metric_size(); ++i) { + const int64_t noReportMetric = config.no_report_metric(i); + if (newMetricProducerMap.find(noReportMetric) == newMetricProducerMap.end()) { + ALOGW("no_report_metric %" PRId64 " not exist", noReportMetric); + return false; + } + noReportMetricIds.insert(noReportMetric); + } const set atomsAllowedFromAnyUid(config.whitelisted_atom_ids().begin(), config.whitelisted_atom_ids().end()); for (int i = 0; i < allMetricsCount; i++) { diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp index 9455304a1af6a..1d8371638e908 100644 --- a/cmds/statsd/tests/ConfigManager_test.cpp +++ b/cmds/statsd/tests/ConfigManager_test.cpp @@ -44,8 +44,8 @@ static ostream& operator<<(ostream& os, const StatsdConfig& config) { */ class MockListener : public ConfigListener { public: - MOCK_METHOD3(OnConfigUpdated, void(const int64_t timestampNs, const ConfigKey& key, - const StatsdConfig& config)); + MOCK_METHOD4(OnConfigUpdated, void(const int64_t timestampNs, const ConfigKey& key, + const StatsdConfig& config, bool modularUpdate)); MOCK_METHOD1(OnConfigRemoved, void(const ConfigKey& key)); }; @@ -89,26 +89,26 @@ TEST(ConfigManagerTest, TestAddUpdateRemove) { manager->StartupForTest(); // Add another one - EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")), - StatsdConfigEq(91))) + EXPECT_CALL(*(listener.get()), + OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")), StatsdConfigEq(91), _)) .RetiresOnSaturation(); manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config91); // Update It - EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")), - StatsdConfigEq(92))) + EXPECT_CALL(*(listener.get()), + OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")), StatsdConfigEq(92), _)) .RetiresOnSaturation(); manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config92); // Add one with the same uid but a different name - EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(1, StringToId("yyy")), - StatsdConfigEq(93))) + EXPECT_CALL(*(listener.get()), + OnConfigUpdated(_, ConfigKeyEq(1, StringToId("yyy")), StatsdConfigEq(93), _)) .RetiresOnSaturation(); manager->UpdateConfig(ConfigKey(1, StringToId("yyy")), config93); // Add one with the same name but a different uid - EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(2, StringToId("zzz")), - StatsdConfigEq(94))) + EXPECT_CALL(*(listener.get()), + OnConfigUpdated(_, ConfigKeyEq(2, StringToId("zzz")), StatsdConfigEq(94), _)) .RetiresOnSaturation(); manager->UpdateConfig(ConfigKey(2, StringToId("zzz")), config94); @@ -143,7 +143,7 @@ TEST(ConfigManagerTest, TestRemoveUid) { StatsdConfig config; - EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _, _)).Times(5); + EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _, _, _)).Times(5); EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("xxx")))); EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("yyy")))); EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("zzz")))); diff --git a/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp new file mode 100644 index 0000000000000..e01a0b63a0ca4 --- /dev/null +++ b/cmds/statsd/tests/e2e/ConfigUpdate_e2e_test.cpp @@ -0,0 +1,307 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include // std::this_thread::sleep_for + +#include "android-base/stringprintf.h" +#include "src/StatsLogProcessor.h" +#include "src/storage/StorageManager.h" +#include "tests/statsd_test_util.h" + +namespace android { +namespace os { +namespace statsd { + +#ifdef __ANDROID__ +#define STATS_DATA_DIR "/data/misc/stats-data" +using android::base::StringPrintf; + +namespace { + +StatsdConfig CreateSimpleConfig() { + StatsdConfig config; + config.add_allowed_log_source("AID_STATSD"); + config.set_hash_strings_in_metric_report(false); + + *config.add_atom_matcher() = CreateBatteryStateUsbMatcher(); + // Simple count metric so the config isn't empty. + CountMetric* countMetric1 = config.add_count_metric(); + countMetric1->set_id(StringToId("Count1")); + countMetric1->set_what(config.atom_matcher(0).id()); + countMetric1->set_bucket(FIVE_MINUTES); + return config; +} +} // namespace + +// Setup for parameterized tests. +class ConfigUpdateE2eTest : public TestWithParam {}; + +INSTANTIATE_TEST_SUITE_P(ConfigUpdateE2eTest, ConfigUpdateE2eTest, testing::Bool()); + +TEST_P(ConfigUpdateE2eTest, TestUidMapVersionStringInstaller) { + sp uidMap = new UidMap(); + vector uids({1000}); + vector versions({1}); + vector apps({String16("app1")}); + vector versionStrings({String16("v1")}); + vector installers({String16("installer1")}); + uidMap->updateMap(1, uids, versions, versionStrings, apps, installers); + + StatsdConfig config = CreateSimpleConfig(); + config.set_version_strings_in_metric_report(true); + config.set_installer_in_metric_report(false); + int64_t baseTimeNs = getElapsedRealtimeNs(); + + ConfigKey cfgKey(0, 12345); + sp processor = + CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey, nullptr, 0, uidMap); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + sp metricsManager = processor->mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + + // Now update. + config.set_version_strings_in_metric_report(false); + config.set_installer_in_metric_report(true); + processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam()); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_EQ(metricsManager == processor->mMetricsManagers.begin()->second, GetParam()); + EXPECT_TRUE(metricsManager->isConfigValid()); + + ConfigMetricsReportList reports; + vector buffer; + processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + // First report is written to disk when the update happens. + ASSERT_EQ(reports.reports_size(), 2); + UidMapping uidMapping = reports.reports(1).uid_map(); + ASSERT_EQ(uidMapping.snapshots_size(), 1); + ASSERT_EQ(uidMapping.snapshots(0).package_info_size(), 1); + EXPECT_FALSE(uidMapping.snapshots(0).package_info(0).has_version_string()); + EXPECT_EQ(uidMapping.snapshots(0).package_info(0).installer(), "installer1"); +} + +TEST_P(ConfigUpdateE2eTest, TestHashStrings) { + sp uidMap = new UidMap(); + vector uids({1000}); + vector versions({1}); + vector apps({String16("app1")}); + vector versionStrings({String16("v1")}); + vector installers({String16("installer1")}); + uidMap->updateMap(1, uids, versions, versionStrings, apps, installers); + + StatsdConfig config = CreateSimpleConfig(); + config.set_version_strings_in_metric_report(true); + config.set_hash_strings_in_metric_report(true); + int64_t baseTimeNs = getElapsedRealtimeNs(); + + ConfigKey cfgKey(0, 12345); + sp processor = + CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey, nullptr, 0, uidMap); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + sp metricsManager = processor->mMetricsManagers.begin()->second; + EXPECT_TRUE(metricsManager->isConfigValid()); + + // Now update. + config.set_hash_strings_in_metric_report(false); + processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam()); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + EXPECT_EQ(metricsManager == processor->mMetricsManagers.begin()->second, GetParam()); + EXPECT_TRUE(metricsManager->isConfigValid()); + + ConfigMetricsReportList reports; + vector buffer; + processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + // First report is written to disk when the update happens. + ASSERT_EQ(reports.reports_size(), 2); + UidMapping uidMapping = reports.reports(1).uid_map(); + ASSERT_EQ(uidMapping.snapshots_size(), 1); + ASSERT_EQ(uidMapping.snapshots(0).package_info_size(), 1); + EXPECT_TRUE(uidMapping.snapshots(0).package_info(0).has_version_string()); + EXPECT_FALSE(uidMapping.snapshots(0).package_info(0).has_version_string_hash()); +} + +TEST_P(ConfigUpdateE2eTest, TestAnnotations) { + StatsdConfig config = CreateSimpleConfig(); + StatsdConfig_Annotation* annotation = config.add_annotation(); + annotation->set_field_int64(11); + annotation->set_field_int32(1); + int64_t baseTimeNs = getElapsedRealtimeNs(); + ConfigKey cfgKey(0, 12345); + sp processor = + CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey); + + // Now update + config.clear_annotation(); + annotation = config.add_annotation(); + annotation->set_field_int64(22); + annotation->set_field_int32(2); + processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam()); + + ConfigMetricsReportList reports; + vector buffer; + processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + // First report is written to disk when the update happens. + ASSERT_EQ(reports.reports_size(), 2); + ConfigMetricsReport report = reports.reports(1); + EXPECT_EQ(report.annotation_size(), 1); + EXPECT_EQ(report.annotation(0).field_int64(), 22); + EXPECT_EQ(report.annotation(0).field_int32(), 2); +} + +TEST_P(ConfigUpdateE2eTest, TestPersistLocally) { + StatsdConfig config = CreateSimpleConfig(); + config.set_persist_locally(false); + int64_t baseTimeNs = getElapsedRealtimeNs(); + ConfigKey cfgKey(0, 12345); + sp processor = + CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey); + ConfigMetricsReportList reports; + vector buffer; + processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + ASSERT_EQ(reports.reports_size(), 1); + // Number of reports should still be 1 since persist_locally is false. + reports.Clear(); + buffer.clear(); + processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + ASSERT_EQ(reports.reports_size(), 1); + + // Now update. + config.set_persist_locally(true); + processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam()); + + // Should get 2: 1 in memory + 1 on disk. Both should be saved on disk. + reports.Clear(); + buffer.clear(); + processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + ASSERT_EQ(reports.reports_size(), 2); + // Should get 3, 2 on disk + 1 in memory. + reports.Clear(); + buffer.clear(); + processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + ASSERT_EQ(reports.reports_size(), 3); + string suffix = StringPrintf("%d_%lld", cfgKey.GetUid(), (long long)cfgKey.GetId()); + StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, suffix.c_str()); + string historySuffix = + StringPrintf("%d_%lld_history", cfgKey.GetUid(), (long long)cfgKey.GetId()); + StorageManager::deleteSuffixedFiles(STATS_DATA_DIR, historySuffix.c_str()); +} + +TEST_P(ConfigUpdateE2eTest, TestNoReportMetrics) { + StatsdConfig config = CreateSimpleConfig(); + // Second simple count metric. + CountMetric* countMetric = config.add_count_metric(); + countMetric->set_id(StringToId("Count2")); + countMetric->set_what(config.atom_matcher(0).id()); + countMetric->set_bucket(FIVE_MINUTES); + config.add_no_report_metric(config.count_metric(0).id()); + int64_t baseTimeNs = getElapsedRealtimeNs(); + ConfigKey cfgKey(0, 12345); + sp processor = + CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey); + + // Now update. + config.clear_no_report_metric(); + config.add_no_report_metric(config.count_metric(1).id()); + processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam()); + + ConfigMetricsReportList reports; + vector buffer; + processor->onDumpReport(cfgKey, baseTimeNs + 1001, false, true, ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + // First report is written to disk when the update happens. + ASSERT_EQ(reports.reports_size(), 2); + // First report (before update) has the first count metric. + ASSERT_EQ(reports.reports(0).metrics_size(), 1); + EXPECT_EQ(reports.reports(0).metrics(0).metric_id(), config.count_metric(1).id()); + // Second report (after update) has the first count metric. + ASSERT_EQ(reports.reports(1).metrics_size(), 1); + EXPECT_EQ(reports.reports(1).metrics(0).metric_id(), config.count_metric(0).id()); +} + +TEST_P(ConfigUpdateE2eTest, TestAtomsAllowedFromAnyUid) { + StatsdConfig config = CreateSimpleConfig(); + int64_t baseTimeNs = getElapsedRealtimeNs(); + ConfigKey cfgKey(0, 12345); + sp processor = + CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey); + // Uses AID_ROOT, which isn't in allowed log sources. + unique_ptr event = CreateBatteryStateChangedEvent( + baseTimeNs + 2, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB); + processor->OnLogEvent(event.get()); + ConfigMetricsReportList reports; + vector buffer; + processor->onDumpReport(cfgKey, baseTimeNs + 1001, true, true, ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + ASSERT_EQ(reports.reports_size(), 1); + // Check the metric and make sure it has 0 count. + ASSERT_EQ(reports.reports(0).metrics_size(), 1); + EXPECT_FALSE(reports.reports(0).metrics(0).has_count_metrics()); + + // Now update. Allow plugged state to be logged from any uid, so the atom will be counted. + config.add_whitelisted_atom_ids(util::PLUGGED_STATE_CHANGED); + processor->OnConfigUpdated(baseTimeNs + 1000, cfgKey, config, /*modularUpdate=*/GetParam()); + unique_ptr event2 = CreateBatteryStateChangedEvent( + baseTimeNs + 2000, BatteryPluggedStateEnum::BATTERY_PLUGGED_USB); + processor->OnLogEvent(event.get()); + reports.Clear(); + buffer.clear(); + processor->onDumpReport(cfgKey, baseTimeNs + 3000, true, true, ADB_DUMP, FAST, &buffer); + EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size())); + ASSERT_EQ(reports.reports_size(), 2); + // Check the metric and make sure it has 0 count. + ASSERT_EQ(reports.reports(1).metrics_size(), 1); + EXPECT_TRUE(reports.reports(1).metrics(0).has_count_metrics()); + ASSERT_EQ(reports.reports(1).metrics(0).count_metrics().data_size(), 1); + ASSERT_EQ(reports.reports(1).metrics(0).count_metrics().data(0).bucket_info_size(), 1); + EXPECT_EQ(reports.reports(1).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1); +} + +TEST_P(ConfigUpdateE2eTest, TestConfigTtl) { + StatsdConfig config = CreateSimpleConfig(); + config.set_ttl_in_seconds(1); + int64_t baseTimeNs = getElapsedRealtimeNs(); + ConfigKey cfgKey(0, 12345); + sp processor = + CreateStatsLogProcessor(baseTimeNs, baseTimeNs, config, cfgKey); + EXPECT_EQ(processor->mMetricsManagers.size(), 1u); + sp metricsManager = processor->mMetricsManagers.begin()->second; + EXPECT_EQ(metricsManager->getTtlEndNs(), baseTimeNs + NS_PER_SEC); + + config.set_ttl_in_seconds(5); + processor->OnConfigUpdated(baseTimeNs + 2 * NS_PER_SEC, cfgKey, config, + /*modularUpdate=*/GetParam()); + metricsManager = processor->mMetricsManagers.begin()->second; + EXPECT_EQ(metricsManager->getTtlEndNs(), baseTimeNs + 7 * NS_PER_SEC); + + // Clear the data stored on disk as a result of the update. + vector buffer; + processor->onDumpReport(cfgKey, baseTimeNs + 3 * NS_PER_SEC, false, true, ADB_DUMP, FAST, + &buffer); +} + +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif + +} // namespace statsd +} // namespace os +} // namespace android