基于Android 14
在配对完成之后需要进行SDP完成服务的搜索然后进行连接的,代码中对应的是处理BTA_DM_AUTH_CMPL_EVT事件,然后到btif_dm_auth_cmpl_evt函数中。
- btif_dm_auth_cmpl_evt
认证完成,绑定消息的上报之前需要完成sdp的搜索
static void btif_dm_auth_cmpl_evt(tBTA_DM_AUTH_CMPL* p_auth_cmpl) {
...
// 如果不是临时的lnk key 则进行保存
if ((p_auth_cmpl->success) && (p_auth_cmpl->key_present)) {
/**
1. 如果key_type类型不是debug且未认证类型,或者bond_type是BOND_TYPE_PERSISTENT
如果地址不为空调用btif_storage_add_bonded_device,添加新的设备、link key、
key type、pin key length到NVRAM中;否则设置标志位ret为BT_STATUS_FAIL
2. 不满足条件 1,认定link key为临时的,然后判断bond_type如果为BOND_TYPE_TEMPORARY,
调用btif_storage_remove_bonded_device从NVRAM中移除绑定设备
**/
}
if (p_auth_cmpl->success) {
// save remote info to iot conf file
btif_iot_update_remote_info(p_auth_cmpl, false, pairing_cb.is_ssp);
// 大段的注释,简单的意思是没有经过配对流程收到新的link key的认证设备不进行SDP。
// link key从安全LTK派生的情况下需要进行SDP。
/**
1. 认证地址和配对地址不同,并且没有收到对端的加密key就跳过SDP
2. 保存设备类型
3. is_crosskey的判断,牵扯到ctkd配对模式,如果不是crosskey则btif_update_remote_properties
4. sdp黑名单, 并且是hid设备跳过sdp
**/
if (!pairing_cb.is_local_initiated && skip_sdp) {
//不是本地发起的配对连接,并且不需要跳过SDP,则断定为hid设备,更新prop并回调
} else {
// crosskey,保存静态地址
if (!is_crosskey ||
!(stack_config_get_interface()->get_pts_crosskey_sdp_disable())) {
/**
1. sdp期间停掉inquiry(cancel_discovery)
2. 触发设备的sdp(pairing_cb.sdp_attempts = 1;)
3. 如果crossk-key配对时发生绑定,发送地址合并回调,否则就更新绑定状态
**/
// sdp_over_classic在前面尚未赋值过,为初始值NOT_STARTED
if (pairing_cb.sdp_over_classic ==
btif_dm_pairing_cb_t::ServiceDiscoveryState::NOT_STARTED) {
LOG_INFO("scheduling SDP for %s", ADDRESS_TO_LOGGABLE_CSTR(bd_addr));
pairing_cb.sdp_over_classic =
btif_dm_pairing_cb_t::ServiceDiscoveryState::SCHEDULED;
// 通过地址和通道来进行设备的SDP
btif_dm_get_remote_services(bd_addr, BT_TRANSPORT_BR_EDR);
}
}
}
// Do not call bond_state_changed_cb yet. Wait until remote service
// discovery is complete
} else {
// 认证失败的一些处理
}
}
内容太多了,使用中文进行了简单描述,另外最后的原文注释中有提到在service discovery完成之后才调用bond_state_changed_cb
- btif_dm_get_remote_services
void btif_dm_get_remote_services(RawAddress remote_addr, const int transport) {
BTIF_TRACE_EVENT("%s: transport=%d, remote_addr=%s", __func__, transport,
ADDRESS_TO_LOGGABLE_CSTR(remote_addr));
BTM_LogHistory(
kBtmLogTag, remote_addr, "Service discovery",
base::StringPrintf("transport:%s", bt_transport_text(transport).c_str()));
BTA_DmDiscover(remote_addr, btif_dm_search_services_evt, transport);
}
- BTA_DmDiscover
到BTA中进行消息发送与处理,相比之前多了个参数,是回调
void BTA_DmDiscover(const RawAddress& bd_addr, tBTA_DM_SEARCH_CBACK* p_cback,
tBT_TRANSPORT transport) {
tBTA_DM_API_DISCOVER* p_msg =
(tBTA_DM_API_DISCOVER*)osi_calloc(sizeof(tBTA_DM_API_DISCOVER));
p_msg->hdr.event = BTA_DM_API_DISCOVER_EVT;
p_msg->bd_addr = bd_addr;
p_msg->transport = transport;
p_msg->p_cback = p_cback;
bta_sys_sendmsg(p_msg);
}
- bta_dm_search_sm_execute
为Device manager处理各种状态机的evt
bool bta_dm_search_sm_execute(BT_HDR_RIGID* p_msg) {
...
tBTA_DM_MSG* message = (tBTA_DM_MSG*)p_msg;
switch (bta_dm_search_get_state()) {
case BTA_DM_SEARCH_IDLE:
switch (p_msg->event) {
...
case BTA_DM_API_DISCOVER_EVT:
// 先将状态设置为BTA_DM_DISCOVER_ACTIVE,然后处理消息,后面处就会在BTA_DM_DISCOVER_ACTIVE状态处理消息
bta_dm_search_set_state(BTA_DM_DISCOVER_ACTIVE);
bta_dm_discover(message);
break;
扫描完成后会bta_dm_search_set_state为idle,这里初始状态为idle
- bta_dm_discover
结构体里的参数都预置个值方便后面使用
void bta_dm_discover(tBTA_DM_MSG* p_data) {
/* save the search condition */
bta_dm_search_cb.services = BTA_ALL_SERVICE_MASK;//0x7FFFFFFF
bta_dm_gattc_register();
bta_dm_search_cb.p_search_cback = p_data->discover.p_cback;
bta_dm_search_cb.services_to_search = bta_dm_search_cb.services;
bta_dm_search_cb.service_index = 0;
bta_dm_search_cb.services_found = 0;
bta_dm_search_cb.peer_name[0] = 0;
bta_dm_search_cb.p_btm_inq_info = BTM_InqDbRead(p_data->discover.bd_addr);
bta_dm_search_cb.transport = p_data->discover.transport;
bta_dm_search_cb.name_discover_done = false;
bta_dm_discover_device(p_data->discover.bd_addr);
}
- bta_dm_discover_device
涉及EIR相关
static void bta_dm_discover_device(const RawAddress& remote_bd_addr) {
/**
1. 设置transport
2. bta_dm_search_cb保存对端地址
3. 判断p_btm_inq_info是否有内容,打印内容;p_btm_inq_info是BTM保存在数据库中的inquiry的response信息,EIR相关
4. ble设备在inquiry之后不进行rnr,(INTEROP_DISABLE_NAME_REQUEST名单匹配)
5. 知道名字的情况下,跳过rnr
6. 名字未知且需要查询的时候进行的操作
7. 为下次discovery重置transport
**/
/* if application wants to discover service */
if (bta_dm_search_cb.services) { //根据前面赋值知道0x7FFFFFFF
/* bta_dm_discover中也有进行过,因为此函数被多次调用,这里再次初始化变量 */
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;//0x7FFFFFFF
/* if seaching with EIR is not completed */
if (bta_dm_search_cb.services_to_search) {
/*
1. ACL链路检查,起了就设置wait_disc为false,否则为true;wait_disc跟下个设备的EIR相关
2. 判断并打印p_btm_inq_info内容
*/
if (transport == BT_TRANSPORT_LE) {
if (bta_dm_search_cb.services_to_search & BTA_BLE_SERVICE_MASK) {
...
/* start GATT for service discovery,BLE的处理,这里是BR就跳过,后续再看 */
btm_dm_start_gatt_discovery(bta_dm_search_cb.peer_bdaddr);
return;
}
} else {
LOG_INFO("bta_dm_discovery: starting SDP discovery on %s",
ADDRESS_TO_LOGGABLE_CSTR(bta_dm_search_cb.peer_bdaddr));
bta_dm_search_cb.sdp_results = false;
//终于开始了SDP的内容了
bta_dm_find_services(bta_dm_search_cb.peer_bdaddr);
return;
}
}
}
// 名字和service discovery完成后发送BTA_DM_DISCOVERY_RESULT_EVT
...
bta_sys_sendmsg(p_msg);//BTA_DM_DISCOVERY_RESULT_EVT
}
- bta_dm_find_services
循环的查找service
static void bta_dm_find_services(const RawAddress& bd_addr) {
while (bta_dm_search_cb.service_index < BTA_MAX_SERVICE_ID) {
Uuid uuid = Uuid::kEmpty;
if (bta_dm_search_cb.services_to_search &
(tBTA_SERVICE_MASK)(
BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index))) {
...
/* try to search all services by search based on L2CAP UUID */
if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) {
...
if (bta_dm_search_cb.services_to_search & BTA_RES_SERVICE_MASK) {
uuid = Uuid::From16Bit(bta_service_id_to_uuid_lkup_tbl[0]);
// 第一次搜完PNP之后,services_to_search = 0x7FFFFFFE,下此循环不在进行这个
bta_dm_search_cb.services_to_search &= ~BTA_RES_SERVICE_MASK;
} else {// services_to_search 置0后,while里的第一个if就进不来了
uuid = Uuid::From16Bit(UUID_PROTOCOL_L2CAP);
bta_dm_search_cb.services_to_search = 0;
}
} else {
/* for LE only profile */
if (bta_dm_search_cb.service_index == BTA_BLE_SERVICE_ID) {
uuid = Uuid::From16Bit(
bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index]);
bta_dm_search_cb.services_to_search &= (tBTA_SERVICE_MASK)(~(
BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index)));
} else {
/* remove the service from services to be searched */
bta_dm_search_cb.services_to_search &= (tBTA_SERVICE_MASK)(~(
BTA_SERVICE_ID_TO_SERVICE_MASK(bta_dm_search_cb.service_index)));
uuid = Uuid::From16Bit(
bta_service_id_to_uuid_lkup_tbl[bta_dm_search_cb.service_index]);
}
}
// 初始换discovery数据库
SDP_InitDiscoveryDb(bta_dm_search_cb.p_sdp_db, BTA_DM_SDP_DB_SIZE, 1,
&uuid, 0, NULL);
memset(g_disc_raw_data_buf, 0, sizeof(g_disc_raw_data_buf));
bta_dm_search_cb.p_sdp_db->raw_data = g_disc_raw_data_buf;
bta_dm_search_cb.p_sdp_db->raw_size = MAX_DISC_RAW_DATA_BUF;
if (!SDP_ServiceSearchAttributeRequest(bd_addr, bta_dm_search_cb.p_sdp_db,
&bta_dm_sdp_callback)) {
/* 当前的设备的SDP进行失败,service_index设置为最大,进行下个设备的 */
osi_free_and_reset((void**)&bta_dm_search_cb.p_sdp_db);
bta_dm_search_cb.service_index = BTA_MAX_SERVICE_ID;
} else {
if (uuid == Uuid::From16Bit(UUID_PROTOCOL_L2CAP)) {
// 通过INTEROP_DISABLE_PCE_SDP_AFTER_PAIRING名单匹配
if (!is_sdp_pbap_pce_disabled(bd_addr)) {
LOG_DEBUG("SDP search for PBAP Client ");
// 针对单个uuid进行查询的接口
BTA_SdpSearch(bd_addr, Uuid::From16Bit(UUID_SERVCLASS_PBAP_PCE));
}
}
bta_dm_search_cb.service_index++;//只在SDP通道建立成功时
return;//当前的uuid的跳出,等待对端回应后在执行下次循环
}
}
bta_dm_search_cb.service_index++; // while 循环的,while内的第一个if判断没进
}
/* services discovery 完之后,发送BTA_DM_DISCOVERY_RESULT_EVT */
if (bta_dm_search_cb.service_index >= BTA_MAX_SERVICE_ID) {
...
bta_sys_sendmsg(p_msg);//BTA_DM_DISCOVERY_RESULT_EVT
}
}
第一次的uuid为UUID_SERVCLASS_PNP_INFORMATION
,第二次services_to_search = 0x7FFFFFFE
就会进行UUID_PROTOCOL_L2CAP
的,但是看逻辑怎么进行除上两个之外的?
两个疑问:
-
L2CAP的搜完之后,
bta_dm_search_cb.services_to_search = 0
怎么进行下一次?并且uuid没有找到其他的
使用的是 -
每次循环完成前, 都会return,该怎么进行循环?
当前的uuid搜索的时候不会在进行下一次,直到收到对端回应后才会进行下一次的,并且最多只能同时建立4条通道#define SDP_MAX_CONNECTIONS 4
是不是说这里的while循环就没有必要了呢?L2CAP的搜完后,此函数中没有其他的uuid赋值了?循环但是内容执行?
- SDP_ServiceSearchAttributeRequest
查询SDP server的信息,组合了SDP_SERVICE_SEARCH_REQ
和SDP_SERVICE_ATTR_REQ
bool SDP_ServiceSearchAttributeRequest(const RawAddress& p_bd_addr,
tSDP_DISCOVERY_DB* p_db,
tSDP_DISC_CMPL_CB* p_cb) {
tCONN_CB* p_ccb;
/* Specific BD address */
p_ccb = sdp_conn_originate(p_bd_addr); // 建立SDP通道
if (!p_ccb) return (false);
p_ccb->disc_state = SDP_DISC_WAIT_CONN;
p_ccb->p_db = p_db;
p_ccb->p_cb = p_cb;
p_ccb->is_attr_search = true;
return (true);
}
- sdp_conn_originate
建立通道
tCONN_CB* sdp_conn_originate(const RawAddress& p_bd_addr) {
tCONN_CB* p_ccb;
uint16_t cid;
/* 分配connection control block,一个连接通道一个,最多4个*/
p_ccb = sdpu_allocate_ccb();
if (p_ccb == NULL) {
SDP_TRACE_WARNING("%s: no spare CCB for peer %s", __func__,
ADDRESS_TO_LOGGABLE_CSTR(p_bd_addr));
return (NULL);
}
/* We are the originator of this connection */
p_ccb->con_flags |= SDP_FLAGS_IS_ORIG; //0x1
/* Save the BD Address and Channel ID. */
p_ccb->device_address = p_bd_addr;
// Transition to the next appropriate state, waiting for connection confirm.
p_ccb->con_state = SDP_STATE_CONN_SETUP;
// Look for any active sdp connection on the remote device,遍历p_ccb
cid = sdpu_get_active_ccb_cid(p_bd_addr);
// sdp_serialization_is_enabled是不是rust定义的,触及到了知识盲区了。。。
if (!bluetooth::common::init_flags::sdp_serialization_is_enabled() ||
cid == 0) {//SDP串口没有开启或者没有active通道,创建L2cap连接
p_ccb->con_state = SDP_STATE_CONN_SETUP;
cid = L2CA_ConnectReq2(BT_PSM_SDP, p_bd_addr, BTM_SEC_NONE);
} else {// 已有通道,等待连接
p_ccb->con_state = SDP_STATE_CONN_PEND;
SDP_TRACE_WARNING("SDP already active for peer %s. cid=%#0x",
ADDRESS_TO_LOGGABLE_CSTR(p_bd_addr), cid);
}
/* Check if L2CAP started the connection process,SDP是建立在L2cap的基础上的,协议定义 */
if (cid == 0) {
SDP_TRACE_WARNING("%s: SDP - Originate failed for peer %s", __func__,
ADDRESS_TO_LOGGABLE_CSTR(p_bd_addr));
sdpu_release_ccb(*p_ccb);// 释放
return (NULL);
}
p_ccb->connection_id = cid;
return (p_ccb);
}
中间有一个疑问,bluetooth::common::init_flags::sdp_serialization_is_enabled()
定义在init_flags.rs文件中,是rust吗?
对应的hci如下:
- 第一组建立一个L2CAP通道
- 第二组配置通道的MTU
- 第三组是配置成功的回应
- 第四组是uuid的request与回应,有的时候会有多组回应,看Bytes for continuation length是否为0
- 第五组为L2CAP的断开请求与回应
至于为啥会确定这个是同一组的,可以通过Source CID和Dest. ID判断,另外有的时候会发现同一个L2CAP通道建立之后,会有一组以上的SDP(多个uuid的request)就对应了代码中的sdpu_get_active_ccb_cid
- sdp_init
蓝牙开启时event_start_up_stack
里会调用sdp_init
,其中的sdp_cb.reg_info为L2CAP的注册回调
void sdp_init(void) {
/* Clears all structures and local SDP database (if Server is enabled) */
memset(&sdp_cb, 0, sizeof(tSDP_CB));
for (int i = 0; i < SDP_MAX_CONNECTIONS; i++) { // 解释了前面说的最多4条通道
sdp_cb.ccb[i].sdp_conn_timer = alarm_new("sdp.sdp_conn_timer");
}
/* Initialize the L2CAP configuration. We only care about MTU */
sdp_cb.l2cap_my_cfg.mtu_present = true;
sdp_cb.l2cap_my_cfg.mtu = SDP_MTU_SIZE;
sdp_cb.max_attr_list_size = SDP_MTU_SIZE - 16;
sdp_cb.max_recs_per_search = SDP_MAX_DISC_SERVER_RECS;
sdp_cb.trace_level = BT_TRACE_LEVEL_WARNING;
sdp_cb.reg_info.pL2CA_ConnectInd_Cb = sdp_connect_ind; //收到对端发来的连接请求 L2CAP_CONNECTION_REQ
sdp_cb.reg_info.pL2CA_ConnectCfm_Cb = sdp_connect_cfm; //收到对端的连接回复 L2CAP_CONNECTION_RSP
sdp_cb.reg_info.pL2CA_ConfigInd_Cb = sdp_config_ind; //收到对端配置请求 L2CAP_CONFIGRATION_RQE
sdp_cb.reg_info.pL2CA_ConfigCfm_Cb = sdp_config_cfm; //收到对端配置回复 L2CAP_CONFIGRATION_RSP
sdp_cb.reg_info.pL2CA_DisconnectInd_Cb = sdp_disconnect_ind; //收到对端断开请求 L2CAP_DISCONNECTION_REQ
sdp_cb.reg_info.pL2CA_DisconnectCfm_Cb = sdp_disconnect_cfm; // 收到对端断开回复 L2CAP_DISCONNECTION_RSP
sdp_cb.reg_info.pL2CA_DataInd_Cb = sdp_data_ind;
sdp_cb.reg_info.pL2CA_Error_Cb = sdp_on_l2cap_error;
/* Now, register with L2CAP */
if (!L2CA_Register2(BT_PSM_SDP, sdp_cb.reg_info, true /* enable_snoop */,
nullptr, SDP_MTU_SIZE, 0, BTM_SEC_NONE)) {
SDP_TRACE_ERROR("SDP Registration failed");
}
}
前面是发送连接请求,根据交互知道会收到对端的L2CAP_CONNECTION_RSP,也就是L2CAP通道打开之后会调用pL2CA_ConnectCfm_Cb,也就是sdp_connect_cfm函数内容。
- sdp_connect_cfm
static void sdp_connect_cfm(uint16_t l2cap_cid, uint16_t result) {
tCONN_CB* p_ccb;
/* Find CCB based on CID */
p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
if (p_ccb == NULL) {
SDP_TRACE_WARNING("SDP - Rcvd conn cnf for unknown CID 0x%x", l2cap_cid);
return;
}
/* If the connection response contains success status, then Transition to the next state and startup the timer.*/
if ((result == L2CAP_CONN_OK) && (p_ccb->con_state == SDP_STATE_CONN_SETUP)) {
p_ccb->con_state = SDP_STATE_CFG_SETUP;
} else {
LOG(ERROR) << __func__ << ": invoked with non OK status";
}
}
处理完sdp_connect_cfm之后怎么发送L2CAP_CONFIGRATION_RQE呢?其实发送connection request 之后,l2cap channel状态是等待对端回应的状态的,在收到L2CEVT_L2CAP_CONNECT_RSP
之后,l2cap_channel状态机会调用函数L2CEVT_L2CAP_CONNECT_RSP
发送个配置请求。
- l2c_csm_send_config_req
l2cap配置的过程中只关心MTU,发送的request告诉server自己这边的最大的MTU,对端也会发送告诉client自己的mtu,然后选择个小的。
static void l2c_csm_send_config_req(tL2C_CCB* p_ccb) {
tL2CAP_CFG_INFO config{};
config.mtu_present = true;
config.mtu = p_ccb->p_rcb->my_mtu;
p_ccb->max_rx_mtu = config.mtu;
if (p_ccb->p_rcb->ertm_info.preferred_mode != L2CAP_FCR_BASIC_MODE) {
config.fcr_present = true;
config.fcr = kDefaultErtmOptions;
}
p_ccb->our_cfg = config;
l2c_csm_execute(p_ccb, L2CEVT_L2CA_CONFIG_REQ, &config);// l2cap_channel 状态机的
}
由于之前channel状态已经走到了CST_CONFIG,接下来l2c_csm_config
会在本地处理L2CEVT_L2CA_CONFIG_REQ
。
共有两个步骤:
l2cu_process_our_cfg_req
提取感兴趣的信息保存在ccb中l2cu_send_peer_config_req
建立并发送L2cap消息给到对方
相应的收到对端L2CEVT_L2CAP_CONFIG_RSP
之后,最终会调用l2c_csm_indicate_connection_open
,然后在调用api.pL2CA_ConfigCfm_Cb
,实现在sdp_config_cfm,中间的L2CAP发送和处理消息的过程就省略了
- sdp_config_cfm
更新了con_state 状态,另外sdp_config_ind
中保存了对端发来的MTU
static void sdp_config_cfm(uint16_t l2cap_cid, uint16_t initiator,
tL2CAP_CFG_INFO* p_cfg) {
sdp_config_ind(l2cap_cid, p_cfg); // 对端发的请求,保存对端发的MTK
tCONN_CB* p_ccb;
SDP_TRACE_EVENT("SDP - Rcvd cfg cfm, CID: 0x%x", l2cap_cid);
/* Find CCB based on CID */
p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
if (p_ccb == NULL) {
SDP_TRACE_WARNING("SDP - Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
return;
}
/* For now, always accept configuration from the other side */
p_ccb->con_state = SDP_STATE_CONNECTED;
if (p_ccb->con_flags & SDP_FLAGS_IS_ORIG) { // true,p_ccb->con_flags在前面sdp_conn_originate时有赋值
sdp_disc_connected(p_ccb);
} else {
/* Start inactivity timer */
alarm_set_on_mloop(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
sdp_conn_timer_timeout, p_ccb);
}
}
- sdp_disc_connected
void sdp_disc_connected(tCONN_CB* p_ccb) {
if (p_ccb->is_attr_search) { //true,SDP_ServiceSearchAttributeRequest时有赋值
p_ccb->disc_state = SDP_DISC_WAIT_SEARCH_ATTR;
process_service_search_attr_rsp(p_ccb, NULL, NULL);
} else {
/* First step is to get a list of the handles from the server. */
/* We are not searching for a specific attribute, so we will */
/* first search for the service, then get all attributes of it */
p_ccb->num_handles = 0;
sdp_snd_service_search_req(p_ccb, 0, NULL);
}
}
process_service_search_attr_rsp相比与sdp_snd_service_search_req多了一个attribute,hci区别如下:
attribute的回复中多了红框内容,包含配置及其依赖的协议,版本,支持的feature等。
- process_service_search_attr_rsp
static void process_service_search_attr_rsp(tCONN_CB* p_ccb, uint8_t* p_reply,
uint8_t* p_reply_end) {
uint8_t *p, *p_start, *p_end, *p_param_len;
uint8_t type;
uint32_t seq_len;
uint16_t param_len, lists_byte_count = 0;
bool cont_request_needed = false;
/* If p_reply is NULL, we were called for the initial read */
if (p_reply) {
// 回复内容的处理,回复数据长度的安全检查
}
/* If continuation request (or first time request) */
if ((cont_request_needed) || (!p_reply)) {
//写发送的数据
}
/*******************************************************************/
/* We now have the full response, which is a sequence of sequences */
/*******************************************************************/
// attribute的数据处理
...
/* Since we got everything we need, disconnect the call */
sdpu_log_attribute_metrics(p_ccb->device_address, p_ccb->p_db);
sdp_disconnect(p_ccb, SDP_SUCCESS);
}
开始还疑问是rsp,而不是req;看到逻辑得知,会发多次,并不知道之前有没有发或者有没有对端的rsp数据过来,所以先处理p_reply,如果为空在写发送的数据。
最后会调用sdp_disconnect
去告诉用户断开原因,重置con_state为SDP_STATE_IDLE,并删除可能持有的任何响应指针和清空response buffer。
然后还是同样的l2cap中走一圈然后到sdp_disconnect_cfm
- sdp_disconnect_cfm
回调并释放
static void sdp_disconnect_cfm(uint16_t l2cap_cid,
UNUSED_ATTR uint16_t result) {
tCONN_CB* p_ccb;
/* Find CCB based on CID */
p_ccb = sdpu_find_ccb_by_cid(l2cap_cid);
if (p_ccb == NULL) {
SDP_TRACE_WARNING("SDP - Rcvd L2CAP disc cfm, unknown CID: 0x%x",
l2cap_cid);
return;
}
tCONN_CB& ccb = *p_ccb;
SDP_TRACE_EVENT("SDP - Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
sdpu_callback(ccb, static_cast<tSDP_STATUS>(ccb.disconnect_reason));
sdpu_process_pend_ccb_new_cid(ccb);
sdpu_release_ccb(ccb);
}
- sdpu_callback
void sdpu_callback(tCONN_CB& ccb, tSDP_REASON reason) {
if (ccb.p_cb) {
(ccb.p_cb)(reason);
} else if (ccb.p_cb2) {
(ccb.p_cb2)(reason, ccb.user_data);
}
}
- bta_dm_sdp_callback
sdpu_callback怎么到bta_dm_sdp_callback呢,因为SDP_ServiceSearchAttributeRequest
中给的回调。
static void bta_dm_sdp_callback(tSDP_STATUS sdp_status) {
tBTA_DM_SDP_RESULT* p_msg =
(tBTA_DM_SDP_RESULT*)osi_malloc(sizeof(tBTA_DM_SDP_RESULT));
p_msg->hdr.event = BTA_DM_SDP_RESULT_EVT;
p_msg->sdp_result = sdp_status;
bta_sys_sendmsg(p_msg);
}
- bta_dm_search_sm_execute
BTA_DM_DISCOVER_ACTIVE
状态处理BTA_DM_SDP_RESULT_EVT
bool bta_dm_search_sm_execute(BT_HDR_RIGID* p_msg) {
...
case BTA_DM_DISCOVER_ACTIVE:
switch (p_msg->event) {
...
case BTA_DM_SDP_RESULT_EVT:
bta_dm_sdp_result(message);
break;
为啥会在BTA_DM_DISCOVER_ACTIVE
状态呢?
因为之前在BTA_DM_SEARCH_IDLE
状态处理BTA_DM_API_DISCOVER_EVT
消息时设置了此状态。
- bta_dm_sdp_result
处理SDP结果
void bta_dm_sdp_result(tBTA_DM_MSG* p_data) {
...
if ((p_data->sdp_event.sdp_result == SDP_SUCCESS) ||
(p_data->sdp_event.sdp_result == SDP_NO_RECS_MATCH) ||
(p_data->sdp_event.sdp_result == SDP_DB_FULL)) { // 内容都在这个判断中
/*
1. while循环,通过bta_dm_search_cb.service_index判断是对那个service查询的,是否需要继续查询这样
2. 收集128位的service并将其放入到list数据库
*/
...
/* Collect the 128-bit services here and put them into the list */
if (bta_dm_search_cb.services == BTA_ALL_SERVICE_MASK) {
p_sdp_rec = NULL;
do {
/* find a service record, report it */
p_sdp_rec =
SDP_FindServiceInDb_128bit(bta_dm_search_cb.p_sdp_db, p_sdp_rec);
if (p_sdp_rec) {
// SDP_FindServiceUUIDInRec_128bit is used only once, refactor?
Uuid temp_uuid;
if (SDP_FindServiceUUIDInRec_128bit(p_sdp_rec, &temp_uuid)) {
uuid_list.push_back(temp_uuid);
}
}
} while (p_sdp_rec);
}
...
/* if there are more services to search for */
if (bta_dm_search_cb.services_to_search) { // 搜pnp之后值为 0x7FFFFFFE,但是搜完L2cap之后又变回0了
/* Free up the p_sdp_db before checking the next one */
bta_dm_free_sdp_db();
bta_dm_find_services(bta_dm_search_cb.peer_bdaddr); // 继续下一次的service查找,pnp之后就是l2cap了
} else {
/* callbacks */
/* start next bd_addr if necessary */
...
} else {
// 发送BTA_DM_DISCOVERY_RESULT_EVT事件
}
}
这里需要解释下为啥看这个循环好像只循环了两次
第一次:
搜pnp,serice_to_search
为0x7FFFFFFE,service_index
为1,由于serice_to_search
不为0,然后需要进行第二次搜索,也就是L2cap的搜索
第二次:
L2cap搜完之后,service_index
为0,service_index
为2。因为是组合了SDP_SERVICE_SEARCH_REQ
和SDP_SERVICE_ATTR_REQ
,所以回复中Continuation length bytes不为0,会有多次回复,attribute中包含了对端支持的所有的profile & protocol。后面的回复内容不为空,所以会将所有的内容进行存储。
后续的PCE是在bta_dm_find_services
中有判断如果是UUID_PROTOCOL_L2CAP
,则进行地址名单匹配。
再后面的Handsfree和AudioSink是对应的profile连接的时候发起的。
- bta_dm_search_sm_execute
BTA_DM_DISCOVER_ACTIVE
状态处理BTA_DM_DISCOVERY_RESULT_EVT
bool bta_dm_search_sm_execute(BT_HDR_RIGID* p_msg) {
...
case BTA_DM_DISCOVER_ACTIVE:
switch (p_msg->event) {
...
case BTA_DM_DISCOVERY_RESULT_EVT:
bta_dm_disc_result(message);
break;
- bta_dm_disc_result
void bta_dm_disc_result(tBTA_DM_MSG* p_data) {
APPL_TRACE_EVENT("%s", __func__);
/* disc_res.device_type is set only when GATT discovery is finished in
* bta_dm_gatt_disc_complete */
bool is_gatt_over_ble = ((p_data->disc_result.result.disc_res.device_type &
BT_DEVICE_TYPE_BLE) != 0);
/* if any BR/EDR service discovery has been done, report the event */
if (!is_gatt_over_ble && (bta_dm_search_cb.services &
((BTA_ALL_SERVICE_MASK | BTA_USER_SERVICE_MASK) &
~BTA_BLE_SERVICE_MASK)))
bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT,
&p_data->disc_result.result);
bta_dm_search_cmpl();
}
bta_dm_search_cb.p_search_cback
对应的是btif_dm_search_services_evt
,在调用BTA_DmDiscover
是传入。
btif_dm_search_services_evt
内容是uuid的存储,并更新device properties给到framework。
大致流程btif_dm_search_services_evt
--> invoke_remote_device_properties_cb
--> remote_device_properties_callback
--> ```devicePropertyChangedCallback``
- bta_dm_search_cmpl
void bta_dm_search_cmpl() {
bta_dm_search_set_state(BTA_DM_SEARCH_IDLE);
uint16_t conn_id = bta_dm_search_cb.conn_id;
tBTA_DM_SEARCH result;
std::vector<Uuid> gatt_services;
result.disc_ble_res.services = &gatt_services;
result.disc_ble_res.bd_addr = bta_dm_search_cb.peer_bdaddr;
strlcpy((char*)result.disc_ble_res.bd_name, bta_dm_get_remname(),
BD_NAME_LEN + 1);
bool send_gatt_results =
bluetooth::common::init_flags::
always_send_services_if_gatt_disc_done_is_enabled()
? bta_dm_search_cb.gatt_disc_active
: false;
/* no BLE connection, i.e. Classic service discovery end */
if (conn_id == GATT_INVALID_CONN_ID) {
if (bta_dm_search_cb.gatt_disc_active) {
LOG_WARN(
"GATT active but no BLE connection, likely disconnected midway "
"through");
} else {
LOG_INFO("No BLE connection, processing classic results");
}
} else {
btgatt_db_element_t* db = NULL;
int count = 0;
BTA_GATTC_GetGattDb(conn_id, 0x0000, 0xFFFF, &db, &count);
if (count != 0) {
for (int i = 0; i < count; i++) {
// we process service entries only
if (db[i].type == BTGATT_DB_PRIMARY_SERVICE) {
gatt_services.push_back(db[i].uuid);
}
}
osi_free(db);
LOG_INFO(
"GATT services discovered using LE Transport, will always send to "
"upper layer");
send_gatt_results = true;
} else {
LOG_WARN("Empty GATT database - no BLE services discovered");
}
}
// send all result back to app
if (send_gatt_results) {
LOG_INFO("Sending GATT results to upper layer");
bta_dm_search_cb.p_search_cback(BTA_DM_GATT_OVER_LE_RES_EVT, &result);
}
bta_dm_search_cb.p_search_cback(BTA_DM_DISC_CMPL_EVT, nullptr);//对应事件没有处理内容
bta_dm_search_cb.gatt_disc_active = false;
#if TARGET_FLOSS
if (DIS_ReadDISInfo(bta_dm_search_cb.peer_bdaddr, bta_dm_read_dis_cmpl,
DIS_ATTR_PNP_ID_BIT)) {
return;
}
#endif
bta_dm_execute_queued_request();
}
- bta_dm_execute_queued_request
将状态转为pending
void bta_dm_execute_queued_request() {
tBTA_DM_MSG* p_pending_discovery = (tBTA_DM_MSG*)fixed_queue_try_dequeue(
bta_dm_search_cb.pending_discovery_queue);
if (p_pending_discovery) {
LOG_INFO("%s Start pending discovery", __func__);
bta_sys_sendmsg(p_pending_discovery);
} else if (bta_dm_search_cb.p_pending_search) {
LOG_INFO("%s Start pending search", __func__);
bta_sys_sendmsg(bta_dm_search_cb.p_pending_search);
bta_dm_search_cb.p_pending_search = NULL;
}
}
参考:
https://www.cnblogs.com/libs-liu/p/9399517.html
http://aospxref.com/