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