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