1 /******************************************************************************
2 *
3 * Copyright (C) 2009-2012 Broadcom Corporation
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 /************************************************************************************
20 *
21 * Filename: btif_config.c
22 *
23 * Description: Stores the local BT adapter and remote device properties in
24 * NVRAM storage, typically as xml file in the
25 * mobile's filesystem
26 *
27 *
28 ***********************************************************************************/
29 #include <stdlib.h>
30 #include <time.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stdio.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <dirent.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/mman.h>
41 #include <stdlib.h>
42 #include <private/android_filesystem_config.h>
43
44 #define LOG_TAG "btif_config"
45
46 #include <hardware/bluetooth.h>
47 #include "btif_api.h"
48 #include "btif_config.h"
49 #include "btif_config_util.h"
50 #include "btif_sock_thread.h"
51 #include "btif_sock_util.h"
52 #include "btif_util.h"
53
54 //#define UNIT_TEST
55 #define CFG_PATH "/data/misc/bluedroid/"
56 #define CFG_FILE_NAME "bt_config"
57 #define CFG_FILE_EXT ".xml"
58 #define CFG_FILE_EXT_OLD ".old"
59 #define CFG_FILE_EXT_NEW ".new"
60 #define CFG_GROW_SIZE (10*sizeof(cfg_node))
61 #define GET_CHILD_MAX_COUNT(node) (short)((int)(node)->bytes / sizeof(cfg_node))
62 #define GET_CHILD_COUNT(p) (short)((int)(p)->used / sizeof(cfg_node))
63 #define ADD_CHILD_COUNT(p, c) (p)->used += (short)((c)*sizeof(cfg_node))
64 #define DEC_CHILD_COUNT(p, c) (p)->used -= (short)((c)*sizeof(cfg_node))
65 #define GET_NODE_COUNT(bytes) (bytes / sizeof(cfg_node))
66 #define GET_NODE_BYTES(c) (c * sizeof(cfg_node))
67 #define MAX_NODE_BYTES 32000
68 #define CFG_CMD_SAVE 1
69
70 #ifndef FALSE
71 #define TRUE 1
72 #define FALSE 0
73 #endif
74 typedef struct cfg_node_s
75 {
76 const char* name;
77 union
78 {
79 struct cfg_node_s* child;
80 char* value;
81 };
82 short bytes;
83 short type;
84 short used;
85 short flag;
86 } cfg_node;
87
88 static pthread_mutex_t slot_lock;
89 static int pth = -1; //poll thread handle
90 static cfg_node root;
91 static int cached_change;
92 static int save_cmds_queued;
93 static void cfg_cmd_callback(int cmd_fd, int type, int flags, uint32_t user_id);
94 static inline short alloc_node(cfg_node* p, short grow);
95 static inline void free_node(cfg_node* p);
96 static inline short find_inode(const cfg_node* p, const char* name);
97 static cfg_node* find_node(const char* section, const char* key, const char* name);
98 static int remove_node(const char* section, const char* key, const char* name);
99 static int remove_filter_node(const char* section, const char* filter[], int filter_count, int max_allowed);
100 static inline cfg_node* find_free_node(cfg_node* p);
101 static int set_node(const char* section, const char* key, const char* name,
102 const char* value, short bytes, short type);
103 static int save_cfg();
104 static void load_cfg();
105 static short find_next_node(const cfg_node* p, short start, char* name, int* bytes);
106 #ifdef UNIT_TEST
107 static void cfg_test_load();
108 static void cfg_test_write();
109 static void cfg_test_read();
110 #endif
111 #define MY_LOG_LEVEL appl_trace_level
112 #define MY_LOG_LAYER TRACE_LAYER_NONE | TRACE_ORG_APPL
113
dump_node(const char * title,const cfg_node * p)114 static inline void dump_node(const char* title, const cfg_node* p)
115 {
116 if(p) {
117 bdld("%s, p->name:%s, child/value:%p, bytes:%d",
118 title, p->name, p->child, p->bytes);
119 bdld("p->used:%d, type:%x, p->flag:%d",
120 p->used, p->type, p->flag);
121 } else bdld("%s is NULL", title);
122 }
123
124 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
btif_config_init()125 int btif_config_init()
126 {
127 static int initialized;
128 bdld("in initialized:%d", initialized);
129 if(!initialized)
130 {
131 initialized = 1;
132 struct stat st;
133 if(stat(CFG_PATH, &st) != 0)
134 bdle("%s does not exist, need provision", CFG_PATH);
135 btsock_thread_init();
136 init_slot_lock(&slot_lock);
137 lock_slot(&slot_lock);
138 root.name = "Bluedroid";
139 alloc_node(&root, CFG_GROW_SIZE);
140 dump_node("root", &root);
141 pth = btsock_thread_create(NULL, cfg_cmd_callback);
142 load_cfg();
143 unlock_slot(&slot_lock);
144 #ifdef UNIT_TEST
145 cfg_test_write();
146 //cfg_test_read();
147 exit(0);
148 #endif
149 }
150 return pth >= 0;
151 }
btif_config_get_int(const char * section,const char * key,const char * name,int * value)152 int btif_config_get_int(const char* section, const char* key, const char* name, int* value)
153 {
154 int size = sizeof(*value);
155 int type = BTIF_CFG_TYPE_INT;
156 return btif_config_get(section, key, name, (char*)value, &size, &type);
157 }
btif_config_set_int(const char * section,const char * key,const char * name,int value)158 int btif_config_set_int(const char* section, const char* key, const char* name, int value)
159 {
160 return btif_config_set(section, key, name, (char*)&value, sizeof(value), BTIF_CFG_TYPE_INT);
161 }
btif_config_get_str(const char * section,const char * key,const char * name,char * value,int * size)162 int btif_config_get_str(const char* section, const char* key, const char* name, char* value, int* size)
163 {
164 int type = BTIF_CFG_TYPE_STR;
165 if(value)
166 *value = 0;
167 return btif_config_get(section, key, name, value, size, &type);
168 }
btif_config_set_str(const char * section,const char * key,const char * name,const char * value)169 int btif_config_set_str(const char* section, const char* key, const char* name, const char* value)
170 {
171 value = value ? value : "";
172 return btif_config_set(section, key, name, value, strlen(value) + 1, BTIF_CFG_TYPE_STR);
173 }
btif_config_exist(const char * section,const char * key,const char * name)174 int btif_config_exist(const char* section, const char* key, const char* name)
175 {
176 int ret = FALSE;
177 if(section && *section && key && *key)
178 {
179 lock_slot(&slot_lock);
180 ret = find_node(section, key, name) != NULL;
181 unlock_slot(&slot_lock);
182 }
183 return ret;
184 }
btif_config_get(const char * section,const char * key,const char * name,char * value,int * bytes,int * type)185 int btif_config_get(const char* section, const char* key, const char* name, char* value, int* bytes, int* type)
186 {
187 int ret = FALSE;
188 bdla(section && *section && key && *key && name && *name && bytes && type);
189 bdld("section:%s, key:%s, name:%s, value:%p, bytes:%d, type:%d",
190 section, key, name, value, *bytes, *type);
191 if(section && *section && key && *key && name && *name && bytes && type)
192 {
193 lock_slot(&slot_lock);
194 const cfg_node* node = find_node(section, key, name);
195 dump_node("found node", node);
196 if(node)
197 {
198 if(*type == node->type && value && *bytes >= node->used)
199 {
200 if(node->used > 0)
201 memcpy(value, node->value, node->used);
202 ret = TRUE;
203 }
204 *type = node->type;
205 *bytes = node->used;
206 if(ret != TRUE)
207 {
208 if(*type != node->type)
209 bdle("value:%s, wrong type:%d, need to be type: %d",
210 name, *type, node->type);
211 if(value && *bytes < node->used)
212 bdle("value:%s, not enough size: %d bytes, need %d bytes",
213 name, node->used, *bytes);
214 }
215 }
216 unlock_slot(&slot_lock);
217 }
218 return ret;
219 }
btif_config_set(const char * section,const char * key,const char * name,const char * value,int bytes,int type)220 int btif_config_set(const char* section, const char* key, const char* name, const char* value, int bytes, int type)
221 {
222 int ret = FALSE;
223 bdla(section && *section && key && *key && name && *name);
224 bdla(bytes < MAX_NODE_BYTES);
225 if(section && *section && key && *key && name && *name && bytes < MAX_NODE_BYTES)
226 {
227 lock_slot(&slot_lock);
228 ret = set_node(section, key, name, value, (short)bytes, (short)type);
229 if(ret && !(type & BTIF_CFG_TYPE_VOLATILE))
230 cached_change++;
231 unlock_slot(&slot_lock);
232 }
233 return ret;
234 }
btif_config_remove(const char * section,const char * key,const char * name)235 int btif_config_remove(const char* section, const char* key, const char* name)
236 {
237 bdla(section && *section && key && *key);
238 bdld("section:%s, key:%s, name:%s", section, key, name);
239 int ret = FALSE;
240 if(section && *section && key && *key)
241 {
242 lock_slot(&slot_lock);
243 ret = remove_node(section, key, name);
244 if(ret)
245 cached_change++;
246 unlock_slot(&slot_lock);
247 }
248 return ret;
249 }
250
btif_config_filter_remove(const char * section,const char * filter[],int filter_count,int max_allowed)251 int btif_config_filter_remove(const char* section, const char* filter[], int filter_count, int max_allowed)
252 {
253 bdla(section && *section && max_allowed > 0);
254 bdld("section:%s, filter:%s, filter count:%d, max allowed:%d",
255 section, filter[0], filter_count, max_allowed);
256 int ret = FALSE;
257 if(section && *section && max_allowed > 0)
258 {
259 lock_slot(&slot_lock);
260 ret = remove_filter_node(section, filter, filter_count, max_allowed);
261 if(ret)
262 cached_change++;
263 unlock_slot(&slot_lock);
264 }
265 return ret;
266 }
267 typedef struct {
268 short si;
269 short ki;
270 short vi;
271 short reserved;
272 } cfg_node_pos;
btif_config_next_key(short pos,const char * section,char * name,int * bytes)273 short btif_config_next_key(short pos, const char* section, char * name, int* bytes)
274 {
275 int next = -1;
276 lock_slot(&slot_lock);
277 short si = find_inode(&root, section);
278 if(si >= 0)
279 {
280 const cfg_node* section_node = &root.child[si];
281 next = find_next_node(section_node, pos, name, bytes);
282 }
283 unlock_slot(&slot_lock);
284 return next;
285 }
btif_config_next_value(short pos,const char * section,const char * key,char * name,int * bytes)286 short btif_config_next_value(short pos, const char* section, const char* key, char* name, int* bytes)
287 {
288 int next = -1;
289 lock_slot(&slot_lock);
290 short si = find_inode(&root, section);
291 if(si >= 0)
292 {
293 const cfg_node* section_node = &root.child[si];
294 short ki = find_inode(section_node, key);
295 if(ki >= 0)
296 {
297 const cfg_node* key_node = §ion_node->child[ki];
298 next = find_next_node(key_node, pos, name, bytes);
299 }
300 }
301 unlock_slot(&slot_lock);
302 return next;
303 }
btif_config_enum(btif_config_enum_callback cb,void * user_data)304 int btif_config_enum(btif_config_enum_callback cb, void* user_data)
305 {
306 bdla(cb);
307 if(!cb)
308 return FALSE;
309 lock_slot(&slot_lock);
310 int si, ki, vi;
311 cfg_node *section_node, *key_node, *value_node;
312 for(si = 0; si < GET_CHILD_COUNT(&root); si++)
313 {
314 section_node = &root.child[si];
315 if(section_node->name && *section_node->name)
316 {
317 for(ki = 0; ki < GET_CHILD_COUNT(section_node); ki++)
318 {
319 key_node = §ion_node->child[ki];
320 if(key_node->name && *key_node->name)
321 {
322 for(vi = 0; vi < GET_CHILD_COUNT(key_node); vi++)
323 {
324 value_node = &key_node->child[vi];
325 if(value_node->name && *value_node->name)
326 {
327 cb(user_data, section_node->name, key_node->name, value_node->name,
328 value_node->value, value_node->used, value_node->type);
329 }
330 }
331 }
332 }
333 }
334 }
335 unlock_slot(&slot_lock);
336 return TRUE;
337 }
btif_config_save()338 int btif_config_save()
339 {
340 int post_cmd = 0;
341 lock_slot(&slot_lock);
342 bdld("save_cmds_queued:%d, cached_change:%d", save_cmds_queued, cached_change);
343 if((save_cmds_queued == 0) && (cached_change > 0))
344 {
345 post_cmd = 1;
346 save_cmds_queued++;
347 bdld("post_cmd set to 1, save_cmds_queued:%d", save_cmds_queued);
348 }
349 unlock_slot(&slot_lock);
350 /* don't hold lock when invoking send or else a deadlock could
351 * occur when the socket thread tries to do the actual saving.
352 */
353 if (post_cmd)
354 btsock_thread_post_cmd(pth, CFG_CMD_SAVE, NULL, 0, 0);
355
356 return TRUE;
357 }
btif_config_flush()358 void btif_config_flush()
359 {
360 lock_slot(&slot_lock);
361 if(cached_change > 0)
362 save_cfg();
363 unlock_slot(&slot_lock);
364 }
365 /////////////////////////////////////////////////////////////////////////////////////////////
alloc_node(cfg_node * p,short grow)366 static inline short alloc_node(cfg_node* p, short grow)
367 {
368 int new_bytes = p->bytes + grow;
369 if(grow > 0 && new_bytes < MAX_NODE_BYTES)
370 {
371 char* value = (char*)realloc(p->value, new_bytes);
372 if(value)
373 {
374 short old_bytes = p->bytes;
375 //clear to zero
376 memset(value + old_bytes, 0, grow);
377 p->bytes = old_bytes + grow;
378 p->value = value;
379 return old_bytes;//return the previous size
380 }
381 else bdle("realloc failed, old_bytes:%d, grow:%d, total:%d", p->bytes, grow, p->bytes + grow);
382 }
383 return -1;
384 }
free_node(cfg_node * p)385 static inline void free_node(cfg_node* p)
386 {
387 if(p)
388 {
389 if(p->child)
390 {
391 free(p->child);
392 p->child = NULL;
393 }
394 if(p->name)
395 {
396 free((void*)p->name);
397 p->name = 0;
398 }
399 p->used = p->bytes = p->flag = p->type = 0;
400 }
401 }
find_inode(const cfg_node * p,const char * name)402 static inline short find_inode(const cfg_node* p, const char* name)
403 {
404 if(p && p->child && name && *name)
405 {
406 int i;
407 int count = GET_CHILD_COUNT(p);
408 //bdld("parent name:%s, child name:%s, child count:%d", p->name, name, count);
409 for(i = 0; i < count; i++)
410 {
411 if(p->child[i].name && *p->child[i].name &&
412 strcmp(p->child[i].name, name) == 0)
413 {
414 return (short)i;
415 }
416 }
417 }
418 return -1;
419 }
find_free_node(cfg_node * p)420 static inline cfg_node* find_free_node(cfg_node* p)
421 {
422 if(p && p->child)
423 {
424 int count = GET_CHILD_COUNT(p);
425 if(count < GET_CHILD_MAX_COUNT(p))
426 return p->child + count;
427 }
428 return NULL;
429 }
find_add_node(cfg_node * p,const char * name)430 static cfg_node* find_add_node(cfg_node* p, const char* name)
431 {
432 int i = -1;
433 cfg_node* node = NULL;
434 if((i = find_inode(p, name)) < 0)
435 {
436 if(!(node = find_free_node(p)))
437 {
438 int old_size = alloc_node(p, CFG_GROW_SIZE);
439 if(old_size >= 0)
440 {
441 i = GET_NODE_COUNT(old_size);
442 node = &p->child[i];
443 ADD_CHILD_COUNT(p, 1);
444 }
445 } else ADD_CHILD_COUNT(p, 1);
446 }
447 else node = &p->child[i];
448 if(node && (!node->name))
449 node->name = strdup(name);
450 return node;
451 }
set_node(const char * section,const char * key,const char * name,const char * value,short bytes,short type)452 static int set_node(const char* section, const char* key, const char* name,
453 const char* value, short bytes, short type)
454 {
455 int si = -1, ki = -1, vi = -1;
456 cfg_node* section_node = NULL;
457 if((section_node = find_add_node(&root, section)))
458 {
459 cfg_node* key_node;
460 if((key_node = find_add_node(section_node, key)))
461 {
462 cfg_node* value_node;
463 if((value_node = find_add_node(key_node, name)))
464 {
465 if(value_node->bytes < bytes)
466 {
467 if(value_node->value)
468 free(value_node->value);
469 value_node->value = (char*)malloc(bytes);
470 if(value_node->value)
471 value_node->bytes = bytes;
472 else
473 {
474 bdle("not enough memory!");
475 value_node->bytes = 0;
476 return FALSE;
477 }
478 }
479 if(value_node->value && value != NULL && bytes > 0)
480 memcpy(value_node->value, value, bytes);
481 value_node->type = type;
482 value_node->used = bytes;
483 return TRUE;
484 }
485 }
486 }
487 return FALSE;
488 }
find_node(const char * section,const char * key,const char * name)489 static cfg_node* find_node(const char* section, const char* key, const char* name)
490 {
491 int si = -1, ki = -1, vi = -1;
492 if((si = find_inode(&root, section)) >= 0)
493 {
494 cfg_node* section_node = &root.child[si];
495 if(key)
496 {
497 if((ki = find_inode(section_node, key)) >= 0)
498 {
499 cfg_node* key_node = §ion_node->child[ki];
500 if(name)
501 {
502 if((vi = find_inode(key_node, name)) >= 0)
503 {
504 return &key_node->child[vi];
505 }
506 return NULL;
507 }
508 return key_node;
509 }
510 return NULL;
511 }
512 return section_node;
513 }
514 return NULL;
515 }
find_next_node(const cfg_node * p,short start,char * name,int * bytes)516 static short find_next_node(const cfg_node* p, short start, char* name, int* bytes)
517 {
518 bdla(0 <= start && start < GET_CHILD_COUNT(p));
519 bdld("in, start:%d, child count:%d, max count:%d", start, GET_CHILD_COUNT(p), GET_CHILD_MAX_COUNT(p));
520 short next = -1;
521 if(name) *name = 0;
522 if(0 <= start && start < GET_CHILD_COUNT(p))
523 {
524 int i;
525 for(i = start; i < GET_CHILD_COUNT(p); i++)
526 {
527 cfg_node* child = &p->child[i];
528 if(child->name)
529 {
530 int name_bytes = strlen(child->name) + 1;
531 if(name && bytes && *bytes >= name_bytes)
532 {
533 memcpy(name, child->name, name_bytes);
534 if(i + 1 < GET_CHILD_COUNT(p))
535 next = (short)(i + 1);
536 *bytes = name_bytes;
537 }
538 else if(bytes)
539 {
540 *bytes = name_bytes;
541 }
542 break;
543 }
544 }
545 }
546 return next;
547 }
free_child(cfg_node * p,int ichild,int count)548 static void free_child(cfg_node* p, int ichild, int count)
549 {
550 int child_count = GET_CHILD_COUNT(p);
551 bdla(p && ichild + count <= child_count && count > 0);
552 int icount = ichild + count;
553 icount = icount <= child_count ? icount : child_count;
554 int i;
555 for(i = ichild; i < icount; i++)
556 free_node(p->child + i);
557 if(i < child_count)
558 {
559 int mv_count = child_count - i;
560 memmove(p->child + ichild, p->child + i, GET_NODE_BYTES(mv_count));
561 //cleanup the buffer of already moved children
562 memset(p->child + i, 0, GET_NODE_BYTES(mv_count));
563 }
564 DEC_CHILD_COUNT(p, i - ichild);
565 }
remove_node(const char * section,const char * key,const char * name)566 static int remove_node(const char* section, const char* key, const char* name)
567 {
568 short si = -1, ki = -1, vi = -1;
569 if((si = find_inode(&root, section)) >= 0)
570 {
571 cfg_node* section_node = &root.child[si];
572 if((ki = find_inode(section_node, key)) >= 0)
573 {
574 cfg_node* key_node = §ion_node->child[ki];
575 if(name == NULL)
576 {
577 int count = GET_CHILD_COUNT(key_node);
578 int i;
579 free_child(key_node, 0, count);
580 free_child(section_node, ki, 1);
581 return TRUE;
582 }
583 else if((vi = find_inode(key_node, name)) >= 0)
584 {
585 free_child(key_node, vi, 1);
586 return TRUE;
587 }
588 }
589 }
590 return FALSE;
591 }
find_first_empty(cfg_node * p,int start,int count)592 static inline int find_first_empty(cfg_node*p, int start, int count)
593 {
594 int i;
595 for(i = start; i < count; i++)
596 {
597 if(p->child[i].name == NULL)
598 return i;
599 }
600 return -1;
601 }
find_first_occupy(cfg_node * p,int start,int count)602 static inline int find_first_occupy(cfg_node*p, int start, int count)
603 {
604 int i;
605 for(i = start; i < count; i++)
606 if(p->child[i].name)
607 return i;
608 return -1;
609 }
610
pack_child(cfg_node * p)611 static void pack_child(cfg_node* p)
612 {
613 int child_count = GET_CHILD_COUNT(p);
614 int occupy = 1;
615 int empty = 0;
616 int i;
617 for(;;)
618 {
619 empty = find_first_empty(p, empty, child_count);
620 if(empty >= 0)
621 {
622 if(occupy <= empty)
623 occupy = empty + 1;
624 occupy = find_first_occupy(p, occupy, child_count);
625 bdla(occupy != 0);
626 if(occupy > 0)
627 {//move
628 p->child[empty] = p->child[occupy];
629 memset(&p->child[occupy], 0, sizeof(cfg_node));
630 empty++;
631 occupy++;
632 }
633 else break;
634 }
635 else break;
636 }
637 }
value_in_filter(cfg_node * key,const char * filter[],int filter_count)638 static inline int value_in_filter(cfg_node* key, const char* filter[], int filter_count)
639 {
640 int i, j;
641 int child_count = GET_CHILD_COUNT(key);
642 for(i = 0; i < child_count; i++)
643 {
644 if(key->child[i].name && *key->child[i].name)
645 {
646 for(j = 0; j < filter_count; j++)
647 if(strcmp(filter[j], key->child[i].name) == 0)
648 return TRUE;
649 }
650 }
651 return FALSE;
652 }
remove_filter_node(const char * section,const char * filter[],int filter_count,int max_allowed)653 static int remove_filter_node(const char* section, const char* filter[], int filter_count, int max_allowed)
654 {
655 int si = -1;
656 if((si = find_inode(&root, section)) < 0)
657 {
658 bdle("cannot find section:%s", section);
659 return FALSE;
660 }
661 cfg_node* s = &root.child[si];
662 int child_count = GET_CHILD_COUNT(s);
663 bdld("section:%s, curr child count:%d, filter count:%d", section, child_count, filter_count);
664 if(child_count < max_allowed)
665 return FALSE;
666 //remove until half of max allowance left
667 int total_rm = child_count - max_allowed / 2;
668 int rm_count = 0;
669 int i;
670 for(i = 0; i < child_count; i++)
671 {
672 if(!value_in_filter(&s->child[i], filter, filter_count))
673 {
674 free_child(&s->child[i], 0, GET_CHILD_COUNT(&s->child[i]));
675 free_node(&s->child[i]);
676 rm_count++;
677 if(rm_count >= total_rm)
678 break;
679 }
680 }
681 if(rm_count)
682 {
683 pack_child(s);
684 DEC_CHILD_COUNT(s, rm_count);
685 return TRUE;
686 }
687 return FALSE;
688 }
689
save_cfg()690 static int save_cfg()
691 {
692 const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
693 const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
694 const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
695 int ret = FALSE;
696 if(access(file_name_old, F_OK) == 0)
697 unlink(file_name_old);
698 if(access(file_name_new, F_OK) == 0)
699 unlink(file_name_new);
700 if(btif_config_save_file(file_name_new))
701 {
702 cached_change = 0;
703 chown(file_name_new, -1, AID_NET_BT_STACK);
704 chmod(file_name_new, 0660);
705 rename(file_name, file_name_old);
706 rename(file_name_new, file_name);
707 ret = TRUE;
708 }
709 else bdle("btif_config_save_file failed");
710 return ret;
711 }
712
load_bluez_cfg()713 static int load_bluez_cfg()
714 {
715 char adapter_path[256];
716 if(load_bluez_adapter_info(adapter_path, sizeof(adapter_path)))
717 {
718 if(load_bluez_linkkeys(adapter_path))
719 return TRUE;
720 }
721 return FALSE;
722 }
remove_bluez_cfg()723 static void remove_bluez_cfg()
724 {
725 rename(BLUEZ_PATH, BLUEZ_PATH_BAK);
726 }
clean_newline_char()727 static void clean_newline_char()
728 {
729 char kname[128], vname[128];
730 short kpos = 0;
731 int kname_size, vname_size;
732 vname[0] = 0;
733 vname_size = sizeof(vname);
734 //bdld("removing newline at the end of the adapter and device name");
735 if(btif_config_get_str("Local", "Adapter", "Name", vname, &vname_size) &&
736 vname_size > 2)
737 {
738 if(vname[vname_size - 2] == '\n')
739 {
740 bdld("remove newline at the end of the adapter name:%s", vname);
741 vname[vname_size - 2] = 0;
742 btif_config_set_str("Local", "Adapter", "Name", vname);
743 }
744 }
745 do
746 {
747 kname_size = sizeof(kname);
748 kname[0] = 0;
749 kpos = btif_config_next_key(kpos, "Remote", kname, &kname_size);
750 //bdld("Remote device:%s, size:%d", kname, kname_size);
751 vname_size = sizeof(vname);
752 vname[0] = 0;
753 if(btif_config_get_str("Remote", kname, "Name", vname, &vname_size) &&
754 vname_size > 2)
755 {
756 bdld("remote device name:%s", vname);
757 if(vname[vname_size - 2] == '\n')
758 {
759 bdld("remove newline at the end of the device name:%s", vname);
760 vname[vname_size - 2] = 0;
761 btif_config_set_str("Remote", kname, "Name", vname);
762 }
763 }
764 } while(kpos != -1);
765 }
load_cfg()766 static void load_cfg()
767 {
768 const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
769 const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
770 const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
771 if(!btif_config_load_file(file_name))
772 {
773 unlink(file_name);
774 if(!btif_config_load_file(file_name_old))
775 {
776 unlink(file_name_old);
777 if(load_bluez_cfg() && save_cfg())
778 remove_bluez_cfg();
779 }
780 }
781 int bluez_migration_done = 0;
782 btif_config_get_int("Local", "Adapter", "BluezMigrationDone", &bluez_migration_done);
783 if(!bluez_migration_done)
784 {
785 //clean the new line char at the end of the device name. Caused by bluez config import bug
786 clean_newline_char();
787 btif_config_set_int("Local", "Adapter", "BluezMigrationDone", 1);
788 btif_config_save();
789 }
790 }
cfg_cmd_callback(int cmd_fd,int type,int size,uint32_t user_id)791 static void cfg_cmd_callback(int cmd_fd, int type, int size, uint32_t user_id)
792 {
793 UNUSED(cmd_fd);
794 UNUSED(size);
795 UNUSED(user_id);
796
797 switch(type)
798 {
799 case CFG_CMD_SAVE:
800 {
801 int i;
802 int last_cached_change;
803
804 // grab lock while accessing cached_change.
805 lock_slot(&slot_lock);
806 bdla(save_cmds_queued > 0);
807 save_cmds_queued--;
808 last_cached_change = cached_change;
809 //hold the file saving until no more change in last 3 seconds.
810 bdld("wait until no more changes in short time, cached change:%d", cached_change);
811 for(i = 0; i < 100; i ++) //5 minutes max waiting
812 {
813 // don't sleep if there is nothing to do
814 if(cached_change == 0)
815 break;
816 // release lock during sleep
817 unlock_slot(&slot_lock);
818 sleep(3);
819 lock_slot(&slot_lock);
820 if(last_cached_change == cached_change)
821 break;
822 last_cached_change = cached_change;
823 }
824 bdld("writing the bt_config.xml now, cached change:%d", cached_change);
825 if(cached_change > 0)
826 save_cfg();
827 unlock_slot(&slot_lock);
828 break;
829 }
830 }
831 }
832 #ifdef UNIT_TEST
cfg_test_load()833 static void cfg_test_load()
834 {
835 load_cfg();
836 char kname[128], vname[128];
837 short kpos, vpos;
838 int kname_size, vname_size;
839 bdld("list all remote devices values:");
840 kname_size = sizeof(kname);
841 kname[0] = 0;
842 kpos = 0;
843 do
844 {
845 kpos = btif_config_next_key(kpos, "Remote Devices", kname, &kname_size);
846 bdld("Remote devices:%s, size:%d", kname, kname_size);
847 vpos = 0;
848 vname[0] = 0;
849 vname_size = sizeof(vname);
850 while((vpos = btif_config_next_value(vpos, "Remote Devices", kname, vname, &vname_size)) != -1)
851 {
852 char v[128] = {0};
853 int vtype = BTIF_CFG_TYPE_STR;
854 int vsize = sizeof(v);
855 int ret = btif_config_get("Remote Devices", kname, vname, v, &vsize, &vtype);
856 bdld("btif_config_get return:%d, Remote devices:%s, value name:%s, value:%s, value size:%d, type:0x%x",
857 ret, kname, vname, v, vsize, vtype);
858
859 vname[0] = 0;
860 vname_size = sizeof(vname);
861 }
862 kname[0] = 0;
863 kname_size = sizeof(kname);
864 } while(kpos != -1);
865 }
cfg_test_write()866 static void cfg_test_write()
867 {
868 int i;
869
870 char key[128];
871 const char* section = "Remote";
872 char link_key[64];
873 for(i = 0; i < (int)sizeof(link_key); i++)
874 link_key[i] = i;
875 bdld("[start write testing");
876 if(btif_config_exist("test", "test cfg", "write"))
877 return;
878 btif_config_set_int("test", "test cfg", "write", 1);
879 for(i = 0; i < 50; i++)
880 {
881 if(i % 3 == 0)
882 sprintf(key, "Remote paired %d", i);
883 else sprintf(key, "Remote %d", i);
884 link_key[0] = i;
885 btif_config_set_str(section, key, "class", "smart phone");
886 if(i % 3 == 0)
887 {
888 if(i % 6 == 0)
889 btif_config_set(section, key, "LinkKey", link_key, sizeof(link_key), BTIF_CFG_TYPE_BIN);
890 else btif_config_set(section, key, "LE_KEY_LCSRK", link_key, sizeof(link_key), BTIF_CFG_TYPE_BIN);
891 }
892 btif_config_set_int(section, key, "count", i);
893 if(!btif_config_exist(section, key, "time stamp"))
894 btif_config_set_int(section, key, "time stamp", time(NULL));
895 }
896 static const char* exclude_filter[] =
897 {"LinkKey", "LE_KEY_PENC", "LE_KEY_PID", "LE_KEY_PCSRK", "LE_KEY_LENC", "LE_KEY_LCSRK"};
898 const int max_allowed_remote_device = 40;
899 btif_config_filter_remove("Remote", exclude_filter, sizeof(exclude_filter)/sizeof(char*),
900 max_allowed_remote_device);
901 bdld("]end write testing");
902 btif_config_flush();
903 }
cfg_test_read()904 static void cfg_test_read()
905 {
906 //debug("in");
907 char class[128] = {0};
908 char link_key[128] = {0};
909 int size, type;
910 char key[128];
911 const char* section;
912 int ret, i;
913 for(i = 0; i < 100; i++)
914 {
915 sprintf(key, "00:22:5F:97:56:%02d", i);
916 section = "Remote";
917 size = sizeof(class);
918 ret = btif_config_get_str(section, key, "class", class, &size);
919 bdld("btif_config_get_str return:%d, Remote devices:%s, class:%s", ret, key, class);
920
921 size = sizeof(link_key);
922 type = BTIF_CFG_TYPE_BIN;
923 ret = btif_config_get(section, key, "link keys", link_key, &size, &type);
924 //debug("btif_config_get return:%d, Remote devices:%s, link key:%x, %x",
925 // ret, key, *(int *)link_key, *((int *)link_key + 1));
926
927 int timeout;
928 ret = btif_config_get_int(section, key, "connect time out", &timeout);
929 //debug("btif_config_get_int return:%d, Remote devices:%s, connect time out:%d", ret, key, timeout);
930 }
931
932 // debug("testing btif_config_remove");
933 size = sizeof(class);
934 type = BTIF_CFG_TYPE_STR;
935 btif_config_set("Remote", "00:22:5F:97:56:04", "Class Delete", class, strlen(class) + 1, BTIF_CFG_TYPE_STR);
936
937 btif_config_get("Remote", "00:22:5F:97:56:04", "Class Delete", class, &size, &type);
938 // debug("Remote devices, 00:22:5F:97:56:04 Class Delete:%s", class);
939 btif_config_remove("Remote", "00:22:5F:97:56:04", "Class Delete");
940
941 size = sizeof(class);
942 type = BTIF_CFG_TYPE_STR;
943 ret = btif_config_get("Remote", "00:22:5F:97:56:04", "Class Delete", class, &size, &type);
944 // debug("after removed, btif_config_get ret:%d, Remote devices, 00:22:5F:97:56:04 Class Delete:%s", ret, class);
945 // debug("out");
946 }
947 #endif
948