BlueZ 作为 Linux 官方蓝牙协议栈,其整体工作流程涵盖了从蓝牙适配器初始化、设备发现、配对绑定到数据交互的完整生命周期。本文基于 BlueZ 5.x 源码,从时间维度逐层拆解整个工作流程,深入剖析各阶段的核心职责、状态机跳转、异常处理机制,为蓝牙开发者提供一份系统级的架构参考。
目录
一、阶段一:开机初始化 - Bluetooth Daemon 启动
二、阶段二:适配器唤醒 - Powered On
三、阶段三:扫描广播 - 设备发现
四、阶段四:设备配对 - Bonding
五、阶段五:绑定连接 - 建立链路
六、阶段六:数据交互 - Profile 通信
七、关键源码函数索引
八、常见流程认知误区与纠正
九、总结
一、阶段一:开机初始化 - Bluetooth Daemon 启动
1.1main() 入口与初始化顺序
蓝牙守护进程的启动入口位于src/main.c,其初始化顺序严格遵循依赖关系:
int main(int argc, char *argv[]) { init_defaults(); // 1. 设置默认选项 ... mainloop_init(); // 2. 初始化主事件循环 __btd_log_init(option_debug, option_detach); // 3. 日志初始化 ... if (connect_dbus() < 0) { // 4. 建立 DBus 连接 error("Unable to get on D-Bus"); exit(1); } ... if (adapter_init() < 0) { // 5. 适配器管理初始化 error("Adapter handling initialization failed"); exit(1); } btd_device_init(); // 6. 设备管理初始化 btd_agent_init(); // 7. Agent 初始化 btd_profile_init(); // 8. Profile 初始化 ... plugin_init(option_plugin, option_noplugin); // 9. 插件加载 ... mainloop_run_with_signal(signal_callback, NULL); // 10. 进入主循环1.2DBus连接建立
DBus 是 BlueZ 5.x 的核心通信机制,connect_dbus()函数负责注册服务名和附加对象管理器:
static int connect_dbus(void) { DBusConnection *conn; DBusError err; conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, BLUEZ_NAME, &err); if (!conn) { ... return -EIO; } set_dbus_connection(conn); g_dbus_set_disconnect_function(conn, disconnected_dbus, NULL, NULL); g_dbus_attach_object_manager(conn); // 附加 ObjectManager return 0; }1.3适配器管理初始化
adapter_init()是适配器管理的关键入口,负责创建 Management Socket 并与内核通信:
int adapter_init(void) { dbus_conn = btd_get_dbus_connection(); mgmt_primary = mgmt_new_default(); // 创建 Management Socket if (!mgmt_primary) { error("Failed to access management interface"); return -EIO; } // 发送 MGMT_OP_READ_VERSION 命令 if (mgmt_send(mgmt_primary, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, 0, NULL, read_version_complete, NULL, NULL) > 0) return 0; ... }1.4 Management Socket 创建
Management Socket 是 BlueZ 用户态与内核态通信的核心通道:
struct mgmt *mgmt_new_default(void) { struct mgmt *mgmt; int fd; // 创建 HCI Raw Socket,绑定到 Control Channel fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, BTPROTO_HCI); ... addr.hci.hci_family = AF_BLUETOOTH; addr.hci.hci_dev = HCI_DEV_NONE; addr.hci.hci_channel = HCI_CHANNEL_CONTROL; // Control 通道 bind(fd, &addr.common, sizeof(addr.hci)); ... }1.5 版本读取与事件注册
版本读取完成后,BlueZ 会注册关键事件回调:
static void read_version_complete(uint8_t status, uint16_t length, const void *param, void *user_data) { ... mgmt_version = rp->version; mgmt_revision = btohs(rp->revision); // 注册适配器添加/移除事件 mgmt_register(mgmt_primary, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE, index_added, NULL, NULL); mgmt_register(mgmt_primary, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE, index_removed, NULL, NULL); // 读取控制器索引列表 mgmt_send(mgmt_primary, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL, read_index_list_complete, NULL, NULL); }初始化阶段总结:
步骤 | 函数 | 职责 |
1 |
| 设置全局默认配置(名称、设备类别、超时等) |
2 |
| 初始化 GLib 主事件循环 |
3 |
| 连接系统 DBus,注册服务名 |
4 |
| 创建 Management Socket,读取版本信息 |
5 |
| 初始化设备管理子系统 |
6 |
| 初始化认证代理子系统 |
7 |
| 初始化 Profile 管理子系统 |
8 |
| 动态加载各功能插件 |
9 |
| 进入事件循环,等待事件触发 |
二、阶段二:适配器唤醒 - Powered On
2.1 DBus 属性设置触发
当用户通过bluetoothctl或其他客户端设置Powered属性为true时,触发property_set_powered():
static void property_set_powered(const GDBusPropertyTable *property, DBusMessageIter *iter, GDBusPendingPropertySet id, void *user_data) { struct btd_adapter *adapter = user_data; if (powering_down) { g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed", "Powering down"); return; } property_set_mode(adapter, MGMT_SETTING_POWERED, iter, id); }2.2 Management 命令下发
property_set_mode()最终通过 Management Socket 向内核发送MGMT_OP_SET_POWERED命令:
static bool set_mode(struct btd_adapter *adapter, uint16_t opcode, uint8_t mode) { struct mgmt_cp_set_power cp; memset(&cp, 0, sizeof(cp)); cp.powered = mode; // 发送设置电源命令 if (!mgmt_send(adapter->mgmt, MGMT_OP_SET_POWERED, adapter->dev_id, sizeof(cp), &cp, set_mode_complete, adapter, NULL)) { return false; } adapter->pending_settings |= MGMT_SETTING_POWERED; return true; }2.3 内核设置变更回调
内核完成电源设置后,通过MGMT_EV_NEW_SETTINGS事件通知 BlueZ:
static void settings_changed(struct btd_adapter *adapter, uint32_t settings) { uint32_t changed_mask = adapter->current_settings ^ settings; adapter->current_settings = settings; adapter->pending_settings &= ~changed_mask; // 电源状态变化 if (changed_mask & MGMT_SETTING_POWERED) { g_dbus_emit_property_changed(dbus_conn, adapter->path, ADAPTER_INTERFACE, "Powered"); if (adapter->current_settings & MGMT_SETTING_POWERED) { // 适配器上电后触发被动扫描 trigger_passive_scanning(adapter); } } ... }2.4 被动扫描触发
适配器上电后自动启动 LE 被动扫描,用于发现可连接设备:
static void trigger_passive_scanning(struct btd_adapter *adapter) { if (!(adapter->current_settings & MGMT_SETTING_LE)) return; // 内核支持连接控制时,由内核负责后台扫描 if (btd_has_kernel_features(KERNEL_CONN_CONTROL)) return; // 启动 LE 被动扫描 adapter->passive_scan_timeout = timeout_add(1000, passive_scanning_timeout, adapter, NULL); }适配器唤醒阶段数据流:
DBus Client (bluetoothctl) | v Set("Powered", true) DBus Message | v property_set_powered() | v property_set_mode() -> mgmt_send(MGMT_OP_SET_POWERED) | v [Management Socket] | v Linux Kernel Bluetooth Subsystem | v MGMT_EV_NEW_SETTINGS | v settings_changed() | v trigger_passive_scanning() -> MGMT_OP_START_DISCOVERY | v 适配器进入扫描状态三、阶段三:扫描广播 - 设备发现
3.1 主动发现启动
当调用StartDiscovery()DBus 方法时,触发主动扫描:
static DBusMessage *start_discovery(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_adapter *adapter = data; ... // 创建发现客户端 client = discovery_client_new(msg, discovery_client_destroy); if (!client) return btd_error_failed(msg, "Unable to allocate memory"); // 添加到发现列表 adapter->discovery_list = g_slist_append(adapter->discovery_list, client); // 延迟启动发现(避免频繁开关) trigger_start_discovery(adapter, adapter->no_scan_restart_delay ? 0 : SCAN_RESTART_DELAY); return NULL; }3.2 Management 发现命令
trigger_start_discovery()发送MGMT_OP_START_DISCOVERY命令:
static void trigger_start_discovery(struct btd_adapter *adapter, guint delay) { struct mgmt_cp_start_discovery cp; cp.type = SCAN_TYPE_DUAL; // 同时扫描 BR/EDR 和 LE mgmt_send(adapter->mgmt, MGMT_OP_START_DISCOVERY, adapter->dev_id, sizeof(cp), &cp, start_discovery_complete, adapter, NULL); }3.3 设备发现事件处理
内核发现设备后,通过MGMT_EV_DEVICE_FOUND事件上报:
static void device_found_callback(uint16_t index, uint16_t length, const void *param, void *user_data) { const struct mgmt_ev_device_found *ev = param; struct btd_adapter *adapter = user_data; // 更新发现设备信息 btd_adapter_update_found_device(adapter, &ev->addr.bdaddr, ev->addr.type, ev->rssi, ev->flags & MGMT_DEV_FOUND_CONFIRM_NAME, ev->flags & MGMT_DEV_FOUND_LEGACY_PAIRING, ev->flags & MGMT_DEV_FOUND_NOT_CONNECTABLE, ev->flags & MGMT_DEV_FOUND_NAME_REQUEST_FAILED, ev->data, ev->data_len, false); }3.4 设备对象创建
btd_adapter_update_found_device()创建或更新设备对象:
void btd_adapter_update_found_device(struct btd_adapter *adapter, const bdaddr_t *bdaddr, uint8_t bdaddr_type, ...) { struct btd_device *device; // 查找现有设备或创建新设备 device = btd_adapter_get_device(adapter, bdaddr, bdaddr_type); if (!device) { device = adapter_create_device(adapter, bdaddr, bdaddr_type); if (!device) return; } // 更新设备信息(RSSI、名称、广播数据等) device_update_info(device, data, data_len, rssi, ...); // 发射设备属性变化信号 g_dbus_emit_property_changed(dbus_conn, device->path, DEVICE_INTERFACE, "RSSI"); }扫描阶段状态机:
状态 | 条件 | 转换 |
IDLE | 调用 StartDiscovery | -> DISCOVERING |
DISCOVERING | 收到 MGMT_EV_DEVICE_FOUND | 更新设备列表 |
DISCOVERING | 调用 StopDiscovery | -> IDLE |
IDLE | 适配器上电(无内核连接控制) | -> PASSIVE_SCANNING |
四、阶段四:设备配对 - Bonding
4.1 Pair 方法调用
当调用设备的Pair()方法时,进入配对流程:
static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_device *device = data; struct btd_adapter *adapter = device->adapter; struct bonding_req *bonding; uint8_t io_cap; int err; // 检查是否已有绑定进行中 if (device->bonding) return btd_error_in_progress(msg); // 获取 Agent 的 IO 能力 agent = agent_get(sender); io_cap = agent ? agent_get_io_capability(agent) : IO_CAPABILITY_NOINPUTNOOUTPUT; // 创建绑定请求 bonding = bonding_request_new(msg, device, bdaddr_type, agent); device->bonding = bonding; // LE 设备需要先连接 ATT 通道 if (bdaddr_type != BDADDR_BREDR) { if (!state->connected && btd_le_connect_before_pairing()) err = device_connect_le(device); else err = adapter_create_bonding(adapter, &device->bdaddr, device->bdaddr_type, io_cap); } else { err = adapter_create_bonding(adapter, &device->bdaddr, BDADDR_BREDR, io_cap); } ... }4.2 创建绑定
adapter_create_bonding()暂停扫描并发起绑定尝试:
int adapter_create_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr, uint8_t addr_type, uint8_t io_cap) { suspend_discovery(adapter); // 暂停发现以节省资源 return adapter_bonding_attempt(adapter, bdaddr, addr_type, io_cap); }4.3 发送配对命令
adapter_bonding_attempt()通过 Management Socket 发送配对命令:
int adapter_bonding_attempt(struct btd_adapter *adapter, const bdaddr_t *bdaddr, uint8_t addr_type, uint8_t io_cap) { struct mgmt_cp_pair_device cp; memset(&cp, 0, sizeof(cp)); bacpy(&cp.addr.bdaddr, bdaddr); cp.addr.type = addr_type; cp.io_cap = io_cap; // 发送 MGMT_OP_PAIR_DEVICE 命令 mgmt_send(adapter->mgmt, MGMT_OP_PAIR_DEVICE, adapter->dev_id, sizeof(cp), &cp, pair_device_complete, data, NULL); }4.4 SSP 安全协议交互
配对过程中可能触发多种安全请求,BlueZ 通过事件回调处理:
// PIN 码请求 mgmt_register(adapter->mgmt, MGMT_EV_PIN_CODE_REQUEST, adapter->dev_id, pin_code_request_callback, adapter, NULL); // 用户确认请求 mgmt_register(adapter->mgmt, MGMT_EV_USER_CONFIRM_REQUEST, adapter->dev_id, user_confirm_request_callback, adapter, NULL); // 用户 Passkey 请求 mgmt_register(adapter->mgmt, MGMT_EV_USER_PASSKEY_REQUEST, adapter->dev_id, user_passkey_request_callback, adapter, NULL);4.5 绑定完成处理
绑定成功后,内核通过MGMT_EV_NEW_LINK_KEY或MGMT_EV_NEW_LONG_TERM_KEY上报密钥:
static void new_link_key_callback(uint16_t index, uint16_t length, const void *param, void *user_data) { const struct mgmt_ev_new_link_key *ev = param; struct btd_adapter *adapter = user_data; // 存储密钥到文件系统 store_link_key(adapter, &ev->addr.bdaddr, ev->type, ev->link_key, ev->pin_length, ev->flags & MGMT_LINK_KEY_FLAG_LOCAL); // 更新设备绑定状态 device = btd_adapter_find_device(adapter, &ev->addr.bdaddr, BDADDR_BREDR); if (device) btd_device_bonded(device, BDADDR_BREDR); }配对阶段时序图:
五、阶段五:绑定连接 - 建立链路
5.1 Connect 方法调用
当调用设备的Connect()方法时,发起连接:
static DBusMessage *connect_device(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_device *device = data; ... // 检查状态 if (dev->connect) return btd_error_in_progress(msg); // 标记连接中 dev->connect = dbus_message_ref(msg); // 优先尝试 LE 连接 if (dev->le && !dev->le_state.connected) { err = device_connect_le(dev); if (!err) return NULL; } // 回退到 BR/EDR 连接 if (dev->bredr) { err = device_connect_bredr(dev); ... } }5.2 LE 连接建立
device_connect_le()通过 btio 建立 LE 连接:
static int device_connect_le(struct btd_device *device) { GIOChannel *io; GError *gerr = NULL; io = bt_io_connect(device_le_connect_cb, device, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, btd_adapter_get_address(adapter), BT_IO_OPT_SOURCE_TYPE, btd_adapter_get_address_type(adapter), BT_IO_OPT_DEST_BDADDR, device_get_address(device), BT_IO_OPT_DEST_TYPE, device_get_le_address_type(device), BT_IO_OPT_MODE, BT_IO_MODE_LE, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, BT_IO_OPT_INVALID); ... }5.3 连接完成回调
连接完成后触发device_connect_cb():
static void device_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data) { struct device_connect_data *data = user_data; struct btd_adapter *adapter =>int device_discover_services(struct btd_device *device) { int err; if (device->bredr) err = device_browse_sdp(device, NULL); // BR/EDR: SDP 浏览 else err = device_browse_gatt(device, NULL); // LE: GATT 发现 ... }5.5 服务连接
服务发现完成后,自动连接已解析的服务:
static void device_browse_cb(struct btd_device *dev, int err, void *user_data) { if (!err) btd_device_connect_services(dev, NULL); // 连接所有服务 }btd_device_connect_services()遍历服务列表并逐一连接:
int btd_device_connect_services(struct btd_device *dev, GSList *services) { if (services) { for (l = services; l; l = g_slist_next(l)) { struct btd_service *service = l->data; dev->pending = g_slist_append(dev->pending, service); } } else { dev->pending = create_pending_list(dev, NULL); // 创建待连接服务列表 } return connect_next(dev); }static int connect_next(struct btd_device *dev) { struct btd_service *service; while (dev->pending) { service = dev->pending->data; err = btd_service_connect(service); // 连接单个服务 if (!err) return 0; dev->pending = g_slist_delete_link(dev->pending, dev->pending); } return err; }连接阶段关键数据流:
Connect() DBus Call | v connect_device() | v device_connect_le() / device_connect_bredr() | v bt_io_connect() -> L2CAP Socket 连接 | v device_connect_cb() | v device_attach_att() [LE] / device_discover_services() | v device_browse_sdp() / device_browse_gatt() | v btd_device_connect_services() | v connect_next() -> btd_service_connect() | v Profile 级连接完成六、阶段六:数据交互 - Profile 通信
6.1 Profile 连接机制
每个 Profile(如 A2DP、HFP、GATT)都有独立的连接流程:
int btd_service_connect(struct btd_service *service) { struct btd_profile *profile = btd_service_get_profile(service); // 调用 Profile 特定的连接函数 return profile->connect(service); }6.2 GATT 数据交互
GATT 客户端初始化流程:
static bool gatt_client_init(struct bt_gatt_client *client, uint16_t mtu) { struct discovery_op *op; // 1. Exchange MTU(仅 LE) if (bt_att_get_link_type(client->att) == BT_ATT_LE) { client->mtu_req_id = bt_gatt_exchange_mtu(client->att, mtu, exchange_mtu_cb, ...); } // 2. 发现所有主服务 client->discovery_req = bt_gatt_discover_all_primary_services( client->att, NULL, discover_primary_cb, ...); ... }6.3 ATT 层数据传输
ATT 层提供 GATT 数据传输的基础:
// 发送 ATT 请求 uint16_t bt_gatt_read_value(struct bt_att *att, uint16_t handle, bt_att_result_cb cb, void *user_data, GDestroyNotify destroy); // 发送 ATT 命令 uint16_t bt_gatt_write_value(struct bt_att *att, uint16_t handle, const uint8_t *value, size_t length, bt_att_result_cb cb, void *user_data, GDestroyNotify destroy); // 注册通知回调 uint16_t bt_gatt_register_notify(struct bt_att *att, uint16_t handle, bt_att_notify_cb cb, void *user_data, GDestroyNotify destroy);6.4 服务状态机
每个服务都有独立的状态机管理连接生命周期:
enum btd_service_state_t { BTD_SERVICE_STATE_DISCONNECTED, BTD_SERVICE_STATE_CONNECTING, BTD_SERVICE_STATE_CONNECTED, BTD_SERVICE_STATE_DISCONNECTING, }; static void change_state(struct btd_service *service, enum btd_service_state_t new_state) { enum btd_service_state_t old_state = service->state; service->state = new_state; // 通知状态变化 if (service->state_changed) service->state_changed(service, old_state, new_state); // 发射 DBus 属性变化信号 g_dbus_emit_property_changed(dbus_conn, service->path, SERVICE_INTERFACE, "Connected"); }七、关键源码函数索引
阶段 | 文件 | 函数 | 核心职责 |
初始化 |
|
| 守护进程入口,初始化各子系统 |
初始化 |
|
| 创建 Management Socket,注册事件 |
适配器唤醒 |
|
| 处理 Powered 属性设置 |
适配器唤醒 |
|
| 处理内核设置变更事件 |
扫描发现 |
|
| 启动主动发现 |
扫描发现 |
|
| 处理设备发现事件 |
设备配对 |
|
| 处理 Pair DBus 方法 |
设备配对 |
|
| 创建绑定请求 |
设备配对 |
|
| 发送配对命令 |
建立连接 |
|
| 发起设备连接 |
建立连接 |
|
| 连接完成回调 |
服务发现 |
|
| 服务发现入口 |
服务连接 |
|
| 连接已发现服务 |
服务连接 |
|
| 遍历连接服务列表 |
八、常见流程认知误区与纠正
误区一:扫描和连接可以同时进行
纠正:BlueZ 在配对时会调用 suspend_discovery() 暂停扫描,这是因为扫描和配对都需要占用控制器资源,同时进行会导致性能下降。
误区二:连接成功后数据立即可用
纠正:连接成功只是建立了底层 L2CAP/ATT 链路,还需要经过服务发现(SDP/GATT)才能知道对方支持哪些服务,然后才能建立 Profile 级别的数据通道。
误区三:配对和连接是同一过程
纠正:配对(Pairing)是建立安全密钥的过程,连接(Connection)是建立通信链路的过程。配对可以在连接之前或之后进行,已配对设备重新连接时不需要再次配对。
误区四:DBus 信号是实时的
纠正:DBus 信号通过 GLib 主循环分发,在密集计算或阻塞操作期间可能会延迟。开发时应避免在回调中执行耗时操作。
误区五:适配器上电后立即开始扫描
纠正:适配器上电后仅启动被动扫描(trigger_passive_scanning),主动扫描需要显式调用 StartDiscovery()。
九、总结
BlueZ 5.x 的整体工作流程体现了分层解耦的设计思想:
1.Management Interface层:负责用户态与内核态的控制命令交互
2.DBus 层:负责蓝牙守护进程与外部客户端的通信
3.Adapter/Device 层:负责适配器和设备的状态管理
4.Profile 层:负责具体蓝牙应用协议的实现
从开机到数据交互的完整链路中,每个阶段都有明确的职责边界和状态机管理。理解这一流程对于蓝牙应用开发、协议栈定制和问题排查都具有重要意义。