• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2020 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 #include "btif_config_cache.h"
18 
19 #include <limits>
20 #include <vector>
21 
22 #include "stack/include/bt_octets.h"
23 #include "types/raw_address.h"
24 
25 #include <base/logging.h>
26 
27 namespace {
28 
29 const std::unordered_set<std::string> kLinkKeyTypes = {
30     "LinkKey",      "LE_KEY_PENC", "LE_KEY_PID",
31     "LE_KEY_PCSRK", "LE_KEY_LENC", "LE_KEY_LCSRK"};
32 
33 const std::unordered_set<std::string> kLocalSectionNames = {"Info", "Metrics",
34                                                             "Adapter"};
35 
is_link_key(const std::string & key)36 bool is_link_key(const std::string& key) {
37   return kLinkKeyTypes.find(key) != kLinkKeyTypes.end();
38 }
39 
has_link_key_in_section(const section_t & section)40 bool has_link_key_in_section(const section_t& section) {
41   for (const auto& entry : section.entries) {
42     if (is_link_key(entry.key)) {
43       return true;
44     }
45   }
46   return false;
47 }
48 
is_local_section_info(const std::string & section)49 bool is_local_section_info(const std::string& section) {
50   return kLocalSectionNames.find(section) != kLocalSectionNames.end();
51 }
52 
53 // trim new line in place, return true if newline was found
trim_new_line(std::string & value)54 bool trim_new_line(std::string& value) {
55   size_t newline_position = value.find_first_of('\n');
56   if (newline_position != std::string::npos) {
57     value.erase(newline_position);
58     return true;
59   }
60   return false;
61 }
62 
63 }  // namespace
64 
BtifConfigCache(size_t capacity)65 BtifConfigCache::BtifConfigCache(size_t capacity)
66     : unpaired_devices_cache_(capacity, "bt_config_cache") {
67   LOG(INFO) << __func__ << ", capacity: " << capacity;
68 }
69 
~BtifConfigCache()70 BtifConfigCache::~BtifConfigCache() { Clear(); }
71 
Clear()72 void BtifConfigCache::Clear() {
73   unpaired_devices_cache_.Clear();
74   paired_devices_list_.sections.clear();
75 }
76 
Init(std::unique_ptr<config_t> source)77 void BtifConfigCache::Init(std::unique_ptr<config_t> source) {
78   // get the config persistent data from btif_config file
79   paired_devices_list_ = std::move(*source);
80   source.reset();
81 }
82 
HasPersistentSection(const std::string & section_name)83 bool BtifConfigCache::HasPersistentSection(const std::string& section_name) {
84   return paired_devices_list_.Find(section_name) !=
85          paired_devices_list_.sections.end();
86 }
87 
HasUnpairedSection(const std::string & section_name)88 bool BtifConfigCache::HasUnpairedSection(const std::string& section_name) {
89   return unpaired_devices_cache_.HasKey(section_name);
90 }
91 
HasSection(const std::string & section_name)92 bool BtifConfigCache::HasSection(const std::string& section_name) {
93   return HasUnpairedSection(section_name) || HasPersistentSection(section_name);
94 }
95 
HasKey(const std::string & section_name,const std::string & key)96 bool BtifConfigCache::HasKey(const std::string& section_name,
97                              const std::string& key) {
98   auto section_iter = paired_devices_list_.Find(section_name);
99   if (section_iter != paired_devices_list_.sections.end()) {
100     return section_iter->Has(key);
101   }
102   section_t* section = unpaired_devices_cache_.Find(section_name);
103   if (section == nullptr) {
104     return false;
105   }
106   return section->Has(key);
107 }
108 
109 // remove sections with the restricted key
RemovePersistentSectionsWithKey(const std::string & key)110 void BtifConfigCache::RemovePersistentSectionsWithKey(const std::string& key) {
111   for (auto it = paired_devices_list_.sections.begin();
112        it != paired_devices_list_.sections.end();) {
113     if (it->Has(key)) {
114       it = paired_devices_list_.sections.erase(it);
115       continue;
116     }
117     it++;
118   }
119 }
120 
121 /* remove a key from section, section itself is removed when empty */
RemoveKey(const std::string & section_name,const std::string & key)122 bool BtifConfigCache::RemoveKey(const std::string& section_name,
123                                 const std::string& key) {
124   section_t* section = unpaired_devices_cache_.Find(section_name);
125   if (section != nullptr) {
126     auto entry_iter = section->Find(key);
127     if (entry_iter == section->entries.end()) {
128       return false;
129     }
130     section->entries.erase(entry_iter);
131     if (section->entries.empty()) {
132       unpaired_devices_cache_.Remove(section_name);
133     }
134     return true;
135   } else {
136     auto section_iter = paired_devices_list_.Find(section_name);
137     if (section_iter == paired_devices_list_.sections.end()) {
138       return false;
139     }
140     auto entry_iter = section_iter->Find(key);
141     if (entry_iter == section_iter->entries.end()) {
142       return false;
143     }
144     section_iter->entries.erase(entry_iter);
145     if (section_iter->entries.empty()) {
146       paired_devices_list_.sections.erase(section_iter);
147     } else if (!has_link_key_in_section(*section_iter)) {
148       // if no link key in section after removal, move it to unpaired section
149       auto moved_section = std::move(*section_iter);
150       paired_devices_list_.sections.erase(section_iter);
151       unpaired_devices_cache_.Put(section_name, std::move(moved_section));
152     }
153     return true;
154   }
155 }
156 
GetPersistentSectionNames()157 std::vector<std::string> BtifConfigCache::GetPersistentSectionNames() {
158   std::vector<std::string> result;
159   result.reserve(paired_devices_list_.sections.size());
160   for (const auto& section : paired_devices_list_.sections) {
161     result.emplace_back(section.name);
162   }
163   return result;
164 }
165 
166 /* clone persistent sections (Local Adapter sections, remote paired devices
167  * section,..) */
PersistentSectionCopy()168 config_t BtifConfigCache::PersistentSectionCopy() {
169   return paired_devices_list_;
170 }
171 
SetString(std::string section_name,std::string key,std::string value)172 void BtifConfigCache::SetString(std::string section_name, std::string key,
173                                 std::string value) {
174   trim_new_line(section_name);
175   trim_new_line(key);
176   trim_new_line(value);
177   if (section_name.empty()) {
178     LOG(FATAL) << "Empty section not allowed";
179     return;
180   }
181   if (key.empty()) {
182     LOG(FATAL) << "Empty key not allowed";
183     return;
184   }
185   if (!paired_devices_list_.Has(section_name)) {
186     // section is not in paired_device_list, handle it in unpaired devices cache
187     section_t section = {};
188     bool in_unpaired_cache = true;
189     if (!unpaired_devices_cache_.Get(section_name, &section)) {
190       // it's a new unpaired section, add it to unpaired devices cache
191       section.name = section_name;
192       in_unpaired_cache = false;
193     }
194     // set key to value and replace existing key if already exist
195     section.Set(key, value);
196 
197     if (is_local_section_info(section_name) ||
198         (is_link_key(key) && RawAddress::IsValidAddress(section_name))) {
199       // remove this section that has the LinkKey from unpaired devices cache.
200       if (in_unpaired_cache) {
201         unpaired_devices_cache_.Remove(section_name);
202       }
203       // when a unpaired section got the LinkKey, move this section to the
204       // paired devices list
205       paired_devices_list_.sections.emplace_back(std::move(section));
206     } else {
207       // update to the unpaired devices cache
208       unpaired_devices_cache_.Put(section_name, section);
209     }
210   } else {
211     // already have section in paired device list, add key-value entry.
212     auto section_found = paired_devices_list_.Find(section_name);
213     if (section_found == paired_devices_list_.sections.end()) {
214       LOG(WARNING) << __func__ << " , section_found not found!";
215       return;
216     }
217     section_found->Set(key, value);
218   }
219 }
220 
GetString(const std::string & section_name,const std::string & key)221 std::optional<std::string> BtifConfigCache::GetString(
222     const std::string& section_name, const std::string& key) {
223   // Check paired sections first
224   auto section_iter = paired_devices_list_.Find(section_name);
225   if (section_iter != paired_devices_list_.sections.end()) {
226     auto entry_iter = section_iter->Find(key);
227     if (entry_iter == section_iter->entries.end()) {
228       return std::nullopt;
229     }
230     return entry_iter->value;
231   }
232   // Check unpaired sections later
233   section_t section = {};
234   if (!unpaired_devices_cache_.Get(section_name, &section)) {
235     return std::nullopt;
236   }
237   auto entry_iter = section.Find(key);
238   if (entry_iter == section.entries.end()) {
239     return std::nullopt;
240   }
241   return entry_iter->value;
242 }
243 
SetInt(std::string section_name,std::string key,int value)244 void BtifConfigCache::SetInt(std::string section_name, std::string key,
245                              int value) {
246   SetString(std::move(section_name), std::move(key), std::to_string(value));
247 }
248 
GetInt(const std::string & section_name,const std::string & key)249 std::optional<int> BtifConfigCache::GetInt(const std::string& section_name,
250                                            const std::string& key) {
251   auto value = GetString(section_name, key);
252   if (!value) {
253     return std::nullopt;
254   }
255   char* endptr;
256   long ret_long = strtol(value->c_str(), &endptr, 0);
257   if (*endptr != '\0') {
258     LOG(WARNING) << "Failed to parse value to long for section " << section_name
259                  << ", key " << key;
260     return std::nullopt;
261   }
262   if (ret_long >= std::numeric_limits<int>::max()) {
263     LOG(WARNING) << "Integer overflow when parsing value to int for section "
264                  << section_name << ", key " << key;
265     return std::nullopt;
266   }
267   return static_cast<int>(ret_long);
268 }
269 
SetUint64(std::string section_name,std::string key,uint64_t value)270 void BtifConfigCache::SetUint64(std::string section_name, std::string key,
271                                 uint64_t value) {
272   SetString(std::move(section_name), std::move(key), std::to_string(value));
273 }
274 
GetUint64(const std::string & section_name,const std::string & key)275 std::optional<uint64_t> BtifConfigCache::GetUint64(
276     const std::string& section_name, const std::string& key) {
277   auto value = GetString(section_name, key);
278   if (!value) {
279     return std::nullopt;
280   }
281   char* endptr;
282   uint64_t ret = strtoull(value->c_str(), &endptr, 0);
283   if (*endptr != '\0') {
284     LOG(WARNING) << "Failed to parse value to uint64 for section "
285                  << section_name << ", key " << key;
286     return std::nullopt;
287   }
288   return ret;
289 }
290 
SetBool(std::string section_name,std::string key,bool value)291 void BtifConfigCache::SetBool(std::string section_name, std::string key,
292                               bool value) {
293   SetString(std::move(section_name), std::move(key), value ? "true" : "false");
294 }
295 
GetBool(const std::string & section_name,const std::string & key)296 std::optional<bool> BtifConfigCache::GetBool(const std::string& section_name,
297                                              const std::string& key) {
298   auto value = GetString(section_name, key);
299   if (!value) {
300     return std::nullopt;
301   }
302   if (*value == "true") {
303     return true;
304   }
305   if (*value == "false") {
306     return false;
307   }
308   LOG(WARNING) << "Failed to parse value to boolean for section "
309                << section_name << ", key " << key;
310   return std::nullopt;
311 }
312