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