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