diff options
Diffstat (limited to 'cmds/statsd/src/config/ConfigManager.cpp')
-rw-r--r-- | cmds/statsd/src/config/ConfigManager.cpp | 523 |
1 files changed, 523 insertions, 0 deletions
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp new file mode 100644 index 000000000000..06ff603f083f --- /dev/null +++ b/cmds/statsd/src/config/ConfigManager.cpp @@ -0,0 +1,523 @@ +/* + * 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 "config/ConfigManager.h" +#include "storage/StorageManager.h" + +#include "stats_util.h" + +#include <android-base/file.h> +#include <dirent.h> +#include <stdio.h> +#include <vector> +#include "android-base/stringprintf.h" + +namespace android { +namespace os { +namespace statsd { + +using std::map; +using std::pair; +using std::set; +using std::string; +using std::vector; + +#define STATS_SERVICE_DIR "/data/misc/stats-service" + +using android::base::StringPrintf; +using std::unique_ptr; + +ConfigManager::ConfigManager() { +} + +ConfigManager::~ConfigManager() { +} + +void ConfigManager::Startup() { + map<ConfigKey, StatsdConfig> configsFromDisk; + StorageManager::readConfigFromDisk(configsFromDisk); + for (const auto& pair : configsFromDisk) { + UpdateConfig(pair.first, pair.second); + } +} + +void ConfigManager::StartupForTest() { + // Dummy function to avoid reading configs from disks for tests. +} + +void ConfigManager::AddListener(const sp<ConfigListener>& listener) { + mListeners.push_back(listener); +} + +void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& config) { + // Add to set + mConfigs.insert(key); + + // Save to disk + update_saved_configs(key, config); + + // Tell everyone + for (auto& listener : mListeners) { + listener->OnConfigUpdated(key, config); + } +} + +void ConfigManager::SetConfigReceiver(const ConfigKey& key, const sp<IBinder>& intentSender) { + mConfigReceivers[key] = intentSender; +} + +void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) { + mConfigReceivers.erase(key); +} + +void ConfigManager::RemoveConfig(const ConfigKey& key) { + auto it = mConfigs.find(key); + if (it != mConfigs.end()) { + // Remove from map + mConfigs.erase(it); + + // Tell everyone + for (auto& listener : mListeners) { + listener->OnConfigRemoved(key); + } + } + + // Remove from disk. There can still be a lingering file on disk so we check + // whether or not the config was on memory. + remove_saved_configs(key); +} + +void ConfigManager::remove_saved_configs(const ConfigKey& key) { + string suffix = StringPrintf("%d-%lld", key.GetUid(), (long long)key.GetId()); + StorageManager::deleteSuffixedFiles(STATS_SERVICE_DIR, suffix.c_str()); +} + +void ConfigManager::RemoveConfigs(int uid) { + vector<ConfigKey> removed; + + for (auto it = mConfigs.begin(); it != mConfigs.end();) { + // Remove from map + if (it->GetUid() == uid) { + remove_saved_configs(*it); + removed.push_back(*it); + mConfigReceivers.erase(*it); + it = mConfigs.erase(it); + } else { + it++; + } + } + + // Remove separately so if they do anything in the callback they can't mess up our iteration. + for (auto& key : removed) { + // Tell everyone + for (auto& listener : mListeners) { + listener->OnConfigRemoved(key); + } + } +} + +void ConfigManager::RemoveAllConfigs() { + vector<ConfigKey> removed; + + for (auto it = mConfigs.begin(); it != mConfigs.end();) { + // Remove from map + removed.push_back(*it); + auto receiverIt = mConfigReceivers.find(*it); + if (receiverIt != mConfigReceivers.end()) { + mConfigReceivers.erase(*it); + } + it = mConfigs.erase(it); + } + + // Remove separately so if they do anything in the callback they can't mess up our iteration. + for (auto& key : removed) { + // Tell everyone + for (auto& listener : mListeners) { + listener->OnConfigRemoved(key); + } + } +} + +vector<ConfigKey> ConfigManager::GetAllConfigKeys() const { + vector<ConfigKey> ret; + for (auto it = mConfigs.cbegin(); it != mConfigs.cend(); ++it) { + ret.push_back(*it); + } + return ret; +} + +const sp<android::IBinder> ConfigManager::GetConfigReceiver(const ConfigKey& key) const { + auto it = mConfigReceivers.find(key); + if (it == mConfigReceivers.end()) { + return nullptr; + } else { + return it->second; + } +} + +void ConfigManager::Dump(FILE* out) { + fprintf(out, "CONFIGURATIONS (%d)\n", (int)mConfigs.size()); + fprintf(out, " uid name\n"); + for (const auto& key : mConfigs) { + fprintf(out, " %6d %lld\n", key.GetUid(), (long long)key.GetId()); + auto receiverIt = mConfigReceivers.find(key); + if (receiverIt != mConfigReceivers.end()) { + fprintf(out, " -> received by PendingIntent as binder\n"); + } + } +} + +void ConfigManager::update_saved_configs(const ConfigKey& key, const StatsdConfig& config) { + // If there is a pre-existing config with same key we should first delete it. + remove_saved_configs(key); + + // Then we save the latest config. + string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_SERVICE_DIR, time(nullptr), + key.GetUid(), (long long)key.GetId()); + const int numBytes = config.ByteSize(); + vector<uint8_t> buffer(numBytes); + config.SerializeToArray(&buffer[0], numBytes); + StorageManager::writeFile(file_name.c_str(), &buffer[0], numBytes); +} + +StatsdConfig build_fake_config() { + // HACK: Hard code a test metric for counting screen on events... + StatsdConfig config; + config.set_id(12345); + + int WAKE_LOCK_TAG_ID = 1111; // put a fake id here to make testing easier. + int WAKE_LOCK_UID_KEY_ID = 1; + int WAKE_LOCK_NAME_KEY = 3; + int WAKE_LOCK_STATE_KEY = 4; + int WAKE_LOCK_ACQUIRE_VALUE = 1; + int WAKE_LOCK_RELEASE_VALUE = 0; + + int APP_USAGE_TAG_ID = 12345; + int APP_USAGE_UID_KEY_ID = 1; + int APP_USAGE_STATE_KEY = 2; + int APP_USAGE_FOREGROUND = 1; + int APP_USAGE_BACKGROUND = 0; + + int SCREEN_EVENT_TAG_ID = 29; + int SCREEN_EVENT_STATE_KEY = 1; + int SCREEN_EVENT_ON_VALUE = 2; + int SCREEN_EVENT_OFF_VALUE = 1; + + int UID_PROCESS_STATE_TAG_ID = 27; + int UID_PROCESS_STATE_UID_KEY = 1; + + int KERNEL_WAKELOCK_TAG_ID = 1004; + int KERNEL_WAKELOCK_COUNT_KEY = 2; + int KERNEL_WAKELOCK_NAME_KEY = 1; + + int DEVICE_TEMPERATURE_TAG_ID = 33; + int DEVICE_TEMPERATURE_KEY = 1; + + // Count Screen ON events. + CountMetric* metric = config.add_count_metric(); + metric->set_id(1); // METRIC_1 + metric->set_what(102); // "SCREEN_TURNED_ON" + metric->set_bucket(ONE_MINUTE); + + // Anomaly threshold for screen-on count. + // TODO(b/70627390): Uncomment once the bug is fixed. + /*Alert* alert = config.add_alert(); + alert->set_id("ALERT_1"); + alert->set_metric_name("METRIC_1"); + alert->set_number_of_buckets(6); + alert->set_trigger_if_sum_gt(10); + alert->set_refractory_period_secs(30); + Alert::IncidentdDetails* details = alert->mutable_incidentd_details(); + details->add_section(12); + details->add_section(13);*/ + + config.add_allowed_log_source("AID_ROOT"); + config.add_allowed_log_source("AID_SYSTEM"); + config.add_allowed_log_source("AID_BLUETOOTH"); + config.add_allowed_log_source("com.android.statsd.dogfood"); + config.add_allowed_log_source("com.android.systemui"); + + // Count process state changes, slice by uid. + metric = config.add_count_metric(); + metric->set_id(2); // "METRIC_2" + metric->set_what(104); + metric->set_bucket(ONE_MINUTE); + FieldMatcher* dimensions = metric->mutable_dimensions_in_what(); + dimensions->set_field(UID_PROCESS_STATE_TAG_ID); + dimensions->add_child()->set_field(UID_PROCESS_STATE_UID_KEY); + + // Anomaly threshold for background count. + // TODO(b/70627390): Uncomment once the bug is fixed. + /* + alert = config.add_alert(); + alert->set_id("ALERT_2"); + alert->set_metric_name("METRIC_2"); + alert->set_number_of_buckets(4); + alert->set_trigger_if_sum_gt(30); + alert->set_refractory_period_secs(20); + details = alert->mutable_incidentd_details(); + details->add_section(14); + details->add_section(15);*/ + + // Count process state changes, slice by uid, while SCREEN_IS_OFF + metric = config.add_count_metric(); + metric->set_id(3); + metric->set_what(104); + metric->set_bucket(ONE_MINUTE); + + dimensions = metric->mutable_dimensions_in_what(); + dimensions->set_field(UID_PROCESS_STATE_TAG_ID); + dimensions->add_child()->set_field(UID_PROCESS_STATE_UID_KEY); + metric->set_condition(202); + + // Count wake lock, slice by uid, while SCREEN_IS_ON and app in background + metric = config.add_count_metric(); + metric->set_id(4); + metric->set_what(107); + metric->set_bucket(ONE_MINUTE); + dimensions = metric->mutable_dimensions_in_what(); + dimensions->set_field(WAKE_LOCK_TAG_ID); + dimensions->add_child()->set_field(WAKE_LOCK_UID_KEY_ID); + + + metric->set_condition(204); + MetricConditionLink* link = metric->add_links(); + link->set_condition(203); + link->mutable_fields_in_what()->set_field(WAKE_LOCK_TAG_ID); + link->mutable_fields_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID); + link->mutable_fields_in_condition()->set_field(APP_USAGE_TAG_ID); + link->mutable_fields_in_condition()->add_child()->set_field(APP_USAGE_UID_KEY_ID); + + // Duration of an app holding any wl, while screen on and app in background, slice by uid + DurationMetric* durationMetric = config.add_duration_metric(); + durationMetric->set_id(5); + durationMetric->set_bucket(ONE_MINUTE); + durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM); + dimensions = durationMetric->mutable_dimensions_in_what(); + dimensions->set_field(WAKE_LOCK_TAG_ID); + dimensions->add_child()->set_field(WAKE_LOCK_UID_KEY_ID); + durationMetric->set_what(205); + durationMetric->set_condition(204); + link = durationMetric->add_links(); + link->set_condition(203); + link->mutable_fields_in_what()->set_field(WAKE_LOCK_TAG_ID); + link->mutable_fields_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID); + link->mutable_fields_in_condition()->set_field(APP_USAGE_TAG_ID); + link->mutable_fields_in_condition()->add_child()->set_field(APP_USAGE_UID_KEY_ID); + + // max Duration of an app holding any wl, while screen on and app in background, slice by uid + durationMetric = config.add_duration_metric(); + durationMetric->set_id(6); + durationMetric->set_bucket(ONE_MINUTE); + durationMetric->set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE); + dimensions = durationMetric->mutable_dimensions_in_what(); + dimensions->set_field(WAKE_LOCK_TAG_ID); + dimensions->add_child()->set_field(WAKE_LOCK_UID_KEY_ID); + durationMetric->set_what(205); + durationMetric->set_condition(204); + link = durationMetric->add_links(); + link->set_condition(203); + link->mutable_fields_in_what()->set_field(WAKE_LOCK_TAG_ID); + link->mutable_fields_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID); + link->mutable_fields_in_condition()->set_field(APP_USAGE_TAG_ID); + link->mutable_fields_in_condition()->add_child()->set_field(APP_USAGE_UID_KEY_ID); + + // Duration of an app holding any wl, while screen on and app in background + durationMetric = config.add_duration_metric(); + durationMetric->set_id(7); + durationMetric->set_bucket(ONE_MINUTE); + durationMetric->set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE); + durationMetric->set_what(205); + durationMetric->set_condition(204); + link = durationMetric->add_links(); + link->set_condition(203); + link->mutable_fields_in_what()->set_field(WAKE_LOCK_TAG_ID); + link->mutable_fields_in_what()->add_child()->set_field(WAKE_LOCK_UID_KEY_ID); + link->mutable_fields_in_condition()->set_field(APP_USAGE_TAG_ID); + link->mutable_fields_in_condition()->add_child()->set_field(APP_USAGE_UID_KEY_ID); + + + // Duration of screen on time. + durationMetric = config.add_duration_metric(); + durationMetric->set_id(8); + durationMetric->set_bucket(ONE_MINUTE); + durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM); + durationMetric->set_what(201); + + // Anomaly threshold for background count. + // TODO(b/70627390): Uncomment once the bug is fixed. + /* + alert = config.add_alert(); + alert->set_id(308); + alert->set_metric_id(8); + alert->set_number_of_buckets(4); + alert->set_trigger_if_sum_gt(2000000000); // 2 seconds + alert->set_refractory_period_secs(120); + details = alert->mutable_incidentd_details(); + details->add_section(-1);*/ + + // Value metric to count KERNEL_WAKELOCK when screen turned on + ValueMetric* valueMetric = config.add_value_metric(); + valueMetric->set_id(11); + valueMetric->set_what(109); + valueMetric->mutable_value_field()->set_field(KERNEL_WAKELOCK_TAG_ID); + valueMetric->mutable_value_field()->add_child()->set_field(KERNEL_WAKELOCK_COUNT_KEY); + valueMetric->set_condition(201); + dimensions = valueMetric->mutable_dimensions_in_what(); + dimensions->set_field(KERNEL_WAKELOCK_TAG_ID); + dimensions->add_child()->set_field(KERNEL_WAKELOCK_NAME_KEY); + // This is for testing easier. We should never set bucket size this small. + durationMetric->set_bucket(ONE_MINUTE); + + // Add an EventMetric to log process state change events. + EventMetric* eventMetric = config.add_event_metric(); + eventMetric->set_id(9); + eventMetric->set_what(102); // "SCREEN_TURNED_ON" + + // Add an GaugeMetric. + GaugeMetric* gaugeMetric = config.add_gauge_metric(); + gaugeMetric->set_id(10); + gaugeMetric->set_what(101); + auto gaugeFieldMatcher = gaugeMetric->mutable_gauge_fields_filter()->mutable_fields(); + gaugeFieldMatcher->set_field(DEVICE_TEMPERATURE_TAG_ID); + gaugeFieldMatcher->add_child()->set_field(DEVICE_TEMPERATURE_KEY); + durationMetric->set_bucket(ONE_MINUTE); + + // Event matchers. + AtomMatcher* temperatureAtomMatcher = config.add_atom_matcher(); + temperatureAtomMatcher->set_id(101); // "DEVICE_TEMPERATURE" + temperatureAtomMatcher->mutable_simple_atom_matcher()->set_atom_id( + DEVICE_TEMPERATURE_TAG_ID); + + AtomMatcher* eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(102); // "SCREEN_TURNED_ON" + SimpleAtomMatcher* simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(SCREEN_EVENT_TAG_ID); + FieldValueMatcher* fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher(); + fieldValueMatcher->set_field(SCREEN_EVENT_STATE_KEY); + fieldValueMatcher->set_eq_int(SCREEN_EVENT_ON_VALUE); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(103); // "SCREEN_TURNED_OFF" + simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(SCREEN_EVENT_TAG_ID); + fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher(); + fieldValueMatcher->set_field(SCREEN_EVENT_STATE_KEY); + fieldValueMatcher->set_eq_int(SCREEN_EVENT_OFF_VALUE); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(104); // "PROCESS_STATE_CHANGE" + simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(UID_PROCESS_STATE_TAG_ID); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(105); // "APP_GOES_BACKGROUND" + simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(APP_USAGE_TAG_ID); + fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher(); + fieldValueMatcher->set_field(APP_USAGE_STATE_KEY); + fieldValueMatcher->set_eq_int(APP_USAGE_BACKGROUND); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(106); // "APP_GOES_FOREGROUND" + simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(APP_USAGE_TAG_ID); + fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher(); + fieldValueMatcher->set_field(APP_USAGE_STATE_KEY); + fieldValueMatcher->set_eq_int(APP_USAGE_FOREGROUND); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(107); // "APP_GET_WL" + simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(WAKE_LOCK_TAG_ID); + fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher(); + fieldValueMatcher->set_field(WAKE_LOCK_STATE_KEY); + fieldValueMatcher->set_eq_int(WAKE_LOCK_ACQUIRE_VALUE); + + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(108); //"APP_RELEASE_WL" + simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(WAKE_LOCK_TAG_ID); + fieldValueMatcher = simpleAtomMatcher->add_field_value_matcher(); + fieldValueMatcher->set_field(WAKE_LOCK_STATE_KEY); + fieldValueMatcher->set_eq_int(WAKE_LOCK_RELEASE_VALUE); + + // pulled events + eventMatcher = config.add_atom_matcher(); + eventMatcher->set_id(109); // "KERNEL_WAKELOCK" + simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher(); + simpleAtomMatcher->set_atom_id(KERNEL_WAKELOCK_TAG_ID); + + // Predicates............. + Predicate* predicate = config.add_predicate(); + predicate->set_id(201); // "SCREEN_IS_ON" + SimplePredicate* simplePredicate = predicate->mutable_simple_predicate(); + simplePredicate->set_start(102); // "SCREEN_TURNED_ON" + simplePredicate->set_stop(103); + simplePredicate->set_count_nesting(false); + + predicate = config.add_predicate(); + predicate->set_id(202); // "SCREEN_IS_OFF" + simplePredicate = predicate->mutable_simple_predicate(); + simplePredicate->set_start(103); + simplePredicate->set_stop(102); // "SCREEN_TURNED_ON" + simplePredicate->set_count_nesting(false); + + predicate = config.add_predicate(); + predicate->set_id(203); // "APP_IS_BACKGROUND" + simplePredicate = predicate->mutable_simple_predicate(); + simplePredicate->set_start(105); + simplePredicate->set_stop(106); + FieldMatcher* predicate_dimension1 = simplePredicate->mutable_dimensions(); + predicate_dimension1->set_field(APP_USAGE_TAG_ID); + predicate_dimension1->add_child()->set_field(APP_USAGE_UID_KEY_ID); + simplePredicate->set_count_nesting(false); + + predicate = config.add_predicate(); + predicate->set_id(204); // "APP_IS_BACKGROUND_AND_SCREEN_ON" + Predicate_Combination* combination_predicate = predicate->mutable_combination(); + combination_predicate->set_operation(LogicalOperation::AND); + combination_predicate->add_predicate(203); + combination_predicate->add_predicate(201); + + predicate = config.add_predicate(); + predicate->set_id(205); // "WL_HELD_PER_APP_PER_NAME" + simplePredicate = predicate->mutable_simple_predicate(); + simplePredicate->set_start(107); + simplePredicate->set_stop(108); + FieldMatcher* predicate_dimension = simplePredicate->mutable_dimensions(); + predicate_dimension1->set_field(WAKE_LOCK_TAG_ID); + predicate_dimension->add_child()->set_field(WAKE_LOCK_UID_KEY_ID); + predicate_dimension->add_child()->set_field(WAKE_LOCK_NAME_KEY); + simplePredicate->set_count_nesting(true); + + predicate = config.add_predicate(); + predicate->set_id(206); // "WL_HELD_PER_APP" + simplePredicate = predicate->mutable_simple_predicate(); + simplePredicate->set_start(107); + simplePredicate->set_stop(108); + simplePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE); + predicate_dimension = simplePredicate->mutable_dimensions(); + predicate_dimension->set_field(WAKE_LOCK_TAG_ID); + predicate_dimension->add_child()->set_field(WAKE_LOCK_UID_KEY_ID); + simplePredicate->set_count_nesting(true); + + return config; +} + +} // namespace statsd +} // namespace os +} // namespace android |