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