// Copyright (C) 2017 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 #include #include #include #include #include #include "metrics/metrics_test_helper.h" #include "src/condition/ConditionTracker.h" #include "src/matchers/AtomMatchingTracker.h" #include "src/metrics/CountMetricProducer.h" #include "src/metrics/GaugeMetricProducer.h" #include "src/metrics/MetricProducer.h" #include "src/metrics/NumericValueMetricProducer.h" #include "src/metrics/parsing_utils/metrics_manager_util.h" #include "src/state/StateManager.h" #include "src/statsd_config.pb.h" #include "statsd_test_util.h" #include "statslog_statsdtest.h" using namespace testing; using android::sp; using android::os::statsd::Predicate; using std::map; using std::set; using std::unordered_map; using std::vector; #ifdef __ANDROID__ namespace android { namespace os { namespace statsd { namespace { const int kConfigId = 12345; const ConfigKey kConfigKey(0, kConfigId); const long timeBaseSec = 1000; StatsdConfig buildEventConfig(bool isRestricted) { StatsdConfig config; config.set_id(kConfigId); if (isRestricted) { config.set_restricted_metrics_delegate_package_name("delegate"); } AtomMatcher* eventMatcher = config.add_atom_matcher(); eventMatcher->set_id(StringToId("SCREEN_IS_ON")); SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); simpleAtomMatcher->set_atom_id(2 /*SCREEN_STATE_CHANGE*/); EventMetric* metric = config.add_event_metric(); metric->set_id(3); metric->set_what(StringToId("SCREEN_IS_ON")); return config; } StatsdConfig buildGoodRestrictedConfig() { return buildEventConfig(/*isRestricted*/ true); } StatsdConfig buildGoodEventConfig() { return buildEventConfig(/*isRestricted*/ false); } set unionSet(const vector> sets) { set toRet; for (const set& s : sets) { toRet.insert(s.begin(), s.end()); } return toRet; } } // anonymous namespace TEST(MetricsManagerTest, TestLogSources) { string app1 = "app1"; set app1Uids = {1111, 11111}; string app2 = "app2"; set app2Uids = {2222}; string app3 = "app3"; set app3Uids = {3333, 1111}; map> pkgToUids; pkgToUids[app1] = app1Uids; pkgToUids[app2] = app2Uids; pkgToUids[app3] = app3Uids; int32_t atom1 = 10, atom2 = 20, atom3 = 30; sp uidMap = new StrictMock(); EXPECT_CALL(*uidMap, getAppUid(_)) .Times(4) .WillRepeatedly(Invoke([&pkgToUids](const string& pkg) { const auto& it = pkgToUids.find(pkg); if (it != pkgToUids.end()) { return it->second; } return set(); })); sp pullerManager = new StrictMock(); EXPECT_CALL(*pullerManager, RegisterPullUidProvider(kConfigKey, _)).Times(1); EXPECT_CALL(*pullerManager, UnregisterPullUidProvider(kConfigKey, _)).Times(1); sp anomalyAlarmMonitor; sp periodicAlarmMonitor; StatsdConfig config; config.add_allowed_log_source("AID_SYSTEM"); config.add_allowed_log_source(app1); config.add_default_pull_packages("AID_SYSTEM"); config.add_default_pull_packages("AID_ROOT"); const set defaultPullUids = {AID_SYSTEM, AID_ROOT}; PullAtomPackages* pullAtomPackages = config.add_pull_atom_packages(); pullAtomPackages->set_atom_id(atom1); pullAtomPackages->add_packages(app1); pullAtomPackages->add_packages(app3); pullAtomPackages = config.add_pull_atom_packages(); pullAtomPackages->set_atom_id(atom2); pullAtomPackages->add_packages(app2); pullAtomPackages->add_packages("AID_STATSD"); MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor); EXPECT_TRUE(metricsManager.isConfigValid()); EXPECT_THAT(metricsManager.mAllowedUid, ElementsAre(AID_SYSTEM)); EXPECT_THAT(metricsManager.mAllowedPkg, ElementsAre(app1)); EXPECT_THAT(metricsManager.mAllowedLogSources, ContainerEq(unionSet(vector>({app1Uids, {AID_SYSTEM}})))); EXPECT_THAT(metricsManager.mDefaultPullUids, ContainerEq(defaultPullUids)); vector atom1Uids = metricsManager.getPullAtomUids(atom1); EXPECT_THAT(atom1Uids, UnorderedElementsAreArray(unionSet({defaultPullUids, app1Uids, app3Uids}))); vector atom2Uids = metricsManager.getPullAtomUids(atom2); EXPECT_THAT(atom2Uids, UnorderedElementsAreArray(unionSet({defaultPullUids, app2Uids, {AID_STATSD}}))); vector atom3Uids = metricsManager.getPullAtomUids(atom3); EXPECT_THAT(atom3Uids, UnorderedElementsAreArray(defaultPullUids)); } TEST(MetricsManagerTest, TestLogSourcesOnConfigUpdate) { string app1 = "app1"; set app1Uids = {11110, 11111}; string app2 = "app2"; set app2Uids = {22220}; string app3 = "app3"; set app3Uids = {33330, 11110}; map> pkgToUids; pkgToUids[app1] = app1Uids; pkgToUids[app2] = app2Uids; pkgToUids[app3] = app3Uids; int32_t atom1 = 10, atom2 = 20, atom3 = 30; sp uidMap = new StrictMock(); EXPECT_CALL(*uidMap, getAppUid(_)) .Times(8) .WillRepeatedly(Invoke([&pkgToUids](const string& pkg) { const auto& it = pkgToUids.find(pkg); if (it != pkgToUids.end()) { return it->second; } return set(); })); sp pullerManager = new StrictMock(); EXPECT_CALL(*pullerManager, RegisterPullUidProvider(kConfigKey, _)).Times(1); EXPECT_CALL(*pullerManager, UnregisterPullUidProvider(kConfigKey, _)).Times(1); sp anomalyAlarmMonitor; sp periodicAlarmMonitor; StatsdConfig config; config.add_allowed_log_source(app1); config.add_default_pull_packages("AID_SYSTEM"); config.add_default_pull_packages("AID_ROOT"); PullAtomPackages* pullAtomPackages = config.add_pull_atom_packages(); pullAtomPackages->set_atom_id(atom1); pullAtomPackages->add_packages(app1); pullAtomPackages->add_packages(app3); pullAtomPackages = config.add_pull_atom_packages(); pullAtomPackages->set_atom_id(atom2); pullAtomPackages->add_packages(app2); pullAtomPackages->add_packages("AID_STATSD"); MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor); EXPECT_TRUE(metricsManager.isConfigValid()); // Update with new allowed log sources. StatsdConfig newConfig; newConfig.add_allowed_log_source(app2); newConfig.add_default_pull_packages("AID_SYSTEM"); newConfig.add_default_pull_packages("AID_STATSD"); pullAtomPackages = newConfig.add_pull_atom_packages(); pullAtomPackages->set_atom_id(atom2); pullAtomPackages->add_packages(app1); pullAtomPackages->add_packages(app3); pullAtomPackages = newConfig.add_pull_atom_packages(); pullAtomPackages->set_atom_id(atom3); pullAtomPackages->add_packages(app2); pullAtomPackages->add_packages("AID_ADB"); metricsManager.updateConfig(newConfig, timeBaseSec, timeBaseSec, anomalyAlarmMonitor, periodicAlarmMonitor); EXPECT_TRUE(metricsManager.isConfigValid()); EXPECT_THAT(metricsManager.mAllowedPkg, ElementsAre(app2)); EXPECT_THAT(metricsManager.mAllowedLogSources, ContainerEq(unionSet(vector>({app2Uids})))); const set defaultPullUids = {AID_SYSTEM, AID_STATSD}; EXPECT_THAT(metricsManager.mDefaultPullUids, ContainerEq(defaultPullUids)); vector atom1Uids = metricsManager.getPullAtomUids(atom1); EXPECT_THAT(atom1Uids, UnorderedElementsAreArray(defaultPullUids)); vector atom2Uids = metricsManager.getPullAtomUids(atom2); EXPECT_THAT(atom2Uids, UnorderedElementsAreArray(unionSet({defaultPullUids, app1Uids, app3Uids}))); vector atom3Uids = metricsManager.getPullAtomUids(atom3); EXPECT_THAT(atom3Uids, UnorderedElementsAreArray(unionSet({defaultPullUids, app2Uids, {AID_ADB}}))); } struct MetricsManagerServerFlagParam { string flagValue; string label; }; class MetricsManagerTest_SPlus : public ::testing::Test, public ::testing::WithParamInterface { protected: void SetUp() override { if (shouldSkipTest()) { GTEST_SKIP() << skipReason(); } } bool shouldSkipTest() const { return !isAtLeastS(); } string skipReason() const { return "Skipping MetricsManagerTest_SPlus because device is not S+"; } std::optional originalFlagValue; }; INSTANTIATE_TEST_SUITE_P( MetricsManagerTest_SPlus, MetricsManagerTest_SPlus, testing::ValuesIn({ // Server flag values {FLAG_TRUE, "ServerFlagTrue"}, {FLAG_FALSE, "ServerFlagFalse"}, }), [](const testing::TestParamInfo& info) { return info.param.label; }); TEST(MetricsManagerTest, TestCheckLogCredentialsWhitelistedAtom) { sp uidMap; sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp periodicAlarmMonitor; StatsdConfig config; config.add_whitelisted_atom_ids(3); config.add_whitelisted_atom_ids(4); MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor); const int32_t customAppUid = AID_APP_START + 1; LogEvent event(customAppUid /* uid */, 0 /* pid */); CreateNoValuesLogEvent(&event, 10 /* atom id */, 0 /* timestamp */); EXPECT_FALSE(metricsManager.checkLogCredentials(event)); CreateNoValuesLogEvent(&event, 3 /* atom id */, 0 /* timestamp */); EXPECT_TRUE(metricsManager.checkLogCredentials(event)); CreateNoValuesLogEvent(&event, 4 /* atom id */, 0 /* timestamp */); EXPECT_TRUE(metricsManager.checkLogCredentials(event)); } TEST(MetricsManagerTest, TestWhitelistedAtomStateTracker) { sp uidMap; sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp periodicAlarmMonitor; StatsdConfig config = buildGoodConfig(kConfigId); config.add_allowed_log_source("AID_SYSTEM"); config.add_whitelisted_atom_ids(3); config.add_whitelisted_atom_ids(4); State state; state.set_id(1); state.set_atom_id(3); *config.add_state() = state; config.mutable_count_metric(0)->add_slice_by_state(state.id()); StateManager::getInstance().clear(); MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor); EXPECT_EQ(0, StateManager::getInstance().getStateTrackersCount()); EXPECT_FALSE(metricsManager.isConfigValid()); } TEST_P(MetricsManagerTest_SPlus, TestRestrictedMetricsConfig) { sp uidMap; sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp periodicAlarmMonitor; StatsdConfig config = buildGoodRestrictedConfig(); config.add_allowed_log_source("AID_SYSTEM"); config.set_restricted_metrics_delegate_package_name("rm"); MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor); if (isAtLeastU()) { EXPECT_TRUE(metricsManager.isConfigValid()); } else { EXPECT_EQ(metricsManager.mInvalidConfigReason, INVALID_CONFIG_REASON_RESTRICTED_METRIC_NOT_ENABLED); ASSERT_FALSE(metricsManager.isConfigValid()); } } TEST_P(MetricsManagerTest_SPlus, TestRestrictedMetricsConfigUpdate) { sp uidMap; sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp periodicAlarmMonitor; StatsdConfig config = buildGoodRestrictedConfig(); config.add_allowed_log_source("AID_SYSTEM"); config.set_restricted_metrics_delegate_package_name("rm"); MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor); StatsdConfig config2 = buildGoodRestrictedConfig(); metricsManager.updateConfig(config, timeBaseSec, timeBaseSec, anomalyAlarmMonitor, periodicAlarmMonitor); if (isAtLeastU()) { EXPECT_TRUE(metricsManager.isConfigValid()); } else { EXPECT_EQ(metricsManager.mInvalidConfigReason, INVALID_CONFIG_REASON_RESTRICTED_METRIC_NOT_ENABLED); ASSERT_FALSE(metricsManager.isConfigValid()); } } TEST(MetricsManagerTest, TestMaxMetricsMemoryKb) { sp uidMap; sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp periodicAlarmMonitor; size_t memoryLimitKb = 8 * 1024; StatsdConfig config = buildGoodConfig(kConfigId); config.add_allowed_log_source("AID_SYSTEM"); config.set_max_metrics_memory_kb(memoryLimitKb); MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor); EXPECT_EQ(memoryLimitKb, metricsManager.getMaxMetricsBytes() / 1024); EXPECT_TRUE(metricsManager.isConfigValid()); } TEST(MetricsManagerTest, TestMaxMetricsMemoryKbOnConfigUpdate) { sp uidMap; sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp periodicAlarmMonitor; size_t memoryLimitKb = 8 * 1024; StatsdConfig config = buildGoodConfig(kConfigId); config.add_allowed_log_source("AID_SYSTEM"); config.set_max_metrics_memory_kb(memoryLimitKb); MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor); EXPECT_EQ(memoryLimitKb, metricsManager.getMaxMetricsBytes() / 1024); EXPECT_TRUE(metricsManager.isConfigValid()); // Update with new memory limit size_t newMemoryLimitKb = 10 * 1024; StatsdConfig newConfig; newConfig.add_allowed_log_source("AID_SYSTEM"); newConfig.set_max_metrics_memory_kb(newMemoryLimitKb); metricsManager.updateConfig(newConfig, timeBaseSec, timeBaseSec, anomalyAlarmMonitor, periodicAlarmMonitor); EXPECT_EQ(newMemoryLimitKb, metricsManager.getMaxMetricsBytes() / 1024); EXPECT_TRUE(metricsManager.isConfigValid()); } TEST(MetricsManagerTest, TestMaxMetricsMemoryKbInvalid) { sp uidMap; sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp periodicAlarmMonitor; size_t memoryLimitKb = (StatsdStats::kHardMaxMetricsBytesPerConfig / 1024) + 1; size_t defaultMemoryLimit = StatsdStats::kDefaultMaxMetricsBytesPerConfig; StatsdConfig config = buildGoodConfig(kConfigId); config.add_allowed_log_source("AID_SYSTEM"); config.set_max_metrics_memory_kb(memoryLimitKb); MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor); // Since 20MB + 1B is invalid for the memory limit, we default back to 2MB EXPECT_EQ(defaultMemoryLimit, metricsManager.getMaxMetricsBytes()); EXPECT_TRUE(metricsManager.isConfigValid()); } TEST(MetricsManagerTest, TestGetTriggerMemoryKb) { sp uidMap; sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp periodicAlarmMonitor; size_t memoryLimitKb = 8 * 1024; StatsdConfig config = buildGoodConfig(kConfigId); config.add_allowed_log_source("AID_SYSTEM"); config.set_soft_metrics_memory_kb(memoryLimitKb); MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor); EXPECT_EQ(memoryLimitKb, metricsManager.getTriggerGetDataBytes() / 1024); EXPECT_TRUE(metricsManager.isConfigValid()); } TEST(MetricsManagerTest, TestGetTriggerMemoryKbOnConfigUpdate) { sp uidMap; sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp periodicAlarmMonitor; size_t memoryLimitKb = 8 * 1024; StatsdConfig config = buildGoodConfig(kConfigId); config.add_allowed_log_source("AID_SYSTEM"); config.set_soft_metrics_memory_kb(memoryLimitKb); MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor); EXPECT_EQ(memoryLimitKb, metricsManager.getTriggerGetDataBytes() / 1024); EXPECT_TRUE(metricsManager.isConfigValid()); // Update with new memory limit size_t newMemoryLimitKb = 9 * 1024; StatsdConfig newConfig; newConfig.add_allowed_log_source("AID_SYSTEM"); newConfig.set_soft_metrics_memory_kb(newMemoryLimitKb); metricsManager.updateConfig(newConfig, timeBaseSec, timeBaseSec, anomalyAlarmMonitor, periodicAlarmMonitor); EXPECT_EQ(newMemoryLimitKb, metricsManager.getTriggerGetDataBytes() / 1024); EXPECT_TRUE(metricsManager.isConfigValid()); } TEST(MetricsManagerTest, TestGetTriggerMemoryKbInvalid) { sp uidMap; sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp periodicAlarmMonitor; size_t memoryLimitKb = (StatsdStats::kHardMaxTriggerGetDataBytes / 1024) + 1; size_t defaultMemoryLimit = StatsdStats::kDefaultBytesPerConfigTriggerGetData; StatsdConfig config = buildGoodConfig(kConfigId); config.add_allowed_log_source("AID_SYSTEM"); config.set_soft_metrics_memory_kb(memoryLimitKb); MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor); // Since 10MB + 1B is invalid for the memory limit, we default back to 192KB EXPECT_EQ(defaultMemoryLimit, metricsManager.getTriggerGetDataBytes()); EXPECT_TRUE(metricsManager.isConfigValid()); } TEST(MetricsManagerTest, TestGetTriggerMemoryKbUnset) { sp uidMap; sp pullerManager = new StatsPullerManager(); sp anomalyAlarmMonitor; sp periodicAlarmMonitor; size_t defaultMemoryLimit = StatsdStats::kDefaultBytesPerConfigTriggerGetData; StatsdConfig config = buildGoodConfig(kConfigId); config.add_allowed_log_source("AID_SYSTEM"); MetricsManager metricsManager(kConfigKey, config, timeBaseSec, timeBaseSec, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor); // Since the memory limit is unset, we default back to 192KB EXPECT_EQ(defaultMemoryLimit, metricsManager.getTriggerGetDataBytes()); EXPECT_TRUE(metricsManager.isConfigValid()); } } // namespace statsd } // namespace os } // namespace android #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif