Home | History | Annotate | Download | only in src
      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
     76 typedef 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 
     90 static pthread_mutex_t slot_lock;
     91 static int pth = -1; //poll thread handle
     92 static cfg_node root;
     93 static int cached_change;
     94 static void cfg_cmd_callback(int cmd_fd, int type, int flags, uint32_t user_id);
     95 static inline short alloc_node(cfg_node* p, short grow);
     96 static inline void free_node(cfg_node* p);
     97 static inline void free_inode(cfg_node* p, int child);
     98 static inline short find_inode(const cfg_node* p, const char* name);
     99 static cfg_node* find_node(const char* section, const char* key, const char* name);
    100 static int remove_node(const char* section, const char* key, const char* name);
    101 static inline cfg_node* find_free_node(cfg_node* p);
    102 static int set_node(const char* section, const char* key, const char* name,
    103                         const char* value, short bytes, short type);
    104 static int save_cfg();
    105 static void load_cfg();
    106 static short find_next_node(const cfg_node* p, short start, char* name, int* bytes);
    107 static int create_dir(const char* path);
    108 #ifdef UNIT_TEST
    109 static void cfg_test_load();
    110 static void cfg_test_write();
    111 static void cfg_test_read();
    112 #endif
    113 static 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 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    121 int 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 }
    148 int 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 }
    154 int 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 }
    158 int 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 }
    165 int 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 }
    170 int 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 }
    181 int 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 }
    217 int 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 }
    236 int 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 }
    250 typedef struct {
    251     short si;
    252     short ki;
    253     short vi;
    254     short reserved;
    255 } cfg_node_pos;
    256 short 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 }
    269 short 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 }
    287 int 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 }
    321 int 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 }
    332 void btif_config_flush()
    333 {
    334     lock_slot(&slot_lock);
    335     if(cached_change > 0)
    336         save_cfg();
    337     unlock_slot(&slot_lock);
    338 }
    339 /////////////////////////////////////////////////////////////////////////////////////////////
    340 static 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 }
    362 static 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 }
    379 static 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 }
    400 static 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 }
    415 static 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 }
    438 static 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 }
    481 static 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 }
    514 static 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 }
    548 static 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 }
    576 static 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 
    601 static 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 }
    611 static void remove_bluez_cfg()
    612 {
    613     rename(BLUEZ_PATH, BLUEZ_PATH_BAK);
    614 }
    615 static 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 }
    631 static 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
    644 static 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 }
    679 static 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 }
    701 static 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