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