OSDN Git Service

Add config source to dumpsys output
[android-x86/system-bt.git] / btif / src / btif_config.c
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 <unistd.h>
29
30 #include "bt_types.h"
31 #include "btcore/include/bdaddr.h"
32 #include "btcore/include/module.h"
33 #include "btif_common.h"
34 #include "btif_config.h"
35 #include "btif_util.h"
36 #include "osi/include/alarm.h"
37 #include "osi/include/allocator.h"
38 #include "osi/include/compat.h"
39 #include "osi/include/config.h"
40 #include "osi/include/log.h"
41 #include "osi/include/osi.h"
42
43 // TODO(armansito): Find a better way than searching by a hardcoded path.
44 #if defined(OS_GENERIC)
45 static const char *CONFIG_FILE_PATH = "bt_config.conf";
46 static const char *CONFIG_BACKUP_PATH = "bt_config.bak";
47 #else  // !defined(OS_GENERIC)
48 static const char *CONFIG_FILE_PATH = "/data/misc/bluedroid/bt_config.conf";
49 static const char *CONFIG_BACKUP_PATH = "/data/misc/bluedroid/bt_config.bak";
50 #endif  // defined(OS_GENERIC)
51 static const period_ms_t CONFIG_SETTLE_PERIOD_MS = 3000;
52
53 static void timer_config_save_cb(void *data);
54 static void btif_config_write(UINT16 event, char *p_param);
55 static void btif_config_devcache_cleanup(void);
56
57 static enum ConfigSource {
58   NOT_LOADED,
59   ORIGINAL,
60   BACKUP,
61   NEW_FILE,
62   RESET
63 } btif_config_source = NOT_LOADED;
64
65
66 // TODO(zachoverflow): Move these two functions out, because they are too specific for this file
67 // {grumpy-cat/no, monty-python/you-make-me-sad}
68 bool btif_get_device_type(const BD_ADDR bd_addr, int *p_device_type)
69 {
70     if (p_device_type == NULL)
71         return FALSE;
72
73     bt_bdaddr_t bda;
74     bdcpy(bda.address, bd_addr);
75
76     bdstr_t bd_addr_str;
77     bdaddr_to_string(&bda, bd_addr_str, sizeof(bd_addr_str));
78
79     if (!btif_config_get_int(bd_addr_str, "DevType", p_device_type))
80         return FALSE;
81
82     LOG_DEBUG(LOG_TAG, "%s: Device [%s] type %d", __FUNCTION__, bd_addr_str, *p_device_type);
83     return TRUE;
84 }
85
86 bool btif_get_address_type(const BD_ADDR bd_addr, int *p_addr_type)
87 {
88     if (p_addr_type == NULL)
89         return FALSE;
90
91     bt_bdaddr_t bda;
92     bdcpy(bda.address, bd_addr);
93
94     bdstr_t bd_addr_str;
95     bdaddr_to_string(&bda, bd_addr_str, sizeof(bd_addr_str));
96
97     if (!btif_config_get_int(bd_addr_str, "AddrType", p_addr_type))
98         return FALSE;
99
100     LOG_DEBUG(LOG_TAG, "%s: Device [%s] address type %d", __FUNCTION__, bd_addr_str, *p_addr_type);
101     return TRUE;
102 }
103
104 static pthread_mutex_t lock;  // protects operations on |config|.
105 static config_t *config;
106 static alarm_t *config_timer;
107
108 // Module lifecycle functions
109
110 static future_t *init(void) {
111   pthread_mutex_init(&lock, NULL);
112   config = config_new(CONFIG_FILE_PATH);
113   btif_config_source = ORIGINAL;
114   if (!config) {
115     LOG_WARN(LOG_TAG, "%s unable to load config file: %s; using backup.",
116               __func__, CONFIG_FILE_PATH);
117     config = config_new(CONFIG_BACKUP_PATH);
118     btif_config_source = BACKUP;
119     if (!config) {
120       LOG_ERROR(LOG_TAG, "%s unable to load backup; creating empty config.", __func__);
121       config = config_new_empty();
122       btif_config_source = NEW_FILE;
123       if (!config) {
124         LOG_ERROR(LOG_TAG, "%s unable to allocate a config object.", __func__);
125         goto error;
126       }
127     }
128   }
129
130   btif_config_devcache_cleanup();
131
132   // TODO(sharvil): use a non-wake alarm for this once we have
133   // API support for it. There's no need to wake the system to
134   // write back to disk.
135   config_timer = alarm_new("btif.config");
136   if (!config_timer) {
137     LOG_ERROR(LOG_TAG, "%s unable to create alarm.", __func__);
138     goto error;
139   }
140
141   return future_new_immediate(FUTURE_SUCCESS);
142
143 error:
144   alarm_free(config_timer);
145   config_free(config);
146   pthread_mutex_destroy(&lock);
147   config_timer = NULL;
148   config = NULL;
149   return future_new_immediate(FUTURE_FAIL);
150 }
151
152 static future_t *shut_down(void) {
153   btif_config_flush();
154   return future_new_immediate(FUTURE_SUCCESS);
155 }
156
157 static future_t *clean_up(void) {
158   btif_config_flush();
159
160   alarm_free(config_timer);
161   config_free(config);
162   pthread_mutex_destroy(&lock);
163   config_timer = NULL;
164   config = NULL;
165   return future_new_immediate(FUTURE_SUCCESS);
166 }
167
168 EXPORT_SYMBOL const module_t btif_config_module = {
169   .name = BTIF_CONFIG_MODULE,
170   .init = init,
171   .start_up = NULL,
172   .shut_down = shut_down,
173   .clean_up = clean_up,
174   .dependencies = {
175     NULL
176   }
177 };
178
179 bool btif_config_has_section(const char *section) {
180   assert(config != NULL);
181   assert(section != NULL);
182
183   pthread_mutex_lock(&lock);
184   bool ret = config_has_section(config, section);
185   pthread_mutex_unlock(&lock);
186
187   return ret;
188 }
189
190 bool btif_config_exist(const char *section, const char *key) {
191   assert(config != NULL);
192   assert(section != NULL);
193   assert(key != NULL);
194
195   pthread_mutex_lock(&lock);
196   bool ret = config_has_key(config, section, key);
197   pthread_mutex_unlock(&lock);
198
199   return ret;
200 }
201
202 bool btif_config_get_int(const char *section, const char *key, int *value) {
203   assert(config != NULL);
204   assert(section != NULL);
205   assert(key != NULL);
206   assert(value != NULL);
207
208   pthread_mutex_lock(&lock);
209   bool ret = config_has_key(config, section, key);
210   if (ret)
211     *value = config_get_int(config, section, key, *value);
212   pthread_mutex_unlock(&lock);
213
214   return ret;
215 }
216
217 bool btif_config_set_int(const char *section, const char *key, int value) {
218   assert(config != NULL);
219   assert(section != NULL);
220   assert(key != NULL);
221
222   pthread_mutex_lock(&lock);
223   config_set_int(config, section, key, value);
224   pthread_mutex_unlock(&lock);
225
226   return true;
227 }
228
229 bool btif_config_get_str(const char *section, const char *key, char *value, int *size_bytes) {
230   assert(config != NULL);
231   assert(section != NULL);
232   assert(key != NULL);
233   assert(value != NULL);
234   assert(size_bytes != NULL);
235
236   pthread_mutex_lock(&lock);
237   const char *stored_value = config_get_string(config, section, key, NULL);
238   pthread_mutex_unlock(&lock);
239
240   if (!stored_value)
241     return false;
242
243   strlcpy(value, stored_value, *size_bytes);
244   *size_bytes = strlen(value) + 1;
245
246   return true;
247 }
248
249 bool btif_config_set_str(const char *section, const char *key, const char *value) {
250   assert(config != NULL);
251   assert(section != NULL);
252   assert(key != NULL);
253   assert(value != NULL);
254
255   pthread_mutex_lock(&lock);
256   config_set_string(config, section, key, value);
257   pthread_mutex_unlock(&lock);
258
259   return true;
260 }
261
262 bool btif_config_get_bin(const char *section, const char *key, uint8_t *value, size_t *length) {
263   assert(config != NULL);
264   assert(section != NULL);
265   assert(key != NULL);
266   assert(value != NULL);
267   assert(length != NULL);
268
269   pthread_mutex_lock(&lock);
270   const char *value_str = config_get_string(config, section, key, NULL);
271   pthread_mutex_unlock(&lock);
272
273   if (!value_str)
274     return false;
275
276   size_t value_len = strlen(value_str);
277   if ((value_len % 2) != 0 || *length < (value_len / 2))
278     return false;
279
280   for (size_t i = 0; i < value_len; ++i)
281     if (!isxdigit(value_str[i]))
282       return false;
283
284   for (*length = 0; *value_str; value_str += 2, *length += 1)
285     sscanf(value_str, "%02hhx", &value[*length]);
286
287   return true;
288 }
289
290 size_t btif_config_get_bin_length(const char *section, const char *key) {
291   assert(config != NULL);
292   assert(section != NULL);
293   assert(key != NULL);
294
295   pthread_mutex_lock(&lock);
296   const char *value_str = config_get_string(config, section, key, NULL);
297   pthread_mutex_unlock(&lock);
298
299   if (!value_str)
300     return 0;
301
302   size_t value_len = strlen(value_str);
303   return ((value_len % 2) != 0) ? 0 : (value_len / 2);
304 }
305
306 bool btif_config_set_bin(const char *section, const char *key, const uint8_t *value, size_t length) {
307   const char *lookup = "0123456789abcdef";
308
309   assert(config != NULL);
310   assert(section != NULL);
311   assert(key != NULL);
312
313   if (length > 0)
314       assert(value != NULL);
315
316   char *str = (char *)osi_calloc(length * 2 + 1);
317
318   for (size_t i = 0; i < length; ++i) {
319     str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F];
320     str[(i * 2) + 1] = lookup[value[i] & 0x0F];
321   }
322
323   pthread_mutex_lock(&lock);
324   config_set_string(config, section, key, str);
325   pthread_mutex_unlock(&lock);
326
327   osi_free(str);
328   return true;
329 }
330
331 const btif_config_section_iter_t *btif_config_section_begin(void) {
332   assert(config != NULL);
333   return (const btif_config_section_iter_t *)config_section_begin(config);
334 }
335
336 const btif_config_section_iter_t *btif_config_section_end(void) {
337   assert(config != NULL);
338   return (const btif_config_section_iter_t *)config_section_end(config);
339 }
340
341 const btif_config_section_iter_t *btif_config_section_next(const btif_config_section_iter_t *section) {
342   assert(config != NULL);
343   assert(section != NULL);
344   return (const btif_config_section_iter_t *)config_section_next((const config_section_node_t *)section);
345 }
346
347 const char *btif_config_section_name(const btif_config_section_iter_t *section) {
348   assert(config != NULL);
349   assert(section != NULL);
350   return config_section_name((const config_section_node_t *)section);
351 }
352
353 bool btif_config_remove(const char *section, const char *key) {
354   assert(config != NULL);
355   assert(section != NULL);
356   assert(key != NULL);
357
358   pthread_mutex_lock(&lock);
359   bool ret = config_remove_key(config, section, key);
360   pthread_mutex_unlock(&lock);
361
362   return ret;
363 }
364
365 void btif_config_save(void) {
366   assert(config_timer != NULL);
367   assert(config != NULL);
368
369   alarm_set(config_timer, CONFIG_SETTLE_PERIOD_MS, timer_config_save_cb, NULL);
370 }
371
372 void btif_config_flush(void) {
373   assert(config != NULL);
374   assert(config_timer != NULL);
375
376   alarm_cancel(config_timer);
377   btif_config_write(0, NULL);
378
379   pthread_mutex_lock(&lock);
380   config_save(config, CONFIG_FILE_PATH);
381   pthread_mutex_unlock(&lock);
382 }
383
384 bool btif_config_clear(void){
385   assert(config != NULL);
386   assert(config_timer != NULL);
387
388   alarm_cancel(config_timer);
389
390   pthread_mutex_lock(&lock);
391   config_free(config);
392
393   config = config_new_empty();
394   if (config == NULL) {
395     pthread_mutex_unlock(&lock);
396     return false;
397   }
398
399   bool ret = config_save(config, CONFIG_FILE_PATH);
400   btif_config_source = RESET;
401   pthread_mutex_unlock(&lock);
402   return ret;
403 }
404
405 static void timer_config_save_cb(UNUSED_ATTR void *data) {
406   // Moving file I/O to btif context instead of timer callback because
407   // it usually takes a lot of time to be completed, introducing
408   // delays during A2DP playback causing blips or choppiness.
409   btif_transfer_context(btif_config_write, 0, NULL, 0, NULL);
410 }
411
412 static void btif_config_write(UNUSED_ATTR UINT16 event, UNUSED_ATTR char *p_param) {
413   assert(config != NULL);
414   assert(config_timer != NULL);
415
416   btif_config_devcache_cleanup();
417
418   pthread_mutex_lock(&lock);
419   rename(CONFIG_FILE_PATH, CONFIG_BACKUP_PATH);
420   config_save(config, CONFIG_FILE_PATH);
421   pthread_mutex_unlock(&lock);
422 }
423
424 static void btif_config_devcache_cleanup(void) {
425   assert(config != NULL);
426
427   // The config accumulates cached information about remote
428   // devices during regular inquiry scans. We remove some of these
429   // so the cache doesn't grow indefinitely.
430   // We don't remove information about bonded devices (which have link keys).
431   static const size_t ADDRS_MAX = 512;
432   size_t total_addrs = 0;
433
434   pthread_mutex_lock(&lock);
435   const config_section_node_t *snode = config_section_begin(config);
436   while (snode != config_section_end(config)) {
437     const char *section = config_section_name(snode);
438     if (string_is_bdaddr(section)) {
439       ++total_addrs;
440
441       if ((total_addrs > ADDRS_MAX) &&
442           !config_has_key(config, section, "LinkKey") &&
443           !config_has_key(config, section, "LE_KEY_PENC") &&
444           !config_has_key(config, section, "LE_KEY_PID") &&
445           !config_has_key(config, section, "LE_KEY_PCSRK") &&
446           !config_has_key(config, section, "LE_KEY_LENC") &&
447           !config_has_key(config, section, "LE_KEY_LCSRK")) {
448         snode = config_section_next(snode);
449         config_remove_section(config, section);
450         continue;
451       }
452     }
453     snode = config_section_next(snode);
454   }
455   pthread_mutex_unlock(&lock);
456 }
457
458 void btif_debug_config_dump(int fd) {
459     pthread_mutex_lock(&lock);
460
461     dprintf(fd, "\nBluetooth Config:\n");
462
463     dprintf(fd, "  Config Source: ");
464     switch(btif_config_source) {
465         case NOT_LOADED:
466             dprintf(fd, "Not loaded\n");
467             break;
468         case ORIGINAL:
469             dprintf(fd, "Original file\n");
470             break;
471         case BACKUP:
472             dprintf(fd, "Backup file\n");
473             break;
474         case NEW_FILE:
475             dprintf(fd, "New file\n");
476             break;
477         case RESET:
478             dprintf(fd, "Reset file\n");
479             break;
480     }
481
482     pthread_mutex_unlock(&lock);
483 }