btif_config.c revision 831423ea1879244e746f39d7696ad4a66681f306
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
74typedef 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
88static pthread_mutex_t slot_lock;
89static int pth = -1; //poll thread handle
90static cfg_node root;
91static int cached_change;
92static int processing_save_cmd;
93static void cfg_cmd_callback(int cmd_fd, int type, int flags, uint32_t user_id);
94static inline short alloc_node(cfg_node* p, short grow);
95static inline void free_node(cfg_node* p);
96static inline short find_inode(const cfg_node* p, const char* name);
97static cfg_node* find_node(const char* section, const char* key, const char* name);
98static int remove_node(const char* section, const char* key, const char* name);
99static int remove_filter_node(const char* section, const char* filter[], int filter_count, int max_allowed);
100static inline cfg_node* find_free_node(cfg_node* p);
101static int set_node(const char* section, const char* key, const char* name,
102                        const char* value, short bytes, short type);
103static int save_cfg();
104static void load_cfg();
105static short find_next_node(const cfg_node* p, short start, char* name, int* bytes);
106#ifdef UNIT_TEST
107static void cfg_test_load();
108static void cfg_test_write();
109static 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
114static 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////////////////////////////////////////////////////////////////////////////////////////////////////////////
125int 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}
152int 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}
158int 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}
162int 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}
169int 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}
174int 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}
185int 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}
220int 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}
235int 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
251int 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}
267typedef struct {
268    short si;
269    short ki;
270    short vi;
271    short reserved;
272} cfg_node_pos;
273short 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}
286short 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}
304int 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}
338int btif_config_save()
339{
340    lock_slot(&slot_lock);
341    bdld("processing_save_cmd:%d, cached change:%d", processing_save_cmd, cached_change);
342    if(!processing_save_cmd && cached_change > 0)
343        btsock_thread_post_cmd(pth, CFG_CMD_SAVE, NULL, 0, 0);
344    unlock_slot(&slot_lock);
345    return TRUE;
346}
347void btif_config_flush()
348{
349    lock_slot(&slot_lock);
350    if(cached_change > 0)
351        save_cfg();
352    unlock_slot(&slot_lock);
353}
354/////////////////////////////////////////////////////////////////////////////////////////////
355static inline short alloc_node(cfg_node* p, short grow)
356{
357    int new_bytes = p->bytes + grow;
358    if(grow > 0 && new_bytes < MAX_NODE_BYTES)
359    {
360        char* value = (char*)realloc(p->value, new_bytes);
361        if(value)
362        {
363            short old_bytes = p->bytes;
364            //clear to zero
365            memset(value + old_bytes, 0, grow);
366            p->bytes = old_bytes + grow;
367            p->value = value;
368            return old_bytes;//return the previous size
369        }
370        else bdle("realloc failed, old_bytes:%d, grow:%d, total:%d", p->bytes, grow,  p->bytes + grow);
371    }
372    return -1;
373}
374static inline void free_node(cfg_node* p)
375{
376    if(p)
377    {
378        if(p->child)
379        {
380            free(p->child);
381            p->child = NULL;
382        }
383        if(p->name)
384        {
385            free((void*)p->name);
386            p->name = 0;
387        }
388        p->used = p->bytes = p->flag = p->type = 0;
389    }
390}
391static inline short find_inode(const cfg_node* p, const char* name)
392{
393    if(p && p->child && name && *name)
394    {
395        int i;
396        int count = GET_CHILD_COUNT(p);
397        //bdld("parent name:%s, child name:%s, child count:%d", p->name, name, count);
398        for(i = 0; i < count; i++)
399        {
400            if(p->child[i].name && *p->child[i].name &&
401                strcmp(p->child[i].name, name) == 0)
402            {
403                  return (short)i;
404            }
405        }
406    }
407    return -1;
408}
409static inline cfg_node* find_free_node(cfg_node* p)
410{
411    if(p && p->child)
412    {
413        int count = GET_CHILD_COUNT(p);
414        if(count < GET_CHILD_MAX_COUNT(p))
415            return  p->child + count;
416    }
417    return NULL;
418}
419static cfg_node* find_add_node(cfg_node* p, const char* name)
420{
421    int i = -1;
422    cfg_node* node = NULL;
423    if((i = find_inode(p, name)) < 0)
424    {
425        if(!(node = find_free_node(p)))
426        {
427            int old_size = alloc_node(p, CFG_GROW_SIZE);
428            if(old_size >= 0)
429            {
430                i = GET_NODE_COUNT(old_size);
431                node = &p->child[i];
432                ADD_CHILD_COUNT(p, 1);
433            }
434        } else ADD_CHILD_COUNT(p, 1);
435    }
436    else node = &p->child[i];
437    if(node && (!node->name))
438        node->name = strdup(name);
439    return node;
440}
441static int set_node(const char* section, const char* key, const char* name,
442                    const char* value, short bytes, short type)
443{
444    int si = -1, ki = -1, vi = -1;
445    cfg_node* section_node = NULL;
446    if((section_node = find_add_node(&root, section)))
447    {
448        cfg_node* key_node;
449        if((key_node = find_add_node(section_node, key)))
450        {
451            cfg_node* value_node;
452            if((value_node = find_add_node(key_node, name)))
453            {
454                if(value_node->bytes < bytes)
455                {
456                    if(value_node->value)
457                        free(value_node->value);
458                    value_node->value = (char*)malloc(bytes);
459                    if(value_node->value)
460                        value_node->bytes = bytes;
461                    else
462                    {
463                        bdle("not enough memory!");
464                        value_node->bytes = 0;
465                        return FALSE;
466                    }
467                }
468                if(value_node->value && value != NULL && bytes > 0)
469                    memcpy(value_node->value, value, bytes);
470                value_node->type = type;
471                value_node->used = bytes;
472                return TRUE;
473            }
474        }
475    }
476    return FALSE;
477}
478static cfg_node* find_node(const char* section, const char* key, const char* name)
479{
480    int si = -1, ki = -1, vi = -1;
481    if((si = find_inode(&root, section)) >= 0)
482    {
483        cfg_node* section_node = &root.child[si];
484        if(key)
485        {
486            if((ki = find_inode(section_node, key)) >= 0)
487            {
488                cfg_node* key_node = &section_node->child[ki];
489                if(name)
490                {
491                    if((vi = find_inode(key_node, name)) >= 0)
492                    {
493                        return &key_node->child[vi];
494                    }
495                    return NULL;
496                }
497                return key_node;
498            }
499            return NULL;
500        }
501        return section_node;
502    }
503    return NULL;
504}
505static short find_next_node(const cfg_node* p, short start, char* name, int* bytes)
506{
507    bdla(0 <= start && start < GET_CHILD_COUNT(p));
508    bdld("in, start:%d, child count:%d, max count:%d", start, GET_CHILD_COUNT(p), GET_CHILD_MAX_COUNT(p));
509    short next = -1;
510    if(name) *name = 0;
511    if(0 <= start && start < GET_CHILD_COUNT(p))
512    {
513        int i;
514        for(i = start; i < GET_CHILD_COUNT(p); i++)
515        {
516            cfg_node* child = &p->child[i];
517            if(child->name)
518            {
519                int name_bytes = strlen(child->name) + 1;
520                if(name && bytes && *bytes >= name_bytes)
521                {
522                    memcpy(name, child->name, name_bytes);
523                    if(i + 1 < GET_CHILD_COUNT(p))
524                        next = (short)(i + 1);
525                    *bytes = name_bytes;
526                }
527                else if(bytes)
528                {
529                    *bytes = name_bytes;
530                }
531                break;
532            }
533        }
534    }
535    return next;
536}
537static void free_child(cfg_node* p, int ichild, int count)
538{
539    int child_count = GET_CHILD_COUNT(p);
540    bdla(p && ichild + count <= child_count && count > 0);
541    int icount = ichild + count;
542    icount = icount <= child_count ? icount : child_count;
543    int i;
544    for(i = ichild; i < icount; i++)
545        free_node(p->child + i);
546    if(i < child_count)
547    {
548        int mv_count = child_count - i;
549        memmove(p->child + ichild, p->child + i, GET_NODE_BYTES(mv_count));
550        //cleanup the buffer of already moved children
551        memset(p->child + i, 0, GET_NODE_BYTES(mv_count));
552    }
553    DEC_CHILD_COUNT(p, i - ichild);
554}
555static int remove_node(const char* section, const char* key, const char* name)
556{
557    short  si = -1, ki = -1, vi = -1;
558    if((si = find_inode(&root, section)) >= 0)
559    {
560        cfg_node* section_node = &root.child[si];
561        if((ki = find_inode(section_node, key)) >= 0)
562        {
563            cfg_node* key_node = &section_node->child[ki];
564            if(name == NULL)
565            {
566                int count = GET_CHILD_COUNT(key_node);
567                int i;
568                free_child(key_node, 0, count);
569                free_child(section_node, ki, 1);
570                return TRUE;
571            }
572            else if((vi = find_inode(key_node, name)) >= 0)
573            {
574                free_child(key_node, vi, 1);
575                return TRUE;
576            }
577        }
578    }
579    return FALSE;
580}
581static inline int find_first_empty(cfg_node*p, int start, int count)
582{
583    int i;
584    for(i = start; i < count; i++)
585    {
586        if(p->child[i].name == NULL)
587            return i;
588    }
589    return -1;
590}
591static inline int find_first_occupy(cfg_node*p, int start, int count)
592{
593    int i;
594    for(i = start; i < count; i++)
595        if(p->child[i].name)
596            return i;
597    return -1;
598}
599
600static void pack_child(cfg_node* p)
601{
602    int child_count = GET_CHILD_COUNT(p);
603    int occupy = 1;
604    int empty = 0;
605    int i;
606    for(;;)
607    {
608        empty = find_first_empty(p, empty, child_count);
609        if(empty >= 0)
610        {
611            if(occupy <= empty)
612                occupy = empty + 1;
613            occupy = find_first_occupy(p, occupy, child_count);
614            bdla(occupy != 0);
615            if(occupy > 0)
616            {//move
617                p->child[empty] = p->child[occupy];
618                memset(&p->child[occupy], 0, sizeof(cfg_node));
619                empty++;
620                occupy++;
621            }
622            else break;
623        }
624        else break;
625    }
626}
627static inline int value_in_filter(cfg_node* key, const char* filter[], int filter_count)
628{
629    int i, j;
630    int child_count = GET_CHILD_COUNT(key);
631    for(i = 0; i < child_count; i++)
632    {
633        if(key->child[i].name && *key->child[i].name)
634        {
635            for(j = 0; j < filter_count; j++)
636                if(strcmp(filter[j], key->child[i].name) == 0)
637                    return TRUE;
638        }
639    }
640    return FALSE;
641}
642static int remove_filter_node(const char* section, const char* filter[], int filter_count, int max_allowed)
643{
644    int  si = -1;
645    if((si = find_inode(&root, section)) < 0)
646    {
647        bdle("cannot find section:%s", section);
648        return FALSE;
649    }
650    cfg_node* s = &root.child[si];
651    int child_count = GET_CHILD_COUNT(s);
652    bdld("section:%s, curr child count:%d, filter count:%d", section, child_count, filter_count);
653    if(child_count < max_allowed)
654        return FALSE;
655    //remove until half of max allowance left
656    int total_rm = child_count - max_allowed / 2;
657    int rm_count = 0;
658    int i;
659    for(i = 0; i < child_count; i++)
660    {
661        if(!value_in_filter(&s->child[i], filter, filter_count))
662        {
663            free_child(&s->child[i], 0, GET_CHILD_COUNT(&s->child[i]));
664            free_node(&s->child[i]);
665            rm_count++;
666            if(rm_count >= total_rm)
667                break;
668        }
669    }
670    if(rm_count)
671    {
672        pack_child(s);
673        DEC_CHILD_COUNT(s, rm_count);
674        return TRUE;
675    }
676    return FALSE;
677}
678
679static int save_cfg()
680{
681    const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
682    const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
683    const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
684    int ret = FALSE;
685    if(access(file_name_old,  F_OK) == 0)
686        unlink(file_name_old);
687    if(access(file_name_new, F_OK) == 0)
688        unlink(file_name_new);
689   if(btif_config_save_file(file_name_new))
690    {
691        cached_change = 0;
692        processing_save_cmd = 0;
693        chown(file_name_new, -1, AID_NET_BT_STACK);
694        chmod(file_name_new, 0660);
695        rename(file_name, file_name_old);
696        rename(file_name_new, file_name);
697        ret = TRUE;
698    }
699    else bdle("btif_config_save_file failed");
700    return ret;
701}
702
703static int load_bluez_cfg()
704{
705    char adapter_path[256];
706    if(load_bluez_adapter_info(adapter_path, sizeof(adapter_path)))
707    {
708        if(load_bluez_linkkeys(adapter_path))
709            return TRUE;
710    }
711    return FALSE;
712}
713static void remove_bluez_cfg()
714{
715    rename(BLUEZ_PATH, BLUEZ_PATH_BAK);
716}
717static void clean_newline_char()
718{
719    char kname[128], vname[128];
720    short kpos = 0;
721    int kname_size, vname_size;
722    vname[0] = 0;
723    vname_size = sizeof(vname);
724    //bdld("removing newline at the end of the adapter and device name");
725    if(btif_config_get_str("Local", "Adapter", "Name", vname, &vname_size) &&
726        vname_size > 2)
727    {
728        if(vname[vname_size - 2] == '\n')
729        {
730            bdld("remove newline at the end of the adapter name:%s", vname);
731            vname[vname_size - 2] = 0;
732            btif_config_set_str("Local", "Adapter", "Name", vname);
733        }
734    }
735    do
736    {
737        kname_size = sizeof(kname);
738        kname[0] = 0;
739        kpos = btif_config_next_key(kpos, "Remote", kname, &kname_size);
740        //bdld("Remote device:%s, size:%d", kname, kname_size);
741        vname_size = sizeof(vname);
742        vname[0] = 0;
743        if(btif_config_get_str("Remote", kname, "Name", vname, &vname_size) &&
744            vname_size > 2)
745        {
746            bdld("remote device name:%s", vname);
747            if(vname[vname_size - 2] == '\n')
748            {
749                bdld("remove newline at the end of the device name:%s", vname);
750                vname[vname_size - 2] = 0;
751                btif_config_set_str("Remote", kname, "Name", vname);
752            }
753        }
754     } while(kpos != -1);
755}
756static void load_cfg()
757{
758    const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
759    const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
760    const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
761    if(!btif_config_load_file(file_name))
762    {
763        unlink(file_name);
764        if(!btif_config_load_file(file_name_old))
765        {
766            unlink(file_name_old);
767            if(load_bluez_cfg() && save_cfg())
768                remove_bluez_cfg();
769        }
770    }
771    int bluez_migration_done = 0;
772    btif_config_get_int("Local", "Adapter", "BluezMigrationDone", &bluez_migration_done);
773    if(!bluez_migration_done)
774    {
775        //clean the new line char at the end of the device name. Caused by bluez config import bug
776        clean_newline_char();
777        btif_config_set_int("Local", "Adapter", "BluezMigrationDone", 1);
778        btif_config_save();
779    }
780}
781static void cfg_cmd_callback(int cmd_fd, int type, int size, uint32_t user_id)
782{
783    UNUSED(cmd_fd);
784    UNUSED(size);
785    UNUSED(user_id);
786
787  //bdld("cmd type:%d, size:%d", type, size);
788    switch(type)
789    {
790        case CFG_CMD_SAVE:
791        {
792            int last_cached_change = cached_change;
793            processing_save_cmd = 1;
794            //hold the file saving until no more change in last 3 seconds.
795            bdld("wait until no more changes in short time, cached change:%d", cached_change);
796            int i;
797            for(i = 0; i < 100; i ++) //5 minitue max waiting
798            {
799                sleep(3);
800                if(cached_change == 0 || last_cached_change == cached_change)
801                    break;
802                last_cached_change = cached_change;
803            }
804            bdld("writing the bt_config.xml now, cached change:%d", cached_change);
805            lock_slot(&slot_lock);
806            if(cached_change > 0)
807                save_cfg();
808            unlock_slot(&slot_lock);
809            break;
810        }
811    }
812}
813#ifdef UNIT_TEST
814static void cfg_test_load()
815{
816    load_cfg();
817    char kname[128], vname[128];
818    short kpos, vpos;
819    int kname_size, vname_size;
820    bdld("list all remote devices values:");
821    kname_size = sizeof(kname);
822    kname[0] = 0;
823    kpos = 0;
824    do
825    {
826        kpos = btif_config_next_key(kpos, "Remote Devices", kname, &kname_size);
827        bdld("Remote devices:%s, size:%d", kname, kname_size);
828        vpos = 0;
829        vname[0] = 0;
830        vname_size = sizeof(vname);
831        while((vpos = btif_config_next_value(vpos, "Remote Devices", kname, vname, &vname_size)) != -1)
832        {
833            char v[128] = {0};
834            int vtype = BTIF_CFG_TYPE_STR;
835            int vsize = sizeof(v);
836            int ret = btif_config_get("Remote Devices", kname, vname, v, &vsize, &vtype);
837            bdld("btif_config_get return:%d, Remote devices:%s, value name:%s, value:%s, value size:%d, type:0x%x",
838                              ret, kname, vname, v, vsize, vtype);
839
840            vname[0] = 0;
841            vname_size = sizeof(vname);
842        }
843        kname[0] = 0;
844        kname_size = sizeof(kname);
845    } while(kpos != -1);
846}
847static void cfg_test_write()
848{
849    int i;
850
851    char key[128];
852    const char* section = "Remote";
853    char link_key[64];
854    for(i = 0; i < (int)sizeof(link_key); i++)
855        link_key[i] = i;
856    bdld("[start write testing");
857    if(btif_config_exist("test", "test cfg", "write"))
858        return;
859    btif_config_set_int("test", "test cfg", "write", 1);
860    for(i = 0; i < 50; i++)
861    {
862        if(i % 3 == 0)
863            sprintf(key, "Remote paired %d", i);
864        else sprintf(key, "Remote %d", i);
865        link_key[0] = i;
866        btif_config_set_str(section, key, "class", "smart phone");
867        if(i % 3 == 0)
868        {
869            if(i % 6 == 0)
870                btif_config_set(section, key, "LinkKey", link_key, sizeof(link_key), BTIF_CFG_TYPE_BIN);
871            else btif_config_set(section, key, "LE_KEY_LCSRK", link_key, sizeof(link_key), BTIF_CFG_TYPE_BIN);
872        }
873        btif_config_set_int(section, key, "count", i);
874        if(!btif_config_exist(section, key, "time stamp"))
875            btif_config_set_int(section, key, "time stamp", time(NULL));
876    }
877    static const char* exclude_filter[] =
878    {"LinkKey", "LE_KEY_PENC", "LE_KEY_PID", "LE_KEY_PCSRK", "LE_KEY_LENC", "LE_KEY_LCSRK"};
879    const int max_allowed_remote_device = 40;
880    btif_config_filter_remove("Remote", exclude_filter, sizeof(exclude_filter)/sizeof(char*),
881            max_allowed_remote_device);
882    bdld("]end write testing");
883    btif_config_flush();
884}
885static void cfg_test_read()
886{
887    //debug("in");
888    char class[128] = {0};
889    char link_key[128] = {0};
890    int size, type;
891    char key[128];
892    const char* section;
893    int ret, i;
894    for(i = 0; i < 100; i++)
895    {
896        sprintf(key, "00:22:5F:97:56:%02d", i);
897        section = "Remote";
898        size = sizeof(class);
899        ret = btif_config_get_str(section, key, "class", class, &size);
900        bdld("btif_config_get_str return:%d, Remote devices:%s, class:%s", ret, key, class);
901
902        size = sizeof(link_key);
903        type = BTIF_CFG_TYPE_BIN;
904        ret = btif_config_get(section, key, "link keys", link_key, &size, &type);
905        //debug("btif_config_get return:%d, Remote devices:%s, link key:%x, %x",
906        //            ret, key, *(int *)link_key, *((int *)link_key + 1));
907
908        int timeout;
909        ret = btif_config_get_int(section, key, "connect time out", &timeout);
910        //debug("btif_config_get_int return:%d, Remote devices:%s, connect time out:%d", ret, key, timeout);
911    }
912
913    // debug("testing btif_config_remove");
914    size = sizeof(class);
915    type = BTIF_CFG_TYPE_STR;
916    btif_config_set("Remote", "00:22:5F:97:56:04", "Class Delete", class, strlen(class) + 1, BTIF_CFG_TYPE_STR);
917
918    btif_config_get("Remote", "00:22:5F:97:56:04", "Class Delete", class, &size, &type);
919    // debug("Remote devices, 00:22:5F:97:56:04 Class Delete:%s", class);
920    btif_config_remove("Remote", "00:22:5F:97:56:04", "Class Delete");
921
922    size = sizeof(class);
923    type = BTIF_CFG_TYPE_STR;
924    ret = btif_config_get("Remote", "00:22:5F:97:56:04", "Class Delete", class, &size, &type);
925    // debug("after removed, btif_config_get ret:%d, Remote devices, 00:22:5F:97:56:04 Class Delete:%s", ret, class);
926    // debug("out");
927}
928#endif
929