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 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
     73 typedef 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 
     87 static pthread_mutex_t slot_lock;
     88 static int pth = -1; //poll thread handle
     89 static cfg_node root;
     90 static int cached_change;
     91 static int processing_save_cmd;
     92 static void cfg_cmd_callback(int cmd_fd, int type, int flags, uint32_t user_id);
     93 static inline short alloc_node(cfg_node* p, short grow);
     94 static inline void free_node(cfg_node* p);
     95 static inline void free_inode(cfg_node* p, int child);
     96 static inline short find_inode(const cfg_node* p, const char* name);
     97 static cfg_node* find_node(const char* section, const char* key, const char* name);
     98 static int remove_node(const char* section, const char* key, const char* name);
     99 static int remove_filter_node(const char* section, const char* filter[], int filter_count, int max_allowed);
    100 static inline cfg_node* find_free_node(cfg_node* p);
    101 static int set_node(const char* section, const char* key, const char* name,
    102                         const char* value, short bytes, short type);
    103 static int save_cfg();
    104 static void load_cfg();
    105 static short find_next_node(const cfg_node* p, short start, char* name, int* bytes);
    106 static int create_dir(const char* path);
    107 #ifdef UNIT_TEST
    108 static void cfg_test_load();
    109 static void cfg_test_write();
    110 static 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 
    115 static 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 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    126 int 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 }
    153 int 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 }
    159 int 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 }
    163 int 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 }
    170 int 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 }
    175 int 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 }
    186 int 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 }
    221 int 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 }
    236 int 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 
    252 int 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 }
    268 typedef struct {
    269     short si;
    270     short ki;
    271     short vi;
    272     short reserved;
    273 } cfg_node_pos;
    274 short 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 }
    287 short 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 }
    305 int 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 }
    339 int 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 }
    348 void btif_config_flush()
    349 {
    350     lock_slot(&slot_lock);
    351     if(cached_change > 0)
    352         save_cfg();
    353     unlock_slot(&slot_lock);
    354 }
    355 /////////////////////////////////////////////////////////////////////////////////////////////
    356 static 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 }
    375 static 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 }
    392 static 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 }
    410 static 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 }
    420 static 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 }
    442 static 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 }
    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             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 }
    506 static 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 }
    538 static 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 }
    556 static 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 }
    582 static 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 }
    592 static 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 
    601 static 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 }
    628 static 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 }
    643 static 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 
    680 static 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 
    704 static 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 }
    714 static void remove_bluez_cfg()
    715 {
    716     rename(BLUEZ_PATH, BLUEZ_PATH_BAK);
    717 }
    718 static 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 }
    757 static 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 }
    782 static 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
    811 static 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 }
    844 static 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 }
    882 static 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