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