btif_config.c revision 5738f83aeb59361a0a2eda2460113f6dc9194271
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.c"
45
46#include <hardware/bluetooth.h>
47#include "btif_config.h"
48#include "btif_config_util.h"
49#include "btif_sock_thread.h"
50#include "btif_sock_util.h"
51
52#include <cutils/log.h>
53#define info(fmt, ...)  ALOGI ("%s(L%d): " fmt,__FUNCTION__, __LINE__,  ## __VA_ARGS__)
54#define debug(fmt, ...) ALOGD ("%s(L%d): " fmt,__FUNCTION__, __LINE__,  ## __VA_ARGS__)
55#define warn(fmt, ...) ALOGW ("## WARNING : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__)
56#define error(fmt, ...) ALOGE ("## ERROR : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__)
57#define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__)
58//#define UNIT_TEST
59#define CFG_PATH "/data/misc/bluedroid/"
60#define CFG_FILE_NAME "bt_config"
61#define CFG_FILE_EXT ".xml"
62#define CFG_FILE_EXT_OLD ".old"
63#define CFG_FILE_EXT_NEW ".new"
64#define CFG_GROW_SIZE (10*sizeof(cfg_node))
65#define GET_CHILD_MAX_COUNT(node) (short)((int)(node)->bytes / sizeof(cfg_node))
66#define IS_EMPTY(node) ((node)->name == NULL)
67#define GET_NODE_COUNT(bytes) (bytes / sizeof(cfg_node))
68#define MAX_NODE_BYTES 32000
69#define MAX_CACHED_COUNT 150
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 void cfg_cmd_callback(int cmd_fd, int type, int flags, uint32_t user_id);
95static inline short alloc_node(cfg_node* p, short grow);
96static inline void free_node(cfg_node* p);
97static inline void free_inode(cfg_node* p, int child);
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 inline cfg_node* find_free_node(cfg_node* p);
102static int set_node(const char* section, const char* key, const char* name,
103                        const char* value, short bytes, short type);
104static int save_cfg();
105static void load_cfg();
106static short find_next_node(const cfg_node* p, short start, char* name, int* bytes);
107static int create_dir(const char* path);
108#ifdef UNIT_TEST
109static void cfg_test_load();
110static void cfg_test_write();
111static void cfg_test_read();
112#endif
113static inline void dump_node(const char* title, const cfg_node* p)
114{
115    if(p)
116        debug("%s, p->name:%s, child/value:%p, bytes:%d, p->used:%d, type:%x, p->flag:%d",
117            title, p->name, p->child, p->bytes, p->used, p->type, p->flag);
118    else debug("%s is NULL", title);
119}
120////////////////////////////////////////////////////////////////////////////////////////////////////////////
121int btif_config_init()
122{
123    static int initialized;
124    debug("in initialized:%d", initialized);
125    if(!initialized)
126    {
127        initialized = 1;
128        struct stat st;
129        if(stat(CFG_PATH, &st) != 0)
130            error("%s does not exist, need provision", CFG_PATH);
131        btsock_thread_init();
132        init_slot_lock(&slot_lock);
133        lock_slot(&slot_lock);
134        root.name = "Bluedroid";
135        alloc_node(&root, CFG_GROW_SIZE);
136        dump_node("root", &root);
137        pth = btsock_thread_create(NULL, cfg_cmd_callback);
138        load_cfg();
139        unlock_slot(&slot_lock);
140        #ifdef UNIT_TEST
141            //cfg_test_load();
142            cfg_test_write();
143            cfg_test_read();
144        #endif
145    }
146    return pth >= 0;
147}
148int btif_config_get_int(const char* section, const char* key, const char* name, int* value)
149{
150    int size = sizeof(*value);
151    int type = BTIF_CFG_TYPE_INT;
152    return btif_config_get(section, key, name, (char*)value, &size, &type);
153}
154int btif_config_set_int(const char* section, const char* key, const char* name, int value)
155{
156    return btif_config_set(section, key, name, (char*)&value, sizeof(value), BTIF_CFG_TYPE_INT);
157}
158int btif_config_get_str(const char* section, const char* key, const char* name, char* value, int* size)
159{
160    int type = BTIF_CFG_TYPE_STR;
161    if(value)
162        *value = 0;
163    return btif_config_get(section, key, name, value, size, &type);
164}
165int btif_config_set_str(const char* section, const char* key, const char* name, const char* value)
166{
167   value = value ? value : "";
168   return btif_config_set(section, key, name, value, strlen(value) + 1, BTIF_CFG_TYPE_STR);
169}
170int btif_config_exist(const char* section, const char* key, const char* name)
171{
172    int ret = FALSE;
173    if(section && *section && key && *key)
174    {
175        lock_slot(&slot_lock);
176        ret = find_node(section, key, name) != NULL;
177        unlock_slot(&slot_lock);
178    }
179    return ret;
180}
181int btif_config_get(const char* section, const char* key, const char* name, char* value, int* bytes, int* type)
182{
183    //debug("in");
184
185    int ret = FALSE;
186    asrt(section && *section && key && *key && name && *name && bytes && type);
187    //debug("section:%s, key:%s, name:%s, value:%p, bytes:%d, type:%d",
188    //            section, key, name, value, *bytes, *type);
189    if(section && *section && key && *key && name && *name && bytes && type)
190    {
191        lock_slot(&slot_lock);
192        const cfg_node* node = find_node(section, key, name);
193        dump_node("found node", node);
194        if(node)
195        {
196            if(*type == node->type && value && *bytes >= node->used)
197            {
198                if(node->used > 0)
199                    memcpy(value, node->value, node->used);
200                ret = TRUE;
201            }
202            *type = node->type;
203            *bytes = node->used;
204            if(ret != TRUE)
205            {
206                if(*type != node->type)
207                    error("value:%s, wrong type:%d, need to be type: %d", name, *type, node->type);
208                if(value && *bytes < node->used)
209                    error("value:%s, not enough size: %d bytes, need %d bytes", name, node->used, *bytes);
210            }
211        }
212        unlock_slot(&slot_lock);
213    }
214    //debug("out");
215    return ret;
216}
217int btif_config_set(const char* section, const char* key, const char* name, const char*  value, int bytes, int type)
218{
219    int ret = FALSE;
220    asrt(section && *section && key && *key && name && *name);
221    asrt(bytes < MAX_NODE_BYTES);
222    if(section && *section && key && *key && name && *name && bytes < MAX_NODE_BYTES)
223    {
224        lock_slot(&slot_lock);
225        ret = set_node(section, key, name, value, (short)bytes, (short)type);
226        if(ret && !(type & BTIF_CFG_TYPE_VOLATILE) && ++cached_change > MAX_CACHED_COUNT)
227        {
228            cached_change = 0;
229            btsock_thread_post_cmd(pth, CFG_CMD_SAVE, NULL, 0, 0);
230        }
231
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    asrt(section && *section && key && *key);
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}
250typedef struct {
251    short si;
252    short ki;
253    short vi;
254    short reserved;
255} cfg_node_pos;
256short btif_config_next_key(short pos, const char* section, char * name, int* bytes)
257{
258    int next = -1;
259    lock_slot(&slot_lock);
260    short si = find_inode(&root, section);
261    if(si >= 0)
262    {
263        const cfg_node* section_node = &root.child[si];
264        next = find_next_node(section_node, pos, name, bytes);
265    }
266    unlock_slot(&slot_lock);
267    return next;
268}
269short btif_config_next_value(short pos, const char* section, const char* key, char* name, int* bytes)
270{
271    int next = -1;
272    lock_slot(&slot_lock);
273    short si = find_inode(&root, section);
274    if(si >= 0)
275    {
276        const cfg_node* section_node = &root.child[si];
277        short ki = find_inode(section_node, key);
278        if(ki >= 0)
279        {
280            const cfg_node* key_node = &section_node->child[ki];
281            next = find_next_node(key_node, pos, name, bytes);
282        }
283    }
284    unlock_slot(&slot_lock);
285    return next;
286}
287int btif_config_enum(btif_config_enum_callback cb, void* user_data)
288{
289    asrt(cb);
290    if(!cb)
291        return FALSE;
292    lock_slot(&slot_lock);
293    int si, ki, vi;
294    cfg_node *section_node, *key_node, *value_node;
295    for(si = 0; si < GET_CHILD_MAX_COUNT(&root); si++)
296    {
297        section_node = &root.child[si];
298        if(section_node->name && *section_node->name)
299        {
300            for(ki = 0; ki < GET_CHILD_MAX_COUNT(section_node); ki++)
301            {
302                key_node = &section_node->child[ki];
303                if(key_node->name && *key_node->name)
304                {
305                    for(vi = 0; vi < GET_CHILD_MAX_COUNT(key_node); vi++)
306                    {
307                        value_node = &key_node->child[vi];
308                        if(value_node->name && *value_node->name)
309                        {
310                            cb(user_data, section_node->name, key_node->name, value_node->name,
311                                            value_node->value, value_node->used, value_node->type);
312                        }
313                    }
314                }
315            }
316        }
317    }
318    unlock_slot(&slot_lock);
319    return TRUE;
320}
321int btif_config_save()
322{
323    lock_slot(&slot_lock);
324    if(cached_change > 0)
325    {
326        cached_change = 0;
327        btsock_thread_post_cmd(pth, CFG_CMD_SAVE, NULL, 0, 0);
328    }
329    unlock_slot(&slot_lock);
330    return TRUE;
331}
332void btif_config_flush()
333{
334    lock_slot(&slot_lock);
335    if(cached_change > 0)
336        save_cfg();
337    unlock_slot(&slot_lock);
338}
339/////////////////////////////////////////////////////////////////////////////////////////////
340static inline short alloc_node(cfg_node* p, short grow)
341{
342    int new_bytes = p->bytes + grow;
343    //debug("in, bytes:%d, new bytes:%d, grow:%d", p->bytes, new_bytes, grow);
344    if(grow > 0 && new_bytes < MAX_NODE_BYTES)
345    {
346        char* value = (char*)realloc(p->value, new_bytes);
347        if(value)
348        {
349            short old_bytes = p->bytes;
350            //clear to zero
351            memset(value + old_bytes, 0, grow);
352            p->bytes = old_bytes + grow;
353            p->value = value;
354            //debug("out");
355            return old_bytes;//return the previous size
356        }
357        else error("realloc failed, old_bytes:%d, grow:%d, total:%d", p->bytes, grow,  p->bytes + grow);
358    }
359    //debug("out, alloc failed");
360    return -1;
361}
362static inline void free_node(cfg_node* p)
363{
364    if(p)
365    {
366        if(p->child)
367        {
368            free(p->child);
369            p->child = NULL;
370        }
371        if(p->name)
372        {
373            free((void*)p->name);
374            p->name = 0;
375        }
376        p->used = p->bytes = p->flag = p->type = 0;
377    }
378}
379static inline short find_inode(const cfg_node* p, const char* name)
380{
381    //debug("in");
382    if(p && p->child && name && *name)
383    {
384        int i;
385        int count = GET_CHILD_MAX_COUNT(p);
386        //debug("child name:%s, child max count:%d", name, count);
387        for(i = 0; i < count; i++)
388        {
389            if(p->child[i].name && *p->child[i].name &&
390                strcmp(p->child[i].name, name) == 0)
391            {
392                  //debug("out found child index:%d", i);
393                  return (short)i;
394            }
395        }
396    }
397    //debug("out, child name: %s not found", name);
398    return -1;
399}
400static inline cfg_node* find_free_node(cfg_node* p)
401{
402    if(p && p->child)
403    {
404        int i;
405        int count = GET_CHILD_MAX_COUNT(p);
406        //debug("p->name:%s, max child count:%d", p->name, count);
407        for(i = 0; i < count; i++)
408        {
409            if(IS_EMPTY(p->child + i))
410                return p->child + i;
411        }
412    }
413    return NULL;
414}
415static cfg_node* find_add_node(cfg_node* p, const char* name)
416{
417    int i = -1;
418    cfg_node* node = NULL;
419    //debug("in, p->name:%s, p->bytes:%d, adding child:%s", p->name, p->bytes, name);
420    if((i = find_inode(p, name)) < 0)
421    {
422        if(!(node = find_free_node(p)))
423        {
424            int old_size = alloc_node(p, CFG_GROW_SIZE);
425            if(old_size >= 0)
426            {
427                i = GET_NODE_COUNT(old_size);
428                node = &p->child[i];
429            }
430        }
431    }
432    else node = &p->child[i];
433    if(!node->name)
434        node->name = strdup(name);
435    //debug("out");
436    return node;
437}
438static int set_node(const char* section, const char* key, const char* name,
439                    const char* value, short bytes, short type)
440{
441    int si = -1, ki = -1, vi = -1;
442    cfg_node* section_node = NULL;
443    //debug("in");
444    //dump_node("root", &root);
445    if((section_node = find_add_node(&root, section)))
446    {
447        //dump_node("section node", section_node);
448        cfg_node* key_node;
449        if((key_node = find_add_node(section_node, key)))
450        {
451            //dump_node("key node", key_node);
452            cfg_node* value_node;
453            if((value_node = find_add_node(key_node, name)))
454            {
455                //dump_node("value node", value_node);
456                if(value_node->bytes < bytes)
457                {
458                    if(value_node->value)
459                        free(value_node->value);
460                    value_node->value = (char*)malloc(bytes);
461                    if(value_node->value)
462                        value_node->bytes = bytes;
463                    else
464                    {
465                        error("not enough memory!");
466                        value_node->bytes = 0;
467                        return FALSE;
468                    }
469                }
470                if(value_node->value && value != NULL && bytes > 0)
471                    memcpy(value_node->value, value, bytes);
472                value_node->type = type;
473                value_node->used = bytes;
474                //dump_node("changed value node", value_node);
475                return TRUE;
476            }
477        }
478    }
479    return FALSE;
480}
481static cfg_node* find_node(const char* section, const char* key, const char* name)
482{
483    int si = -1, ki = -1, vi = -1;
484    if((si = find_inode(&root, section)) >= 0)
485    {
486        cfg_node* section_node = &root.child[si];
487        if(key)
488        {
489            //dump_node("found section node", section_node);
490            if((ki = find_inode(section_node, key)) >= 0)
491            {
492                cfg_node* key_node = &section_node->child[ki];
493                //dump_node("found key node", key_node);
494                if(name)
495                {
496                    if((vi = find_inode(key_node, name)) >= 0)
497                    {
498                        //dump_node("found value node", &key_node->child[vi]);
499                        return &key_node->child[vi];
500                    }
501                    //debug("value node:%s not found", name);
502                    return NULL;
503                }
504                return key_node;
505            }
506            //debug("key node:%s not found", key);
507            return NULL;
508        }
509        return section_node;
510    }
511    //debug("section node:%s not found", section);
512    return NULL;
513}
514static short find_next_node(const cfg_node* p, short start, char* name, int* bytes)
515{
516    asrt(0 <= start && start < GET_CHILD_MAX_COUNT(p));
517    //debug("in, start:%d, max child count:%d", start, GET_CHILD_MAX_COUNT(p));
518    //dump_node("find_next_node, parent", p);
519    short next = -1;
520    if(name) *name = 0;
521    if(0 <= start && start < GET_CHILD_MAX_COUNT(p))
522    {
523        int i;
524        for(i = start; i < GET_CHILD_MAX_COUNT(p); i++)
525        {
526            cfg_node* child = &p->child[i];
527            if(child->name)
528            {
529                int name_bytes = strlen(child->name) + 1;
530                if(name && bytes && *bytes >= name_bytes)
531                {
532                    memcpy(name, child->name, name_bytes);
533                    if(i + 1 < GET_CHILD_MAX_COUNT(p))
534                        next = (short)(i + 1);
535                    *bytes = name_bytes;
536                }
537                else if(bytes)
538                {
539                    //debug("not enough room to copy the name, size in:%d, size needed:%d", *bytes, name_bytes);
540                    *bytes = name_bytes;
541                }
542                break;
543            }
544        }
545    }
546    return next;
547}
548static int remove_node(const char* section, const char* key, const char* name)
549{
550    short  si = -1, ki = -1, vi = -1;
551    if((si = find_inode(&root, section)) >= 0)
552    {
553        cfg_node* section_node = &root.child[si];
554        if((ki = find_inode(section_node, key)) >= 0)
555        {
556            cfg_node* key_node = &section_node->child[ki];
557            if(name == NULL)
558            {
559                int count = GET_CHILD_MAX_COUNT(key_node);
560                int i;
561                for(i = 0; i < count; i++)
562                    free_node(&key_node->child[i]);
563                free_node(key_node);
564                return TRUE;
565            }
566            else if((vi = find_inode(key_node, name)) >= 0)
567            {
568                //debug("remove value:%s", key_node->child[vi].name);
569                free_node(&key_node->child[vi]);
570                return TRUE;
571            }
572        }
573    }
574    return FALSE;
575}
576static int save_cfg()
577{
578    debug("in");
579    const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
580    const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
581    const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
582    int ret = FALSE;
583    if(access(file_name_old,  F_OK) == 0)
584        unlink(file_name_old);
585    if(access(file_name_new, F_OK) == 0)
586        unlink(file_name_new);
587   if(btif_config_save_file(file_name_new))
588    {
589        cached_change = 0;
590        chown(file_name_new, -1, AID_NET_BT_STACK);
591        chmod(file_name_new, 0660);
592        rename(file_name, file_name_old);
593        rename(file_name_new, file_name);
594        ret = TRUE;
595    }
596    else error("btif_config_save_file failed");
597    debug("out");
598    return ret;
599}
600
601static int load_bluez_cfg()
602{
603    char adapter_path[256];
604    if(load_bluez_adapter_info(adapter_path, sizeof(adapter_path)))
605    {
606        if(load_bluez_linkkeys(adapter_path))
607            return TRUE;
608    }
609    return FALSE;
610}
611static void remove_bluez_cfg()
612{
613    rename(BLUEZ_PATH, BLUEZ_PATH_BAK);
614}
615static void load_cfg()
616{
617    const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
618    const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
619    const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
620    if(!btif_config_load_file(file_name))
621    {
622        unlink(file_name);
623        if(!btif_config_load_file(file_name_old))
624        {
625            unlink(file_name_old);
626            if(load_bluez_cfg() && save_cfg())
627                remove_bluez_cfg();
628        }
629    }
630}
631static void cfg_cmd_callback(int cmd_fd, int type, int size, uint32_t user_id)
632{
633    debug("cmd type:%d, size:%d", type, size);
634    switch(type)
635    {
636        case CFG_CMD_SAVE:
637            lock_slot(&slot_lock);
638            save_cfg();
639            unlock_slot(&slot_lock);
640            break;
641    }
642}
643#ifdef UNIT_TEST
644static void cfg_test_load()
645{
646    load_cfg();
647    char kname[128], vname[128];
648    short kpos, vpos;
649    int kname_size, vname_size;
650    debug("in");
651    debug("list all remote devices values:");
652    kname_size = sizeof(kname);
653    kname[0] = 0;
654    kpos = 0;
655    do
656    {
657        kpos = btif_config_next_key(kpos, "Remote Devices", kname, &kname_size);
658        debug("Remote devices:%s, size:%d", kname, kname_size);
659        vpos = 0;
660        vname[0] = 0;
661        vname_size = sizeof(vname);
662        while((vpos = btif_config_next_value(vpos, "Remote Devices", kname, vname, &vname_size)) != -1)
663        {
664            char v[128] = {0};
665            int vtype = BTIF_CFG_TYPE_STR;
666            int vsize = sizeof(v);
667            int ret = btif_config_get("Remote Devices", kname, vname, v, &vsize, &vtype);
668            debug("btif_config_get return:%d, Remote devices:%s, value name:%s, value:%s, value size:%d, type:0x%x",
669                    ret, kname, vname, v, vsize, vtype);
670
671            vname[0] = 0;
672            vname_size = sizeof(vname);
673        }
674        kname[0] = 0;
675        kname_size = sizeof(kname);
676    } while(kpos != -1);
677    debug("out");
678}
679static void cfg_test_write()
680{
681    debug("in");
682    int i;
683
684    char key[128];
685    const char* section;
686    char link_key[64];
687    for(i = 0; i < (int)sizeof(link_key); i++)
688        link_key[i] = i;
689    for(i = 0; i < 100; i++)
690    {
691        sprintf(key, "00:22:5F:97:56:%02d", i);
692        link_key[0] = i;
693        section = "Remote Devices";
694        btif_config_set_str(section, key, "class", "smart phone");
695        btif_config_set(section, key, "link keys", link_key, sizeof(link_key), BTIF_CFG_TYPE_BIN);
696        btif_config_set_int(section, key, "connect time out", i);
697    }
698    btif_config_save();
699    debug("out");
700}
701static void cfg_test_read()
702{
703    debug("in");
704    char class[128] = {0};
705    char link_key[128] = {0};
706    int size, type;
707    char key[128];
708    const char* section;
709    int ret, i;
710    for(i = 0; i < 100; i++)
711    {
712        sprintf(key, "00:22:5F:97:56:%02d", i);
713        section = "Remote Devices";
714        size = sizeof(class);
715        ret = btif_config_get_str(section, key, "class", class, &size);
716        debug("btif_config_get_str return:%d, Remote devices:%s, class:%s", ret, key, class);
717
718        size = sizeof(link_key);
719        type = BTIF_CFG_TYPE_BIN;
720        ret = btif_config_get(section, key, "link keys", link_key, &size, &type);
721        debug("btif_config_get return:%d, Remote devices:%s, link key:%x, %x",
722                    ret, key, *(int *)link_key, *((int *)link_key + 1));
723
724        int timeout;
725        ret = btif_config_get_int(section, key, "connect time out", &timeout);
726        debug("btif_config_get_int return:%d, Remote devices:%s, connect time out:%d", ret, key, timeout);
727    }
728
729    debug("testing btif_config_remove");
730    size = sizeof(class);
731    type = BTIF_CFG_TYPE_STR;
732    btif_config_set("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, strlen(class) + 1, BTIF_CFG_TYPE_STR);
733
734    btif_config_get("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, &size, &type);
735    debug("Remote devices, 00:22:5F:97:56:04 Class Delete:%s", class);
736    btif_config_remove("Remote Devices", "00:22:5F:97:56:04", "Class Delete");
737
738    size = sizeof(class);
739    type = BTIF_CFG_TYPE_STR;
740    ret = btif_config_get("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, &size, &type);
741    debug("after removed, btif_config_get ret:%d, Remote devices, 00:22:5F:97:56:04 Class Delete:%s", ret, class);
742    debug("out");
743}
744#endif
745