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 = §ion_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 = §ion_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 = §ion_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 = §ion_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