inquiry流程一般持續有12s多,當inquiry完成的時候,設備端會上報一個Event: Inquiry Complete 上來,那協議棧是如何把這個事件上傳到應用層的呢?本篇文章來分析一下其具體的流程。
void btu_hcif_process_event (UNUSED_ATTR UINT8 controller_id, BT_HDR *p_msg) { UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset; UINT8 hci_evt_code, hci_evt_len; STREAM_TO_UINT8 (hci_evt_code, p); STREAM_TO_UINT8 (hci_evt_len, p); switch (hci_evt_code) { case HCI_INQUIRY_COMP_EVT: btu_hcif_inquiry_comp_evt (p); break; ...
看btu_hcif_inquiry_comp_evt 的實現:
static void btu_hcif_inquiry_comp_evt (UINT8 *p) { UINT8 status; STREAM_TO_UINT8 (status, p); /* Tell inquiry processing that we are done */ btm_process_inq_complete(status, BTM_BR_INQUIRY_MASK); }
繼續看btm_process_inq_complete 的實現:
其中:
#define BTM_BR_INQUIRY_MASK (BTM_GENERAL_INQUIRY | BTM_LIMITED_INQUIRY)
btm_process_inq_complete 其實現在btm_inq.c里面:
void btm_process_inq_complete (UINT8 status, UINT8 mode) { tBTM_CMPL_CB *p_inq_cb = btm_cb.btm_inq_vars.p_inq_cmpl_cb;//保存回調函數指針 tBTM_INQUIRY_VAR_ST *p_inq = &btm_cb.btm_inq_vars; ... #if (!defined(BTA_HOST_INTERLEAVE_SEARCH) || BTA_HOST_INTERLEAVE_SEARCH == FALSE) p_inq->inqparms.mode &= ~(mode); #endif btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT);//向上傳遞 /* Ignore any stray or late complete messages if the inquiry is not active */ if (p_inq->inq_active) { p_inq->inq_cmpl_info.status = (tBTM_STATUS)((status == HCI_SUCCESS) ? BTM_SUCCESS : BTM_ERR_PROCESSING); /* Notify caller that the inquiry has completed; (periodic inquiries do not send completion events */ if (!(p_inq->inq_active & BTM_PERIODIC_INQUIRY_ACTIVE) && p_inq->inqparms.mode == 0)//mode前面已經置0 { #if BLE_INCLUDED == TRUE btm_clear_all_pending_le_entry();//清除還沒有活動scan response的設備消息 #endif p_inq->state = BTM_INQ_INACTIVE_STATE;//設置inquiry的狀態 /* Increment so the start of a next inquiry has a new count */ p_inq->inq_counter++;//增加搜索的計數 btm_clr_inq_result_flt(); if((p_inq->inq_cmpl_info.status == BTM_SUCCESS) && controller_get_interface()->supports_rssi_with_inquiry_results()) { btm_sort_inq_result();//根據rssi排序 } /* Clear the results callback if set */ p_inq->p_inq_results_cb = (tBTM_INQ_RESULTS_CB *) NULL; p_inq->inq_active = BTM_INQUIRY_INACTIVE;//設置0 p_inq->p_inq_cmpl_cb = (tBTM_CMPL_CB *) NULL; if (p_inq_cb)//執行回調函數,在bta_dm_search_start 進行注冊bta_dm_inq_cmpl_cb (p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info); } } if(p_inq->inqparms.mode == 0 && p_inq->scan_type == INQ_GENERAL)//this inquiry is complete { p_inq->scan_type = INQ_NONE;//scan_type置0 #if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE) /* check if the LE observe is pending */ if(p_inq->p_inq_ble_results_cb != NULL)//==NULL { BTM_TRACE_DEBUG("BTM Inq Compl: resuming a pending LE scan"); BTM_BleObserve(1,0, p_inq->p_inq_ble_results_cb, p_inq->p_inq_ble_cmpl_cb); } #endif } }
這里主要分三部分:
- btm_acl_update_busy_level (BTM_BLI_INQ_DONE_EVT); 向上層匯報狀態
- 清各種狀態標志位
- (p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info);
我們主要看一下第一部分和第三部分:
1.btm_acl_update_busy_level
其實現btm_acl.c:
void btm_acl_update_busy_level (tBTM_BLI_EVENT event) { tBTM_BL_UPDATE_DATA evt; UINT8 busy_level; BTM_TRACE_DEBUG ("btm_acl_update_busy_level"); BOOLEAN old_inquiry_state = btm_cb.is_inquiry; switch (event) { ... case BTM_BLI_INQ_DONE_EVT: BTM_TRACE_DEBUG ("BTM_BLI_INQ_DONE_EVT"); btm_cb.is_inquiry = FALSE; evt.busy_level_flags = BTM_BL_INQUIRY_COMPLETE; break; } ... if ((busy_level != btm_cb.busy_level) ||(old_inquiry_state != btm_cb.is_inquiry)) { evt.event = BTM_BL_UPDATE_EVT; evt.busy_level = busy_level; btm_cb.busy_level = busy_level; if (btm_cb.p_bl_changed_cb && (btm_cb.bl_evt_mask & BTM_BL_UPDATE_MASK)) { (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt); } } }
可以看出,主要做的事情是組建一個evt:
evt.event = BTM_BL_UPDATE_EVT;
evt.busy_level = busy_level;
evt.busy_level_flags = BTM_BL_INQUIRY_COMPLETE;
然后調用 (*btm_cb.p_bl_changed_cb)((tBTM_BL_EVENT_DATA *)&evt);
看看這個回調函數是在哪里注冊的呢?
在btm_acl.c有個注冊函數:
tBTM_STATUS BTM_RegBusyLevelNotif (tBTM_BL_CHANGE_CB *p_cb, UINT8 *p_level, tBTM_BL_EVENT_MASK evt_mask) { ...
btm_cb.bl_evt_mask = evt_mask; ... btm_cb.p_bl_changed_cb = p_cb;//保存回調 return(BTM_SUCCESS); }
發現該函數是在bta_dm_sys_hw_cback里面注冊的:
BTM_RegBusyLevelNotif (bta_dm_bl_change_cback, NULL, BTM_BL_UPDATE_MASK|BTM_BL_ROLE_CHG_MASK);
我們發現這個回調函數就是bta_dm_bl_change_cback ,其實現在bta_dm_act.c中:
根據上面的分析,我們知道這次傳入的event = BTM_BL_UPDATE_EVT;
static void bta_dm_bl_change_cback (tBTM_BL_EVENT_DATA *p_data) { tBTA_DM_ACL_CHANGE * p_msg; if ((p_msg = (tBTA_DM_ACL_CHANGE *) GKI_getbuf(sizeof(tBTA_DM_ACL_CHANGE))) != NULL) { p_msg->event = p_data->event;.//繼承上面event p_msg->is_new = FALSE;//is_new = false switch(p_msg->event) { ... case BTM_BL_UPDATE_EVT: p_msg->busy_level = p_data->update.busy_level; p_msg->busy_level_flags = p_data->update.busy_level_flags; break; ... } p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT; bta_sys_sendmsg(p_msg); } }
觀其實現,還是組建了一個 tBTA_DM_ACL_CHANGE 這樣的事件,然后發送到btu 線程:
p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT;
p_msg->event = p_data->event = BTM_BL_UPDATE_EVT;
p_msg->is_new = FALSE;
這邊追蹤一下代碼,處理這個BTA_DM_ACL_CHANGE_EVT的函數是:
/******************************************************************************* ** ** Function bta_dm_acl_change ** ** Description Process BTA_DM_ACL_CHANGE_EVT ** ** ** Returns void ** *******************************************************************************/ void bta_dm_acl_change(tBTA_DM_MSG *p_data) { UINT8 i; UINT8 *p; tBTA_DM_SEC conn; BOOLEAN is_new = p_data->acl_change.is_new; BD_ADDR_PTR p_bda = p_data->acl_change.bd_addr; BOOLEAN need_policy_change = FALSE; BOOLEAN issue_unpair_cb = FALSE; tBTA_DM_PEER_DEVICE *p_dev; memset(&conn, 0, sizeof(tBTA_DM_SEC)); switch(p_data->acl_change.event) { case BTM_BL_UPDATE_EVT: /* busy level update */ if( bta_dm_cb.p_sec_cback ) { conn.busy_level.level = p_data->acl_change.busy_level; conn.busy_level.level_flags = p_data->acl_change.busy_level_flags; bta_dm_cb.p_sec_cback(BTA_DM_BUSY_LEVEL_EVT, &conn);//回調到上層 } return; ...
這邊的核心代碼還是組建事件往上層回調,:
conn.busy_level.level = p_data->acl_change.busy_level;
conn.busy_level.level_flags = p_data->acl_change.busy_level_flags = BTM_BL_INQUIRY_COMPLETE;
bta_dm_cb.p_sec_cback(BTA_DM_BUSY_LEVEL_EVT, &conn);
那我們現在看看bta_dm_cb.p_sec_cback 這個回調函數是在哪里注冊的:
void bta_dm_enable(tBTA_DM_MSG *p_data){ ... /* first, register our callback to SYS HW manager */ bta_sys_hw_register( BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback ); bta_dm_cb.p_sec_cback = p_data->enable.p_sec_cback;//注冊回調 ... }
發現是在bta_dm_enable 里面注冊的,也就是在tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK *p_cback) 傳入的回調函數:
void btif_init_ok(UNUSED_ATTR uint16_t event, UNUSED_ATTR char *p_param) { BTIF_TRACE_DEBUG("btif_task: received trigger stack init event"); #if (BLE_INCLUDED == TRUE) btif_dm_load_ble_local_keys(); #endif BTA_EnableBluetooth(bte_dm_evt);//這里注冊 }
那我們知道上面回調的內容如下:
conn.busy_level.level = p_data->acl_change.busy_level;
conn.busy_level.level_flags = p_data->acl_change.busy_level_flags = BTM_BL_INQUIRY_COMPLETE;
bte_dm_evt(BTA_DM_BUSY_LEVEL_EVT, &conn);
,下面繼續分析bte_dm_evt:
void bte_dm_evt(tBTA_DM_SEC_EVT event, tBTA_DM_SEC *p_data) { /* switch context to btif task context (copy full union size for convenience) */ bt_status_t status = btif_transfer_context(btif_dm_upstreams_evt, (uint16_t)event, (void*)p_data, sizeof(tBTA_DM_SEC), btif_dm_data_copy); /* catch any failed context transfers */ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status); }
發現該函數就是一個中轉,他把事件交與bt_jni_workqueue_thread 線程中的btif_dm_upstreams_evt 函數去執行了。event從btu task 轉換到了bt_jni_workqueue_thread ,我們也能感受到,事件正在一層一層往上面走,
看看btif_dm_upstreams_evt 的實現,這里面肯定也是會去處理各種不同的event:我們這種case 要處理的event = BTA_DM_BUSY_LEVEL_EVT,
/******************************************************************************* ** ** Function btif_dm_upstreams_cback ** ** Description Executes UPSTREAMS events in btif context ** ** Returns void ** *******************************************************************************/ static void btif_dm_upstreams_evt(UINT16 event, char* p_param) { tBTA_DM_SEC *p_data = (tBTA_DM_SEC*)p_param; tBTA_SERVICE_MASK service_mask; uint32_t i; bt_bdaddr_t bd_addr; switch (event) { case BTA_DM_BUSY_LEVEL_EVT: { if (p_data->busy_level.level_flags & BTM_BL_INQUIRY_PAGING_MASK) { if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_STARTED) { HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STARTED); btif_dm_inquiry_in_progress = TRUE; } else if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_CANCELLED) { HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STOPPED); btif_dm_inquiry_in_progress = FALSE; } else if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_COMPLETE) { btif_dm_inquiry_in_progress = FALSE;//設置了這個值 } } }
從上面的代碼分析,這里做的最重要的一件事就是:
btif_dm_inquiry_in_progress = FALSE;
第一部分的分析到此結束,下面開始看inquiry結束之后的回調函數:
3.(p_inq_cb)((tBTM_INQUIRY_CMPL *) &p_inq->inq_cmpl_info) = bta_dm_inq_cmpl_cb
這個回調函數的注冊是在 進行搜索的時候:
void bta_dm_search_start (tBTA_DM_MSG *p_data){ ... result.status = BTM_StartInquiry( (tBTM_INQ_PARMS*)&p_data->search.inq_params, bta_dm_inq_results_cb, (tBTM_CMPL_CB*) bta_dm_inq_cmpl_cb); ... }
我們看看bta_dm_inq_cmpl_cb的實現:
/******************************************************************************* ** ** Function bta_dm_inq_cmpl_cb ** ** Description Inquiry complete callback from BTM ** ** Returns void ** *******************************************************************************/ static void bta_dm_inq_cmpl_cb (void * p_result) { tBTA_DM_MSG * p_msg; if (bta_dm_search_cb.cancel_pending == FALSE) { p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG)); p_msg->inq_cmpl.hdr.event = BTA_DM_INQUIRY_CMPL_EVT; p_msg->inq_cmpl.num = ((tBTM_INQUIRY_CMPL *)p_result)->num_resp; bta_sys_sendmsg(p_msg); }
這里發現是組建了一個msg,然后發送到btu 線程:
p_msg->inq_cmpl.hdr.event = BTA_DM_INQUIRY_CMPL_EVT;
p_msg->inq_cmpl.num = ((tBTM_INQUIRY_CMPL *)p_result)->num_resp;
BTA_DM_API_SEARCH_EVT = BTA_SYS_EVT_START(BTA_ID_DM_SEARCH), BTA_DM_API_SEARCH_CANCEL_EVT, BTA_DM_API_DISCOVER_EVT, BTA_DM_INQUIRY_CMPL_EVT,//0x203 ...
處理該event 是handler是:
static const tBTA_SYS_REG bta_dm_search_reg = { bta_dm_search_sm_execute, bta_dm_search_sm_disable };
bta_dm_search_sm_execute:
BOOLEAN bta_dm_search_sm_execute(BT_HDR *p_msg) { tBTA_DM_ST_TBL state_table; UINT8 action; int i; /* look up the state table for the current state */ state_table = bta_dm_search_st_tbl[bta_dm_search_cb.state]; bta_dm_search_cb.state = state_table[p_msg->event & 0x00ff][BTA_DM_SEARCH_NEXT_STATE]; /* execute action functions */ for (i = 0; i < BTA_DM_SEARCH_ACTIONS; i++) { if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_DM_SEARCH_IGNORE) { (*bta_dm_search_action[action])( (tBTA_DM_MSG*) p_msg); } } return TRUE; }
他的處理流程是先找到該狀態的table,然后賦值下一個狀態,然后根據event 在table中查找該事件應該執行的action,這些action 有函數和他們一一對應,執行這些函數就行。
我們當前的狀態是bta_dm_search_search_active_st_table,需要執行的action = BTA_DM_INQUIRY_CMPL,下一個狀態依然是BTA_DM_SEARCH_ACTIVE
我們看看BTA_DM_INQUIRY_CMPL 對應的函數是什么?
/* action function list */ const tBTA_DM_ACTION bta_dm_search_action[] = { bta_dm_search_start, /* 0 BTA_DM_API_SEARCH */ bta_dm_search_cancel, /* 1 BTA_DM_API_SEARCH_CANCEL */ bta_dm_discover, /* 2 BTA_DM_API_DISCOVER */ bta_dm_inq_cmpl, /* 3 BTA_DM_INQUIRY_CMPL */ bta_dm_rmt_name, /* 4 BTA_DM_REMT_NAME */
看看 回調函數的具體實現:
/******************************************************************************* ** ** Function bta_dm_inq_cmpl ** ** Description Process the inquiry complete event from BTM ** ** Returns void ** *******************************************************************************/ void bta_dm_inq_cmpl (tBTA_DM_MSG *p_data) { tBTA_DM_MSG * p_msg; tBTA_DM_SEARCH data; APPL_TRACE_DEBUG("bta_dm_inq_cmpl"); data.inq_cmpl.num_resps = p_data->inq_cmpl.num; bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data);//執行回調,向上層通知 if((bta_dm_search_cb.p_btm_inq_info = BTM_InqDbFirst()) != NULL)//如果搜索到設備了,對設備做discover的動作 { /* start name and service discovery from the first device on inquiry result */ bta_dm_search_cb.name_discover_done = FALSE; bta_dm_search_cb.peer_name[0] = 0; bta_dm_discover_device(bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr); } else //否則結束,向上層傳 BTA_DM_SEARCH_CMPL_EVT; { /* no devices, search complete */ bta_dm_search_cb.services = 0; if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) { p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; bta_sys_sendmsg(p_msg); } } }
這一部分的內容也可以分為三部分:
- bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data);
- 有搜索到設備,進行discovery
- 沒有搜索到設備,上報BTA_DM_SEARCH_CMPL_EVT
首先來看看 第一部分:
3.1 bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data);
bta_dm_search_cb.p_search_cback 在BTA_DmSearch 中賦值的,為bte_search_devices_evt ,我們看看其實現:
/******************************************************************************* ** ** Function bte_search_devices_evt ** ** Description Switches context from BTE to BTIF for DM search events ** ** Returns void ** *******************************************************************************/ static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_data) { UINT16 param_len = 0; ... btif_transfer_context (btif_dm_search_devices_evt , (UINT16) event, (void *)p_data, param_len, (param_len > sizeof(tBTA_DM_SEARCH)) ? search_devices_copy_cb : NULL); }
發現其直接被transfer 到btif線程 中執行btif_dm_search_devices_evt:
/****************************************************************************** ** ** Function btif_dm_search_devices_evt ** ** Description Executes search devices callback events in btif context ** ** Returns void ** ******************************************************************************/ static void btif_dm_search_devices_evt (UINT16 event, char *p_param) { tBTA_DM_SEARCH *p_search_data; BTIF_TRACE_EVENT("%s event=%s", __FUNCTION__, dump_dm_search_event(event)); switch (event) { ... case BTA_DM_INQ_CMPL_EVT://並沒有進一步去通知上層 { #if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE)) tBTA_DM_BLE_PF_FILT_PARAMS adv_filt_param; memset(&adv_filt_param, 0, sizeof(tBTA_DM_BLE_PF_FILT_PARAMS)); BTA_DmBleScanFilterSetup(BTA_DM_BLE_SCAN_COND_DELETE, 0, &adv_filt_param, NULL, bte_scan_filt_param_cfg_evt, 0); #endif } break; case BTA_DM_DISC_CMPL_EVT: { HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STOPPED);//如果是BTA_DM_DISC_CMPL_EVT:會進一步通知上層 } break;
這里發現,BTA_DM_INQ_CMPL_EVT:並不會一直往上面傳,而 BTA_DM_DISC_CMPL_EVT:則是會上報給上層。那如果一直搜索不到設備就不會給上層答復嗎?我們看看第三部分的行為。
3.2 有搜索到設備,進行discovery
再次貼上代碼:
if((bta_dm_search_cb.p_btm_inq_info = BTM_InqDbFirst()) != NULL) { /* start name and service discovery from the first device on inquiry result */ bta_dm_search_cb.name_discover_done = FALSE; bta_dm_search_cb.peer_name[0] = 0; bta_dm_discover_device(bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr); }
看代碼的注釋,是開始名字和service 的discovery 的工作。看看 這個函數的實現:
首先簡述一下該函數的作用:
- 判斷是否需要去獲取對端設備的名字。不需要跳過,需要就去獲取名字並返回,這里猜想服務方面的搜索肯定是在獲取名字返回的函數里面進行。
- 判斷是否需要進行服務的搜索,需要則 進行,從開始 的discovery的接口看,應該是不需要進行服務的搜索。
- 發出服務完成的event,發送到btu 線程。
下面看代碼:
/******************************************************************************* ** ** Function bta_dm_discover_device ** ** Description Starts name and service discovery on the device ** ** Returns void ** *******************************************************************************/ static void bta_dm_discover_device(BD_ADDR remote_bd_addr) { tBTA_DM_MSG * p_msg; tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR; #if BLE_INCLUDED == TRUE if (bta_dm_search_cb.transport == BTA_TRANSPORT_UNKNOWN)//一開始都是unkown,會BTM_ReadDevInfo來判斷transport { tBT_DEVICE_TYPE dev_type; tBLE_ADDR_TYPE addr_type; BTM_ReadDevInfo(remote_bd_addr, &dev_type, &addr_type); if (dev_type == BT_DEVICE_TYPE_BLE || addr_type == BLE_ADDR_RANDOM) transport = BT_TRANSPORT_LE; } else { transport = bta_dm_search_cb.transport; } #endif /* Reset transport state for next discovery */ bta_dm_search_cb.transport = BTA_TRANSPORT_UNKNOWN;//reset bdcpy(bta_dm_search_cb.peer_bdaddr, remote_bd_addr); if (bta_dm_search_cb.p_btm_inq_info) { APPL_TRACE_DEBUG("%s appl_knows_rem_name %d", __func__, bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name);//顯示app是否已經知道名字,這是inquiry db里面的數據 } if((bta_dm_search_cb.p_btm_inq_info) && (bta_dm_search_cb.p_btm_inq_info->results.device_type == BT_DEVICE_TYPE_BLE) && (bta_dm_search_cb.state == BTA_DM_SEARCH_ACTIVE)) { /* Do not perform RNR for LE devices at inquiry complete*/ bta_dm_search_cb.name_discover_done = TRUE; //不要去查找LE 設備的名字 } /* if name discovery is not done and application needs remote name */ if ((!bta_dm_search_cb.name_discover_done) && (( bta_dm_search_cb.p_btm_inq_info == NULL ) ||(bta_dm_search_cb.p_btm_inq_info && (!bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name))))//需要名字則進行名字的搜索 { if (bta_dm_read_remote_device_name(bta_dm_search_cb.peer_bdaddr, transport) == TRUE) return;//返回 /* starting name discovery failed */ bta_dm_search_cb.name_discover_done = TRUE; } /* if application wants to discover service */ if ( bta_dm_search_cb.services )//一般是0 { /* initialize variables */ bta_dm_search_cb.service_index = 0; bta_dm_search_cb.services_found = 0; bta_dm_search_cb.services_to_search = bta_dm_search_cb.services; #if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE bta_dm_search_cb.uuid_to_search = bta_dm_search_cb.num_uuid; #endif if ((bta_dm_search_cb.p_btm_inq_info != NULL) && bta_dm_search_cb.services != BTA_USER_SERVICE_MASK &&(bta_dm_search_cb.sdp_search == FALSE)) { /* check if EIR provides the information of supported services */ bta_dm_eir_search_services( &bta_dm_search_cb.p_btm_inq_info->results, &bta_dm_search_cb.services_to_search, &bta_dm_search_cb.services_found ); } /* if seaching with EIR is not completed */ if(bta_dm_search_cb.services_to_search) { /* check whether connection already exists to the device if connection exists, we don't have to wait for ACL link to go down to start search on next device */ if (BTM_IsAclConnectionUp(bta_dm_search_cb.peer_bdaddr, BT_TRANSPORT_BR_EDR)) bta_dm_search_cb.wait_disc = FALSE; else bta_dm_search_cb.wait_disc = TRUE; #if (BLE_INCLUDED == TRUE && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)) if ( bta_dm_search_cb.p_btm_inq_info ) { APPL_TRACE_DEBUG("%s p_btm_inq_info 0x%x results.device_type 0x%x services_to_search 0x%x", __func__, bta_dm_search_cb.p_btm_inq_info, bta_dm_search_cb.p_btm_inq_info->results.device_type, bta_dm_search_cb.services_to_search); } if (transport == BT_TRANSPORT_LE) { if (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK) { //set the raw data buffer here memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf)); bta_dm_search_cb.p_ble_rawdata = g_disc_raw_data_buf; bta_dm_search_cb.ble_raw_size = MAX_DISC_RAW_DATA_BUF; bta_dm_search_cb.ble_raw_used = 0; /* start GATT for service discovery */ btm_dm_start_gatt_discovery(bta_dm_search_cb.peer_bdaddr); return; } } else #endif { bta_dm_search_cb.sdp_results = FALSE; bta_dm_find_services(bta_dm_search_cb.peer_bdaddr); return; } } } /* name discovery and service discovery are done for this device */ if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) { p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;//發送event到btu 線程 /* initialize the data structure - includes p_raw_data and raw_data_size */ memset(&(p_msg->disc_result.result), 0, sizeof(tBTA_DM_DISC_RES)); p_msg->disc_result.result.disc_res.result = BTA_SUCCESS; p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found; bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr); BCM_STRNCPY_S((char*)p_msg->disc_result.result.disc_res.bd_name, sizeof(BD_NAME), (char*)bta_dm_search_cb.peer_name, (BD_NAME_LEN-1)); /* make sure the string is terminated */ p_msg->disc_result.result.disc_res.bd_name[BD_NAME_LEN-1] = 0; bta_sys_sendmsg(p_msg); } }
服務方面 ok了之后是 會向btu 線程發送event:
p_msg->hdr.event = BTA_DM_DISCOVERY_RESULT_EVT;
p_msg->disc_result.result.disc_res.result = BTA_SUCCESS;
p_msg->disc_result.result.disc_res.services = bta_dm_search_cb.services_found;
bdcpy (p_msg->disc_result.result.disc_res.bd_addr, bta_dm_search_cb.peer_bdaddr);
BTA_DM_DISCOVERY_RESULT_EVT = 0x207
執行的action = BTA_DM_SEARCH_RESULT,對應的函數是bta_dm_search_result,看看其具體的實現:
/******************************************************************************* ** ** Function bta_dm_search_result ** ** Description Service discovery result while searching for devices ** ** Returns void ** *******************************************************************************/ void bta_dm_search_result (tBTA_DM_MSG *p_data) { /* call back if application wants name discovery or found services that application is searching */ if (( !bta_dm_search_cb.services ) ||(( bta_dm_search_cb.services ) && ( p_data->disc_result.result.disc_res.services ))) { bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, &p_data->disc_result.result);//回調 } /* if searching did not initiate to create link */ if(!bta_dm_search_cb.wait_disc )//如果沒有pending { /* if service searching is done with EIR, don't search next device */ if( bta_dm_search_cb.p_btm_inq_info ) bta_dm_discover_next_device();//去搜索下一個設備的服務 } else { /* wait until link is disconnected or timeout */ bta_dm_search_cb.sdp_results = TRUE; bta_dm_search_cb.search_timer.p_cback = (TIMER_CBACK*)&bta_dm_search_timer_cback; bta_sys_start_timer(&bta_dm_search_cb.search_timer, 0, 1000*(L2CAP_LINK_INACTIVITY_TOUT+1) );//如果pending了,那么設置定時器,並且在回調函數里面繼續執行搜索下一個設備的服務 } }
這里簡單分析兩點:
- bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, &p_data->disc_result.result)
- bta_dm_discover_next_device,如果有數據庫里面還有設備的話,那么繼續搜索服務,如果沒有設備的話,向上面傳:BTA_DM_SEARCH_CMPL_EVT,最終也會上報到java層。前面已經分析過。‘
分析一下bta_dm_search_cb.p_search_cback,我們又遇到這個函數了,其實是bte_search_devices_evt-->btif_dm_search_devices_evt:
/****************************************************************************** ** ** Function btif_dm_search_devices_evt ** ** Description Executes search devices callback events in btif context ** ** Returns void ** ******************************************************************************/ static void btif_dm_search_devices_evt (UINT16 event, char *p_param) { tBTA_DM_SEARCH *p_search_data; switch (event) { case BTA_DM_DISC_RES_EVT: { p_search_data = (tBTA_DM_SEARCH *)p_param; /* Remote name update */ if (strlen((const char *) p_search_data->disc_res.bd_name))//如果早先已經知道了名字,這里的名字的長度0 { bt_property_t properties[1]; bt_bdaddr_t bdaddr; bt_status_t status; properties[0].type = BT_PROPERTY_BDNAME; properties[0].val = p_search_data->disc_res.bd_name; properties[0].len = strlen((char *)p_search_data->disc_res.bd_name); bdcpy(bdaddr.address, p_search_data->disc_res.bd_addr); status = btif_storage_set_remote_device_property(&bdaddr, &properties[0]); ASSERTC(status == BT_STATUS_SUCCESS, "failed to save remote device property", status); HAL_CBACK(bt_hal_cbacks, remote_device_properties_cb, status, &bdaddr, 1, properties); }
現在簡單看下:bta_dm_discover_next_device:
/******************************************************************************* ** ** Function bta_dm_discover_next_device ** ** Description Starts discovery on the next device in Inquiry data base ** ** Returns void ** *******************************************************************************/ static void bta_dm_discover_next_device(void) { tBTA_DM_MSG * p_msg; /* searching next device on inquiry result */ if((bta_dm_search_cb.p_btm_inq_info = BTM_InqDbNext(bta_dm_search_cb.p_btm_inq_info)) != NULL) { bta_dm_search_cb.name_discover_done = FALSE; bta_dm_search_cb.peer_name[0] = 0; bta_dm_discover_device(bta_dm_search_cb.p_btm_inq_info->results.remote_bd_addr);//繼續搜索服務 } else { /* no devices, search complete */ bta_dm_search_cb.services = 0; if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) { p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;//都搜索我弄成之后上報event,結束discovery的流程 p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; bta_sys_sendmsg(p_msg); } } }
服務搜索部分就介紹到這里。
3.3 沒有搜索到設備或者搜索完成,上報BTA_DM_SEARCH_CMPL_EVT
再附上這段代碼:
{ /* no devices, search complete */ bta_dm_search_cb.services = 0; if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL) { p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT; p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT; bta_sys_sendmsg(p_msg); }
這邊還是組裝了一個event:
p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
相應的log也就是:BTA got event 0x206
const tBTA_DM_ACTION bta_dm_search_action[] = { bta_dm_search_start, /* 0 BTA_DM_API_SEARCH */ bta_dm_search_cancel, /* 1 BTA_DM_API_SEARCH_CANCEL */ bta_dm_discover, /* 2 BTA_DM_API_DISCOVER */ bta_dm_inq_cmpl, /* 3 BTA_DM_INQUIRY_CMPL */ bta_dm_rmt_name, /* 4 BTA_DM_REMT_NAME */ bta_dm_sdp_result, /* 5 BTA_DM_SDP_RESULT */ bta_dm_search_cmpl, /* 6 BTA_DM_SEARCH_CMPL */
執行的就是bta_dm_search_cmpl:
/******************************************************************************* ** ** Function bta_dm_search_cmpl ** ** Description Sends event to application ** ** Returns void ** *******************************************************************************/ void bta_dm_search_cmpl (tBTA_DM_MSG *p_data) { APPL_TRACE_EVENT("%s", __func__); ... if (p_data->hdr.layer_specific == BTA_DM_API_DI_DISCOVER_EVT) bta_dm_di_disc_cmpl(p_data); else bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, NULL); #endif }
函數如注釋闡明的那樣:Sends event to application
我們前面已經分析過bta_dm_search_cb.p_search_cback=bte_search_devices_evt ,這次傳入的事件是BTA_DM_DISC_CMPL_EVT
bte_search_devices_evt --->繼續進入到btif_dm_search_devices_evt:
/****************************************************************************** ** ** Function btif_dm_search_devices_evt ** ** Description Executes search devices callback events in btif context ** ** Returns void ** ******************************************************************************/ static void btif_dm_search_devices_evt (UINT16 event, char *p_param) { tBTA_DM_SEARCH *p_search_data; BTIF_TRACE_EVENT("%s event=%s", __FUNCTION__, dump_dm_search_event(event)); switch (event) { ... case BTA_DM_DISC_CMPL_EVT: { HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STOPPED); } break; ...
這一段其實再第一部分已經分析過,當傳入的事件是BTA_DM_DISC_CMPL_EVT,那么就會調用:HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STOPPED); 來通知上層 。
其實也就是說,即便一條設備信息也搜索不到,那么也會發送BTA_DM_SEARCH_CMPL_EVT---->BTA_DM_DISC_CMPL_EVT --->調用HAL_CBACK:BT_DISCOVERY_STOPPED 來通知上層。
到這里 inquiry complete的流程就已經分析完畢了。
總結:
Inquiry Complete
- update level busy,(btm_acl_update_busy_level)並不會上報到java層
- 執行bta_dm_inq_cmpl_cb
- bta_dm_search_cb.p_search_cback(BTA_DM_INQ_CMPL_EVT, &data); 該函數不會通知上層,
- 有搜索到設備,進行discovery
- 沒有搜索到設備,上報BTA_DM_SEARCH_CMPL_EVT ,並通知到上層。