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 asrt(s) if(!(s)) BTIF_TRACE_ERROR3 ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
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 IS_EMPTY(node) ((node)->name == NULL)
63 #define GET_NODE_COUNT(bytes) (bytes / sizeof(cfg_node))
64 #define MAX_NODE_BYTES 32000
65 #define MAX_CACHED_COUNT 150
66 #define CFG_CMD_SAVE 1
67
68 #ifndef FALSE
69 #define TRUE 1
70 #define FALSE 0
71 #endif
72 typedef struct cfg_node_s
73 {
74 const char* name;
75 union
76 {
77 struct cfg_node_s* child;
78 char* value;
79 };
80 short bytes;
81 short type;
82 short used;
83 short flag;
84 } cfg_node;
85
86 static pthread_mutex_t slot_lock;
87 static int pth = -1; //poll thread handle
88 static cfg_node root;
89 static int cached_change;
90 static void cfg_cmd_callback(int cmd_fd, int type, int flags, uint32_t user_id);
91 static inline short alloc_node(cfg_node* p, short grow);
92 static inline void free_node(cfg_node* p);
93 static inline void free_inode(cfg_node* p, int child);
94 static inline short find_inode(const cfg_node* p, const char* name);
95 static cfg_node* find_node(const char* section, const char* key, const char* name);
96 static int remove_node(const char* section, const char* key, const char* name);
97 static inline cfg_node* find_free_node(cfg_node* p);
98 static int set_node(const char* section, const char* key, const char* name,
99 const char* value, short bytes, short type);
100 static int save_cfg();
101 static void load_cfg();
102 static short find_next_node(const cfg_node* p, short start, char* name, int* bytes);
103 static int create_dir(const char* path);
104 #ifdef UNIT_TEST
105 static void cfg_test_load();
106 static void cfg_test_write();
107 static void cfg_test_read();
108 #endif
dump_node(const char * title,const cfg_node * p)109 static inline void dump_node(const char* title, const cfg_node* p)
110 {
111 if(p) {
112 BTIF_TRACE_DEBUG4("%s, p->name:%s, child/value:%p, bytes:%d",
113 title, p->name, p->child, p->bytes);
114 BTIF_TRACE_DEBUG3("p->used:%d, type:%x, p->flag:%d",
115 p->used, p->type, p->flag);
116 } else BTIF_TRACE_DEBUG1("%s is NULL", title);
117 }
118 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
btif_config_init()119 int btif_config_init()
120 {
121 static int initialized;
122 BTIF_TRACE_DEBUG1("in initialized:%d", initialized);
123 if(!initialized)
124 {
125 initialized = 1;
126 struct stat st;
127 if(stat(CFG_PATH, &st) != 0)
128 BTIF_TRACE_ERROR1("%s does not exist, need provision", CFG_PATH);
129 btsock_thread_init();
130 init_slot_lock(&slot_lock);
131 lock_slot(&slot_lock);
132 root.name = "Bluedroid";
133 alloc_node(&root, CFG_GROW_SIZE);
134 dump_node("root", &root);
135 pth = btsock_thread_create(NULL, cfg_cmd_callback);
136 load_cfg();
137 unlock_slot(&slot_lock);
138 #ifdef UNIT_TEST
139 //cfg_test_load();
140 cfg_test_write();
141 cfg_test_read();
142 #endif
143 }
144 return pth >= 0;
145 }
btif_config_get_int(const char * section,const char * key,const char * name,int * value)146 int btif_config_get_int(const char* section, const char* key, const char* name, int* value)
147 {
148 int size = sizeof(*value);
149 int type = BTIF_CFG_TYPE_INT;
150 return btif_config_get(section, key, name, (char*)value, &size, &type);
151 }
btif_config_set_int(const char * section,const char * key,const char * name,int value)152 int btif_config_set_int(const char* section, const char* key, const char* name, int value)
153 {
154 return btif_config_set(section, key, name, (char*)&value, sizeof(value), BTIF_CFG_TYPE_INT);
155 }
btif_config_get_str(const char * section,const char * key,const char * name,char * value,int * size)156 int btif_config_get_str(const char* section, const char* key, const char* name, char* value, int* size)
157 {
158 int type = BTIF_CFG_TYPE_STR;
159 if(value)
160 *value = 0;
161 return btif_config_get(section, key, name, value, size, &type);
162 }
btif_config_set_str(const char * section,const char * key,const char * name,const char * value)163 int btif_config_set_str(const char* section, const char* key, const char* name, const char* value)
164 {
165 value = value ? value : "";
166 return btif_config_set(section, key, name, value, strlen(value) + 1, BTIF_CFG_TYPE_STR);
167 }
btif_config_exist(const char * section,const char * key,const char * name)168 int btif_config_exist(const char* section, const char* key, const char* name)
169 {
170 int ret = FALSE;
171 if(section && *section && key && *key)
172 {
173 lock_slot(&slot_lock);
174 ret = find_node(section, key, name) != NULL;
175 unlock_slot(&slot_lock);
176 }
177 return ret;
178 }
btif_config_get(const char * section,const char * key,const char * name,char * value,int * bytes,int * type)179 int btif_config_get(const char* section, const char* key, const char* name, char* value, int* bytes, int* type)
180 {
181 int ret = FALSE;
182 asrt(section && *section && key && *key && name && *name && bytes && type);
183 //debug("section:%s, key:%s, name:%s, value:%p, bytes:%d, type:%d",
184 // section, key, name, value, *bytes, *type);
185 if(section && *section && key && *key && name && *name && bytes && type)
186 {
187 lock_slot(&slot_lock);
188 const cfg_node* node = find_node(section, key, name);
189 dump_node("found node", node);
190 if(node)
191 {
192 if(*type == node->type && value && *bytes >= node->used)
193 {
194 if(node->used > 0)
195 memcpy(value, node->value, node->used);
196 ret = TRUE;
197 }
198 *type = node->type;
199 *bytes = node->used;
200 if(ret != TRUE)
201 {
202 if(*type != node->type)
203 BTIF_TRACE_ERROR3("value:%s, wrong type:%d, need to be type: %d",
204 name, *type, node->type);
205 if(value && *bytes < node->used)
206 BTIF_TRACE_ERROR3("value:%s, not enough size: %d bytes, need %d bytes",
207 name, node->used, *bytes);
208 }
209 }
210 unlock_slot(&slot_lock);
211 }
212 //debug("out");
213 return ret;
214 }
btif_config_set(const char * section,const char * key,const char * name,const char * value,int bytes,int type)215 int btif_config_set(const char* section, const char* key, const char* name, const char* value, int bytes, int type)
216 {
217 int ret = FALSE;
218 asrt(section && *section && key && *key && name && *name);
219 asrt(bytes < MAX_NODE_BYTES);
220 if(section && *section && key && *key && name && *name && bytes < MAX_NODE_BYTES)
221 {
222 lock_slot(&slot_lock);
223 ret = set_node(section, key, name, value, (short)bytes, (short)type);
224 if(ret && !(type & BTIF_CFG_TYPE_VOLATILE) && ++cached_change > MAX_CACHED_COUNT)
225 {
226 cached_change = 0;
227 btsock_thread_post_cmd(pth, CFG_CMD_SAVE, NULL, 0, 0);
228 }
229
230 unlock_slot(&slot_lock);
231 }
232 return ret;
233 }
btif_config_remove(const char * section,const char * key,const char * name)234 int btif_config_remove(const char* section, const char* key, const char* name)
235 {
236 asrt(section && *section && key && *key);
237 int ret = FALSE;
238 if(section && *section && key && *key)
239 {
240 lock_slot(&slot_lock);
241 ret = remove_node(section, key, name);
242 if(ret)
243 cached_change++;
244 unlock_slot(&slot_lock);
245 }
246 return ret;
247 }
248 typedef struct {
249 short si;
250 short ki;
251 short vi;
252 short reserved;
253 } cfg_node_pos;
btif_config_next_key(short pos,const char * section,char * name,int * bytes)254 short btif_config_next_key(short pos, const char* section, char * name, int* bytes)
255 {
256 int next = -1;
257 lock_slot(&slot_lock);
258 short si = find_inode(&root, section);
259 if(si >= 0)
260 {
261 const cfg_node* section_node = &root.child[si];
262 next = find_next_node(section_node, pos, name, bytes);
263 }
264 unlock_slot(&slot_lock);
265 return next;
266 }
btif_config_next_value(short pos,const char * section,const char * key,char * name,int * bytes)267 short btif_config_next_value(short pos, const char* section, const char* key, char* name, int* bytes)
268 {
269 int next = -1;
270 lock_slot(&slot_lock);
271 short si = find_inode(&root, section);
272 if(si >= 0)
273 {
274 const cfg_node* section_node = &root.child[si];
275 short ki = find_inode(section_node, key);
276 if(ki >= 0)
277 {
278 const cfg_node* key_node = §ion_node->child[ki];
279 next = find_next_node(key_node, pos, name, bytes);
280 }
281 }
282 unlock_slot(&slot_lock);
283 return next;
284 }
btif_config_enum(btif_config_enum_callback cb,void * user_data)285 int btif_config_enum(btif_config_enum_callback cb, void* user_data)
286 {
287 asrt(cb);
288 if(!cb)
289 return FALSE;
290 lock_slot(&slot_lock);
291 int si, ki, vi;
292 cfg_node *section_node, *key_node, *value_node;
293 for(si = 0; si < GET_CHILD_MAX_COUNT(&root); si++)
294 {
295 section_node = &root.child[si];
296 if(section_node->name && *section_node->name)
297 {
298 for(ki = 0; ki < GET_CHILD_MAX_COUNT(section_node); ki++)
299 {
300 key_node = §ion_node->child[ki];
301 if(key_node->name && *key_node->name)
302 {
303 for(vi = 0; vi < GET_CHILD_MAX_COUNT(key_node); vi++)
304 {
305 value_node = &key_node->child[vi];
306 if(value_node->name && *value_node->name)
307 {
308 cb(user_data, section_node->name, key_node->name, value_node->name,
309 value_node->value, value_node->used, value_node->type);
310 }
311 }
312 }
313 }
314 }
315 }
316 unlock_slot(&slot_lock);
317 return TRUE;
318 }
btif_config_save()319 int btif_config_save()
320 {
321 lock_slot(&slot_lock);
322 if(cached_change > 0)
323 {
324 cached_change = 0;
325 btsock_thread_post_cmd(pth, CFG_CMD_SAVE, NULL, 0, 0);
326 }
327 unlock_slot(&slot_lock);
328 return TRUE;
329 }
btif_config_flush()330 void btif_config_flush()
331 {
332 lock_slot(&slot_lock);
333 if(cached_change > 0)
334 save_cfg();
335 unlock_slot(&slot_lock);
336 }
337 /////////////////////////////////////////////////////////////////////////////////////////////
alloc_node(cfg_node * p,short grow)338 static inline short alloc_node(cfg_node* p, short grow)
339 {
340 int new_bytes = p->bytes + grow;
341 //debug("in, bytes:%d, new bytes:%d, grow:%d", p->bytes, new_bytes, grow);
342 if(grow > 0 && new_bytes < MAX_NODE_BYTES)
343 {
344 char* value = (char*)realloc(p->value, new_bytes);
345 if(value)
346 {
347 short old_bytes = p->bytes;
348 //clear to zero
349 memset(value + old_bytes, 0, grow);
350 p->bytes = old_bytes + grow;
351 p->value = value;
352 //debug("out");
353 return old_bytes;//return the previous size
354 }
355 else BTIF_TRACE_ERROR3("realloc failed, old_bytes:%d, grow:%d, total:%d", p->bytes, grow, p->bytes + grow);
356 }
357 //debug("out, alloc failed");
358 return -1;
359 }
free_node(cfg_node * p)360 static inline void free_node(cfg_node* p)
361 {
362 if(p)
363 {
364 if(p->child)
365 {
366 free(p->child);
367 p->child = NULL;
368 }
369 if(p->name)
370 {
371 free((void*)p->name);
372 p->name = 0;
373 }
374 p->used = p->bytes = p->flag = p->type = 0;
375 }
376 }
find_inode(const cfg_node * p,const char * name)377 static inline short find_inode(const cfg_node* p, const char* name)
378 {
379 //debug("in");
380 if(p && p->child && name && *name)
381 {
382 int i;
383 int count = GET_CHILD_MAX_COUNT(p);
384 //debug("child name:%s, child max count:%d", name, count);
385 for(i = 0; i < count; i++)
386 {
387 if(p->child[i].name && *p->child[i].name &&
388 strcmp(p->child[i].name, name) == 0)
389 {
390 //debug("out found child index:%d", i);
391 return (short)i;
392 }
393 }
394 }
395 //debug("out, child name: %s not found", name);
396 return -1;
397 }
find_free_node(cfg_node * p)398 static inline cfg_node* find_free_node(cfg_node* p)
399 {
400 if(p && p->child)
401 {
402 int i;
403 int count = GET_CHILD_MAX_COUNT(p);
404 //debug("p->name:%s, max child count:%d", p->name, count);
405 for(i = 0; i < count; i++)
406 {
407 if(IS_EMPTY(p->child + i))
408 return p->child + i;
409 }
410 }
411 return NULL;
412 }
find_add_node(cfg_node * p,const char * name)413 static cfg_node* find_add_node(cfg_node* p, const char* name)
414 {
415 int i = -1;
416 cfg_node* node = NULL;
417 //debug("in, p->name:%s, p->bytes:%d, adding child:%s", p->name, p->bytes, name);
418 if((i = find_inode(p, name)) < 0)
419 {
420 if(!(node = find_free_node(p)))
421 {
422 int old_size = alloc_node(p, CFG_GROW_SIZE);
423 if(old_size >= 0)
424 {
425 i = GET_NODE_COUNT(old_size);
426 node = &p->child[i];
427 }
428 }
429 }
430 else node = &p->child[i];
431 if(!node->name)
432 node->name = strdup(name);
433 //debug("out");
434 return node;
435 }
set_node(const char * section,const char * key,const char * name,const char * value,short bytes,short type)436 static int set_node(const char* section, const char* key, const char* name,
437 const char* value, short bytes, short type)
438 {
439 int si = -1, ki = -1, vi = -1;
440 cfg_node* section_node = NULL;
441 //debug("in");
442 //dump_node("root", &root);
443 if((section_node = find_add_node(&root, section)))
444 {
445 //dump_node("section node", section_node);
446 cfg_node* key_node;
447 if((key_node = find_add_node(section_node, key)))
448 {
449 //dump_node("key node", key_node);
450 cfg_node* value_node;
451 if((value_node = find_add_node(key_node, name)))
452 {
453 //dump_node("value node", value_node);
454 if(value_node->bytes < bytes)
455 {
456 if(value_node->value)
457 free(value_node->value);
458 value_node->value = (char*)malloc(bytes);
459 if(value_node->value)
460 value_node->bytes = bytes;
461 else
462 {
463 BTIF_TRACE_ERROR0("not enough memory!");
464 value_node->bytes = 0;
465 return FALSE;
466 }
467 }
468 if(value_node->value && value != NULL && bytes > 0)
469 memcpy(value_node->value, value, bytes);
470 value_node->type = type;
471 value_node->used = bytes;
472 //dump_node("changed value node", value_node);
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 //dump_node("found section node", section_node);
488 if((ki = find_inode(section_node, key)) >= 0)
489 {
490 cfg_node* key_node = §ion_node->child[ki];
491 //dump_node("found key node", key_node);
492 if(name)
493 {
494 if((vi = find_inode(key_node, name)) >= 0)
495 {
496 //dump_node("found value node", &key_node->child[vi]);
497 return &key_node->child[vi];
498 }
499 //debug("value node:%s not found", name);
500 return NULL;
501 }
502 return key_node;
503 }
504 //debug("key node:%s not found", key);
505 return NULL;
506 }
507 return section_node;
508 }
509 //debug("section node:%s not found", section);
510 return NULL;
511 }
find_next_node(const cfg_node * p,short start,char * name,int * bytes)512 static short find_next_node(const cfg_node* p, short start, char* name, int* bytes)
513 {
514 asrt(0 <= start && start < GET_CHILD_MAX_COUNT(p));
515 //debug("in, start:%d, max child count:%d", start, GET_CHILD_MAX_COUNT(p));
516 //dump_node("find_next_node, parent", p);
517 short next = -1;
518 if(name) *name = 0;
519 if(0 <= start && start < GET_CHILD_MAX_COUNT(p))
520 {
521 int i;
522 for(i = start; i < GET_CHILD_MAX_COUNT(p); i++)
523 {
524 cfg_node* child = &p->child[i];
525 if(child->name)
526 {
527 int name_bytes = strlen(child->name) + 1;
528 if(name && bytes && *bytes >= name_bytes)
529 {
530 memcpy(name, child->name, name_bytes);
531 if(i + 1 < GET_CHILD_MAX_COUNT(p))
532 next = (short)(i + 1);
533 *bytes = name_bytes;
534 }
535 else if(bytes)
536 {
537 //debug("not enough room to copy the name, size in:%d, size needed:%d", *bytes, name_bytes);
538 *bytes = name_bytes;
539 }
540 break;
541 }
542 }
543 }
544 return next;
545 }
remove_node(const char * section,const char * key,const char * name)546 static int remove_node(const char* section, const char* key, const char* name)
547 {
548 short si = -1, ki = -1, vi = -1;
549 if((si = find_inode(&root, section)) >= 0)
550 {
551 cfg_node* section_node = &root.child[si];
552 if((ki = find_inode(section_node, key)) >= 0)
553 {
554 cfg_node* key_node = §ion_node->child[ki];
555 if(name == NULL)
556 {
557 int count = GET_CHILD_MAX_COUNT(key_node);
558 int i;
559 for(i = 0; i < count; i++)
560 free_node(&key_node->child[i]);
561 free_node(key_node);
562 return TRUE;
563 }
564 else if((vi = find_inode(key_node, name)) >= 0)
565 {
566 //debug("remove value:%s", key_node->child[vi].name);
567 free_node(&key_node->child[vi]);
568 return TRUE;
569 }
570 }
571 }
572 return FALSE;
573 }
save_cfg()574 static int save_cfg()
575 {
576 const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
577 const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
578 const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
579 int ret = FALSE;
580 if(access(file_name_old, F_OK) == 0)
581 unlink(file_name_old);
582 if(access(file_name_new, F_OK) == 0)
583 unlink(file_name_new);
584 if(btif_config_save_file(file_name_new))
585 {
586 cached_change = 0;
587 chown(file_name_new, -1, AID_NET_BT_STACK);
588 chmod(file_name_new, 0660);
589 rename(file_name, file_name_old);
590 rename(file_name_new, file_name);
591 ret = TRUE;
592 }
593 else BTIF_TRACE_ERROR0("btif_config_save_file failed");
594 return ret;
595 }
596
load_bluez_cfg()597 static int load_bluez_cfg()
598 {
599 char adapter_path[256];
600 if(load_bluez_adapter_info(adapter_path, sizeof(adapter_path)))
601 {
602 if(load_bluez_linkkeys(adapter_path))
603 return TRUE;
604 }
605 return FALSE;
606 }
remove_bluez_cfg()607 static void remove_bluez_cfg()
608 {
609 rename(BLUEZ_PATH, BLUEZ_PATH_BAK);
610 }
clean_newline_char()611 static void clean_newline_char()
612 {
613 char kname[128], vname[128];
614 short kpos = 0;
615 int kname_size, vname_size;
616 vname[0] = 0;
617 vname_size = sizeof(vname);
618 //BTIF_TRACE_DEBUG0("removing newline at the end of the adapter and device name");
619 if(btif_config_get_str("Local", "Adapter", "Name", vname, &vname_size) &&
620 vname_size > 2)
621 {
622 if(vname[vname_size - 2] == '\n')
623 {
624 BTIF_TRACE_DEBUG1("remove newline at the end of the adapter name:%s", vname);
625 vname[vname_size - 2] = 0;
626 btif_config_set_str("Local", "Adapter", "Name", vname);
627 }
628 }
629 do
630 {
631 kname_size = sizeof(kname);
632 kname[0] = 0;
633 kpos = btif_config_next_key(kpos, "Remote", kname, &kname_size);
634 //BTIF_TRACE_DEBUG2("Remote device:%s, size:%d", kname, kname_size);
635 vname_size = sizeof(vname);
636 vname[0] = 0;
637 if(btif_config_get_str("Remote", kname, "Name", vname, &vname_size) &&
638 vname_size > 2)
639 {
640 BTIF_TRACE_DEBUG1("remote device name:%s", vname);
641 if(vname[vname_size - 2] == '\n')
642 {
643 BTIF_TRACE_DEBUG1("remove newline at the end of the device name:%s", vname);
644 vname[vname_size - 2] = 0;
645 btif_config_set_str("Remote", kname, "Name", vname);
646 }
647 }
648 } while(kpos != -1);
649 }
load_cfg()650 static void load_cfg()
651 {
652 const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
653 const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
654 const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
655 if(!btif_config_load_file(file_name))
656 {
657 unlink(file_name);
658 if(!btif_config_load_file(file_name_old))
659 {
660 unlink(file_name_old);
661 if(load_bluez_cfg() && save_cfg())
662 remove_bluez_cfg();
663 }
664 }
665 int bluez_migration_done = 0;
666 btif_config_get_int("Local", "Adapter", "BluezMigrationDone", &bluez_migration_done);
667 if(!bluez_migration_done)
668 {
669 //clean the new line char at the end of the device name. Caused by bluez config import bug
670 clean_newline_char();
671 btif_config_set_int("Local", "Adapter", "BluezMigrationDone", 1);
672 btif_config_save();
673 }
674 }
cfg_cmd_callback(int cmd_fd,int type,int size,uint32_t user_id)675 static void cfg_cmd_callback(int cmd_fd, int type, int size, uint32_t user_id)
676 {
677 //BTIF_TRACE_DEBUG2("cmd type:%d, size:%d", type, size);
678 switch(type)
679 {
680 case CFG_CMD_SAVE:
681 lock_slot(&slot_lock);
682 save_cfg();
683 unlock_slot(&slot_lock);
684 break;
685 }
686 }
687 #ifdef UNIT_TEST
cfg_test_load()688 static void cfg_test_load()
689 {
690 load_cfg();
691 char kname[128], vname[128];
692 short kpos, vpos;
693 int kname_size, vname_size;
694 BTIF_TRACE_DEBUG0("list all remote devices values:");
695 kname_size = sizeof(kname);
696 kname[0] = 0;
697 kpos = 0;
698 do
699 {
700 kpos = btif_config_next_key(kpos, "Remote Devices", kname, &kname_size);
701 BTIF_TRACE_DEBUG2("Remote devices:%s, size:%d", kname, kname_size);
702 vpos = 0;
703 vname[0] = 0;
704 vname_size = sizeof(vname);
705 while((vpos = btif_config_next_value(vpos, "Remote Devices", kname, vname, &vname_size)) != -1)
706 {
707 char v[128] = {0};
708 int vtype = BTIF_CFG_TYPE_STR;
709 int vsize = sizeof(v);
710 int ret = btif_config_get("Remote Devices", kname, vname, v, &vsize, &vtype);
711 BTIF_TRACE_DEBUG6("btif_config_get return:%d, Remote devices:%s, value name:%s, value:%s, value size:%d, type:0x%x",
712 ret, kname, vname, v, vsize, vtype);
713
714 vname[0] = 0;
715 vname_size = sizeof(vname);
716 }
717 kname[0] = 0;
718 kname_size = sizeof(kname);
719 } while(kpos != -1);
720 }
cfg_test_write()721 static void cfg_test_write()
722 {
723 int i;
724
725 char key[128];
726 const char* section;
727 char link_key[64];
728 for(i = 0; i < (int)sizeof(link_key); i++)
729 link_key[i] = i;
730 for(i = 0; i < 100; i++)
731 {
732 sprintf(key, "00:22:5F:97:56:%02d", i);
733 link_key[0] = i;
734 section = "Remote Devices";
735 btif_config_set_str(section, key, "class", "smart phone");
736 btif_config_set(section, key, "link keys", link_key, sizeof(link_key), BTIF_CFG_TYPE_BIN);
737 btif_config_set_int(section, key, "connect time out", i);
738 }
739 btif_config_save();
740 }
cfg_test_read()741 static void cfg_test_read()
742 {
743 //debug("in");
744 char class[128] = {0};
745 char link_key[128] = {0};
746 int size, type;
747 char key[128];
748 const char* section;
749 int ret, i;
750 for(i = 0; i < 100; i++)
751 {
752 sprintf(key, "00:22:5F:97:56:%02d", i);
753 section = "Remote Devices";
754 size = sizeof(class);
755 ret = btif_config_get_str(section, key, "class", class, &size);
756 BTIF_TRACE_DEBUG3("btif_config_get_str return:%d, Remote devices:%s, class:%s", ret, key, class);
757
758 size = sizeof(link_key);
759 type = BTIF_CFG_TYPE_BIN;
760 ret = btif_config_get(section, key, "link keys", link_key, &size, &type);
761 //debug("btif_config_get return:%d, Remote devices:%s, link key:%x, %x",
762 // ret, key, *(int *)link_key, *((int *)link_key + 1));
763
764 int timeout;
765 ret = btif_config_get_int(section, key, "connect time out", &timeout);
766 //debug("btif_config_get_int return:%d, Remote devices:%s, connect time out:%d", ret, key, timeout);
767 }
768
769 // debug("testing btif_config_remove");
770 size = sizeof(class);
771 type = BTIF_CFG_TYPE_STR;
772 btif_config_set("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, strlen(class) + 1, BTIF_CFG_TYPE_STR);
773
774 btif_config_get("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, &size, &type);
775 // debug("Remote devices, 00:22:5F:97:56:04 Class Delete:%s", class);
776 btif_config_remove("Remote Devices", "00:22:5F:97:56:04", "Class Delete");
777
778 size = sizeof(class);
779 type = BTIF_CFG_TYPE_STR;
780 ret = btif_config_get("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, &size, &type);
781 // debug("after removed, btif_config_get ret:%d, Remote devices, 00:22:5F:97:56:04 Class Delete:%s", ret, class);
782 // debug("out");
783 }
784 #endif
785