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")
61static 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)
65static const char *CONFIG_FILE_PATH = "bt_config.conf";
66static const char *CONFIG_BACKUP_PATH = "bt_config.bak";
67static const char *CONFIG_LEGACY_FILE_PATH = "bt_config.xml";
68#else  // !defined(OS_GENERIC)
69static const char *CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf";
70static const char *CONFIG_BACKUP_PATH = "/data/misc/bluedroid/bt_config.bak";
71static const char *CONFIG_LEGACY_FILE_PATH = "/data/misc/bluedroid/bt_config.xml";
72#endif  // defined(OS_GENERIC)
73static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 3000;
74
75static void timer_config_save_cb(void *data);
76static void btif_config_write(UINT16 event, char *p_param);
77static bool is_factory_reset(void);
78static void delete_config_files(void);
79static void btif_config_remove_unpaired(config_t *config);
80static void btif_config_remove_restricted(config_t *config);
81static config_t *btif_config_open(const char* filename);
82
83static enum ConfigSource {
84  NOT_LOADED,
85  ORIGINAL,
86  BACKUP,
87  LEGACY,
88  NEW_FILE,
89  RESET
90} btif_config_source = NOT_LOADED;
91
92static int btif_config_devices_loaded = -1;
93static 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}
97bool 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
115bool 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
133static pthread_mutex_t lock;  // protects operations on |config|.
134static config_t *config;
135static alarm_t *config_timer;
136
137// Module lifecycle functions
138
139static 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(&current_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
209error:
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
220static 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
234static future_t *shut_down(void) {
235  btif_config_flush();
236  return future_new_immediate(FUTURE_SUCCESS);
237}
238
239static 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
250EXPORT_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
261bool 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
272bool 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
284bool 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
299bool 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
311bool 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
331bool 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
344bool 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
372size_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
388bool 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
413const 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
418const 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
423const 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
429const 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
435bool 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
447void 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
454void 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
462bool 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
483static 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
490static 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
503static 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
534void 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
565static 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
579static 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
585static void delete_config_files(void) {
586  remove(CONFIG_FILE_PATH);
587  remove(CONFIG_BACKUP_PATH);
588  property_set("persist.bluetooth.factoryreset", "false");
589}
590