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