1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define DEBUG false // STOPSHIP if true 18 #include "Log.h" 19 20 #include "config/ConfigManager.h" 21 #include "storage/StorageManager.h" 22 23 #include "guardrail/StatsdStats.h" 24 #include "stats_log_util.h" 25 #include "stats_util.h" 26 #include "stats_log_util.h" 27 28 #include <android-base/file.h> 29 #include <dirent.h> 30 #include <stdio.h> 31 #include <vector> 32 #include "android-base/stringprintf.h" 33 34 namespace android { 35 namespace os { 36 namespace statsd { 37 38 using std::map; 39 using std::pair; 40 using std::set; 41 using std::string; 42 using std::vector; 43 44 #define STATS_SERVICE_DIR "/data/misc/stats-service" 45 46 using android::base::StringPrintf; 47 using std::unique_ptr; 48 49 ConfigManager::ConfigManager() { 50 } 51 52 ConfigManager::~ConfigManager() { 53 } 54 55 void ConfigManager::Startup() { 56 map<ConfigKey, StatsdConfig> configsFromDisk; 57 StorageManager::readConfigFromDisk(configsFromDisk); 58 for (const auto& pair : configsFromDisk) { 59 UpdateConfig(pair.first, pair.second); 60 } 61 } 62 63 void ConfigManager::StartupForTest() { 64 // Dummy function to avoid reading configs from disks for tests. 65 } 66 67 void ConfigManager::AddListener(const sp<ConfigListener>& listener) { 68 lock_guard<mutex> lock(mMutex); 69 mListeners.push_back(listener); 70 } 71 72 void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& config) { 73 vector<sp<ConfigListener>> broadcastList; 74 { 75 lock_guard <mutex> lock(mMutex); 76 77 const int numBytes = config.ByteSize(); 78 vector<uint8_t> buffer(numBytes); 79 config.SerializeToArray(&buffer[0], numBytes); 80 81 auto uidIt = mConfigs.find(key.GetUid()); 82 // GuardRail: Limit the number of configs per uid. 83 if (uidIt != mConfigs.end()) { 84 auto it = uidIt->second.find(key); 85 if (it == uidIt->second.end() && 86 uidIt->second.size() >= StatsdStats::kMaxConfigCountPerUid) { 87 ALOGE("ConfigManager: uid %d has exceeded the config count limit", key.GetUid()); 88 return; 89 } 90 } 91 92 // Check if it's a duplicate config. 93 if (uidIt != mConfigs.end() && uidIt->second.find(key) != uidIt->second.end() && 94 StorageManager::hasIdenticalConfig(key, buffer)) { 95 // This is a duplicate config. 96 ALOGI("ConfigManager This is a duplicate config %s", key.ToString().c_str()); 97 // Update saved file on disk. We still update timestamp of file when 98 // there exists a duplicate configuration to avoid garbage collection. 99 update_saved_configs_locked(key, buffer, numBytes); 100 return; 101 } 102 103 // Update saved file on disk. 104 update_saved_configs_locked(key, buffer, numBytes); 105 106 // Add to set. 107 mConfigs[key.GetUid()].insert(key); 108 109 for (sp<ConfigListener> listener : mListeners) { 110 broadcastList.push_back(listener); 111 } 112 } 113 114 const int64_t timestampNs = getElapsedRealtimeNs(); 115 // Tell everyone 116 for (sp<ConfigListener> listener : broadcastList) { 117 listener->OnConfigUpdated(timestampNs, key, config); 118 } 119 } 120 121 void ConfigManager::SetConfigReceiver(const ConfigKey& key, const sp<IBinder>& intentSender) { 122 lock_guard<mutex> lock(mMutex); 123 mConfigReceivers[key] = intentSender; 124 } 125 126 void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) { 127 lock_guard<mutex> lock(mMutex); 128 mConfigReceivers.erase(key); 129 } 130 131 void ConfigManager::RemoveConfig(const ConfigKey& key) { 132 vector<sp<ConfigListener>> broadcastList; 133 { 134 lock_guard <mutex> lock(mMutex); 135 136 auto uidIt = mConfigs.find(key.GetUid()); 137 if (uidIt != mConfigs.end() && uidIt->second.find(key) != uidIt->second.end()) { 138 // Remove from map 139 uidIt->second.erase(key); 140 for (sp<ConfigListener> listener : mListeners) { 141 broadcastList.push_back(listener); 142 } 143 } 144 145 auto itReceiver = mConfigReceivers.find(key); 146 if (itReceiver != mConfigReceivers.end()) { 147 // Remove from map 148 mConfigReceivers.erase(itReceiver); 149 } 150 151 // Remove from disk. There can still be a lingering file on disk so we check 152 // whether or not the config was on memory. 153 remove_saved_configs(key); 154 } 155 156 for (sp<ConfigListener> listener:broadcastList) { 157 listener->OnConfigRemoved(key); 158 } 159 } 160 161 void ConfigManager::remove_saved_configs(const ConfigKey& key) { 162 string suffix = StringPrintf("%d_%lld", key.GetUid(), (long long)key.GetId()); 163 StorageManager::deleteSuffixedFiles(STATS_SERVICE_DIR, suffix.c_str()); 164 } 165 166 void ConfigManager::RemoveConfigs(int uid) { 167 vector<ConfigKey> removed; 168 vector<sp<ConfigListener>> broadcastList; 169 { 170 lock_guard <mutex> lock(mMutex); 171 172 auto uidIt = mConfigs.find(uid); 173 if (uidIt == mConfigs.end()) { 174 return; 175 } 176 177 for (auto it = uidIt->second.begin(); it != uidIt->second.end(); ++it) { 178 // Remove from map 179 remove_saved_configs(*it); 180 removed.push_back(*it); 181 mConfigReceivers.erase(*it); 182 } 183 184 mConfigs.erase(uidIt); 185 186 for (sp<ConfigListener> listener : mListeners) { 187 broadcastList.push_back(listener); 188 } 189 } 190 191 // Remove separately so if they do anything in the callback they can't mess up our iteration. 192 for (auto& key : removed) { 193 // Tell everyone 194 for (sp<ConfigListener> listener:broadcastList) { 195 listener->OnConfigRemoved(key); 196 } 197 } 198 } 199 200 void ConfigManager::RemoveAllConfigs() { 201 vector<ConfigKey> removed; 202 vector<sp<ConfigListener>> broadcastList; 203 { 204 lock_guard <mutex> lock(mMutex); 205 206 for (auto uidIt = mConfigs.begin(); uidIt != mConfigs.end();) { 207 for (auto it = uidIt->second.begin(); it != uidIt->second.end();) { 208 // Remove from map 209 removed.push_back(*it); 210 it = uidIt->second.erase(it); 211 } 212 uidIt = mConfigs.erase(uidIt); 213 } 214 215 mConfigReceivers.clear(); 216 for (sp<ConfigListener> listener : mListeners) { 217 broadcastList.push_back(listener); 218 } 219 } 220 221 // Remove separately so if they do anything in the callback they can't mess up our iteration. 222 for (auto& key : removed) { 223 // Tell everyone 224 for (sp<ConfigListener> listener:broadcastList) { 225 listener->OnConfigRemoved(key); 226 } 227 } 228 } 229 230 vector<ConfigKey> ConfigManager::GetAllConfigKeys() const { 231 lock_guard<mutex> lock(mMutex); 232 233 vector<ConfigKey> ret; 234 for (auto uidIt = mConfigs.cbegin(); uidIt != mConfigs.cend(); ++uidIt) { 235 for (auto it = uidIt->second.cbegin(); it != uidIt->second.cend(); ++it) { 236 ret.push_back(*it); 237 } 238 } 239 return ret; 240 } 241 242 const sp<android::IBinder> ConfigManager::GetConfigReceiver(const ConfigKey& key) const { 243 lock_guard<mutex> lock(mMutex); 244 245 auto it = mConfigReceivers.find(key); 246 if (it == mConfigReceivers.end()) { 247 return nullptr; 248 } else { 249 return it->second; 250 } 251 } 252 253 void ConfigManager::Dump(FILE* out) { 254 lock_guard<mutex> lock(mMutex); 255 256 fprintf(out, "CONFIGURATIONS\n"); 257 fprintf(out, " uid name\n"); 258 for (auto uidIt = mConfigs.cbegin(); uidIt != mConfigs.cend(); ++uidIt) { 259 for (auto it = uidIt->second.cbegin(); it != uidIt->second.cend(); ++it) { 260 fprintf(out, " %6d %lld\n", it->GetUid(), (long long)it->GetId()); 261 auto receiverIt = mConfigReceivers.find(*it); 262 if (receiverIt != mConfigReceivers.end()) { 263 fprintf(out, " -> received by PendingIntent as binder\n"); 264 } 265 } 266 } 267 } 268 269 void ConfigManager::update_saved_configs_locked(const ConfigKey& key, 270 const vector<uint8_t>& buffer, 271 const int numBytes) { 272 // If there is a pre-existing config with same key we should first delete it. 273 remove_saved_configs(key); 274 275 // Then we save the latest config. 276 string file_name = 277 StringPrintf("%s/%ld_%d_%lld", STATS_SERVICE_DIR, time(nullptr), 278 key.GetUid(), (long long)key.GetId()); 279 StorageManager::writeFile(file_name.c_str(), &buffer[0], numBytes); 280 } 281 282 } // namespace statsd 283 } // namespace os 284 } // namespace android 285