BLE协议栈与Android BLE接口简介
Last updated
Last updated
我们通常所说的蓝牙,即Bluetooth,有两种形式:传统蓝牙BR(Basic Rate)和低功耗蓝牙BLE(Bluetooth Low Energy)。前者的典型使用场景是蓝牙耳机、蓝牙音箱等,而后者的典型使用场景是各种IoT设备,如蓝牙手环等。
蓝牙的数据传输模型如下图2-1所示,分为Physical层、Logical层和L2CAP层:
为了帮助理解,可以类比OSI七层网络协议:数据发送时,高层将数据发送给L2CAP层,并逐层向下流动;数据接收时,设备从Physical层获得数据,并逐层向上流动。对这三层数据传输模型有一些简单的认知,就可以极大的加快我们分析和研究的速度。
首先,来关注下L2CAP层。在这一层中,我们需要关注的内容比较少,高层应用中出现的需要发送的BLE数据和需要接收的BLE数据都会直接出现在这一层之中,所以,如果我们能够抓到这一层的通信数据,则意味着我们可以直接抓到高层应用的通信数据,虽然这些数据可能是在应用层中被加密了,但至少这些数据还没有被BLE协议栈加密。这在某种程度上方便了我们的分析。通过wireshark分析L2CAP层的通信数据如下图:
上图中,ATT协议即为运行于L2CAP层之上的通信协议,wireshark可以直接分析出ATT协议中的通信数据。在本专题的后续文章中,我们可以看到抓取未加密的L2CAP层数据用于辅助分析的案例。
然后,我们再来关注下Physical层。Physical层定义了3个广播信道和37个数据通信信道。两个BLE设备进行连接时,会随机挑选一个广播信道进行广播,连接建立之后,会在37个通信信道上进行跳频通信。下图展示了某一次通信的流程:
上图中,BLE通信在0x27信道进行广播,等待BLE双方成功建立连接之后,会在0x5----0xA----0xF----0x14等信道,按照一定规律进行跳频通信。
最后,我们再来关注下Logical层。该层中主要完成BLE通信过程中的各种逻辑控制,这么说并不准确,但可以帮助我们理解问题。大多数使用场景中,一次BLE通信过程存在master和slave两方,其中master是主动扫描并发起连接的一方,而slave是不断发送广播并等待连接的一方。在一次通信中,master和slave的状态变化如下图所示:
其中,scanner和advertiser分别表示master和slave的扫描状态和广播状态。建立连接之后,开始跳频通信,并成为最终的master和slave。
绝大部分IoT设备都需要与Android/IOS手机通信,而BLE显然是一种很常见的通信方式。为此,我们也有必要了解一下Android设备中,关于BLE通信相关的各种API。
我们先回忆一下TCP的socket通信。在socket通信中,服务端程序运行于某一IP地址上,并持续监听某一端口(port)。客户端程序选择服务端的IP和port,发起socket连接,经过三次TCP握手之后完成socket连接的建立,此后使用该socket进行通信。蓝牙BLE通信也是如此,首先我们需要扫描周围的蓝牙BLE设备,并选择某个BLE设备。此时,需要用到的API如下:
扫描并选择完毕之后,我们就需要与之通信。在TCP通信中,发送数据和接收数据常用的函数为:send和recv。而在BLE通信中,我们使用到的API如下表所示:
上表中,读者可能对characteristic有些陌生,我们在这里对characteristic有一个简短的说明。每一个BLE设备,都有一个对应的profile,用于对这个设备进行描述。一个profile中包含多个service,这些service就是该设备提供的各种服务。而在一个service中,会有多个characteristic,设备提供的service就是靠这些characteristic来完成的。用一张图片来表示上述文字,如下:
上图中,右侧图片为一个BLE设备的实例,可以看到在图片中有4个service,前两个为Unknown service,后两个分别是Battery Service(电池服务)和Current Time Service(当前时间服务)。而在第二个Unknown service中,有一个Unknown Characteristic。值得一提的是,Service和Characteristic各自拥有一个UUID用于标识,在BluetoothGatt类的相关函数中,就是用这些UUID找到所需的service和characteristic,这就相当于TCP通信中的端口(port)。
这个系列的第一篇到此就要结束了,在本篇中,我们简要介绍了一下BLE协议栈以及Android BLE的常用API。