安卓系统蓝牙配对流程分析
配对流程基本上始于首次连接一个蓝牙设备的过程中,本端的搜索流程结束获取到该设备的BluetoothDevice信息,就可以开启配对流程。
配对,顾名思义就是将两个设备通过相关技术进行绑定,达到能够互相识别彼此的目的。因此通过蓝牙技术进行的配对就是大家理解中的蓝牙配对。随着蓝牙技术在消费市场上越来越普及,生活中很容易就能遇到蓝牙配对这一使用蓝牙功能事必不可缺失的步骤。本期我们就简单聊聊安卓系统蓝牙配对的流程是如何运行的。
Application通过framework层BluetoothDevice对外提供的接口createBond()开启这一流程。createBondOutOfBand()通过OOB技术进行配对的接口,一般很少使用。所以应用层需要根据自己的实际使用场景选择正确的接口。
蓝牙服务层在配对流程中基本没有复杂的操作,只是简单地下发指令成功后,通过JNI层的异步回调处理配对状态变化并将该变化对外广播。其时序图如下:
从上图我们唯一需要注意的点就是配对流程开始前需要停掉搜索扫描流程(如果底层正在进行该流程),增加该操作的主要目的是为了确保配对流程能够正常进行。因为搜索扫描和配对流程都会对远端设备进行Discovery操作,防止这两个流程冲突导致配对失败。
协议栈接收到开始配对指令后,主要按照如下的配对状态机进行切换(Numeric Comparison模式):
- IDLE:初始状态值
- GET_REM_NAME:获取远端设备的蓝牙名字
- WAIT_PIN_REQ:等待Controller请求PIN
- WAIT_LOCAL_IOCAPS:等待本端提供IO能力
- WAIT_NUM_CONFIRM:等待本端Host确认配对
- WAIT_AUTH_COMPLETE:等待鉴权(配对)流程完成
状态切换对应到HCI上的交互见下图:
每一个配对状态的切换触发时机从上面这张图就十分明了,这里我就不做过多分析。感兴趣的同学可以尝试跟着上图中HCI命令跟踪下代码流程。
协议栈的配对状态随着鉴权完成事件Authentication Complete的上报就切换到初始值了,那这时是不是就代表整个配对流程完成了呢?非也,其实在安卓系统中到这里还不代表配对已经完成,因为上报JNI层的配对状态变化回调并不是通过鉴权完成事件上报完成而回调的。
配对流程的主要工作完成后,协议栈还会继续对该设备尝试进行SDP服务发现,搜索该设备支持哪些协议服务,SDP服务搜索完成后才会上报JNI层配对状态变成Bonded。
触发SDP服务搜索的触发时机是处理上报Link Key的回调bta_dm_new_link_key_cback()中通过 event = BTA_DM_AUTH_CMPL_EVT 触发的。
随后在函数btif_dm_auth_cmpl_evt()中尝试对该设备进行SDP服务发现,如下图:
SDP服务发现完成后通过回调处理函数btif_dm_search_services_evt()中 event = BTA_DM_DISC_RES_EVT上 报JNI 层配对状态变化到Bonded。
至此安卓系统中蓝牙配对流程才算闭环完成,上述过程我以Numeric Comparison配对模型为依据介绍了整个流程,其他配对模型类似,就不一一做出说明了,但协议栈配对状态机的全部值如下,其他模型的配对流程也是在这几种状态机组合下进行切换运行的:
enum {
BTM_PAIR_STATE_IDLE, /* Idle */
BTM_PAIR_STATE_GET_REM_NAME, /* Getting the remote name
(to check for SM4) */
BTM_PAIR_STATE_WAIT_PIN_REQ, /* Started authentication, waiting for PIN req
(PIN is pre-fetched) */
BTM_PAIR_STATE_WAIT_LOCAL_PIN, /* Waiting for local PIN code */
BTM_PAIR_STATE_WAIT_NUMERIC_CONFIRM, /* Waiting user 'yes' to numeric confirmation */
BTM_PAIR_STATE_KEY_ENTRY, /* Key entry state (we are a keyboard) */
BTM_PAIR_STATE_WAIT_LOCAL_OOB_RSP, /* Waiting for local response to peer OOB
data */
BTM_PAIR_STATE_WAIT_LOCAL_IOCAPS, /* Waiting for local IO capabilities and OOB
data */
BTM_PAIR_STATE_INCOMING_SSP, /* Incoming SSP (got peer IO caps when idle) */
BTM_PAIR_STATE_WAIT_AUTH_COMPLETE, /* All done, waiting authentication
cpmplete */
BTM_PAIR_STATE_WAIT_DISCONNECT /* Waiting to disconnect the ACL */
};
配对流程实际上并不是孤立而存在的,配合着搜索扫描、连接等流程共同起作用的,彼此依赖,缺一不可。
本期的分享就到这里,感兴趣的小伙伴欢迎私信留言一起讨论。