在上一篇Android蓝牙协议栈fluoride(四) - 设备管理(bt interface) 中梳理了设备管理器对上层提供的接口,本文将介绍这些接口的具体实现。
各个模块中采用了API+状态机+数据收发的方式,介绍设备管理时也将采用这个顺序介绍。
核心数据结构
设备管理的核心数据结构如下:
typedef struct {
bool is_bta_dm_active;
tBTA_DM_ACTIVE_LINK device_list; // 已连接设备列表
tBTA_DM_SEC_CBACK* p_sec_cback; // bt interface 注册的事件回调,BTA_EnableBluetooth()调用时注册
uint16_t state; // 设备管理的状态
// 功耗管理与链接策略相关
uint8_t pm_id;
tBTA_PM_TIMER pm_timer[BTA_DM_NUM_PM_TIMER];
uint32_t role_policy_mask;
uint16_t cur_policy;
uint16_t rs_event; // 设备角色切换事件
uint8_t cur_av_count; // 已连接的audio/vedio数量
tBTA_DM_API_SEARCH search_msg; // 搜索设备的消息内容
// page scan和inquiry scan相关参数
uint16_t page_scan_interval;
uint16_t page_scan_window;
uint16_t inquiry_scan_interval;
uint16_t inquiry_scan_window;
// 配对时的pincode相关
RawAddress pin_bd_addr;
DEV_CLASS pin_dev_class;
tBTA_DM_SEC_EVT pin_evt;
// 本机与对端设备的IO能力
tBTA_IO_CAP loc_io_caps;
tBTA_IO_CAP rmt_io_caps;
// 本机和对端设备的身份认证请求
tBTA_AUTH_REQ loc_auth_req;
tBTA_AUTH_REQ rmt_auth_req;
uint32_t num_val; // 简单安全配对时向UI展示的数值,just work模式不需要展示
bool just_works; // 是否是just work模式
uint32_t eir_uuid[BTM_EIR_SERVICE_ARRAY_SIZE]; // EIR中的UUID mask
tBTA_DM_ENCRYPT_CBACK* p_encrypt_cback; // 加密相关的回调, BTA_DmSetEncryption()调用时注册
} tBTA_DM_CB;
搜索设备的核心数据结构如下(只列出了关注的几个字段):
typedef struct {
tBTA_DM_SEARCH_CBACK* p_search_cback; // 设备搜索/服务发现的事件回调,在BTA_DmSearch()/BTA_DmDiscover()函数中注册
tBTM_INQ_INFO* p_btm_inq_info; // inquiry信息
tBTA_SERVICE_MASK services; // 服务的mask
tBTA_SERVICE_MASK services_to_search; // 搜索服务的mask
tBTA_SERVICE_MASK services_found; // 已发现服务的mask
tSDP_DISCOVERY_DB* p_sdp_db; // sdp的数据库
uint16_t state; // 搜索设备的状态
RawAddress peer_bdaddr; // 对端设备的地址
} tBTA_DM_SEARCH_CB;
API
设备管理提供的API如下:
使能蓝牙
// 使能/打开蓝牙, 在btif_init_ok()中调用
tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK* p_cback)
-> bta_sys_register(BTA_ID_DM_SEARCH, &bta_dm_search_reg) // 向系统管理器注册设备管理的事件处理函数
-> bta_dm_enable(p_cback) // enable蓝牙
-> bta_sys_hw_register(BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback) // 向系统管理器注册硬件状态变化回调
-> bta_sys_sendmsg(BTA_SYS_API_ENABLE_EVT) // 向系统管理器发送事件
// 禁用/关闭蓝牙
tBTA_STATUS BTA_DisableBluetooth(void)
设备发现
// 设置本机的发现模式:connectable, discoverable, pairable, conn paired only
void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode, uint8_t pairable_mode, uint8_t conn_filter);
-> bta_dm_set_visibility()
-> BTM_SetDiscoverability()
-> BTM_SetConnectability()
-> BTM_SetPairableMode()
// 搜索周围的蓝牙设备
void BTA_DmSearch(tBTA_DM_INQ* p_dm_inq, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK* p_cback);
-> bta_sys_sendmsg(BTA_DM_API_SEARCH_EVT) //向设备管理的事件处理发送搜索设备的事件
// 服务发现
void BTA_DmDiscover(const RawAddress& bd_addr, tBTA_SERVICE_MASK services, tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search);
-> bta_sys_sendmsg(BTA_DM_API_DISCOVER_EVT)
void BTA_DmDiscoverUUID(const RawAddress& bd_addr, const bluetooth::Uuid& uuid, tBTA_DM_SEARCH_CBACK* p_cback, bool sdp_search);
-> bta_sys_sendmsg(BTA_DM_API_DISCOVER_EVT)
// 取消搜索
void BTA_DmSearchCancel(void);
-> bta_sys_sendmsg(BTA_DM_API_SEARCH_CANCEL_EVT)
// 从EIR中获取service mask
void BTA_GetEirService(uint8_t* p_eir, size_t eir_len, tBTA_SERVICE_MASK* p_services);
配对相关
// 发起配对
void BTA_DmBond(const RawAddress& bd_addr, tBLE_ADDR_TYPE addr_type, tBTA_TRANSPORT transport);
-> bta_dm_bond()
-> BTM_SecBond()
// 取消配对
void BTA_DmBondCancel(const RawAddress& bd_addr);
-> bta_dm_bond_cancel()
-> BTM_SecBondCancel()
// 设置pincode
void BTA_DmPinReply(const RawAddress& bd_addr, bool accept, uint8_t pin_len, uint8_t* p_pin);
-> bta_dm_pin_reply()
-> BTM_PINCodeReply()
// 获取本地的oob数据
void BTA_DmLocalOob(void);
-> BTM_ReadLocalOobData() // 通过bta_dm_co_loc_oob()上报结果
// 接受/拒绝 简单安全配对请求
void BTA_DmConfirm(const RawAddress& bd_addr, bool accept);
-> bta_dm_confirm()
-> BTM_ConfirmReqReply()
// 将已配对对端设备添加到安全数据库中,一般在系统初始化阶段调用
void BTA_DmAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class, const LinkKey& link_key, tBTA_SERVICE_MASK trusted_mask, bool is_trusted, uint8_t key_type, tBTA_IO_CAP io_cap, uint8_t pin_length);
-> bta_dm_add_device()
-> BTM_SecAddDevice()
// 从安全数据库中删除一个对端设备,通常在解除配对时调用
tBTA_STATUS BTA_DmRemoveDevice(const RawAddress& bd_addr);
其他
// 设置本机的蓝牙名称
void BTA_DmSetDeviceName(char* p_name);
// 获取已缓存的对端设备的名称
tBTA_STATUS BTA_DmGetCachedRemoteName(const RawAddress& remote_device, uint8_t** pp_cached_name);
// 获取连接状态
uint16_t BTA_DmGetConnectionState(const RawAddress& bd_addr);
// 向SDP数据库添加本地设备标识的SDP记录
tBTA_STATUS BTA_DmSetLocalDiRecord(tBTA_DI_RECORD* p_device_info, uint32_t* p_handle);
// 强制关闭ACL连接,并从安全数据库中删除该设备
void BTA_DmCloseACL(const RawAddress& bd_addr, bool remove_dev, tBTA_TRANSPORT transport);
BLE 相关的API暂未列举,在后续文章中介绍。
状态机
设备管理中有4个状态,其转换关系如下(图中未列出的事件,表示发生该事件时不切换状态):
search是当前还未发现这个设备,通过inquiry去搜索周围的设备,而discover是已经发现了这个设备,通过SDP去获取这个设备支持的服务或者制定服务。
事件处理
设备管理中的事件处理是通过bta_dm_search_sm_execute()
函数,在BTA_EnableBluetooth()
函数中调用bta_sys_register(BTA_ID_DM_SEARCH, &bta_dm_search_reg)
注册。设备管理中有10个事件以及对应的19处理函数(以下只介绍几个重点关注的函数):
-
bta_dm_search_start()
该函数在idle状态下处理BTA_DM_API_SEARCH_EVT
事件,流程如下:
在idle状态下收到BTA_DM_API_SEARCH_EVT事件后,首先判断是否需要延迟扫描,如:在播放状态下需要将本机角色切换为master,只能在master下进行搜索设备,如是slave将调用BTM_SwitchRole
进行角色切换,切换完成后会通过回调通知调用方。然后需要清除inquiry数据库,并发起inquiry,并将搜索到的结果和搜索完成通过回调通知调用方,调用方将搜索结果通过bta_dm_search_start()调用时注册的回调上报,搜索完成后发出BTA_DM_INQ_CMPL_EVT事件,如果搜索到设备,还会通过bta_dm_discover_device
发现服务,否则直接发出BTA_DM_SEARCH_CMPL_EVT事件。 -
bta_dm_search_cancel()
在search cancel状态下收到BTA_DM_API_SEARCH_CANCEL_EVT,如果正在inquiry(即inquiry active状态)则调用BTM_CancelInquiry
取消inquiry并发出BTA_DM_SEARCH_CMPL_EVT事件,如果是discover active状态则调用BTM_CancelRemoteDeviceName
取消discover并发出BTA_DM_SEARCH_CMPL_EVT事件,否则直接发出BTA_DM_INQUIRY_CMPL_EVT事件。
-
bta_dm_discover()
在idle状态下收到BTA_DM_API_DISCOVER_EVT事件时,发起服务发现动作,首先根据MAC地址获取inquiry信息(调用BTM_InqDbRead
), 然后调用bta_dm_discover_device
发现服务,根据参数判断是否需要获取对端设备的名称,如需要则发起获取名称的请求,获取到对端设备名称后在发起服务发现请求,如果已经获取到对端名称,则判断是否需要发现服务,需要时发起SDP请求,否则直接发出BTA_DM_DISCOVERY_RESULT_EVT事件,函数调用和程序流程如下:
bta_dm_discover()
-> BTM_InqDbRead()
-> bta_dm_discover_device()
-> bta_dm_read_remote_device_name() // 获取对端设备名称
-> BTM_ReadRemoteDeviceName()
-> bta_dm_eir_search_services() // 判断EIR中包含了哪些服务
-> bta_dm_find_services() // 未包含在EIR中的则发起服务发现
-> SDP_InitDiscoveryDb()
-> SDP_ServiceSearchAttributeRequest()
-> bta_sys_sendmsg(BTA_DM_DISCOVERY_RESULT_EVT)
- bta_dm_inq_cmpl()
在search active状态下收到BTA_DM_INQUIRY_CMPL_EVT事件时调用该函数,在bta_dm_search_start
函数中inquiry完成的回调中会收到该事件,此处不再重复描述。 - bta_dm_rmt_name()
在search active状态下收到BTA_DM_REMT_NAME_EVT事件时调用,在该函数中发起服务发现请求,服务发现参考bta_dm_discover
函数, BTA_DM_REMT_NAME_EVT在收到BTM_ReadRemoteDeviceName
中注册,收到对端设备名称时回调。 - bta_dm_sdp_result()
在search active和discover active状态下收到BTA_DM_SDP_RESULT_EVT事件时调用,解析SDP的结果后发出BTA_DM_DISCOVERY_RESULT_EVT事件,BTA_DM_SDP_RESULT_EVT事件在SDP_ServiceSearchAttributeRequest
注册的回调中发出。 - bta_dm_search_cmpl()
在search active和search canceling状态下收到BTA_DM_SEARCH_CMPL_EVT事件时调用,该函数中上报BTA_DM_DI_DISC_CMPL_EVT或BTA_DM_DISC_CMPL_EVT事件。 - bta_dm_disc_result()
在discover active状态下收到BTA_DM_DISCOVERY_RESULT_EVT事件时调用,函数中发出BTA_DM_SEARCH_CMPL_EVT事件,同时在服务发现完成时上报BTA_DM_DISC_RES_EVT事件。 - bta_dm_search_result()
在search active状态下收到BTA_DM_DISCOVERY_RESULT_EVT事件时调用,上报BTA_DM_DISC_RES_EVT事件,如果需要,发起下一个设备的服务发现。