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