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