btif_config.c revision 335aa36bca8532874c23c1afe5bfc2aff7fc01a5
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 save_cmds_queued;
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    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}
358void btif_config_flush()
359{
360    lock_slot(&slot_lock);
361    if(cached_change > 0)
362        save_cfg();
363    unlock_slot(&slot_lock);
364}
365/////////////////////////////////////////////////////////////////////////////////////////////
366static 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}
385static 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}
402static 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}
420static 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}
430static 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}
452static 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}
489static 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}
516static 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}
548static 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}
566static 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}
592static 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}
602static 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
611static 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}
638static 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}
653static 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
690static 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
713static 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}
723static void remove_bluez_cfg()
724{
725    rename(BLUEZ_PATH, BLUEZ_PATH_BAK);
726}
727static 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}
766static 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}
791static 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
833static 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}
866static 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}
904static 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