btif_config.c revision 9d52f88bfc07556cb01ab3055f5b1242c9b467aa
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#include <utils/Log.h> 27 28#include "alarm.h" 29#include "btif_config.h" 30#include "btif_config_transcode.h" 31#include "btif_util.h" 32#include "config.h" 33#include "osi.h" 34 35#include "bd.h" 36 37static const char *CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf"; 38static const char *LEGACY_CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.xml"; 39static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 3000; 40 41static void timer_config_save(void *data); 42 43// TODO(zachoverflow): Move these two functions out, because they are too specific for this file 44// {grumpy-cat/no, monty-python/you-make-me-sad} 45bool btif_get_device_type(const BD_ADDR bd_addr, int *p_device_type) 46{ 47 if (p_device_type == NULL) 48 return FALSE; 49 50 bt_bdaddr_t bda; 51 bdcpy(bda.address, bd_addr); 52 53 char bd_addr_str[18] = {0}; 54 bd2str(&bda, &bd_addr_str); 55 56 if (!btif_config_get_int(bd_addr_str, "DevType", p_device_type)) 57 return FALSE; 58 59 ALOGD("%s: Device [%s] type %d", __FUNCTION__, bd_addr_str, *p_device_type); 60 return TRUE; 61} 62 63bool btif_get_address_type(const BD_ADDR bd_addr, int *p_addr_type) 64{ 65 if (p_addr_type == NULL) 66 return FALSE; 67 68 bt_bdaddr_t bda; 69 bdcpy(bda.address, bd_addr); 70 71 char bd_addr_str[18] = {0}; 72 bd2str(&bda, &bd_addr_str); 73 74 if (!btif_config_get_int(bd_addr_str, "AddrType", p_addr_type)) 75 return FALSE; 76 77 ALOGD("%s: Device [%s] address type %d", __FUNCTION__, bd_addr_str, *p_addr_type); 78 return TRUE; 79} 80 81static pthread_mutex_t lock; // protects operations on |config|. 82static config_t *config; 83static alarm_t *alarm_timer; 84 85bool btif_config_init(void) { 86 pthread_mutex_init(&lock, NULL); 87 config = config_new(CONFIG_FILE_PATH); 88 if (!config) { 89 ALOGW("%s unable to load config file; attempting to transcode legacy file.", __func__); 90 config = btif_config_transcode(LEGACY_CONFIG_FILE_PATH); 91 if (!config) { 92 ALOGW("%s unable to transcode legacy file, starting unconfigured.", __func__); 93 config = config_new_empty(); 94 if (!config) { 95 ALOGE("%s unable to allocate a config object.", __func__); 96 goto error; 97 } 98 } 99 100 if (config_save(config, CONFIG_FILE_PATH)) 101 unlink(LEGACY_CONFIG_FILE_PATH); 102 } 103 104 // TODO(sharvil): use a non-wake alarm for this once we have 105 // API support for it. Threre's no need to wake the system to 106 // write back to disk. 107 alarm_timer = alarm_new(); 108 if (!alarm_timer) { 109 ALOGE("%s unable to create alarm.", __func__); 110 goto error; 111 } 112 113 return true; 114 115error:; 116 alarm_free(alarm_timer); 117 config_free(config); 118 pthread_mutex_destroy(&lock); 119 alarm_timer = NULL; 120 config = NULL; 121 return false; 122} 123 124void btif_config_cleanup(void) { 125 btif_config_flush(); 126 127 alarm_free(alarm_timer); 128 config_free(config); 129 pthread_mutex_destroy(&lock); 130 alarm_timer = NULL; 131 config = NULL; 132} 133 134bool btif_config_has_section(const char *section) { 135 assert(config != NULL); 136 assert(section != NULL); 137 138 pthread_mutex_lock(&lock); 139 bool ret = config_has_section(config, section); 140 pthread_mutex_unlock(&lock); 141 142 return ret; 143} 144 145bool btif_config_exist(const char *section, const char *key) { 146 assert(config != NULL); 147 assert(section != NULL); 148 assert(key != NULL); 149 150 pthread_mutex_lock(&lock); 151 bool ret = config_has_key(config, section, key); 152 pthread_mutex_unlock(&lock); 153 154 return ret; 155} 156 157bool btif_config_get_int(const char *section, const char *key, int *value) { 158 assert(config != NULL); 159 assert(section != NULL); 160 assert(key != NULL); 161 assert(value != NULL); 162 163 pthread_mutex_lock(&lock); 164 bool ret = config_has_key(config, section, key); 165 if (ret) 166 *value = config_get_int(config, section, key, *value); 167 pthread_mutex_unlock(&lock); 168 169 return ret; 170} 171 172bool btif_config_set_int(const char *section, const char *key, int value) { 173 assert(config != NULL); 174 assert(section != NULL); 175 assert(key != NULL); 176 177 pthread_mutex_lock(&lock); 178 config_set_int(config, section, key, value); 179 pthread_mutex_unlock(&lock); 180 181 return true; 182} 183 184bool btif_config_get_str(const char *section, const char *key, char *value, int *length) { 185 assert(config != NULL); 186 assert(section != NULL); 187 assert(key != NULL); 188 assert(value != NULL); 189 assert(length != NULL); 190 191 pthread_mutex_lock(&lock); 192 const char *stored_value = config_get_string(config, section, key, NULL); 193 pthread_mutex_unlock(&lock); 194 195 if (!stored_value) 196 return false; 197 198 strlcpy(value, stored_value, *length); 199 *length = strlen(value); 200 201 return true; 202} 203 204bool btif_config_set_str(const char *section, const char *key, const char *value) { 205 assert(config != NULL); 206 assert(section != NULL); 207 assert(key != NULL); 208 assert(value != NULL); 209 210 pthread_mutex_lock(&lock); 211 config_set_string(config, section, key, value); 212 pthread_mutex_unlock(&lock); 213 214 return true; 215} 216 217bool btif_config_get_bin(const char *section, const char *key, uint8_t *value, size_t *length) { 218 assert(config != NULL); 219 assert(section != NULL); 220 assert(key != NULL); 221 assert(value != NULL); 222 assert(length != NULL); 223 224 pthread_mutex_lock(&lock); 225 const char *value_str = config_get_string(config, section, key, NULL); 226 pthread_mutex_unlock(&lock); 227 228 if (!value_str) 229 return false; 230 231 size_t value_len = strlen(value_str); 232 if ((value_len % 2) != 0 || *length < (value_len / 2)) 233 return false; 234 235 for (size_t i = 0; i < value_len; ++i) 236 if (!isxdigit(value_str[i])) 237 return false; 238 239 for (*length = 0; *value_str; value_str += 2, *length += 1) 240 sscanf(value_str, "%02hhx", &value[*length]); 241 242 return true; 243} 244 245size_t btif_config_get_bin_length(const char *section, const char *key) { 246 assert(config != NULL); 247 assert(section != NULL); 248 assert(key != NULL); 249 250 pthread_mutex_lock(&lock); 251 const char *value_str = config_get_string(config, section, key, NULL); 252 pthread_mutex_unlock(&lock); 253 254 if (!value_str) 255 return 0; 256 257 size_t value_len = strlen(value_str); 258 return ((value_len % 2) != 0) ? 0 : (value_len / 2); 259} 260 261bool btif_config_set_bin(const char *section, const char *key, const uint8_t *value, size_t length) { 262 static const char *lookup = "0123456789abcdef"; 263 264 assert(config != NULL); 265 assert(section != NULL); 266 assert(key != NULL); 267 assert(value != NULL); 268 269 char *str = (char *)calloc(length * 2 + 1, 1); 270 if (!str) 271 return false; 272 273 for (size_t i = 0; i < length; ++i) { 274 str[(i * 2) + 0] = lookup[(value[i] >> 0) & 0x0F]; 275 str[(i * 2) + 1] = lookup[(value[i] >> 4) & 0x0F]; 276 } 277 278 pthread_mutex_lock(&lock); 279 config_set_string(config, section, key, str); 280 pthread_mutex_unlock(&lock); 281 282 free(str); 283 return true; 284} 285 286const btif_config_section_iter_t *btif_config_section_begin(void) { 287 assert(config != NULL); 288 return (const btif_config_section_iter_t *)config_section_begin(config); 289} 290 291const btif_config_section_iter_t *btif_config_section_end(void) { 292 assert(config != NULL); 293 return (const btif_config_section_iter_t *)config_section_end(config); 294} 295 296const btif_config_section_iter_t *btif_config_section_next(const btif_config_section_iter_t *section) { 297 assert(config != NULL); 298 assert(section != NULL); 299 return (const btif_config_section_iter_t *)config_section_next((const config_section_node_t *)section); 300} 301 302const char *btif_config_section_name(const btif_config_section_iter_t *section) { 303 assert(config != NULL); 304 assert(section != NULL); 305 return config_section_name((const config_section_node_t *)section); 306} 307 308bool btif_config_remove(const char *section, const char *key) { 309 assert(config != NULL); 310 assert(section != NULL); 311 assert(key != NULL); 312 313 pthread_mutex_lock(&lock); 314 bool ret = config_remove_key(config, section, key); 315 pthread_mutex_unlock(&lock); 316 317 return ret; 318} 319 320void btif_config_save(void) { 321 assert(alarm_timer != NULL); 322 assert(config != NULL); 323 324 alarm_set(alarm_timer, CONFIG_SETTLE_PERIOD_MS, timer_config_save, NULL); 325} 326 327void btif_config_flush(void) { 328 assert(config != NULL); 329 assert(alarm_timer != NULL); 330 331 alarm_cancel(alarm_timer); 332 333 pthread_mutex_lock(&lock); 334 config_save(config, CONFIG_FILE_PATH); 335 pthread_mutex_unlock(&lock); 336} 337 338static void timer_config_save(UNUSED_ATTR void *data) { 339 assert(config != NULL); 340 assert(alarm_timer != NULL); 341 342 // Garbage collection process: the config file accumulates 343 // cached information about remote devices during regular 344 // inquiry scans. We remove some of these junk entries 345 // so the file doesn't grow indefinitely. We have to take care 346 // to make sure we don't remove information about bonded 347 // devices (hence the check for link keys). 348 static const size_t CACHE_MAX = 256; 349 const char *keys[CACHE_MAX]; 350 size_t num_keys = 0; 351 size_t total_candidates = 0; 352 353 pthread_mutex_lock(&lock); 354 for (const config_section_node_t *snode = config_section_begin(config); snode != config_section_end(config); snode = config_section_next(snode)) { 355 const char *section = config_section_name(snode); 356 if (!str_is_bdaddr(section)) 357 continue; 358 359 if (config_has_key(config, section, "LinkKey") || 360 config_has_key(config, section, "LE_KEY_PENC") || 361 config_has_key(config, section, "LE_KEY_PID") || 362 config_has_key(config, section, "LE_KEY_PCSRK") || 363 config_has_key(config, section, "LE_KEY_LENC") || 364 config_has_key(config, section, "LE_KEY_LCSRK")) 365 continue; 366 367 if (num_keys < CACHE_MAX) 368 keys[num_keys++] = section; 369 370 ++total_candidates; 371 } 372 373 if (total_candidates > CACHE_MAX * 2) 374 while (num_keys > 0) 375 config_remove_section(config, keys[--num_keys]); 376 377 config_save(config, CONFIG_FILE_PATH); 378 pthread_mutex_unlock(&lock); 379} 380