btif_config.c revision 5738f83aeb59361a0a2eda2460113f6dc9194271
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.c" 45 46#include <hardware/bluetooth.h> 47#include "btif_config.h" 48#include "btif_config_util.h" 49#include "btif_sock_thread.h" 50#include "btif_sock_util.h" 51 52#include <cutils/log.h> 53#define info(fmt, ...) ALOGI ("%s(L%d): " fmt,__FUNCTION__, __LINE__, ## __VA_ARGS__) 54#define debug(fmt, ...) ALOGD ("%s(L%d): " fmt,__FUNCTION__, __LINE__, ## __VA_ARGS__) 55#define warn(fmt, ...) ALOGW ("## WARNING : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__) 56#define error(fmt, ...) ALOGE ("## ERROR : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__) 57#define asrt(s) if(!(s)) ALOGE ("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__) 58//#define UNIT_TEST 59#define CFG_PATH "/data/misc/bluedroid/" 60#define CFG_FILE_NAME "bt_config" 61#define CFG_FILE_EXT ".xml" 62#define CFG_FILE_EXT_OLD ".old" 63#define CFG_FILE_EXT_NEW ".new" 64#define CFG_GROW_SIZE (10*sizeof(cfg_node)) 65#define GET_CHILD_MAX_COUNT(node) (short)((int)(node)->bytes / sizeof(cfg_node)) 66#define IS_EMPTY(node) ((node)->name == NULL) 67#define GET_NODE_COUNT(bytes) (bytes / sizeof(cfg_node)) 68#define MAX_NODE_BYTES 32000 69#define MAX_CACHED_COUNT 150 70#define CFG_CMD_SAVE 1 71 72#ifndef FALSE 73#define TRUE 1 74#define FALSE 0 75#endif 76typedef 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 90static pthread_mutex_t slot_lock; 91static int pth = -1; //poll thread handle 92static cfg_node root; 93static int cached_change; 94static void cfg_cmd_callback(int cmd_fd, int type, int flags, uint32_t user_id); 95static inline short alloc_node(cfg_node* p, short grow); 96static inline void free_node(cfg_node* p); 97static inline void free_inode(cfg_node* p, int child); 98static inline short find_inode(const cfg_node* p, const char* name); 99static cfg_node* find_node(const char* section, const char* key, const char* name); 100static int remove_node(const char* section, const char* key, const char* name); 101static inline cfg_node* find_free_node(cfg_node* p); 102static int set_node(const char* section, const char* key, const char* name, 103 const char* value, short bytes, short type); 104static int save_cfg(); 105static void load_cfg(); 106static short find_next_node(const cfg_node* p, short start, char* name, int* bytes); 107static int create_dir(const char* path); 108#ifdef UNIT_TEST 109static void cfg_test_load(); 110static void cfg_test_write(); 111static void cfg_test_read(); 112#endif 113static inline void dump_node(const char* title, const cfg_node* p) 114{ 115 if(p) 116 debug("%s, p->name:%s, child/value:%p, bytes:%d, p->used:%d, type:%x, p->flag:%d", 117 title, p->name, p->child, p->bytes, p->used, p->type, p->flag); 118 else debug("%s is NULL", title); 119} 120//////////////////////////////////////////////////////////////////////////////////////////////////////////// 121int btif_config_init() 122{ 123 static int initialized; 124 debug("in initialized:%d", initialized); 125 if(!initialized) 126 { 127 initialized = 1; 128 struct stat st; 129 if(stat(CFG_PATH, &st) != 0) 130 error("%s does not exist, need provision", CFG_PATH); 131 btsock_thread_init(); 132 init_slot_lock(&slot_lock); 133 lock_slot(&slot_lock); 134 root.name = "Bluedroid"; 135 alloc_node(&root, CFG_GROW_SIZE); 136 dump_node("root", &root); 137 pth = btsock_thread_create(NULL, cfg_cmd_callback); 138 load_cfg(); 139 unlock_slot(&slot_lock); 140 #ifdef UNIT_TEST 141 //cfg_test_load(); 142 cfg_test_write(); 143 cfg_test_read(); 144 #endif 145 } 146 return pth >= 0; 147} 148int btif_config_get_int(const char* section, const char* key, const char* name, int* value) 149{ 150 int size = sizeof(*value); 151 int type = BTIF_CFG_TYPE_INT; 152 return btif_config_get(section, key, name, (char*)value, &size, &type); 153} 154int btif_config_set_int(const char* section, const char* key, const char* name, int value) 155{ 156 return btif_config_set(section, key, name, (char*)&value, sizeof(value), BTIF_CFG_TYPE_INT); 157} 158int btif_config_get_str(const char* section, const char* key, const char* name, char* value, int* size) 159{ 160 int type = BTIF_CFG_TYPE_STR; 161 if(value) 162 *value = 0; 163 return btif_config_get(section, key, name, value, size, &type); 164} 165int btif_config_set_str(const char* section, const char* key, const char* name, const char* value) 166{ 167 value = value ? value : ""; 168 return btif_config_set(section, key, name, value, strlen(value) + 1, BTIF_CFG_TYPE_STR); 169} 170int btif_config_exist(const char* section, const char* key, const char* name) 171{ 172 int ret = FALSE; 173 if(section && *section && key && *key) 174 { 175 lock_slot(&slot_lock); 176 ret = find_node(section, key, name) != NULL; 177 unlock_slot(&slot_lock); 178 } 179 return ret; 180} 181int btif_config_get(const char* section, const char* key, const char* name, char* value, int* bytes, int* type) 182{ 183 //debug("in"); 184 185 int ret = FALSE; 186 asrt(section && *section && key && *key && name && *name && bytes && type); 187 //debug("section:%s, key:%s, name:%s, value:%p, bytes:%d, type:%d", 188 // section, key, name, value, *bytes, *type); 189 if(section && *section && key && *key && name && *name && bytes && type) 190 { 191 lock_slot(&slot_lock); 192 const cfg_node* node = find_node(section, key, name); 193 dump_node("found node", node); 194 if(node) 195 { 196 if(*type == node->type && value && *bytes >= node->used) 197 { 198 if(node->used > 0) 199 memcpy(value, node->value, node->used); 200 ret = TRUE; 201 } 202 *type = node->type; 203 *bytes = node->used; 204 if(ret != TRUE) 205 { 206 if(*type != node->type) 207 error("value:%s, wrong type:%d, need to be type: %d", name, *type, node->type); 208 if(value && *bytes < node->used) 209 error("value:%s, not enough size: %d bytes, need %d bytes", name, node->used, *bytes); 210 } 211 } 212 unlock_slot(&slot_lock); 213 } 214 //debug("out"); 215 return ret; 216} 217int btif_config_set(const char* section, const char* key, const char* name, const char* value, int bytes, int type) 218{ 219 int ret = FALSE; 220 asrt(section && *section && key && *key && name && *name); 221 asrt(bytes < MAX_NODE_BYTES); 222 if(section && *section && key && *key && name && *name && bytes < MAX_NODE_BYTES) 223 { 224 lock_slot(&slot_lock); 225 ret = set_node(section, key, name, value, (short)bytes, (short)type); 226 if(ret && !(type & BTIF_CFG_TYPE_VOLATILE) && ++cached_change > MAX_CACHED_COUNT) 227 { 228 cached_change = 0; 229 btsock_thread_post_cmd(pth, CFG_CMD_SAVE, NULL, 0, 0); 230 } 231 232 unlock_slot(&slot_lock); 233 } 234 return ret; 235} 236int btif_config_remove(const char* section, const char* key, const char* name) 237{ 238 asrt(section && *section && key && *key); 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} 250typedef struct { 251 short si; 252 short ki; 253 short vi; 254 short reserved; 255} cfg_node_pos; 256short btif_config_next_key(short pos, const char* section, char * name, int* bytes) 257{ 258 int next = -1; 259 lock_slot(&slot_lock); 260 short si = find_inode(&root, section); 261 if(si >= 0) 262 { 263 const cfg_node* section_node = &root.child[si]; 264 next = find_next_node(section_node, pos, name, bytes); 265 } 266 unlock_slot(&slot_lock); 267 return next; 268} 269short btif_config_next_value(short pos, const char* section, const char* key, char* name, int* bytes) 270{ 271 int next = -1; 272 lock_slot(&slot_lock); 273 short si = find_inode(&root, section); 274 if(si >= 0) 275 { 276 const cfg_node* section_node = &root.child[si]; 277 short ki = find_inode(section_node, key); 278 if(ki >= 0) 279 { 280 const cfg_node* key_node = §ion_node->child[ki]; 281 next = find_next_node(key_node, pos, name, bytes); 282 } 283 } 284 unlock_slot(&slot_lock); 285 return next; 286} 287int btif_config_enum(btif_config_enum_callback cb, void* user_data) 288{ 289 asrt(cb); 290 if(!cb) 291 return FALSE; 292 lock_slot(&slot_lock); 293 int si, ki, vi; 294 cfg_node *section_node, *key_node, *value_node; 295 for(si = 0; si < GET_CHILD_MAX_COUNT(&root); si++) 296 { 297 section_node = &root.child[si]; 298 if(section_node->name && *section_node->name) 299 { 300 for(ki = 0; ki < GET_CHILD_MAX_COUNT(section_node); ki++) 301 { 302 key_node = §ion_node->child[ki]; 303 if(key_node->name && *key_node->name) 304 { 305 for(vi = 0; vi < GET_CHILD_MAX_COUNT(key_node); vi++) 306 { 307 value_node = &key_node->child[vi]; 308 if(value_node->name && *value_node->name) 309 { 310 cb(user_data, section_node->name, key_node->name, value_node->name, 311 value_node->value, value_node->used, value_node->type); 312 } 313 } 314 } 315 } 316 } 317 } 318 unlock_slot(&slot_lock); 319 return TRUE; 320} 321int btif_config_save() 322{ 323 lock_slot(&slot_lock); 324 if(cached_change > 0) 325 { 326 cached_change = 0; 327 btsock_thread_post_cmd(pth, CFG_CMD_SAVE, NULL, 0, 0); 328 } 329 unlock_slot(&slot_lock); 330 return TRUE; 331} 332void btif_config_flush() 333{ 334 lock_slot(&slot_lock); 335 if(cached_change > 0) 336 save_cfg(); 337 unlock_slot(&slot_lock); 338} 339///////////////////////////////////////////////////////////////////////////////////////////// 340static inline short alloc_node(cfg_node* p, short grow) 341{ 342 int new_bytes = p->bytes + grow; 343 //debug("in, bytes:%d, new bytes:%d, grow:%d", p->bytes, new_bytes, grow); 344 if(grow > 0 && new_bytes < MAX_NODE_BYTES) 345 { 346 char* value = (char*)realloc(p->value, new_bytes); 347 if(value) 348 { 349 short old_bytes = p->bytes; 350 //clear to zero 351 memset(value + old_bytes, 0, grow); 352 p->bytes = old_bytes + grow; 353 p->value = value; 354 //debug("out"); 355 return old_bytes;//return the previous size 356 } 357 else error("realloc failed, old_bytes:%d, grow:%d, total:%d", p->bytes, grow, p->bytes + grow); 358 } 359 //debug("out, alloc failed"); 360 return -1; 361} 362static inline void free_node(cfg_node* p) 363{ 364 if(p) 365 { 366 if(p->child) 367 { 368 free(p->child); 369 p->child = NULL; 370 } 371 if(p->name) 372 { 373 free((void*)p->name); 374 p->name = 0; 375 } 376 p->used = p->bytes = p->flag = p->type = 0; 377 } 378} 379static inline short find_inode(const cfg_node* p, const char* name) 380{ 381 //debug("in"); 382 if(p && p->child && name && *name) 383 { 384 int i; 385 int count = GET_CHILD_MAX_COUNT(p); 386 //debug("child name:%s, child max count:%d", name, count); 387 for(i = 0; i < count; i++) 388 { 389 if(p->child[i].name && *p->child[i].name && 390 strcmp(p->child[i].name, name) == 0) 391 { 392 //debug("out found child index:%d", i); 393 return (short)i; 394 } 395 } 396 } 397 //debug("out, child name: %s not found", name); 398 return -1; 399} 400static inline cfg_node* find_free_node(cfg_node* p) 401{ 402 if(p && p->child) 403 { 404 int i; 405 int count = GET_CHILD_MAX_COUNT(p); 406 //debug("p->name:%s, max child count:%d", p->name, count); 407 for(i = 0; i < count; i++) 408 { 409 if(IS_EMPTY(p->child + i)) 410 return p->child + i; 411 } 412 } 413 return NULL; 414} 415static cfg_node* find_add_node(cfg_node* p, const char* name) 416{ 417 int i = -1; 418 cfg_node* node = NULL; 419 //debug("in, p->name:%s, p->bytes:%d, adding child:%s", p->name, p->bytes, name); 420 if((i = find_inode(p, name)) < 0) 421 { 422 if(!(node = find_free_node(p))) 423 { 424 int old_size = alloc_node(p, CFG_GROW_SIZE); 425 if(old_size >= 0) 426 { 427 i = GET_NODE_COUNT(old_size); 428 node = &p->child[i]; 429 } 430 } 431 } 432 else node = &p->child[i]; 433 if(!node->name) 434 node->name = strdup(name); 435 //debug("out"); 436 return node; 437} 438static int set_node(const char* section, const char* key, const char* name, 439 const char* value, short bytes, short type) 440{ 441 int si = -1, ki = -1, vi = -1; 442 cfg_node* section_node = NULL; 443 //debug("in"); 444 //dump_node("root", &root); 445 if((section_node = find_add_node(&root, section))) 446 { 447 //dump_node("section node", section_node); 448 cfg_node* key_node; 449 if((key_node = find_add_node(section_node, key))) 450 { 451 //dump_node("key node", key_node); 452 cfg_node* value_node; 453 if((value_node = find_add_node(key_node, name))) 454 { 455 //dump_node("value node", value_node); 456 if(value_node->bytes < bytes) 457 { 458 if(value_node->value) 459 free(value_node->value); 460 value_node->value = (char*)malloc(bytes); 461 if(value_node->value) 462 value_node->bytes = bytes; 463 else 464 { 465 error("not enough memory!"); 466 value_node->bytes = 0; 467 return FALSE; 468 } 469 } 470 if(value_node->value && value != NULL && bytes > 0) 471 memcpy(value_node->value, value, bytes); 472 value_node->type = type; 473 value_node->used = bytes; 474 //dump_node("changed value node", value_node); 475 return TRUE; 476 } 477 } 478 } 479 return FALSE; 480} 481static cfg_node* find_node(const char* section, const char* key, const char* name) 482{ 483 int si = -1, ki = -1, vi = -1; 484 if((si = find_inode(&root, section)) >= 0) 485 { 486 cfg_node* section_node = &root.child[si]; 487 if(key) 488 { 489 //dump_node("found section node", section_node); 490 if((ki = find_inode(section_node, key)) >= 0) 491 { 492 cfg_node* key_node = §ion_node->child[ki]; 493 //dump_node("found key node", key_node); 494 if(name) 495 { 496 if((vi = find_inode(key_node, name)) >= 0) 497 { 498 //dump_node("found value node", &key_node->child[vi]); 499 return &key_node->child[vi]; 500 } 501 //debug("value node:%s not found", name); 502 return NULL; 503 } 504 return key_node; 505 } 506 //debug("key node:%s not found", key); 507 return NULL; 508 } 509 return section_node; 510 } 511 //debug("section node:%s not found", section); 512 return NULL; 513} 514static short find_next_node(const cfg_node* p, short start, char* name, int* bytes) 515{ 516 asrt(0 <= start && start < GET_CHILD_MAX_COUNT(p)); 517 //debug("in, start:%d, max child count:%d", start, GET_CHILD_MAX_COUNT(p)); 518 //dump_node("find_next_node, parent", p); 519 short next = -1; 520 if(name) *name = 0; 521 if(0 <= start && start < GET_CHILD_MAX_COUNT(p)) 522 { 523 int i; 524 for(i = start; i < GET_CHILD_MAX_COUNT(p); i++) 525 { 526 cfg_node* child = &p->child[i]; 527 if(child->name) 528 { 529 int name_bytes = strlen(child->name) + 1; 530 if(name && bytes && *bytes >= name_bytes) 531 { 532 memcpy(name, child->name, name_bytes); 533 if(i + 1 < GET_CHILD_MAX_COUNT(p)) 534 next = (short)(i + 1); 535 *bytes = name_bytes; 536 } 537 else if(bytes) 538 { 539 //debug("not enough room to copy the name, size in:%d, size needed:%d", *bytes, name_bytes); 540 *bytes = name_bytes; 541 } 542 break; 543 } 544 } 545 } 546 return next; 547} 548static int remove_node(const char* section, const char* key, const char* name) 549{ 550 short si = -1, ki = -1, vi = -1; 551 if((si = find_inode(&root, section)) >= 0) 552 { 553 cfg_node* section_node = &root.child[si]; 554 if((ki = find_inode(section_node, key)) >= 0) 555 { 556 cfg_node* key_node = §ion_node->child[ki]; 557 if(name == NULL) 558 { 559 int count = GET_CHILD_MAX_COUNT(key_node); 560 int i; 561 for(i = 0; i < count; i++) 562 free_node(&key_node->child[i]); 563 free_node(key_node); 564 return TRUE; 565 } 566 else if((vi = find_inode(key_node, name)) >= 0) 567 { 568 //debug("remove value:%s", key_node->child[vi].name); 569 free_node(&key_node->child[vi]); 570 return TRUE; 571 } 572 } 573 } 574 return FALSE; 575} 576static int save_cfg() 577{ 578 debug("in"); 579 const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT; 580 const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW; 581 const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD; 582 int ret = FALSE; 583 if(access(file_name_old, F_OK) == 0) 584 unlink(file_name_old); 585 if(access(file_name_new, F_OK) == 0) 586 unlink(file_name_new); 587 if(btif_config_save_file(file_name_new)) 588 { 589 cached_change = 0; 590 chown(file_name_new, -1, AID_NET_BT_STACK); 591 chmod(file_name_new, 0660); 592 rename(file_name, file_name_old); 593 rename(file_name_new, file_name); 594 ret = TRUE; 595 } 596 else error("btif_config_save_file failed"); 597 debug("out"); 598 return ret; 599} 600 601static int load_bluez_cfg() 602{ 603 char adapter_path[256]; 604 if(load_bluez_adapter_info(adapter_path, sizeof(adapter_path))) 605 { 606 if(load_bluez_linkkeys(adapter_path)) 607 return TRUE; 608 } 609 return FALSE; 610} 611static void remove_bluez_cfg() 612{ 613 rename(BLUEZ_PATH, BLUEZ_PATH_BAK); 614} 615static void load_cfg() 616{ 617 const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT; 618 const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW; 619 const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD; 620 if(!btif_config_load_file(file_name)) 621 { 622 unlink(file_name); 623 if(!btif_config_load_file(file_name_old)) 624 { 625 unlink(file_name_old); 626 if(load_bluez_cfg() && save_cfg()) 627 remove_bluez_cfg(); 628 } 629 } 630} 631static void cfg_cmd_callback(int cmd_fd, int type, int size, uint32_t user_id) 632{ 633 debug("cmd type:%d, size:%d", type, size); 634 switch(type) 635 { 636 case CFG_CMD_SAVE: 637 lock_slot(&slot_lock); 638 save_cfg(); 639 unlock_slot(&slot_lock); 640 break; 641 } 642} 643#ifdef UNIT_TEST 644static void cfg_test_load() 645{ 646 load_cfg(); 647 char kname[128], vname[128]; 648 short kpos, vpos; 649 int kname_size, vname_size; 650 debug("in"); 651 debug("list all remote devices values:"); 652 kname_size = sizeof(kname); 653 kname[0] = 0; 654 kpos = 0; 655 do 656 { 657 kpos = btif_config_next_key(kpos, "Remote Devices", kname, &kname_size); 658 debug("Remote devices:%s, size:%d", kname, kname_size); 659 vpos = 0; 660 vname[0] = 0; 661 vname_size = sizeof(vname); 662 while((vpos = btif_config_next_value(vpos, "Remote Devices", kname, vname, &vname_size)) != -1) 663 { 664 char v[128] = {0}; 665 int vtype = BTIF_CFG_TYPE_STR; 666 int vsize = sizeof(v); 667 int ret = btif_config_get("Remote Devices", kname, vname, v, &vsize, &vtype); 668 debug("btif_config_get return:%d, Remote devices:%s, value name:%s, value:%s, value size:%d, type:0x%x", 669 ret, kname, vname, v, vsize, vtype); 670 671 vname[0] = 0; 672 vname_size = sizeof(vname); 673 } 674 kname[0] = 0; 675 kname_size = sizeof(kname); 676 } while(kpos != -1); 677 debug("out"); 678} 679static void cfg_test_write() 680{ 681 debug("in"); 682 int i; 683 684 char key[128]; 685 const char* section; 686 char link_key[64]; 687 for(i = 0; i < (int)sizeof(link_key); i++) 688 link_key[i] = i; 689 for(i = 0; i < 100; i++) 690 { 691 sprintf(key, "00:22:5F:97:56:%02d", i); 692 link_key[0] = i; 693 section = "Remote Devices"; 694 btif_config_set_str(section, key, "class", "smart phone"); 695 btif_config_set(section, key, "link keys", link_key, sizeof(link_key), BTIF_CFG_TYPE_BIN); 696 btif_config_set_int(section, key, "connect time out", i); 697 } 698 btif_config_save(); 699 debug("out"); 700} 701static void cfg_test_read() 702{ 703 debug("in"); 704 char class[128] = {0}; 705 char link_key[128] = {0}; 706 int size, type; 707 char key[128]; 708 const char* section; 709 int ret, i; 710 for(i = 0; i < 100; i++) 711 { 712 sprintf(key, "00:22:5F:97:56:%02d", i); 713 section = "Remote Devices"; 714 size = sizeof(class); 715 ret = btif_config_get_str(section, key, "class", class, &size); 716 debug("btif_config_get_str return:%d, Remote devices:%s, class:%s", ret, key, class); 717 718 size = sizeof(link_key); 719 type = BTIF_CFG_TYPE_BIN; 720 ret = btif_config_get(section, key, "link keys", link_key, &size, &type); 721 debug("btif_config_get return:%d, Remote devices:%s, link key:%x, %x", 722 ret, key, *(int *)link_key, *((int *)link_key + 1)); 723 724 int timeout; 725 ret = btif_config_get_int(section, key, "connect time out", &timeout); 726 debug("btif_config_get_int return:%d, Remote devices:%s, connect time out:%d", ret, key, timeout); 727 } 728 729 debug("testing btif_config_remove"); 730 size = sizeof(class); 731 type = BTIF_CFG_TYPE_STR; 732 btif_config_set("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, strlen(class) + 1, BTIF_CFG_TYPE_STR); 733 734 btif_config_get("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, &size, &type); 735 debug("Remote devices, 00:22:5F:97:56:04 Class Delete:%s", class); 736 btif_config_remove("Remote Devices", "00:22:5F:97:56:04", "Class Delete"); 737 738 size = sizeof(class); 739 type = BTIF_CFG_TYPE_STR; 740 ret = btif_config_get("Remote Devices", "00:22:5F:97:56:04", "Class Delete", class, &size, &type); 741 debug("after removed, btif_config_get ret:%d, Remote devices, 00:22:5F:97:56:04 Class Delete:%s", ret, class); 742 debug("out"); 743} 744#endif 745