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