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