btif_config.cc revision 646134e0a04459f649cb50aa9f3272054630c345
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 "btif_config.h" 22 23#include <assert.h> 24#include <ctype.h> 25#include <pthread.h> 26#include <stdio.h> 27#include <string.h> 28#include <time.h> 29#include <unistd.h> 30 31#include "bt_types.h" 32#include "btcore/include/bdaddr.h" 33#include "btcore/include/module.h" 34#include "btif_api.h" 35#include "btif_common.h" 36#include "btif_config.h" 37#include "btif_config_transcode.h" 38#include "btif_util.h" 39#include "osi/include/alarm.h" 40#include "osi/include/allocator.h" 41#include "osi/include/compat.h" 42#include "osi/include/config.h" 43#include "osi/include/log.h" 44#include "osi/include/osi.h" 45#include "osi/include/properties.h" 46 47#define INFO_SECTION "Info" 48#define FILE_TIMESTAMP "TimeCreated" 49#define TIME_STRING_LENGTH sizeof("YYYY-MM-DD HH:MM:SS") 50static const char* TIME_STRING_FORMAT = "%Y-%m-%d %H:%M:%S"; 51 52// TODO(armansito): Find a better way than searching by a hardcoded path. 53#if defined(OS_GENERIC) 54static const char *CONFIG_FILE_PATH = "bt_config.conf"; 55static const char *CONFIG_BACKUP_PATH = "bt_config.bak"; 56static const char *CONFIG_LEGACY_FILE_PATH = "bt_config.xml"; 57#else // !defined(OS_GENERIC) 58static const char *CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf"; 59static const char *CONFIG_BACKUP_PATH = "/data/misc/bluedroid/bt_config.bak"; 60static const char *CONFIG_LEGACY_FILE_PATH = "/data/misc/bluedroid/bt_config.xml"; 61#endif // defined(OS_GENERIC) 62static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 3000; 63 64static void timer_config_save_cb(void *data); 65static void btif_config_write(UINT16 event, char *p_param); 66static bool is_factory_reset(void); 67static void delete_config_files(void); 68static void btif_config_remove_unpaired(config_t *config); 69static void btif_config_remove_restricted(config_t *config); 70 71static enum ConfigSource { 72 NOT_LOADED, 73 ORIGINAL, 74 BACKUP, 75 LEGACY, 76 NEW_FILE, 77 RESET 78} btif_config_source = NOT_LOADED; 79 80static int btif_config_devices_loaded = -1; 81static char btif_config_time_created[TIME_STRING_LENGTH]; 82 83// TODO(zachoverflow): Move these two functions out, because they are too specific for this file 84// {grumpy-cat/no, monty-python/you-make-me-sad} 85bool btif_get_device_type(const BD_ADDR bd_addr, int *p_device_type) 86{ 87 if (p_device_type == NULL) 88 return FALSE; 89 90 bt_bdaddr_t bda; 91 bdcpy(bda.address, bd_addr); 92 93 bdstr_t bd_addr_str; 94 bdaddr_to_string(&bda, bd_addr_str, sizeof(bd_addr_str)); 95 96 if (!btif_config_get_int(bd_addr_str, "DevType", p_device_type)) 97 return FALSE; 98 99 LOG_DEBUG(LOG_TAG, "%s: Device [%s] type %d", __FUNCTION__, bd_addr_str, *p_device_type); 100 return TRUE; 101} 102 103bool btif_get_address_type(const BD_ADDR bd_addr, int *p_addr_type) 104{ 105 if (p_addr_type == NULL) 106 return FALSE; 107 108 bt_bdaddr_t bda; 109 bdcpy(bda.address, bd_addr); 110 111 bdstr_t bd_addr_str; 112 bdaddr_to_string(&bda, bd_addr_str, sizeof(bd_addr_str)); 113 114 if (!btif_config_get_int(bd_addr_str, "AddrType", p_addr_type)) 115 return FALSE; 116 117 LOG_DEBUG(LOG_TAG, "%s: Device [%s] address type %d", __FUNCTION__, bd_addr_str, *p_addr_type); 118 return TRUE; 119} 120 121static pthread_mutex_t lock; // protects operations on |config|. 122static config_t *config; 123static alarm_t *config_timer; 124 125// Module lifecycle functions 126 127static future_t *init(void) { 128 pthread_mutex_init(&lock, NULL); 129 pthread_mutex_lock(&lock); 130 131 if (is_factory_reset()) 132 delete_config_files(); 133 134 config = config_new(CONFIG_FILE_PATH); 135 btif_config_source = ORIGINAL; 136 if (!config) { 137 LOG_WARN(LOG_TAG, "%s unable to load config file: %s; using backup.", 138 __func__, CONFIG_FILE_PATH); 139 config = config_new(CONFIG_BACKUP_PATH); 140 btif_config_source = BACKUP; 141 } 142 if (!config) { 143 LOG_WARN(LOG_TAG, "%s unable to load backup; attempting to transcode legacy file.", __func__); 144 config = btif_config_transcode(CONFIG_LEGACY_FILE_PATH); 145 btif_config_source = LEGACY; 146 } 147 if (!config) { 148 LOG_ERROR(LOG_TAG, "%s unable to transcode legacy file; creating empty config.", __func__); 149 config = config_new_empty(); 150 btif_config_source = NEW_FILE; 151 } 152 if (!config) { 153 LOG_ERROR(LOG_TAG, "%s unable to allocate a config object.", __func__); 154 goto error; 155 } 156 157 btif_config_remove_unpaired(config); 158 159 // Cleanup temporary pairings if we have left guest mode 160 if (!is_restricted_mode()) 161 btif_config_remove_restricted(config); 162 163 // Read or set config file creation timestamp 164 const char* time_str = config_get_string(config, INFO_SECTION, FILE_TIMESTAMP, NULL); 165 if (time_str != NULL) { 166 strlcpy(btif_config_time_created, time_str, TIME_STRING_LENGTH); 167 } else { 168 time_t current_time = time(NULL); 169 struct tm* time_created = localtime(¤t_time); 170 strftime(btif_config_time_created, TIME_STRING_LENGTH, TIME_STRING_FORMAT, time_created); 171 config_set_string(config, INFO_SECTION, FILE_TIMESTAMP, btif_config_time_created); 172 } 173 174 // TODO(sharvil): use a non-wake alarm for this once we have 175 // API support for it. There's no need to wake the system to 176 // write back to disk. 177 config_timer = alarm_new("btif.config"); 178 if (!config_timer) { 179 LOG_ERROR(LOG_TAG, "%s unable to create alarm.", __func__); 180 goto error; 181 } 182 183 pthread_mutex_unlock(&lock); 184 return future_new_immediate(FUTURE_SUCCESS); 185 186error: 187 alarm_free(config_timer); 188 config_free(config); 189 pthread_mutex_unlock(&lock); 190 pthread_mutex_destroy(&lock); 191 config_timer = NULL; 192 config = NULL; 193 btif_config_source = NOT_LOADED; 194 return future_new_immediate(FUTURE_FAIL); 195} 196 197static future_t *shut_down(void) { 198 btif_config_flush(); 199 return future_new_immediate(FUTURE_SUCCESS); 200} 201 202static future_t *clean_up(void) { 203 btif_config_flush(); 204 205 alarm_free(config_timer); 206 config_free(config); 207 pthread_mutex_destroy(&lock); 208 config_timer = NULL; 209 config = NULL; 210 return future_new_immediate(FUTURE_SUCCESS); 211} 212 213EXPORT_SYMBOL const module_t btif_config_module = { 214 .name = BTIF_CONFIG_MODULE, 215 .init = init, 216 .start_up = NULL, 217 .shut_down = shut_down, 218 .clean_up = clean_up, 219 .dependencies = { 220 NULL 221 } 222}; 223 224bool btif_config_has_section(const char *section) { 225 assert(config != NULL); 226 assert(section != NULL); 227 228 pthread_mutex_lock(&lock); 229 bool ret = config_has_section(config, section); 230 pthread_mutex_unlock(&lock); 231 232 return ret; 233} 234 235bool btif_config_exist(const char *section, const char *key) { 236 assert(config != NULL); 237 assert(section != NULL); 238 assert(key != NULL); 239 240 pthread_mutex_lock(&lock); 241 bool ret = config_has_key(config, section, key); 242 pthread_mutex_unlock(&lock); 243 244 return ret; 245} 246 247bool btif_config_get_int(const char *section, const char *key, int *value) { 248 assert(config != NULL); 249 assert(section != NULL); 250 assert(key != NULL); 251 assert(value != NULL); 252 253 pthread_mutex_lock(&lock); 254 bool ret = config_has_key(config, section, key); 255 if (ret) 256 *value = config_get_int(config, section, key, *value); 257 pthread_mutex_unlock(&lock); 258 259 return ret; 260} 261 262bool btif_config_set_int(const char *section, const char *key, int value) { 263 assert(config != NULL); 264 assert(section != NULL); 265 assert(key != NULL); 266 267 pthread_mutex_lock(&lock); 268 config_set_int(config, section, key, value); 269 pthread_mutex_unlock(&lock); 270 271 return true; 272} 273 274bool btif_config_get_str(const char *section, const char *key, char *value, int *size_bytes) { 275 assert(config != NULL); 276 assert(section != NULL); 277 assert(key != NULL); 278 assert(value != NULL); 279 assert(size_bytes != NULL); 280 281 pthread_mutex_lock(&lock); 282 const char *stored_value = config_get_string(config, section, key, NULL); 283 pthread_mutex_unlock(&lock); 284 285 if (!stored_value) 286 return false; 287 288 strlcpy(value, stored_value, *size_bytes); 289 *size_bytes = strlen(value) + 1; 290 291 return true; 292} 293 294bool btif_config_set_str(const char *section, const char *key, const char *value) { 295 assert(config != NULL); 296 assert(section != NULL); 297 assert(key != NULL); 298 assert(value != NULL); 299 300 pthread_mutex_lock(&lock); 301 config_set_string(config, section, key, value); 302 pthread_mutex_unlock(&lock); 303 304 return true; 305} 306 307bool btif_config_get_bin(const char *section, const char *key, uint8_t *value, size_t *length) { 308 assert(config != NULL); 309 assert(section != NULL); 310 assert(key != NULL); 311 assert(value != NULL); 312 assert(length != NULL); 313 314 pthread_mutex_lock(&lock); 315 const char *value_str = config_get_string(config, section, key, NULL); 316 pthread_mutex_unlock(&lock); 317 318 if (!value_str) 319 return false; 320 321 size_t value_len = strlen(value_str); 322 if ((value_len % 2) != 0 || *length < (value_len / 2)) 323 return false; 324 325 for (size_t i = 0; i < value_len; ++i) 326 if (!isxdigit(value_str[i])) 327 return false; 328 329 for (*length = 0; *value_str; value_str += 2, *length += 1) 330 sscanf(value_str, "%02hhx", &value[*length]); 331 332 return true; 333} 334 335size_t btif_config_get_bin_length(const char *section, const char *key) { 336 assert(config != NULL); 337 assert(section != NULL); 338 assert(key != NULL); 339 340 pthread_mutex_lock(&lock); 341 const char *value_str = config_get_string(config, section, key, NULL); 342 pthread_mutex_unlock(&lock); 343 344 if (!value_str) 345 return 0; 346 347 size_t value_len = strlen(value_str); 348 return ((value_len % 2) != 0) ? 0 : (value_len / 2); 349} 350 351bool btif_config_set_bin(const char *section, const char *key, const uint8_t *value, size_t length) { 352 const char *lookup = "0123456789abcdef"; 353 354 assert(config != NULL); 355 assert(section != NULL); 356 assert(key != NULL); 357 358 if (length > 0) 359 assert(value != NULL); 360 361 char *str = (char *)osi_calloc(length * 2 + 1); 362 363 for (size_t i = 0; i < length; ++i) { 364 str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F]; 365 str[(i * 2) + 1] = lookup[value[i] & 0x0F]; 366 } 367 368 pthread_mutex_lock(&lock); 369 config_set_string(config, section, key, str); 370 pthread_mutex_unlock(&lock); 371 372 osi_free(str); 373 return true; 374} 375 376const btif_config_section_iter_t *btif_config_section_begin(void) { 377 assert(config != NULL); 378 return (const btif_config_section_iter_t *)config_section_begin(config); 379} 380 381const btif_config_section_iter_t *btif_config_section_end(void) { 382 assert(config != NULL); 383 return (const btif_config_section_iter_t *)config_section_end(config); 384} 385 386const btif_config_section_iter_t *btif_config_section_next(const btif_config_section_iter_t *section) { 387 assert(config != NULL); 388 assert(section != NULL); 389 return (const btif_config_section_iter_t *)config_section_next((const config_section_node_t *)section); 390} 391 392const char *btif_config_section_name(const btif_config_section_iter_t *section) { 393 assert(config != NULL); 394 assert(section != NULL); 395 return config_section_name((const config_section_node_t *)section); 396} 397 398bool btif_config_remove(const char *section, const char *key) { 399 assert(config != NULL); 400 assert(section != NULL); 401 assert(key != NULL); 402 403 pthread_mutex_lock(&lock); 404 bool ret = config_remove_key(config, section, key); 405 pthread_mutex_unlock(&lock); 406 407 return ret; 408} 409 410void btif_config_save(void) { 411 assert(config != NULL); 412 assert(config_timer != NULL); 413 414 alarm_set(config_timer, CONFIG_SETTLE_PERIOD_MS, timer_config_save_cb, NULL); 415} 416 417void btif_config_flush(void) { 418 assert(config != NULL); 419 assert(config_timer != NULL); 420 421 alarm_cancel(config_timer); 422 btif_config_write(0, NULL); 423} 424 425bool btif_config_clear(void) { 426 assert(config != NULL); 427 assert(config_timer != NULL); 428 429 alarm_cancel(config_timer); 430 431 pthread_mutex_lock(&lock); 432 config_free(config); 433 434 config = config_new_empty(); 435 if (config == NULL) { 436 pthread_mutex_unlock(&lock); 437 return false; 438 } 439 440 bool ret = config_save(config, CONFIG_FILE_PATH); 441 btif_config_source = RESET; 442 pthread_mutex_unlock(&lock); 443 return ret; 444} 445 446static void timer_config_save_cb(UNUSED_ATTR void *data) { 447 // Moving file I/O to btif context instead of timer callback because 448 // it usually takes a lot of time to be completed, introducing 449 // delays during A2DP playback causing blips or choppiness. 450 btif_transfer_context(btif_config_write, 0, NULL, 0, NULL); 451} 452 453static void btif_config_write(UNUSED_ATTR UINT16 event, UNUSED_ATTR char *p_param) { 454 assert(config != NULL); 455 assert(config_timer != NULL); 456 457 pthread_mutex_lock(&lock); 458 rename(CONFIG_FILE_PATH, CONFIG_BACKUP_PATH); 459 sync(); 460 config_t *config_paired = config_new_clone(config); 461 btif_config_remove_unpaired(config_paired); 462 config_save(config_paired, CONFIG_FILE_PATH); 463 config_free(config_paired); 464 pthread_mutex_unlock(&lock); 465} 466 467static void btif_config_remove_unpaired(config_t *conf) { 468 assert(conf != NULL); 469 int paired_devices = 0; 470 471 // The paired config used to carry information about 472 // discovered devices during regular inquiry scans. 473 // We remove these now and cache them in memory instead. 474 const config_section_node_t *snode = config_section_begin(conf); 475 while (snode != config_section_end(conf)) { 476 const char *section = config_section_name(snode); 477 if (string_is_bdaddr(section)) { 478 if (!config_has_key(conf, section, "LinkKey") && 479 !config_has_key(conf, section, "LE_KEY_PENC") && 480 !config_has_key(conf, section, "LE_KEY_PID") && 481 !config_has_key(conf, section, "LE_KEY_PCSRK") && 482 !config_has_key(conf, section, "LE_KEY_LENC") && 483 !config_has_key(conf, section, "LE_KEY_LCSRK")) { 484 snode = config_section_next(snode); 485 config_remove_section(conf, section); 486 continue; 487 } 488 paired_devices++; 489 } 490 snode = config_section_next(snode); 491 } 492 493 // should only happen once, at initial load time 494 if (btif_config_devices_loaded == -1) 495 btif_config_devices_loaded = paired_devices; 496} 497 498void btif_debug_config_dump(int fd) { 499 dprintf(fd, "\nBluetooth Config:\n"); 500 501 dprintf(fd, " Config Source: "); 502 switch(btif_config_source) { 503 case NOT_LOADED: 504 dprintf(fd, "Not loaded\n"); 505 break; 506 case ORIGINAL: 507 dprintf(fd, "Original file\n"); 508 break; 509 case BACKUP: 510 dprintf(fd, "Backup file\n"); 511 break; 512 case LEGACY: 513 dprintf(fd, "Legacy file\n"); 514 break; 515 case NEW_FILE: 516 dprintf(fd, "New file\n"); 517 break; 518 case RESET: 519 dprintf(fd, "Reset file\n"); 520 break; 521 } 522 523 dprintf(fd, " Devices loaded: %d\n", btif_config_devices_loaded); 524 dprintf(fd, " File created/tagged: %s\n", btif_config_time_created); 525} 526 527static void btif_config_remove_restricted(config_t* config) { 528 assert(config != NULL); 529 530 const config_section_node_t *snode = config_section_begin(config); 531 while (snode != config_section_end(config)) { 532 const char *section = config_section_name(snode); 533 if (string_is_bdaddr(section) && config_has_key(config, section, "Restricted")) { 534 BTIF_TRACE_DEBUG("%s: Removing restricted device %s", __func__, section); 535 config_remove_section(config, section); 536 } 537 snode = config_section_next(snode); 538 } 539} 540 541static bool is_factory_reset(void) { 542 char factory_reset[PROPERTY_VALUE_MAX] = {0}; 543 osi_property_get("persist.bluetooth.factoryreset", factory_reset, "false"); 544 return strncmp(factory_reset, "true", 4) == 0; 545} 546 547static void delete_config_files(void) { 548 remove(CONFIG_FILE_PATH); 549 remove(CONFIG_BACKUP_PATH); 550 osi_property_set("persist.bluetooth.factoryreset", "false"); 551} 552