蓝牙协议栈源码分析:从Java API到Native层

做蓝牙开发这么多年,我经常被问到同一个问题:「我调用了BluetoothAdapter.enable(),底层到底发生了什么?」

说实话,刚入行那会儿我也挺好奇的。Java层一个简单的API调用,怎么就控制硬件去搜设备、连耳机了?今天我们就从源码角度,把这条链路彻底走一遍。

一、整体架构:三层模型

Android蓝牙协议栈,说白了就是三层结构:

  • Java Framework层 — 我们开发者直接调用的API,比如BluetoothAdapter、BluetoothDevice
  • Native层 — 用C++实现的BluetoothManagerService、AdapterService等核心服务
  • HCI层 — 硬件控制接口,直接和蓝牙芯片打交道

嗯,这里要注意:Java层和Native层之间通过JNI通信,Native层再通过socket或vendor扩展库下发HCI命令。

Android蓝牙协议栈三层架构 Java Framework层 BluetoothAdapter · BluetoothDevice · BluetoothGatt · BluetoothSocket JNI Native层 (C++) BluetoothManagerService · AdapterService · StackManager · Vendor Extensions HCI Command / Vendor HCI HCI层 / 硬件抽象层 UART/USB/SDIO · 蓝牙控制器 (Controller) · Vendor Specific HCI

二、Java API 到 Native 的桥梁

我们以BluetoothAdapter.enable()为例,看看这条调用链。

2.1 Java 端入口

// frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java
public boolean enable() {
    // 检查权限
    if (isEnabled()) {
        return true;
    }
    try {
        return mManagerService.enable();
    } catch (RemoteException e) {
        Log.e(TAG, "", e);
        return false;
    }
}

这里mManagerService是一个Binder代理对象,实际对应的是BluetoothManagerService

个人经验: 我早期调试时经常遇到RemoteException,多半是蓝牙服务进程挂了。建议在调用enable()前先检查isEnabled(),避免重复调用导致异常。

2.2 BluetoothManagerService 的处理

// frameworks/base/services/core/java/com/android/server/bluetooth/BluetoothManagerService.java
public boolean enable() {
    // 状态检查
    if (mState == BluetoothAdapter.STATE_BLE_ON) {
        // 从BLE only切换到BR/EDR
        return enableBle(bridge);
    }
    // 发送消息到内部Handler
    Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
    msg.arg1 = 0; // 静默模式
    mHandler.sendMessage(msg);
    return true;
}

这里有个细节:蓝牙使能不是同步的。Handler收到消息后,会调用enableNative()这个JNI方法。

2.3 JNI 调用到 Native

// frameworks/base/core/jni/android_bluetooth_common.cpp
static jboolean enableNative(JNIEnv* env, jobject obj) {
    // 获取BluetoothService的native实例
    bluetooth::hal::BluetoothInterface* btif = getBluetoothInterface();
    if (btif == nullptr) return JNI_FALSE;
    
    // 调用HAL层接口
    bt_status_t status = btif->enable();
    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

看到没?JNI层其实很薄,就是个转发。真正的逻辑在BluetoothInterface这个HAL接口里。

三、HCI命令下发流程

到了Native层,事情就变得有意思了。我当年啃这块代码时,花了整整两周才理清脉络。

3.1 核心数据结构:HCI Command Packet

HCI命令包格式是固定的:

字段 长度 说明
OpCode 2字节 操作码,高6位是OGF,低10位是OCF
Parameter Total Length 1字节 参数总长度
Parameters 0-255字节 具体参数

举个例子,Reset命令的OpCode是0x0C03:

  • OGF = 0x03 (Controller & Baseband命令)
  • OCF = 0x0003 (Reset)

3.2 命令下发源码追踪

// system/bt/hci/src/hci_layer.cpp
static void transmit_command(command_t* cmd) {
    // 1. 序列化命令
    uint8_t* packet = (uint8_t*)malloc(cmd->packet_size);
    serialize_command(cmd, packet);
    
    // 2. 写入HCI传输层
    hci_transmit(packet, cmd->packet_size);
    
    // 3. 等待命令完成事件
    wait_for_command_complete(cmd->opcode, cmd->timeout_ms);
    
    free(packet);
}

这里hci_transmit最终会调用到bt_vendor_interface_t中的send_hci_command函数指针。

关键点: HCI命令是同步等待的!每个命令发出后,必须等到Controller返回Command Complete或Command Status事件,才能发下一条。这个机制叫「命令流控」。

四、Vendor扩展:芯片厂商的「私房菜」

标准HCI命令只能做通用操作。但每家芯片都有自己的特色功能,比如:

  • Broadcom的「快速连接」优化
  • Qualcomm的「低功耗扫描」
  • MTK的「双模共存」策略

这些功能都通过Vendor Specific HCI Command实现。

4.1 Vendor命令格式

// Vendor命令的OpCode范围:0xFC00 - 0xFFFF
// OGF = 0x3F (Vendor Specific)
// OCF = 0x0000 - 0x03FF

typedef struct {
    uint16_t opcode;      // 0xFC00 + vendor_id
    uint8_t  param_len;
    uint8_t  params[255]; // 厂商自定义格式
} vendor_hci_cmd_t;

4.2 实际项目中的Vendor扩展

我记得在做一个TWS耳机项目时,遇到个坑:耳机连接后频繁断连。抓了HCI log发现,是芯片的「省电模式」参数太激进。

解决方案就是通过Vendor命令调整参数:

// 伪代码:设置Broadcom芯片的省电参数
uint8_t params[] = {0x01, 0x0A, 0x32}; // 模式、超时、间隔
vendor_hci_cmd_t cmd = {
    .opcode = 0xFC45,  // Broadcom自定义
    .param_len = 3,
    .params = {0x01, 0x0A, 0x32}
};
hci_send_vendor_cmd(&cmd);
警告: Vendor命令没有统一标准!同一家芯片的不同型号,命令格式都可能不同。一定要参考芯片厂商的Vendor HCI Specification,别想当然。

五、完整调用链总结

我们从头捋一遍enable()的完整路径:

  1. App调用BluetoothAdapter.enable()
  2. System ServiceBluetoothManagerService.enable()
  3. JNI桥接enableNative()
  4. HAL接口BluetoothInterface::enable()
  5. Stack内部 → 构造HCI Reset命令
  6. HCI层transmit_command() 序列化并发送
  7. Vendor层 → 通过UART/USB写入芯片
  8. Controller → 执行命令,返回Complete事件

整个过程,从Java到硬件,大概经过7-8层函数调用。我刚开始看源码时,经常在JNI和HAL之间迷路。后来养成个习惯:先抓HCI log,再反推代码路径,效率高很多。

调试技巧:adb shell抓取蓝牙HCI log:
adb shell cat /sys/kernel/debug/bluetooth/hci0 > hci_log.bin
然后用hcidumpWireshark解析,能看到每条命令的收发细节。

好了,这一章我们从Java API一路追到了HCI命令和Vendor扩展。说白了,蓝牙协议栈就是个层层封装、逐级下放的过程。理解了这个脉络,后面分析具体功能(扫描、连接、GATT)就会轻松很多。


公众号:蓝海资料掘金营,微信deep3321