ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

【BlueZ 】整体工作流程:从蓝牙开机到设备连接的全链路梳理

【BlueZ 】整体工作流程:从蓝牙开机到设备连接的全链路梳理 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); }初始化阶段总结步骤函数职责1init_defaults()设置全局默认配置名称、设备类别、超时等2mainloop_init()初始化 GLib 主事件循环3connect_dbus()连接系统 DBus注册服务名org.bluez4adapter_init()创建 Management Socket读取版本信息5btd_device_init()初始化设备管理子系统6btd_agent_init()初始化认证代理子系统7btd_profile_init()初始化 Profile 管理子系统8plugin_init()动态加载各功能插件9mainloop_run()进入事件循环等待事件触发二、阶段二适配器唤醒 - Powered On2.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事件通知 BlueZstatic 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- DISCOVERINGDISCOVERING收到 MGMT_EV_DEVICE_FOUND更新设备列表DISCOVERING调用 StopDiscovery- IDLEIDLE适配器上电无内核连接控制- PASSIVE_SCANNING四、阶段四设备配对 - Bonding4.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); }七、关键源码函数索引阶段文件函数核心职责初始化main.cmain()守护进程入口初始化各子系统初始化adapter.cadapter_init()创建 Management Socket注册事件适配器唤醒adapter.cproperty_set_powered()处理 Powered 属性设置适配器唤醒adapter.csettings_changed()处理内核设置变更事件扫描发现adapter.cstart_discovery()启动主动发现扫描发现adapter.cdevice_found_callback()处理设备发现事件设备配对device.cpair_device()处理 Pair DBus 方法设备配对adapter.cadapter_create_bonding()创建绑定请求设备配对adapter.cadapter_bonding_attempt()发送配对命令建立连接adapter.cdevice_connect()发起设备连接建立连接adapter.cdevice_connect_cb()连接完成回调服务发现device.cdevice_discover_services()服务发现入口服务连接device.cbtd_device_connect_services()连接已发现服务服务连接device.cconnect_next()遍历连接服务列表八、常见流程认知误区与纠正误区一扫描和连接可以同时进行纠正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 层负责具体蓝牙应用协议的实现从开机到数据交互的完整链路中每个阶段都有明确的职责边界和状态机管理。理解这一流程对于蓝牙应用开发、协议栈定制和问题排查都具有重要意义。
返回列表