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