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