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