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