1 /****************************************************************************** 2 * 3 * Copyright (C) 2014 Google, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19 #define LOG_TAG "bt_btif_config" 20 21 #include <assert.h> 22 #include <ctype.h> 23 #include <pthread.h> 24 #include <stdio.h> 25 #include <string.h> 26 27 #include "osi/include/alarm.h" 28 #include "osi/include/allocator.h" 29 #include "btcore/include/bdaddr.h" 30 #include "btif_config.h" 31 #include "btif_config_transcode.h" 32 #include "btif_util.h" 33 #include "osi/include/compat.h" 34 #include "osi/include/config.h" 35 #include "btcore/include/module.h" 36 #include "osi/include/osi.h" 37 #include "osi/include/log.h" 38 39 #include "bt_types.h" 40 41 static const char *CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf"; 42 static const char *LEGACY_CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.xml"; 43 static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 3000; 44 45 static void timer_config_save(void *data); 46 47 // TODO(zachoverflow): Move these two functions out, because they are too specific for this file 48 // {grumpy-cat/no, monty-python/you-make-me-sad} 49 bool btif_get_device_type(const BD_ADDR bd_addr, int *p_device_type) 50 { 51 if (p_device_type == NULL) 52 return FALSE; 53 54 bt_bdaddr_t bda; 55 bdcpy(bda.address, bd_addr); 56 57 bdstr_t bd_addr_str; 58 bdaddr_to_string(&bda, bd_addr_str, sizeof(bd_addr_str)); 59 60 if (!btif_config_get_int(bd_addr_str, "DevType", p_device_type)) 61 return FALSE; 62 63 LOG_DEBUG("%s: Device [%s] type %d", __FUNCTION__, bd_addr_str, *p_device_type); 64 return TRUE; 65 } 66 67 bool btif_get_address_type(const BD_ADDR bd_addr, int *p_addr_type) 68 { 69 if (p_addr_type == NULL) 70 return FALSE; 71 72 bt_bdaddr_t bda; 73 bdcpy(bda.address, bd_addr); 74 75 bdstr_t bd_addr_str; 76 bdaddr_to_string(&bda, bd_addr_str, sizeof(bd_addr_str)); 77 78 if (!btif_config_get_int(bd_addr_str, "AddrType", p_addr_type)) 79 return FALSE; 80 81 LOG_DEBUG("%s: Device [%s] address type %d", __FUNCTION__, bd_addr_str, *p_addr_type); 82 return TRUE; 83 } 84 85 static pthread_mutex_t lock; // protects operations on |config|. 86 static config_t *config; 87 static alarm_t *alarm_timer; 88 89 // Module lifecycle functions 90 91 static future_t *init(void) { 92 pthread_mutex_init(&lock, NULL); 93 config = config_new(CONFIG_FILE_PATH); 94 if (!config) { 95 LOG_WARN("%s unable to load config file; attempting to transcode legacy file.", __func__); 96 config = btif_config_transcode(LEGACY_CONFIG_FILE_PATH); 97 if (!config) { 98 LOG_WARN("%s unable to transcode legacy file, starting unconfigured.", __func__); 99 config = config_new_empty(); 100 if (!config) { 101 LOG_ERROR("%s unable to allocate a config object.", __func__); 102 goto error; 103 } 104 } 105 106 if (config_save(config, CONFIG_FILE_PATH)) 107 unlink(LEGACY_CONFIG_FILE_PATH); 108 } 109 110 // TODO(sharvil): use a non-wake alarm for this once we have 111 // API support for it. There's no need to wake the system to 112 // write back to disk. 113 alarm_timer = alarm_new(); 114 if (!alarm_timer) { 115 LOG_ERROR("%s unable to create alarm.", __func__); 116 goto error; 117 } 118 119 return future_new_immediate(FUTURE_SUCCESS); 120 121 error:; 122 alarm_free(alarm_timer); 123 config_free(config); 124 pthread_mutex_destroy(&lock); 125 alarm_timer = NULL; 126 config = NULL; 127 return future_new_immediate(FUTURE_FAIL); 128 } 129 130 static future_t *shut_down(void) { 131 btif_config_flush(); 132 return future_new_immediate(FUTURE_SUCCESS); 133 } 134 135 static future_t *clean_up(void) { 136 btif_config_flush(); 137 138 alarm_free(alarm_timer); 139 config_free(config); 140 pthread_mutex_destroy(&lock); 141 alarm_timer = NULL; 142 config = NULL; 143 return future_new_immediate(FUTURE_SUCCESS); 144 } 145 146 const module_t btif_config_module = { 147 .name = BTIF_CONFIG_MODULE, 148 .init = init, 149 .start_up = NULL, 150 .shut_down = shut_down, 151 .clean_up = clean_up, 152 .dependencies = { 153 NULL 154 } 155 }; 156 157 bool btif_config_has_section(const char *section) { 158 assert(config != NULL); 159 assert(section != NULL); 160 161 pthread_mutex_lock(&lock); 162 bool ret = config_has_section(config, section); 163 pthread_mutex_unlock(&lock); 164 165 return ret; 166 } 167 168 bool btif_config_exist(const char *section, const char *key) { 169 assert(config != NULL); 170 assert(section != NULL); 171 assert(key != NULL); 172 173 pthread_mutex_lock(&lock); 174 bool ret = config_has_key(config, section, key); 175 pthread_mutex_unlock(&lock); 176 177 return ret; 178 } 179 180 bool btif_config_get_int(const char *section, const char *key, int *value) { 181 assert(config != NULL); 182 assert(section != NULL); 183 assert(key != NULL); 184 assert(value != NULL); 185 186 pthread_mutex_lock(&lock); 187 bool ret = config_has_key(config, section, key); 188 if (ret) 189 *value = config_get_int(config, section, key, *value); 190 pthread_mutex_unlock(&lock); 191 192 return ret; 193 } 194 195 bool btif_config_set_int(const char *section, const char *key, int value) { 196 assert(config != NULL); 197 assert(section != NULL); 198 assert(key != NULL); 199 200 pthread_mutex_lock(&lock); 201 config_set_int(config, section, key, value); 202 pthread_mutex_unlock(&lock); 203 204 return true; 205 } 206 207 bool btif_config_get_str(const char *section, const char *key, char *value, int *size_bytes) { 208 assert(config != NULL); 209 assert(section != NULL); 210 assert(key != NULL); 211 assert(value != NULL); 212 assert(size_bytes != NULL); 213 214 pthread_mutex_lock(&lock); 215 const char *stored_value = config_get_string(config, section, key, NULL); 216 pthread_mutex_unlock(&lock); 217 218 if (!stored_value) 219 return false; 220 221 strlcpy(value, stored_value, *size_bytes); 222 *size_bytes = strlen(value) + 1; 223 224 return true; 225 } 226 227 bool btif_config_set_str(const char *section, const char *key, const char *value) { 228 assert(config != NULL); 229 assert(section != NULL); 230 assert(key != NULL); 231 assert(value != NULL); 232 233 pthread_mutex_lock(&lock); 234 config_set_string(config, section, key, value); 235 pthread_mutex_unlock(&lock); 236 237 return true; 238 } 239 240 bool btif_config_get_bin(const char *section, const char *key, uint8_t *value, size_t *length) { 241 assert(config != NULL); 242 assert(section != NULL); 243 assert(key != NULL); 244 assert(value != NULL); 245 assert(length != NULL); 246 247 pthread_mutex_lock(&lock); 248 const char *value_str = config_get_string(config, section, key, NULL); 249 pthread_mutex_unlock(&lock); 250 251 if (!value_str) 252 return false; 253 254 size_t value_len = strlen(value_str); 255 if ((value_len % 2) != 0 || *length < (value_len / 2)) 256 return false; 257 258 for (size_t i = 0; i < value_len; ++i) 259 if (!isxdigit(value_str[i])) 260 return false; 261 262 for (*length = 0; *value_str; value_str += 2, *length += 1) 263 sscanf(value_str, "%02hhx", &value[*length]); 264 265 return true; 266 } 267 268 size_t btif_config_get_bin_length(const char *section, const char *key) { 269 assert(config != NULL); 270 assert(section != NULL); 271 assert(key != NULL); 272 273 pthread_mutex_lock(&lock); 274 const char *value_str = config_get_string(config, section, key, NULL); 275 pthread_mutex_unlock(&lock); 276 277 if (!value_str) 278 return 0; 279 280 size_t value_len = strlen(value_str); 281 return ((value_len % 2) != 0) ? 0 : (value_len / 2); 282 } 283 284 bool btif_config_set_bin(const char *section, const char *key, const uint8_t *value, size_t length) { 285 const char *lookup = "0123456789abcdef"; 286 287 assert(config != NULL); 288 assert(section != NULL); 289 assert(key != NULL); 290 291 if (length > 0) 292 assert(value != NULL); 293 294 char *str = (char *)osi_calloc(length * 2 + 1); 295 if (!str) 296 return false; 297 298 for (size_t i = 0; i < length; ++i) { 299 str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F]; 300 str[(i * 2) + 1] = lookup[value[i] & 0x0F]; 301 } 302 303 pthread_mutex_lock(&lock); 304 config_set_string(config, section, key, str); 305 pthread_mutex_unlock(&lock); 306 307 osi_free(str); 308 return true; 309 } 310 311 const btif_config_section_iter_t *btif_config_section_begin(void) { 312 assert(config != NULL); 313 return (const btif_config_section_iter_t *)config_section_begin(config); 314 } 315 316 const btif_config_section_iter_t *btif_config_section_end(void) { 317 assert(config != NULL); 318 return (const btif_config_section_iter_t *)config_section_end(config); 319 } 320 321 const btif_config_section_iter_t *btif_config_section_next(const btif_config_section_iter_t *section) { 322 assert(config != NULL); 323 assert(section != NULL); 324 return (const btif_config_section_iter_t *)config_section_next((const config_section_node_t *)section); 325 } 326 327 const char *btif_config_section_name(const btif_config_section_iter_t *section) { 328 assert(config != NULL); 329 assert(section != NULL); 330 return config_section_name((const config_section_node_t *)section); 331 } 332 333 bool btif_config_remove(const char *section, const char *key) { 334 assert(config != NULL); 335 assert(section != NULL); 336 assert(key != NULL); 337 338 pthread_mutex_lock(&lock); 339 bool ret = config_remove_key(config, section, key); 340 pthread_mutex_unlock(&lock); 341 342 return ret; 343 } 344 345 void btif_config_save(void) { 346 assert(alarm_timer != NULL); 347 assert(config != NULL); 348 349 alarm_set(alarm_timer, CONFIG_SETTLE_PERIOD_MS, timer_config_save, NULL); 350 } 351 352 void btif_config_flush(void) { 353 assert(config != NULL); 354 assert(alarm_timer != NULL); 355 356 alarm_cancel(alarm_timer); 357 358 pthread_mutex_lock(&lock); 359 config_save(config, CONFIG_FILE_PATH); 360 pthread_mutex_unlock(&lock); 361 } 362 363 int btif_config_clear(void){ 364 assert(config != NULL); 365 assert(alarm_timer != NULL); 366 367 alarm_cancel(alarm_timer); 368 369 pthread_mutex_lock(&lock); 370 config_free(config); 371 372 config = config_new_empty(); 373 if (config == NULL) { 374 pthread_mutex_unlock(&lock); 375 return false; 376 } 377 378 int ret = config_save(config, CONFIG_FILE_PATH); 379 pthread_mutex_unlock(&lock); 380 return ret; 381 } 382 383 static void timer_config_save(UNUSED_ATTR void *data) { 384 assert(config != NULL); 385 assert(alarm_timer != NULL); 386 387 // Garbage collection process: the config file accumulates 388 // cached information about remote devices during regular 389 // inquiry scans. We remove some of these junk entries 390 // so the file doesn't grow indefinitely. We have to take care 391 // to make sure we don't remove information about bonded 392 // devices (hence the check for link keys). 393 static const size_t CACHE_MAX = 256; 394 const char *keys[CACHE_MAX]; 395 size_t num_keys = 0; 396 size_t total_candidates = 0; 397 398 pthread_mutex_lock(&lock); 399 for (const config_section_node_t *snode = config_section_begin(config); snode != config_section_end(config); snode = config_section_next(snode)) { 400 const char *section = config_section_name(snode); 401 if (!string_is_bdaddr(section)) 402 continue; 403 404 if (config_has_key(config, section, "LinkKey") || 405 config_has_key(config, section, "LE_KEY_PENC") || 406 config_has_key(config, section, "LE_KEY_PID") || 407 config_has_key(config, section, "LE_KEY_PCSRK") || 408 config_has_key(config, section, "LE_KEY_LENC") || 409 config_has_key(config, section, "LE_KEY_LCSRK")) 410 continue; 411 412 if (num_keys < CACHE_MAX) 413 keys[num_keys++] = section; 414 415 ++total_candidates; 416 } 417 418 if (total_candidates > CACHE_MAX * 2) 419 while (num_keys > 0) 420 config_remove_section(config, keys[--num_keys]); 421 422 config_save(config, CONFIG_FILE_PATH); 423 pthread_mutex_unlock(&lock); 424 } 425