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