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(&current_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