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
ConfigManager()49 ConfigManager::ConfigManager() {
50 }
51
~ConfigManager()52 ConfigManager::~ConfigManager() {
53 }
54
Startup()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
StartupForTest()63 void ConfigManager::StartupForTest() {
64 // Dummy function to avoid reading configs from disks for tests.
65 }
66
AddListener(const sp<ConfigListener> & listener)67 void ConfigManager::AddListener(const sp<ConfigListener>& listener) {
68 lock_guard<mutex> lock(mMutex);
69 mListeners.push_back(listener);
70 }
71
UpdateConfig(const ConfigKey & key,const StatsdConfig & config)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
SetConfigReceiver(const ConfigKey & key,const sp<IBinder> & intentSender)121 void ConfigManager::SetConfigReceiver(const ConfigKey& key, const sp<IBinder>& intentSender) {
122 lock_guard<mutex> lock(mMutex);
123 mConfigReceivers[key] = intentSender;
124 }
125
RemoveConfigReceiver(const ConfigKey & key)126 void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
127 lock_guard<mutex> lock(mMutex);
128 mConfigReceivers.erase(key);
129 }
130
RemoveConfig(const ConfigKey & key)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
remove_saved_configs(const ConfigKey & key)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
RemoveConfigs(int uid)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
RemoveAllConfigs()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
GetAllConfigKeys() const230 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
GetConfigReceiver(const ConfigKey & key) const242 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
Dump(FILE * out)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
update_saved_configs_locked(const ConfigKey & key,const vector<uint8_t> & buffer,const int numBytes)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