蓝牙BLE设备主机重启回连流程分析
如果一个BLE设备已经与蓝牙中心设备连接上,那么当中心设备的断电重启,其依然会和配对过的BLE设备连接上,而不需要重新走配对的流程,这个过程叫做回连。
这篇文章就分析一下当中心设备断电重启之后,其与BLE设备的回连的流程。
当设备重启之后,蓝牙协议栈以及所有的上层的profile 都要重新进行初始化,之前的配对信息是保存在文件bt_config.conf中,蓝牙起来之后,会去加载这个文件,去解析曾经配对过的设备,对于已经配对过的设备,并且配对信息保持完整,那么就会对该设备发起回连。那么是什么时候进行对bt_config.conf文件的解析的工作的呢?
蓝牙初始化结束之后,会接着对于各个profile的初始化,当Hid host profile 打开完成之后会对bt_config.conf 文件进行解析并 加载相应的设备信息。我们这里从hid host 打开完成之后开始分析:
hid host 打开完成之后,会经过btif_hh_upstreams_evt 来上报消息:
static void btif_hh_upstreams_evt(UINT16 event, char* p_param) { tBTA_HH *p_data = (tBTA_HH *)p_param; btif_hh_device_t *p_dev = NULL; int i; int len, tmplen; BTIF_TRACE_DEBUG("%s: event=%s", __FUNCTION__, dump_hh_event(event)); switch (event) { case BTA_HH_ENABLE_EVT: BTIF_TRACE_DEBUG("%s: BTA_HH_ENABLE_EVT: status =%d",__FUNCTION__, p_data->status); if (p_data->status == BTA_HH_OK) { btif_hh_cb.status = BTIF_HH_ENABLED; BTIF_TRACE_DEBUG("%s--Loading added devices",__FUNCTION__); /* Add hid descriptors for already bonded hid devices*/ btif_storage_load_bonded_hid_info();/*load hid information*/ } ...
我们继续看btif_storage_load_bonded_hid_info 的实现:
/******************************************************************************* ** ** Function btif_storage_load_bonded_hid_info ** ** Description BTIF storage API - Loads hid info for all the bonded devices from NVRAM ** and adds those devices to the BTA_HH. ** ** Returns BT_STATUS_SUCCESS if successful, BT_STATUS_FAIL otherwise ** *******************************************************************************/ bt_status_t btif_storage_load_bonded_hid_info(void) { bt_bdaddr_t bd_addr; tBTA_HH_DEV_DSCP_INFO dscp_info; uint16_t attr_mask; uint8_t sub_class; uint8_t app_id; memset(&dscp_info, 0, sizeof(dscp_info)); for (const btif_config_section_iter_t *iter = btif_config_section_begin(); iter != btif_config_section_end(); iter = btif_config_section_next(iter)) { const char *name = btif_config_section_name(iter); if (!string_is_bdaddr(name)) continue; BTIF_TRACE_DEBUG("Remote device:%s", name); int value; if(btif_in_fetch_bonded_device(name) == BT_STATUS_SUCCESS)//获取bonded devices信息 { if(btif_config_get_int(name, "HidAttrMask", &value))//保存各种属性 { attr_mask = (uint16_t)value; btif_config_get_int(name, "HidSubClass", &value); sub_class = (uint8_t)value; btif_config_get_int(name, "HidAppId", &value); app_id = (uint8_t)value; btif_config_get_int(name, "HidVendorId", &value); dscp_info.vendor_id = (uint16_t) value; btif_config_get_int(name, "HidProductId", &value); dscp_info.product_id = (uint16_t) value; btif_config_get_int(name, "HidVersion", &value); dscp_info.version = (uint8_t) value; btif_config_get_int(name, "HidCountryCode", &value); dscp_info.ctry_code = (uint8_t) value; value = 0; btif_config_get_int(name, "HidSSRMaxLatency", &value); dscp_info.ssr_max_latency = (uint16_t) value; value = 0; btif_config_get_int(name, "HidSSRMinTimeout", &value); dscp_info.ssr_min_tout = (uint16_t) value; size_t len = btif_config_get_bin_length(name, "HidDescriptor"); if(len > 0) { dscp_info.descriptor.dl_len = (uint16_t)len; dscp_info.descriptor.dsc_list = (uint8_t*)alloca(len); btif_config_get_bin(name, "HidDescriptor", (uint8_t *)dscp_info.descriptor.dsc_list, &len); } string_to_bdaddr(name, &bd_addr); // add extracted information to BTA HH if (btif_hh_add_added_dev(bd_addr,attr_mask))//addd new devices to btif_hh_cb.added_devices { BTA_HhAddDev(bd_addr.address, attr_mask, sub_class, app_id, dscp_info);//add device to BTA_HH } } } else { ... } } return BT_STATUS_SUCCESS; }
上面的流程很简单,获取已经绑定的设备各种信息,主要有哪些信息呢?这里附上已经绑定设备的保存的信息(BLE):
[d0:09:09:dc:00:59] DevClass = 1344 AddrType = 0 Name = RCU DevType = 2 LE_KEY_PENC = 23e2e46363ca4ca562dadc625cc244a41f2225d81a0a8d1924e80110 LE_KEY_PID = 0000000000000000000000000000000000d00909dc0059 LE_KEY_PCSRK = 0000000043210c0c420203040505080708090c0101c674e3 LE_KEY_LENC = 09d6fa5537cb5859f7f9220613104ab0a2f11001 LE_KEY_LCSRK = 00000000a2f10122d4ecbea1a40287b6eb74c08767855ce2 LE_KEY_LID = Service = 00001812-0000-1000-8000-00805f9b34fb HidReport = 4d2a0201001a4d2a0101011a4d2a0102020e4d2afd01031a4d2a5a01041a4d2a5a02050e HidAttrMask = 0 HidSubClass = 0 HidAppId = 255 HidVendorId = 93 HidProductId = 2 HidVersion = 0 HidCountryCode = 0 HidSSRMaxLatency = 0 HidSSRMinTimeout = 0 HidDescriptor = 05010906a1018501050719e029e71500250175019508810295017508810195057501050819012905910295017503910195067508150025a40507190029a48100c005010902a10185020901a1000509190129031500250195037501810295017505810105010930093109381581257f750895038106c0c00612ff0a12ffa10185fd0901750895ff16000026ff00190029ff8100c00612ff0a12ffa101855a0901750895ff16000026ff00190029ff8100950875010508190129089102c0
上面的主要流程就是解析文件,确认某个设备的确是已经绑定好的设备,那么接下来就要走回连的流程,将该设备加入到白名单中,以及发起相应的连接流程,该流程的入口函数就是BTA_HhAddDev,下面我们继续分析该函数:
/******************************************************************************* ** ** Function BTA_HhAddDev ** ** Description Add a virtually cabled device into HID-Host device list ** to manage and assign a device handle for future API call, ** host applciation call this API at start-up to initialize its ** virtually cabled devices. ** ** Returns void ** *******************************************************************************/ void BTA_HhAddDev(BD_ADDR bda, tBTA_HH_ATTR_MASK attr_mask, UINT8 sub_class, UINT8 app_id, tBTA_HH_DEV_DSCP_INFO dscp_info) { tBTA_HH_MAINT_DEV *p_buf; UINT16 len = sizeof(tBTA_HH_MAINT_DEV) + dscp_info.descriptor.dl_len; p_buf = (tBTA_HH_MAINT_DEV *)GKI_getbuf(len); if (p_buf != NULL) { memset(p_buf, 0, sizeof(tBTA_HH_MAINT_DEV)); p_buf->hdr.event = BTA_HH_API_MAINT_DEV_EVT;//发送此event p_buf->sub_event = BTA_HH_ADD_DEV_EVT; p_buf->hdr.layer_specific = BTA_HH_INVALID_HANDLE; p_buf->attr_mask = (UINT16) attr_mask; p_buf->sub_class = sub_class; p_buf->app_id = app_id; bdcpy(p_buf->bda, bda); memcpy(&p_buf->dscp_info, &dscp_info, sizeof(tBTA_HH_DEV_DSCP_INFO)); if ( dscp_info.descriptor.dl_len != 0 && dscp_info.descriptor.dsc_list) { p_buf->dscp_info.descriptor.dl_len = dscp_info.descriptor.dl_len; p_buf->dscp_info.descriptor.dsc_list = (UINT8 *)(p_buf + 1); memcpy(p_buf->dscp_info.descriptor.dsc_list, dscp_info.descriptor.dsc_list, dscp_info.descriptor.dl_len); } else { ... } bta_sys_sendmsg(p_buf);//发送消息 } }
向BTU task 发送了BTA_HH_API_MAINT_DEV_EVT,其中包含的数据部分 都是 上面从文件解析出来的。我们继续看BTA_HH_API_MAINT_DEV_EVT 的处理,关于bta_sys_sendmsg 消息传送机制,这里就不讲了。
简单看下消息流向:
/******************************************************************************* ** ** Function bta_hh_hdl_event ** ** Description HID host main event handling function. ** ** ** Returns void ** *******************************************************************************/ BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg) { UINT8 index = BTA_HH_IDX_INVALID; tBTA_HH_DEV_CB *p_cb = NULL; switch (p_msg->event) { ... default: /* all events processed in state machine need to find corresponding CB before proceed */ if (p_msg->event == BTA_HH_API_OPEN_EVT) { index = bta_hh_find_cb(((tBTA_HH_API_CONN *)p_msg)->bd_addr); } else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT)//add { /* if add device */ if (((tBTA_HH_MAINT_DEV *)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT) { index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV *)p_msg)->bda);//find devive control block } ... p_cb = &bta_hh_cb.kdev[index]; ... bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA *) p_msg);//进入状态机
我们看看状态机的轮转情况:
/******************************************************************************* ** ** Function bta_hh_sm_execute ** ** Description State machine event handling function for HID Host ** ** ** Returns void ** *******************************************************************************/ void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data) { tBTA_HH_ST_TBL state_table; UINT8 action; tBTA_HH cback_data; tBTA_HH_EVT cback_event = 0; memset(&cback_data, 0, sizeof(tBTA_HH)); ... { ... state_table = bta_hh_st_tbl[p_cb->state - 1]; event &= 0xff; p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ; if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE) { (*bta_hh_action[action])(p_cb, p_data); } ... } return; }
这里的状态机轮转也是 熟悉的套路,开始是 idle状态,bta_hh_st_idle
/* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_IDLE_ST },
事件处理之后还是idle 状态,执行的行为是BTA_HH_MAINT_DEV_ACT:
/******************************************************************************* ** ** Function bta_hh_maint_dev_act ** ** Description HID Host maintain device list. ** ** ** Returns void ** *******************************************************************************/ void bta_hh_maint_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) { tBTA_HH_MAINT_DEV *p_dev_info = &p_data->api_maintdev; tBTA_HH_DEV_INFO dev_info ; UINT8 dev_handle; dev_info.status = BTA_HH_ERR; dev_info.handle = BTA_HH_INVALID_HANDLE; switch (p_dev_info->sub_event) { case BTA_HH_ADD_DEV_EVT: /* add a device */ bdcpy(dev_info.bda, p_dev_info->bda); /* initialize callback data */ if (p_cb->hid_handle == BTA_HH_INVALID_HANDLE) { #if (BTA_HH_LE_INCLUDED == TRUE) if (bta_hh_is_le_device(p_cb, p_data->api_conn.bd_addr)) { dev_info.handle = bta_hh_le_add_device(p_cb, p_dev_info); dev_info.status = BTA_HH_OK; } else #endif if (HID_HostAddDev(p_dev_info->bda, p_dev_info->attr_mask, &dev_handle)\ == HID_SUCCESS) ... /*非LE部分处理*/ } ... (* bta_hh_cb.p_cback)(p_dev_info->sub_event, (tBTA_HH *)&dev_info);//bte_hh_evt--->btif_hh_upstreams_evt
这里涉及到的回调函数就是bte_hh_evt,其实他最终还是调用btif_hh_upstreams_evt 来完成功能。我们看看其实现:
case BTA_HH_ADD_DEV_EVT: BTIF_TRACE_WARNING("BTA_HH_ADD_DEV_EVT: status = %d, handle = %d",p_data->dev_info.status, p_data->dev_info.handle); int i; for (i = 0; i < BTIF_HH_MAX_ADDED_DEV; i++) { if (memcmp(btif_hh_cb.added_devices[i].bd_addr.address, p_data->dev_info.bda, 6) == 0) { if (p_data->dev_info.status == BTA_HH_OK) { btif_hh_cb.added_devices[i].dev_handle = p_data->dev_info.handle;/*其实就是保存dev_handle*/ } else { /*错误处理*/ } break; } } break;
这个handle 就是我们上面看到的
dev_info.handle = bta_hh_le_add_device(p_cb, p_dev_info);
我们继续看看其干了什么?
我们先看看他的注释怎么说:
/******************************************************************************* ** ** Function bta_hh_le_add_device ** ** Description Add a LE HID device as a known device, and also add the address ** into back ground connection WL for incoming connection. ** ** Returns void ** *******************************************************************************/
添加 该设备地址到whitelist 里面,当设备科连接的时候,就会直接连接上。
UINT8 bta_hh_le_add_device(tBTA_HH_DEV_CB *p_cb, tBTA_HH_MAINT_DEV *p_dev_info) { p_cb->hid_handle = BTA_HH_GET_LE_DEV_HDL(p_cb->index); bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] = p_cb->index; /* update DI information */ bta_hh_update_di_info(p_cb, p_dev_info->dscp_info.vendor_id, p_dev_info->dscp_info.product_id, p_dev_info->dscp_info.version, p_dev_info->dscp_info.flag);/*更新设备消息,这些消息都是从bt_config.conf里面load的*/ /* add to BTA device list */ bta_hh_add_device_to_list(p_cb, p_cb->hid_handle, p_dev_info->attr_mask, &p_dev_info->dscp_info.descriptor, p_dev_info->sub_class, p_dev_info->dscp_info.ssr_max_latency, p_dev_info->dscp_info.ssr_min_tout, p_dev_info->app_id);//添加dscp_info 等消息到p_cb bta_hh_le_add_dev_bg_conn(p_cb, FALSE);/*add device to WL*/ return p_cb->hid_handle; }
上面代码的核心就是 添加 设备到BG connection,我们具体看实现:
static void bta_hh_le_add_dev_bg_conn(tBTA_HH_DEV_CB *p_cb, BOOLEAN check_bond) { UINT8 sec_flag=0; BOOLEAN to_add = TRUE; if (check_bond) { ... } if (/*p_cb->dscp_info.flag & BTA_HH_LE_NORMAL_CONN &&*/ !p_cb->in_bg_conn && to_add) { /* add device into BG connection to accept remote initiated connection */ BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, FALSE, BTA_GATT_TRANSPORT_LE);//gatt_if for hogp p_cb->in_bg_conn = TRUE; BTA_DmBleSetBgConnType(BTA_DM_BLE_CONN_AUTO, NULL);//send msg the auto type } return; }
这里分为两个部分来分析:
- BTA_GATTC_Open(bta_hh_cb.gatt_if, p_cb->addr, FALSE, BTA_GATT_TRANSPORT_LE);添加设备,并且标志为自动连接
- BTA_DmBleSetBgConnType(BTA_DM_BLE_CONN_AUTO, NULL); 开始回连的操作
我们先看BTA_GATTC_OPen的实现,之前其实有一篇文章讲这个,但是那篇文章主要分析是direct connect,而这里主要分析auto connect:
void BTA_GATTC_Open(tBTA_GATTC_IF client_if, BD_ADDR remote_bda, BOOLEAN is_direct, tBTA_GATT_TRANSPORT transport) { tBTA_GATTC_API_OPEN *p_buf; if ((p_buf = (tBTA_GATTC_API_OPEN *) GKI_getbuf(sizeof(tBTA_GATTC_API_OPEN))) != NULL) { p_buf->hdr.event = BTA_GATTC_API_OPEN_EVT; p_buf->client_if = client_if; p_buf->is_direct = is_direct;//false p_buf->transport = transport;//LE memcpy(p_buf->remote_bda, remote_bda, BD_ADDR_LEN); bta_sys_sendmsg(p_buf); } return; }
看看event的处理:
/******************************************************************************* ** ** Function bta_gattc_hdl_event ** ** Description GATT client main event handling function. ** ** ** Returns BOOLEAN ** *******************************************************************************/ BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg) { ... case BTA_GATTC_API_OPEN_EVT: bta_gattc_process_api_open(p_cb, (tBTA_GATTC_DATA *) p_msg); break; ...
看看 关于 auto connection的处理:
/******************************************************************************* ** ** Function bta_gattc_process_api_open ** ** Description process connect API request. ** ** Returns void ** *******************************************************************************/ void bta_gattc_process_api_open (tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA * p_msg) { UINT16 event = ((BT_HDR *)p_msg)->event; tBTA_GATTC_CLCB *p_clcb = NULL; tBTA_GATTC_RCB *p_clreg = bta_gattc_cl_get_regcb(p_msg->api_conn.client_if);//r is register UNUSED(p_cb); if (p_clreg != NULL) { if (p_msg->api_conn.is_direct) { /*直连的处理*/ } else { bta_gattc_init_bk_conn(&p_msg->api_conn, p_clreg); } } }
我们只要是看看 background connection的情况:
/******************************************************************************* ** ** Function bta_gattc_init_bk_conn ** ** Description Process API Open for a background connection ** ** Returns void ** *******************************************************************************/ void bta_gattc_init_bk_conn(tBTA_GATTC_API_OPEN *p_data, tBTA_GATTC_RCB *p_clreg) { tBTA_GATT_STATUS status = BTA_GATT_NO_RESOURCES; UINT16 conn_id; tBTA_GATTC_CLCB *p_clcb; tBTA_GATTC_DATA gattc_data; if (bta_gattc_mark_bg_conn(p_data->client_if, p_data->remote_bda, TRUE, FALSE))//标记 { /* always call open to hold a connection */ if (!GATT_Connect(p_data->client_if, p_data->remote_bda, FALSE, p_data->transport))//gatt 连接,auto connection { uint8_t *bda = (uint8_t *)p_data->remote_bda; status = BTA_GATT_ERROR; } else { status = BTA_GATT_OK; /* if is a connected remote device */ if (GATT_GetConnIdIfConnected(p_data->client_if, p_data->remote_bda, &conn_id, p_data->transport))//走到这里一般只是下发hci的连接命令,并没有连接上 { /*l连接上的处理*/ } } } ... }
我们看看GATT_Connect 的处理:
/******************************************************************************* ** ** Function GATT_Connect ** ** Description This function initiate a connecttion to a remote device on GATT ** channel. ** ** Parameters gatt_if: applicaiton interface ** bd_addr: peer device address. ** is_direct: is a direct conenection or a background auto connection ** ** Returns TRUE if connection started; FALSE if connection start failure. ** *******************************************************************************/ BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct, tBT_TRANSPORT transport) { tGATT_REG *p_reg; BOOLEAN status = FALSE; GATT_TRACE_API ("GATT_Connect gatt_if=%d", gatt_if); /* Make sure app is registered */ if ((p_reg = gatt_get_regcb(gatt_if)) == NULL) { GATT_TRACE_ERROR("GATT_Connect - gatt_if =%d is not registered", gatt_if); return(FALSE); } if (is_direct) status = gatt_act_connect (p_reg, bd_addr, transport); else { if (transport == BT_TRANSPORT_LE) status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr, TRUE);//update auto connection 相关 else { GATT_TRACE_ERROR("Unsupported transport for background connection"); } } return status; }
我们继续看:
/******************************************************************************* ** ** Function gatt_update_auto_connect_dev ** ** Description This function add or remove a device for background connection ** procedure. ** ** Parameters gatt_if: Application ID. ** add: add peer device ** bd_addr: peer device address. ** ** Returns TRUE if connection started; FALSE if connection start failure. ** *******************************************************************************/ BOOLEAN gatt_update_auto_connect_dev (tGATT_IF gatt_if, BOOLEAN add, BD_ADDR bd_addr, BOOLEAN is_initator) { BOOLEAN ret = FALSE; tGATT_REG *p_reg; tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE); GATT_TRACE_API ("gatt_update_auto_connect_dev "); /* Make sure app is registered */ if ((p_reg = gatt_get_regcb(gatt_if)) == NULL) { GATT_TRACE_ERROR("gatt_update_auto_connect_dev - gatt_if is not registered", gatt_if); return(FALSE); } if (add) { ret = gatt_add_bg_dev_list(p_reg, bd_addr, is_initator);/*加入到bg connection*/ if (ret && p_tcb != NULL)/*如果是一个已经连接的设备*/ { /* if a connected device, update the link holding number */ gatt_update_app_use_link_flag(gatt_if, p_tcb, TRUE, TRUE); } } else { ret = gatt_remove_bg_dev_from_list(p_reg, bd_addr, is_initator); } return ret; }
我们继续看gatt_add_bg_dev_list的实现:
/******************************************************************************* ** ** Function gatt_add_bg_dev_list ** ** Description add/remove device from the back ground connection device list ** ** Returns TRUE if device added to the list; FALSE failed ** *******************************************************************************/ BOOLEAN gatt_add_bg_dev_list(tGATT_REG *p_reg, BD_ADDR bd_addr, BOOLEAN is_initator) { tGATT_IF gatt_if = p_reg->gatt_if; tGATT_BG_CONN_DEV *p_dev = NULL; UINT8 i; BOOLEAN ret = FALSE; if ((p_dev = gatt_find_bg_dev(bd_addr)) == NULL) { p_dev = gatt_alloc_bg_dev(bd_addr); } if (p_dev) { for (i = 0; i < GATT_MAX_APPS; i ++) { if (is_initator) { if (p_dev->gatt_if[i] == gatt_if) { GATT_TRACE_ERROR("device already in iniator white list"); return TRUE; } else if (p_dev->gatt_if[i] == 0) { p_dev->gatt_if[i] = gatt_if; if (i == 0) ret = BTM_BleUpdateBgConnDev(TRUE, bd_addr);//update bg connection else ret = TRUE; break; } } else { /*accept role 的处理*/ } } } return ret; }
我们接着看:
/******************************************************************************* ** ** Function BTM_BleUpdateBgConnDev ** ** Description This function is called to add or remove a device into/from ** background connection procedure. The background connection * procedure is decided by the background connection type, it can be * auto connection, or selective connection. ** ** Parameters add_remove: TRUE to add; FALSE to remove. ** remote_bda: device address to add/remove. ** ** Returns void ** *******************************************************************************/ BOOLEAN BTM_BleUpdateBgConnDev(BOOLEAN add_remove, BD_ADDR remote_bda) { BTM_TRACE_EVENT("%s() add=%d", __func__, add_remove); return btm_update_dev_to_white_list(add_remove, remote_bda);//add }
我们继续分析btm_update_dev_to_white_list:
/******************************************************************************* ** ** Function btm_update_dev_to_white_list ** ** Description This function adds or removes a device into/from ** the white list. ** *******************************************************************************/ BOOLEAN btm_update_dev_to_white_list(BOOLEAN to_add, BD_ADDR bd_addr) { tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; if (to_add && p_cb->white_list_avail_size == 0) { BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__); return FALSE; } if (to_add) background_connection_add((bt_bdaddr_t*)bd_addr);//add else background_connection_remove((bt_bdaddr_t*)bd_addr);//remove btm_suspend_wl_activity(p_cb->wl_state);//因为当前的WL没有行为,所以do nothing btm_enq_wl_dev_operation(to_add, bd_addr);//更新btm_cb.ble_ctr_cb.wl_op_q btm_resume_wl_activity(p_cb->wl_state);//恢复WL的行为 return TRUE; }
上面的逻辑很简单,就是把设备的地址add 到bg connection里面。然后更新whitelist的列表,然后重新调度WL的行为。我们先看看background_connection_add的实现:
static void background_connection_add(bt_bdaddr_t *address) { assert(address); background_connections_lazy_init(); background_connection_t *connection = hash_map_get(background_connections, address); if (!connection) { connection = osi_calloc(sizeof(background_connection_t)); connection->address = *address; hash_map_set(background_connections, &(connection->address), connection); } }
组建了 key value 键值对放置 到 background connection里面。
我们在看看btm_resume_wl_activity 的实现:
/******************************************************************************* ** ** Function btm_resume_wl_activity ** ** Description This function is to resume white list related activity ** ** Returns none. ** *******************************************************************************/ static void btm_resume_wl_activity(tBTM_BLE_WL_STATE wl_state) { btm_ble_resume_bg_conn(); if (wl_state & BTM_BLE_WL_ADV) { btm_ble_start_adv(); } }
我们看btm_ble_resume_bg_conn的实现:
/******************************************************************************* ** ** Function btm_ble_resume_bg_conn ** ** Description This function is to resume a background auto connection ** procedure. ** ** Parameters none. ** ** Returns none. ** *******************************************************************************/ BOOLEAN btm_ble_resume_bg_conn(void) { tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; BOOLEAN ret = FALSE; if (p_cb->bg_conn_type != BTM_BLE_CONN_NONE) { if (p_cb->bg_conn_type == BTM_BLE_CONN_AUTO) ret = btm_ble_start_auto_conn(TRUE);//开始auto connection if (p_cb->bg_conn_type == BTM_BLE_CONN_SELECTIVE) ret = btm_ble_start_select_conn(TRUE, btm_cb.ble_ctr_cb.p_select_cback); } return ret; }
我们继续往下看btm_ble_start_auto_conn实现:
/******************************************************************************* ** ** Function btm_ble_start_auto_conn ** ** Description This function is to start/stop auto connection procedure. ** ** Parameters start: TRUE to start; FALSE to stop. ** ** Returns void ** *******************************************************************************/ BOOLEAN btm_ble_start_auto_conn(BOOLEAN start) { tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; BD_ADDR dummy_bda = {0}; BOOLEAN exec = TRUE; UINT16 scan_int; UINT16 scan_win; UINT8 own_addr_type = p_cb->addr_mgnt_cb.own_addr_type; UINT8 peer_addr_type = BLE_ADDR_PUBLIC; if (start) { if ( p_cb->conn_state == BLE_CONN_IDLE ) { exec = btm_execute_wl_dev_operation();//btm_add_dev_to_controller-->btsnd_hcic_ble_add_white_list } if (p_cb->conn_state == BLE_CONN_IDLE && background_connections_pending() && btm_ble_topology_check(BTM_BLE_STATE_INIT)) { p_cb->wl_state |= BTM_BLE_WL_INIT; ... scan_int = (p_cb->scan_int == BTM_BLE_SCAN_PARAM_UNDEF) ? BTM_BLE_SCAN_SLOW_INT_1 : p_cb->scan_int; scan_win = (p_cb->scan_win == BTM_BLE_SCAN_PARAM_UNDEF) ? BTM_BLE_SCAN_SLOW_WIN_1 : p_cb->scan_win; ... if (!btsnd_hcic_ble_create_ll_conn (scan_int, /* UINT16 scan_int */ scan_win, /* UINT16 scan_win */ 0x01, /* UINT8 white_list */ peer_addr_type, /* UINT8 addr_type_peer */ dummy_bda, /* BD_ADDR bda_peer */ own_addr_type, /* UINT8 addr_type_own */ BTM_BLE_CONN_INT_MIN_DEF, /* UINT16 conn_int_min */ BTM_BLE_CONN_INT_MAX_DEF, /* UINT16 conn_int_max */ BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* UINT16 conn_latency */ BTM_BLE_CONN_TIMEOUT_DEF, /* UINT16 conn_timeout */ 0, /* UINT16 min_len */ 0)) /* UINT16 max_len */ { /* start auto connection failed */ exec = FALSE; p_cb->wl_state &= ~BTM_BLE_WL_INIT; } else { btm_ble_set_conn_st (BLE_BG_CONN);//set BLE connection state } } else { exec = FALSE; } } ... return exec; }
上面执行的任务主要就是把设备加入到controller 的whitelist里面,然后下发LE connect 命令到controller,
我们简单看下btm_execute_wl_dev_operation:
/******************************************************************************* ** ** Function btm_execute_wl_dev_operation ** ** Description execute the pending whitelist device operation(loading or removing) *******************************************************************************/ BOOLEAN btm_execute_wl_dev_operation(void) { tBTM_BLE_WL_OP *p_dev_op = btm_cb.ble_ctr_cb.wl_op_q;//btm_enq_wl_dev_operation 更新btm_cb.ble_ctr_cb.wl_op_q UINT8 i = 0; BOOLEAN rt = TRUE; for (i = 0; i < BTM_BLE_MAX_BG_CONN_DEV_NUM && rt; i ++, p_dev_op ++) { if (p_dev_op->in_use) { rt = btm_add_dev_to_controller(p_dev_op->to_add, p_dev_op->bd_addr);//下发HCI command memset(p_dev_op, 0, sizeof(tBTM_BLE_WL_OP)); } else break; } return rt; }
好了,关于BTA_GATTC_Open 就分析到这里,下面我们看看第二点:
2.BTA_DmBleSetBgConnType(BTA_DM_BLE_CONN_AUTO, NULL)的流程:
void BTA_DmBleSetBgConnType(tBTA_DM_BLE_CONN_TYPE bg_conn_type, tBTA_DM_BLE_SEL_CBACK *p_select_cback) { #if BLE_INCLUDED == TRUE tBTA_DM_API_BLE_SET_BG_CONN_TYPE *p_msg; if ((p_msg = (tBTA_DM_API_BLE_SET_BG_CONN_TYPE *) GKI_getbuf(sizeof(tBTA_DM_API_BLE_SET_BG_CONN_TYPE))) != NULL) { memset(p_msg, 0, sizeof(tBTA_DM_API_BLE_SET_BG_CONN_TYPE)); p_msg->hdr.event = BTA_DM_API_BLE_SET_BG_CONN_TYPE; p_msg->bg_conn_type = bg_conn_type; p_msg->p_select_cback = p_select_cback; bta_sys_sendmsg(p_msg); } #endif }
执行的函数是
void bta_dm_ble_set_bg_conn_type (tBTA_DM_MSG *p_data) { BTM_BleSetBgConnType(p_data->ble_set_bd_conn_type.bg_conn_type, p_data->ble_set_bd_conn_type.p_select_cback); }
BOOLEAN BTM_BleSetBgConnType(tBTM_BLE_CONN_TYPE bg_conn_type, tBTM_BLE_SEL_CBACK *p_select_cback) { BOOLEAN started = TRUE; BTM_TRACE_EVENT ("BTM_BleSetBgConnType "); if (!controller_get_interface()->supports_ble()) return FALSE; if (btm_cb.ble_ctr_cb.bg_conn_type != bg_conn_type) { switch (bg_conn_type) { case BTM_BLE_CONN_AUTO: btm_ble_start_auto_conn(TRUE); break;
发现这里最终也会执行到btm_ble_start_auto_conn,流程和上面的流程一样,就不赘述。
关于BLE设备回连的问题就先分析到这里。