【android bluetooth 協議分析 01】【HCI 層介紹 30】【hci_event和le_meta_event如何上報到btu層】

一、引言

在藍牙協議棧中,HCI EventLE Meta Event 是控制器(Controller)向主機(Host)報告事件的兩種形式,它們屬于 HCI(Host Controller Interface)層。這是主機和控制器之間通信的標準接口。 那你清楚 這些 事件是怎么一層層上報到 協議棧, 協議棧有是如何去處理的嗎?


1.1 什么是 HCI Event(傳統事件)

1. 定義:

HCI Event 是 Controller 主動發送給 Host 的消息,用于告知狀態、響應命令、通知連接變化等。

2. 格式:


+------------+------------+----------------------+
| Event Code | Length     | Parameters           |
+------------+------------+----------------------+
| 1 byte     | 1 byte     | Variable length      |
+------------+------------+----------------------+
567	2025-01-05 21:10:13.070497	controller	host	HCI_EVT	258	Rcvd Extended Inquiry Result	Beats Flex	Frame 567: 258 bytes on wire (2064 bits), 258 bytes captured (2064 bits)
Bluetooth
Bluetooth HCI H4
Bluetooth HCI Event - Extended Inquiry ResultEvent Code: Extended Inquiry Result (0x2f) // 1 ByteParameter Total Length: 255                // 2 Byte// Parameters 255 ByteNumber of responses: 1                     BD_ADDR: Apple_01:e1:07 (74:8f:3c:01:e1:07)Page Scan Repetition Mode: R1 (0x01)Reserved: 0x00Class of Device: 0x240418 (Audio/Video:Headphones - services: Rendering Audio).101 0001 0101 0001 = Clock Offset: 0x5151RSSI: -45 dBmExtended Inquiry Response Data

3. 常見的 HCI Event 類型:

Event Code (十六進制)名稱描述
0x01Inquiry Complete設備搜索完成
0x03Connection CompleteBR/EDR 連接完成
0x05Disconnection Complete連接斷開
0x0ECommand Complete命令執行完成的反饋
0x0FCommand Status命令狀態反饋(可能還沒執行完成)
0x2CRead Remote Features Complete遠端設備功能讀取完成

特征:

  • 事件類型豐富,適用于 BR/EDR(經典藍牙)

  • 每個事件用唯一的 Event Code 標識

  • LE(低功耗)事件的統一入口是 LE_META_EVENT(詳見下節)


1.2 什么是 LE Meta Event(低功耗藍牙元事件)

1. 定義:

LE Meta Event 是專門用于 低功耗藍牙(BLE) 的 HCI 事件類型。

  • 它的 Event Code 是固定的 0x3E

  • 所有 BLE 相關的事件都會通過它來傳輸

  • 為了區分具體事件類型,使用一個 Subevent Code 字段

2. 格式:


+------------+------------+-----------------------------+
| Event Code | Length     | Parameters                  |
| (0x3E)     |            |                             |
+------------+------------+-----------------------------++------------------------+| Subevent Code (1 byte) || BLE-specific params    |+------------------------+
574	2025-01-05 21:10:14.359021	controller	host	HCI_EVT	46	Rcvd LE Meta (LE Advertising Report)		Frame 574: 46 bytes on wire (368 bits), 46 bytes captured (368 bits)
Bluetooth
Bluetooth HCI H4
Bluetooth HCI Event - LE MetaEvent Code: LE Meta (0x3e)Parameter Total Length: 43Sub Event: LE Advertising Report (0x02)Num Reports: 1Event Type: Non-Connectable Undirected Advertising (0x03)Peer Address Type: Random Device Address (0x01)BD_ADDR: 27:fb:9b:b7:db:4f (27:fb:9b:b7:db:4f)Data Length: 31Advertising DataRSSI: -77 dBm

3. 常見的 Subevent(SubeventCode)類型:

Subevent Code (十六進制)名稱描述
0x01LE Connection CompleteBLE 連接建立完成
0x02LE Advertising Report廣播報告(掃描到的設備信息)
0x03LE Connection Update Complete連接參數更新完成
0x08LE PHY Update CompletePHY(物理層)更新完成(1M ? 2M ? Coded)
0x0ALE Extended Advertising Report擴展廣播報告(用于 BLE 5.0 以上)
0x0ELE CTE Request Failed定向定位失敗

特征:

  • 所有 BLE 事件都通過一個統一的 Event Code = 0x3E 入口上報

  • 通過 SubeventCode 進一步細分事件類型

  • BLE 特有機制(如定向廣播、周期性廣告、LE Audio)事件都在此定義


1.3 總結

項目HCI EventLE Meta Event
Event Code多種(如 0x0E、0x0F、0x05)固定為 0x3E
用途BR/EDR 和通用事件專用于 BLE 事件
區分子事件方式不需要(每種 EventCode 獨立)使用 Subevent Code(第1字節)
示例Command Complete, DisconnectionLE Connection Complete, Adv Report

二、aosp 協議棧該如何上報處理

在 引言部分,介紹了基礎內容,那協議棧中該如何上報處理???

2.1 Stack::StartEverything

我們先來看看 協議棧在初始化時都做了那些事情。

這里我們先回顧一下, 【android bluetooth 框架分析 02】【Module詳解 2】【gd_shim_module 模塊介紹】 中介紹的內容。


// system/main/shim/stack.ccvoid Stack::StartEverything() {...LOG_INFO("%s Starting Gd stack", __func__);ModuleList modules;modules.add<metrics::CounterMetrics>();modules.add<hal::HciHal>();modules.add<hci::HciLayer>();modules.add<storage::StorageModule>();modules.add<shim::Dumpsys>();modules.add<hci::VendorSpecificEventManager>();modules.add<hci::Controller>();modules.add<hci::AclManager>();
...if (!common::init_flags::gd_core_is_enabled()) {bluetooth::shim::hci_on_reset_complete(); // 重點}...}

當協議棧加載完 各個模塊后, 將 調用 bluetooth::shim::hci_on_reset_complete

2.2 shim::hci_on_reset_complete

這是 shim 層中的回調函數,作用是當控制器完成 HCI Reset 命令之后,通知上層完成一些 事件注冊和初始化工作
shim 層是 Google Gabeldorsche(GD)架構遷移中的中間層,承擔舊系統與新 Rust/C++ 架構的橋接。

// system/main/shim/hci_layer.ccvoid bluetooth::shim::hci_on_reset_complete() {/*斷言 send_data_upwards 函數指針不為空,這個函數通常用來將數據向上發送到 stack 上層(ACL/HCI 事件等),必須先初始化。
*/ASSERT(send_data_upwards);// gd 協議棧暫時沒有啟用 rust,跳過if (bluetooth::common::init_flags::gd_rust_is_enabled()) {::rust::hci_on_reset_complete();}/*注冊所有合法 HCI EventCode遍歷 0x00 ~ 0xFF 范圍的所有可能的 HCI EventCode(256種),轉換為 EventCode 枚舉類型。
*/for (uint16_t event_code_raw = 0; event_code_raw < 0x100; event_code_raw++) {auto event_code = static_cast<bluetooth::hci::EventCode>(event_code_raw);// 跳過無效的事件碼(如保留字段),確保只處理合法事件。if (!is_valid_event_code(event_code)) {continue;}// 逐層檢查事件是否已經在某個模塊注冊過(ACL、Controller、HCI、LE 廣播、LE 掃描等),避免重復注冊。if (event_already_registered_in_acl_layer(event_code)) {continue;} else if (event_already_registered_in_controller_layer(event_code)) {continue;} else if (event_already_registered_in_hci_layer(event_code)) {continue;} else if (event_already_registered_in_le_advertising_manager(event_code)) {continue;} else if (event_already_registered_in_le_scanning_manager(event_code)) {continue;}// 根據當前是否啟用 Rust,選擇用 Rust 或 C++ 的方式注冊事件處理回調。if (bluetooth::common::init_flags::gd_rust_is_enabled()) {::rust::register_event(event_code);} else {cpp::register_event(event_code); // 重點分析}}// 注冊所有合法 HCI SubeventCode(子事件)for (uint16_t subevent_code_raw = 0; subevent_code_raw < 0x100;subevent_code_raw++) {auto subevent_code =static_cast<bluetooth::hci::SubeventCode>(subevent_code_raw);// 過濾無效或已注冊的子事件。if (!is_valid_subevent_code(subevent_code)) {continue;}if (subevent_already_registered_in_le_hci_layer(subevent_code)) {continue;}// 根據是否啟用 Rust,注冊子事件的回調處理邏輯。if (bluetooth::common::init_flags::gd_rust_is_enabled()) {::rust::register_le_event(subevent_code);} else {cpp::register_le_event(subevent_code); // 重點分析}}// 處理 Vendor Specific Event(廠商事件)if (!bluetooth::common::init_flags::gd_rust_is_enabled()) {// 獲取 shim 層的調度 Handler(基于 thread/message loop 的事件處理)。auto handler = bluetooth::shim::GetGdShimHandler();// 注冊對 BQR_EVENT(藍牙質量報告)的處理回調,綁定到 shim 的線程中。該事件用于監聽藍牙底層通信質量指標。bluetooth::shim::GetVendorSpecificEventManager()->RegisterEventHandler(bluetooth::hci::VseSubeventCode::BQR_EVENT,handler->Bind(cpp::vendor_specific_event_callback));}// 注冊 SCO 音頻事件(同步連接)if (bluetooth::common::init_flags::gd_rust_is_enabled()) {::rust::register_for_sco();} else {// 注冊 SCO(同步連接,例如語音通話)相關的事件,按 Rust/C++ 路徑分別處理。cpp::register_for_sco();}// 注冊 ISO 數據通道(用于 BLE Audio)if (bluetooth::common::init_flags::gd_rust_is_enabled()) {::rust::register_for_iso();} else {// 注冊 ISO(Isochronous)通道,BLE Audio 中的核心傳輸通道,用于低延遲、高同步音頻傳輸(如 LE Audio)。cpp::register_for_iso();}
}
步驟功能條件
1確認數據上傳接口初始化必須有 send_data_upwards
2調用 Rust 初始化流程(如果啟用)gd_rust_is_enabled()
3遍歷注冊合法 HCI Event如果未在其他層注冊
4遍歷注冊合法 HCI SubeventLE Meta Events 子事件
5注冊 BQR 廠商事件僅限 C++ shim 模式
6注冊 SCO 音頻事件Rust/C++ 路徑
7注冊 ISO BLE 音頻事件Rust/C++ 路徑

設計意義與架構背景

  • shim 層的職責:適配老 C++ 代碼與新 Rust 模塊,實現平滑過渡。

  • Rust/C++ 雙路徑兼容性:Google 正逐步將 bluedroid 的 HCI 層遷移到 Rust(如 Gabeldorsche 項目),但仍保留 fallback 到 C++ 的能力。

  • 事件注冊的模塊化:避免重復注冊事件,精細劃分 ACL/HCI/LE 層職責。

1. 有效的 HCI Event 表

bool is_valid_event_code(bluetooth::hci::EventCode event_code) {switch (event_code) {case bluetooth::hci::EventCode::INQUIRY_COMPLETE:case bluetooth::hci::EventCode::INQUIRY_RESULT:case bluetooth::hci::EventCode::CONNECTION_COMPLETE:case bluetooth::hci::EventCode::CONNECTION_REQUEST:case bluetooth::hci::EventCode::DISCONNECTION_COMPLETE:case bluetooth::hci::EventCode::AUTHENTICATION_COMPLETE:case bluetooth::hci::EventCode::REMOTE_NAME_REQUEST_COMPLETE:case bluetooth::hci::EventCode::ENCRYPTION_CHANGE:case bluetooth::hci::EventCode::CHANGE_CONNECTION_LINK_KEY_COMPLETE:case bluetooth::hci::EventCode::CENTRAL_LINK_KEY_COMPLETE:case bluetooth::hci::EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE:case bluetooth::hci::EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE:case bluetooth::hci::EventCode::QOS_SETUP_COMPLETE:case bluetooth::hci::EventCode::COMMAND_COMPLETE:case bluetooth::hci::EventCode::COMMAND_STATUS:case bluetooth::hci::EventCode::HARDWARE_ERROR:case bluetooth::hci::EventCode::FLUSH_OCCURRED:case bluetooth::hci::EventCode::ROLE_CHANGE:case bluetooth::hci::EventCode::NUMBER_OF_COMPLETED_PACKETS:case bluetooth::hci::EventCode::MODE_CHANGE:case bluetooth::hci::EventCode::RETURN_LINK_KEYS:case bluetooth::hci::EventCode::PIN_CODE_REQUEST:case bluetooth::hci::EventCode::LINK_KEY_REQUEST:case bluetooth::hci::EventCode::LINK_KEY_NOTIFICATION:case bluetooth::hci::EventCode::LOOPBACK_COMMAND:case bluetooth::hci::EventCode::DATA_BUFFER_OVERFLOW:case bluetooth::hci::EventCode::MAX_SLOTS_CHANGE:case bluetooth::hci::EventCode::READ_CLOCK_OFFSET_COMPLETE:case bluetooth::hci::EventCode::CONNECTION_PACKET_TYPE_CHANGED:case bluetooth::hci::EventCode::QOS_VIOLATION:case bluetooth::hci::EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE:case bluetooth::hci::EventCode::FLOW_SPECIFICATION_COMPLETE:case bluetooth::hci::EventCode::INQUIRY_RESULT_WITH_RSSI:case bluetooth::hci::EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE:case bluetooth::hci::EventCode::SYNCHRONOUS_CONNECTION_COMPLETE:case bluetooth::hci::EventCode::SYNCHRONOUS_CONNECTION_CHANGED:case bluetooth::hci::EventCode::SNIFF_SUBRATING:case bluetooth::hci::EventCode::EXTENDED_INQUIRY_RESULT:case bluetooth::hci::EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE:case bluetooth::hci::EventCode::IO_CAPABILITY_REQUEST:case bluetooth::hci::EventCode::IO_CAPABILITY_RESPONSE:case bluetooth::hci::EventCode::USER_CONFIRMATION_REQUEST:case bluetooth::hci::EventCode::USER_PASSKEY_REQUEST:case bluetooth::hci::EventCode::REMOTE_OOB_DATA_REQUEST:case bluetooth::hci::EventCode::SIMPLE_PAIRING_COMPLETE:case bluetooth::hci::EventCode::LINK_SUPERVISION_TIMEOUT_CHANGED:case bluetooth::hci::EventCode::ENHANCED_FLUSH_COMPLETE:case bluetooth::hci::EventCode::USER_PASSKEY_NOTIFICATION:case bluetooth::hci::EventCode::KEYPRESS_NOTIFICATION:case bluetooth::hci::EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION:case bluetooth::hci::EventCode::NUMBER_OF_COMPLETED_DATA_BLOCKS:return true;case bluetooth::hci::EventCode::VENDOR_SPECIFIC:case bluetooth::hci::EventCode::LE_META_EVENT:  // Private to hcireturn false;}return false;
};
  • 此函數用于在 HCI Reset 完成后,對 所有合法事件碼 進行注冊。

  • 表中 true 的事件都是標準 BR/EDR/LE HCI Event,被上層邏輯接收處理。

  • false 的事件表示當前不處理或已由其他路徑(如 LE Subevent 或 Vendor Handler)處理。

#Event Code EnumEvent Code (Hex)含義(來源于 Bluetooth Core)
1INQUIRY_COMPLETE0x01設備發現過程完成
2INQUIRY_RESULT0x02返回發現到的設備信息(不帶 RSSI)
3CONNECTION_COMPLETE0x03與遠端設備的連接結果(成功或失敗)
4CONNECTION_REQUEST0x04收到遠端設備請求連接
5DISCONNECTION_COMPLETE0x05與設備的連接斷開
6AUTHENTICATION_COMPLETE0x06鏈路級認證完成
7REMOTE_NAME_REQUEST_COMPLETE0x07遠程設備名稱請求響應
8ENCRYPTION_CHANGE0x08加密狀態改變(啟用/禁用)
9CHANGE_CONNECTION_LINK_KEY_COMPLETE0x09鏈路密鑰更換完成
10CENTRAL_LINK_KEY_COMPLETE0x0A中央設備鏈路密鑰完成(少見)
11READ_REMOTE_SUPPORTED_FEATURES_COMPLETE0x0B返回對方支持的 BR/EDR 功能
12READ_REMOTE_VERSION_INFORMATION_COMPLETE0x0C遠端控制器版本信息
13QOS_SETUP_COMPLETE0x0DQoS 服務質量設置結果
14COMMAND_COMPLETE0x0EHCI 命令執行完成并返回
15COMMAND_STATUS0x0FHCI 命令正在處理中(異步通知)
16HARDWARE_ERROR0x10控制器報告硬件故障
17FLUSH_OCCURRED0x11已請求的 flush 操作完成(清除緩存數據)
18ROLE_CHANGE0x12BR/EDR 主從角色發生變化
19NUMBER_OF_COMPLETED_PACKETS0x13指定連接下已完成的數據包數量
20MODE_CHANGE0x14節能模式改變(如 Sniff、Hold)
21RETURN_LINK_KEYS0x15返回多個已配對設備的鏈路密鑰
22PIN_CODE_REQUEST0x16請求用戶輸入 PIN 碼(舊版配對)
23LINK_KEY_REQUEST0x17請求鏈路密鑰(設備重連)
24LINK_KEY_NOTIFICATION0x18新鏈路密鑰生成通知
25LOOPBACK_COMMAND0x19測試環回命令回應
26DATA_BUFFER_OVERFLOW0x1A控制器內部緩沖區溢出
27MAX_SLOTS_CHANGE0x1B最大可用時隙數改變(影響吞吐)
28READ_CLOCK_OFFSET_COMPLETE0x1C時鐘偏移讀取完成
29CONNECTION_PACKET_TYPE_CHANGED0x1D連接使用的數據包類型發生變化
30QOS_VIOLATION0x1E發生 QoS 違規情況
31PAGE_SCAN_REPETITION_MODE_CHANGE0x20遠程設備的 Page Scan 模式變化通知
32FLOW_SPECIFICATION_COMPLETE0x21新版流規范設置結果(替代 QoS)
33INQUIRY_RESULT_WITH_RSSI0x22設備發現結果(包含 RSSI)
34READ_REMOTE_EXTENDED_FEATURES_COMPLETE0x23返回遠端設備的擴展特性(超出基本 feature set)
35SYNCHRONOUS_CONNECTION_COMPLETE0x2CSCO/eSCO 音頻連接建立完成
36SYNCHRONOUS_CONNECTION_CHANGED0x2DSCO/eSCO 音頻連接參數變化
37SNIFF_SUBRATING0x2ESniff 子速率通知(省電優化)
38EXTENDED_INQUIRY_RESULT0x2F擴展設備發現結果(支持 EIR)
39ENCRYPTION_KEY_REFRESH_COMPLETE0x30加密密鑰刷新完成(藍牙安全增強)
40IO_CAPABILITY_REQUEST0x31請求 IO 能力(SSP 配對)
41IO_CAPABILITY_RESPONSE0x32IO 能力響應
42USER_CONFIRMATION_REQUEST0x33用戶確認配對請求(SSP Numeric Comparison)
43USER_PASSKEY_REQUEST0x34用戶輸入配對碼請求
44REMOTE_OOB_DATA_REQUEST0x35請求 Out Of Band 數據(如 NFC)
45SIMPLE_PAIRING_COMPLETE0x36安全簡單配對完成
46LINK_SUPERVISION_TIMEOUT_CHANGED0x38超時設置變更通知
47ENHANCED_FLUSH_COMPLETE0x39增強型 flush 操作完成
48USER_PASSKEY_NOTIFICATION0x3B顯示配對碼給用戶
49KEYPRESS_NOTIFICATION0x3C輸入狀態通知(用戶正在輸入)
50REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION0x3D遠程主機支持特性通知
51NUMBER_OF_COMPLETED_DATA_BLOCKS0x48LE ACL 包完成統計(LE ISO 傳輸時可能用)

2. 有效的 HCI LE Subevent 表格

這些 subevent 都是屬于 LE_META_EVENT(主事件碼 0x3E)的子事件,用于處理 Bluetooth LE 的各種異步事件。

bool is_valid_subevent_code(bluetooth::hci::SubeventCode subevent_code) {switch (subevent_code) {case bluetooth::hci::SubeventCode::CONNECTION_COMPLETE:case bluetooth::hci::SubeventCode::CONNECTION_UPDATE_COMPLETE:case bluetooth::hci::SubeventCode::DATA_LENGTH_CHANGE:case bluetooth::hci::SubeventCode::ENHANCED_CONNECTION_COMPLETE:case bluetooth::hci::SubeventCode::PHY_UPDATE_COMPLETE:case bluetooth::hci::SubeventCode::READ_REMOTE_FEATURES_COMPLETE:case bluetooth::hci::SubeventCode::REMOTE_CONNECTION_PARAMETER_REQUEST:case bluetooth::hci::SubeventCode::READ_LOCAL_P256_PUBLIC_KEY_COMPLETE:case bluetooth::hci::SubeventCode::GENERATE_DHKEY_COMPLETE:case bluetooth::hci::SubeventCode::DIRECTED_ADVERTISING_REPORT:case bluetooth::hci::SubeventCode::EXTENDED_ADVERTISING_REPORT:case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_ESTABLISHED:case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_REPORT:case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST:case bluetooth::hci::SubeventCode::SCAN_TIMEOUT:case bluetooth::hci::SubeventCode::ADVERTISING_SET_TERMINATED:case bluetooth::hci::SubeventCode::SCAN_REQUEST_RECEIVED:case bluetooth::hci::SubeventCode::CHANNEL_SELECTION_ALGORITHM:case bluetooth::hci::SubeventCode::CONNECTIONLESS_IQ_REPORT:case bluetooth::hci::SubeventCode::CONNECTION_IQ_REPORT:case bluetooth::hci::SubeventCode::CTE_REQUEST_FAILED:case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED:case bluetooth::hci::SubeventCode::CIS_ESTABLISHED:case bluetooth::hci::SubeventCode::CIS_REQUEST:case bluetooth::hci::SubeventCode::CREATE_BIG_COMPLETE:case bluetooth::hci::SubeventCode::TERMINATE_BIG_COMPLETE:case bluetooth::hci::SubeventCode::BIG_SYNC_ESTABLISHED:case bluetooth::hci::SubeventCode::BIG_SYNC_LOST:case bluetooth::hci::SubeventCode::REQUEST_PEER_SCA_COMPLETE:case bluetooth::hci::SubeventCode::PATH_LOSS_THRESHOLD:case bluetooth::hci::SubeventCode::TRANSMIT_POWER_REPORTING:case bluetooth::hci::SubeventCode::BIG_INFO_ADVERTISING_REPORT:case bluetooth::hci::SubeventCode::ADVERTISING_REPORT:case bluetooth::hci::SubeventCode::LONG_TERM_KEY_REQUEST:return true;default:return false;}
}
#Subevent Code EnumSubevent Code (Hex)含義(根據 Bluetooth Core)
1CONNECTION_COMPLETE0x01LE 連接建立完成
2CONNECTION_UPDATE_COMPLETE0x03連接參數更新完成(間隔、超時等)
3DATA_LENGTH_CHANGE0x07數據包長度/時間改變(更長更高效)
4ENHANCED_CONNECTION_COMPLETE0x0A建立帶地址類型的 LE 連接(支持隱私)
5PHY_UPDATE_COMPLETE0x0CPHY 更新完成(1M/2M/Coded PHY)
6READ_REMOTE_FEATURES_COMPLETE0x0B遠程設備支持的 LE 特性
7REMOTE_CONNECTION_PARAMETER_REQUEST0x06對方請求修改連接參數
8READ_LOCAL_P256_PUBLIC_KEY_COMPLETE0x08本地 P-256 公鑰生成完成(LE Secure Connections)
9GENERATE_DHKEY_COMPLETE0x09Diffie-Hellman 密鑰生成完成(LE Secure Connections)
10DIRECTED_ADVERTISING_REPORT0x0B接收到 directed 廣播(定向廣告)
11EXTENDED_ADVERTISING_REPORT0x0D擴展廣播數據報告(支持更多字段)
12PERIODIC_ADVERTISING_SYNC_ESTABLISHED0x0E成功同步周期性廣播
13PERIODIC_ADVERTISING_REPORT0x0F周期性廣播數據報告
14PERIODIC_ADVERTISING_SYNC_LOST0x10周期性廣播同步丟失
15SCAN_TIMEOUT0x11掃描操作超時,無設備發現
16ADVERTISING_SET_TERMINATED0x12廣播集終止
17SCAN_REQUEST_RECEIVED0x13收到 SCAN_REQ 請求(用于掃描響應)
18CHANNEL_SELECTION_ALGORITHM0x14通道選擇算法設置通知
19CONNECTIONLESS_IQ_REPORT0x15AoA/AoD 連接無關 IQ 報告(方向查找)
20CONNECTION_IQ_REPORT0x16AoA/AoD 連接相關 IQ 報告
21CTE_REQUEST_FAILED0x17方向查找中的 CTE 請求失敗
22PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED0x18從其他設備接收到同步周期性廣播
23CIS_ESTABLISHED0x19ISO 數據通道 (CIS) 建立完成(LE Audio)
24CIS_REQUEST0x1A請求建立 ISO 數據流(CIS)
25CREATE_BIG_COMPLETE0x1B創建 BIG(Broadcast ISO Group)完成
26TERMINATE_BIG_COMPLETE0x1CBIG 廣播終止
27BIG_SYNC_ESTABLISHED0x1DBIG 同步建立成功
28BIG_SYNC_LOST0x1EBIG 同步丟失
29REQUEST_PEER_SCA_COMPLETE0x1F請求遠程設備的時鐘準確度
30PATH_LOSS_THRESHOLD0x20接收信號路徑損耗超出閾值通知
31TRANSMIT_POWER_REPORTING0x21發射功率狀態報告(事件通知)
32BIG_INFO_ADVERTISING_REPORT0x22BIG 廣播信息報告
33ADVERTISING_REPORT0x02普通廣播數據報告(Legacy 廣播)
34LONG_TERM_KEY_REQUEST0x05加密過程中的 LTK 請求(低功耗配對)
  • 這些 subevent 都是 LE META Event (0x3E) 的子事件碼,用于表示各種低功耗藍牙控制器事件。

  • 本函數用于確認哪些 Subevent 是“合法且應處理”的事件。

  • 它涵蓋了從基本連接到廣播、方向查找(AoA/AoD)、LE Audio(如 BIG、CIS)等 Bluetooth 5.x/5.2 的特性。

  • 若傳入其他未被明確定義的子事件(比如未來新增的或廠商自定義的),將返回 false

3. register_event

函數名為 register_event,作用是向 HCI 層注冊一個事件處理器。
它的參數是 event_code,類型是 bluetooth::hci::EventCode,表示一個具體的 HCI 事件代碼。

// system/main/shim/hci_layer.ccstatic void register_event(bluetooth::hci::EventCode event_code) {auto handler = bluetooth::shim::GetGdShimHandler();bluetooth::shim::GetHciLayer()->RegisterEventHandler(event_code, handler->Bind(event_callback));
}

調用 GetGdShimHandler() 函數,獲取一個 Handler 對象的指針或引用,并賦值給變量 handler

  • bluetooth::shim 是一個 shim 層(適配層),用于在 legacy Bluedroid 和 Gabeldorsche(GD)新架構之間橋接。
  • Handler 是一個任務調度器,用于在線程中異步處理回調(類似線程消息循環的 handler)。

? handler 將用于綁定一個事件回調函數,以便將事件委托給正確線程中的處理邏輯。

  • 調用 GetHciLayer() 得到 HCI 層的接口對象。

  • 調用 RegisterEventHandler() 方法,將特定的 event_code 注冊一個處理函數。

  • handler->Bind(event_callback) 表示將函數 event_callback 綁定到 handler 上,形成一個可調度的回調任務,這樣當事件到來時,HCI 層會通過 handler 異步地調用這個回調函數。

1. HciLayer::RegisterEventHandler
// system/gd/hci/hci_layer.ccvoid HciLayer::RegisterEventHandler(EventCode event, ContextualCallback<void(EventView)> handler) {CallOn(impl_, &impl::register_event, event, handler);
}void register_event(EventCode event, ContextualCallback<void(EventView)> handler) {ASSERT_LOG(event != EventCode::LE_META_EVENT,"Can not register handler for %02hhx (%s)",EventCode::LE_META_EVENT,EventCodeText(EventCode::LE_META_EVENT).c_str());ASSERT_LOG(event_handlers_.count(event) == 0, "Can not register a second handler for %02hhx (%s)", event,EventCodeText(event).c_str());event_handlers_[event] = handler; // 將 每個 hci event 事件的 回調函數都注冊進 event_handlers_}

可以參考 下面的文章, 來梳理 當 收到 hci event 時,如何回調到 hci_layer.cc::event_callback 中。
【android bluetooth 框架分析 02】【Module詳解 5】【HciLayer 模塊介紹】

// system/gd/hci/hci_layer.ccvoid on_hci_event(EventView event) {...event_handlers_[event_code].Invoke(event); // 根據 event, 調用不同的 回調
}
2. event_callback

當 有 hci_event 事件上來時,就會 調用到這里。

// system/main/shim/hci_layer.ccstatic void event_callback(bluetooth::hci::EventView event_packet_view) {if (!send_data_upwards) {return;}LOG_INFO("debug_inquiry %s %d", __func__, __LINE__);send_data_upwards.Run(FROM_HERE, WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT /*關注一下這里*/,&event_packet_view));
}
  • 將 hci_event 通過 send_data_upwards 繼續上報。

bte_main_init->set_data_cb 中 將 post_to_main_message_loop 函數賦值給 send_data_upwards, 也就是這里的 send_data_upwards == post_to_main_message_loop


// system/main/shim/hci_layer.ccstatic void set_data_cb(base::Callback<void(const base::Location&, BT_HDR*)> send_data_cb) {send_data_upwards = std::move(send_data_cb);
}static hci_t interface = {.set_data_cb = set_data_cb,.transmit_command = transmit_command,.transmit_command_futured = transmit_command_futured,.transmit_downward = transmit_downward};const hci_t* bluetooth::shim::hci_layer_get_interface() {packet_fragmenter = packet_fragmenter_get_interface();packet_fragmenter->init(&packet_fragmenter_callbacks);return &interface;
}
// system/main/bte_main.ccvoid bte_main_init(void) {hci = bluetooth::shim::hci_layer_get_interface();if (!hci) {LOG_ERROR("%s could not get hci layer interface.", __func__);return;}hci->set_data_cb(base::Bind(&post_to_main_message_loop));
}/******************************************************************************** Function         post_to_hci_message_loop** Description      Post an HCI event to the main thread** Returns          None******************************************************************************/
static void post_to_main_message_loop(const base::Location& from_here,BT_HDR* p_msg) {if (do_in_main_thread(from_here, base::Bind(&btu_hci_msg_process, p_msg)) !=BT_STATUS_SUCCESS) {LOG(ERROR) << __func__ << ": do_in_main_thread failed from "<< from_here.ToString();}
}

這里在 main_thread 中將 hci_event 事件繼續傳遞到 btu 層

3.btu_hci_msg_process

處理所有從 HCI(Host Controller Interface)上來的消息,包括事件、ACL/SCO/ISO數據、命令、L2CAP傳輸完成通知等。
參數 p_msg 是指向 BT_HDR 的指針,表示一個通用的藍牙數據包結構。


void btu_hci_msg_process(BT_HDR* p_msg) {/* 使用掩碼 BT_EVT_MASK(通常是高 8 位,0xFF00)提取消息類型,進入具體的 case 分支處理。 */switch (p_msg->event & BT_EVT_MASK) {case BT_EVT_TO_BTU_HCI_ACL:// 這是 ACL 數據包(異步連接邏輯鏈路,Asynchronous Connection-Less)/* All Acl Data goes to ACL */acl_rcv_acl_data(p_msg); // 通常是傳給 L2CAP 進行協議解包或數據傳遞。break;case BT_EVT_TO_BTU_L2C_SEG_XMIT:/* L2CAP segment transmit complete */// L2CAP 數據段發送完成通知。// 通知 L2CAP 層,之前分段的 ACL 包已發送完成,可能用于繼續發送剩余段acl_link_segments_xmitted(p_msg);break;case BT_EVT_TO_BTU_HCI_SCO:// 這是 SCO 音頻數據包, 將音頻數據轉發到相應音頻處理路徑。btm_route_sco_data(p_msg);break;case BT_EVT_TO_BTU_HCI_EVT/*關注一下這里*/:/*這是一個 HCI Event(事件包),例如設備連接完成、命令執行完成等。p_msg->event & BT_SUB_EVT_MASK 提取事件的低字節(通常為具體事件碼);調用 btu_hcif_process_event() 進行分發處理;最后釋放 p_msg 內存(事件包只讀,無需傳遞)。*/btu_hcif_process_event((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg); // 這是主事件處理入口,是大部分 HCI 事件(如連接成功、命令完成等)傳入處理的通道。osi_free(p_msg);break;case BT_EVT_TO_BTU_HCI_CMD:// 這是一個待發送的 HCI 命令。btu_hcif_send_cmd((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg); // 通常執行對控制器的指令(如:發起連接、設置參數等)。break;case BT_EVT_TO_BTU_HCI_ISO:IsoManager::GetInstance()->HandleIsoData(p_msg); //ISO(Isochronous)數據包,用于 LE Audio, 交由 IsoManager 管理器處理 ISO 數據,然后釋放數據包。osi_free(p_msg);break;default:osi_free(p_msg);break;}
}

這里關注一下, MSG_HC_TO_STACK_HCI_EVTBT_EVT_TO_BTU_HCI_EVT 之間的映射關系。

// system/hci/include/hci_layer.h/* Message event ID passed from Host/Controller lib to stack */
#define MSG_HC_TO_STACK_HCI_ACL 0x1100      /* eq. BT_EVT_TO_BTU_HCI_ACL */
#define MSG_HC_TO_STACK_HCI_SCO 0x1200      /* eq. BT_EVT_TO_BTU_HCI_SCO */
#define MSG_HC_TO_STACK_HCI_ERR 0x1300      /* eq. BT_EVT_TO_BTU_HCIT_ERR */
#define MSG_HC_TO_STACK_HCI_ISO 0x1700      /* eq. BT_EVT_TO_BTU_HCI_ISO */
#define MSG_HC_TO_STACK_HCI_EVT 0x1000      /* eq. BT_EVT_TO_BTU_HCI_EVT *//* Message event ID passed from stack to vendor lib */
#define MSG_STACK_TO_HC_HCI_ACL 0x2100 /* eq. BT_EVT_TO_LM_HCI_ACL */
#define MSG_STACK_TO_HC_HCI_SCO 0x2200 /* eq. BT_EVT_TO_LM_HCI_SCO */
#define MSG_STACK_TO_HC_HCI_ISO 0x2d00 /* eq. BT_EVT_TO_LM_HCI_ISO */
#define MSG_STACK_TO_HC_HCI_CMD 0x2000 /* eq. BT_EVT_TO_LM_HCI_CMD */
// system/stack/include/bt_types.h/* HCI Event                        */
#define BT_EVT_TO_BTU_HCI_EVT 0x1000
/* ACL Data from HCI                */
#define BT_EVT_TO_BTU_HCI_ACL 0x1100
/* SCO Data from HCI                */
#define BT_EVT_TO_BTU_HCI_SCO 0x1200
/* HCI Transport Error              */
#define BT_EVT_TO_BTU_HCIT_ERR 0x1300/* Serial Port Data                 */
#define BT_EVT_TO_BTU_SP_DATA 0x1500/* HCI command from upper layer     */
#define BT_EVT_TO_BTU_HCI_CMD 0x1600/* ISO Data from HCI                */
#define BT_EVT_TO_BTU_HCI_ISO 0x1700/* L2CAP segment(s) transmitted     */
#define BT_EVT_TO_BTU_L2C_SEG_XMIT 0x1900/* To LM                            */
/************************************/
/* HCI Command                      */
#define BT_EVT_TO_LM_HCI_CMD 0x2000
/* HCI ACL Data                     */
#define BT_EVT_TO_LM_HCI_ACL 0x2100
/* HCI SCO Data                     */
#define BT_EVT_TO_LM_HCI_SCO 0x2200
/* HCI ISO Data                     */
#define BT_EVT_TO_LM_HCI_ISO 0x2d00#define BT_EVT_HCISU 0x5000

4. register_le_event


// system/main/shim/hci_layer.ccstatic void register_le_event(bluetooth::hci::SubeventCode subevent_code) {auto handler = bluetooth::shim::GetGdShimHandler();bluetooth::shim::GetHciLayer()->RegisterLeEventHandler(subevent_code, handler->Bind(subevent_callback));
}
// system/gd/hci/hci_layer.ccvoid HciLayer::RegisterLeEventHandler(SubeventCode event, ContextualCallback<void(LeMetaEventView)> handler) {CallOn(impl_, &impl::register_le_event, event, handler);
}void register_le_event(SubeventCode event, ContextualCallback<void(LeMetaEventView)> handler) {ASSERT_LOG(subevent_handlers_.count(event) == 0, "Can not register a second handler for %02hhx (%s)", event,SubeventCodeText(event).c_str());subevent_handlers_[event] = handler; // 注冊進 subevent_handlers_}
1. subevent_callback
// system/gd/hci/hci_layer.cc// 當有 le_mate event 上報時,就會 回調void on_le_meta_event(EventView event) {LeMetaEventView meta_event_view = LeMetaEventView::Create(event);ASSERT(meta_event_view.IsValid());SubeventCode subevent_code = meta_event_view.GetSubeventCode();if (subevent_handlers_.find(subevent_code) == subevent_handlers_.end()) {LOG_WARN("Unhandled le subevent of type 0x%02hhx (%s)", subevent_code, SubeventCodeText(subevent_code).c_str());return;}subevent_handlers_[subevent_code].Invoke(meta_event_view);}

最終調用到 hci_layer.cc::subevent_callback


// system/main/shim/hci_layer.cc
static void subevent_callback(bluetooth::hci::LeMetaEventView le_meta_event_view) {if (!send_data_upwards) {return;}LOG_INFO("debug_inquiry %s %d", __func__, __LINE__);send_data_upwards.Run(FROM_HERE, WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT,&le_meta_event_view));
}

subevent_callbackevent_callback 向上回調的邏輯都是一樣的,都是通過 send_data_upwards 并且 都是 MSG_HC_TO_STACK_HCI_EVT,
所以最終也會 回調到 btu_hci_msg_process 中。

subevent_callbackevent_callback 區別就是向上回調傳遞的參數類型是不一樣的。

三、btu 層處理

hci_event 和 le_meta_event 最終都會調用到 btu_hci_msg_processBT_EVT_TO_BTU_HCI_EVT case 中。


void btu_hci_msg_process(BT_HDR* p_msg) {/* 使用掩碼 BT_EVT_MASK(通常是高 8 位,0xFF00)提取消息類型,進入具體的 case 分支處理。 */switch (p_msg->event & BT_EVT_MASK) {...case BT_EVT_TO_BTU_HCI_EVT/*關注一下這里*/:/*這是一個 HCI Event(事件包),例如設備連接完成、命令執行完成等。p_msg->event & BT_SUB_EVT_MASK 提取事件的低字節(通常為具體事件碼);調用 btu_hcif_process_event() 進行分發處理;最后釋放 p_msg 內存(事件包只讀,無需傳遞)。*/btu_hcif_process_event((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg); // 這是主事件處理入口,是大部分 HCI 事件(如連接成功、命令完成等)傳入處理的通道。osi_free(p_msg);break;...}
}

3.1 btu_hcif_process_event

所有的事件 處理 最終都會在 btu_hcif_process_event 中。


// system/stack/btu/btu_hcif.cc/********************************************************************************* Function         btu_hcif_process_event** Description      This function is called when an event is received from*                  the Host Controller.** Returns          void*******************************************************************************/
void btu_hcif_process_event(UNUSED_ATTR uint8_t controller_id,const BT_HDR* p_msg) {uint8_t* p = (uint8_t*)(p_msg + 1) + p_msg->offset;uint8_t hci_evt_code, hci_evt_len;uint8_t ble_sub_code;STREAM_TO_UINT8(hci_evt_code, p);STREAM_TO_UINT8(hci_evt_len, p);// validate event sizeif (hci_evt_len < hci_event_parameters_minimum_length[hci_evt_code]) {HCI_TRACE_WARNING("%s: evt:0x%2X, malformed event of size %hhd", __func__,hci_evt_code, hci_evt_len);return;}btu_hcif_log_event_metrics(hci_evt_code, p);LOG_INFO("debug_inquiry %s %d hci_evt_code=%#x", __func__, __LINE__, hci_evt_code);switch (hci_evt_code) {case HCI_INQUIRY_COMP_EVT:btu_hcif_inquiry_comp_evt(p);break;case HCI_INQUIRY_RESULT_EVT:btm_process_inq_results(p, hci_evt_len, BTM_INQ_RESULT_STANDARD);break;case HCI_INQUIRY_RSSI_RESULT_EVT:btm_process_inq_results(p, hci_evt_len, BTM_INQ_RESULT_WITH_RSSI);break;case HCI_EXTENDED_INQUIRY_RESULT_EVT:btm_process_inq_results(p, hci_evt_len, BTM_INQ_RESULT_EXTENDED);break;case HCI_CONNECTION_REQUEST_EVT:btu_hcif_connection_request_evt(p);break;case HCI_DISCONNECTION_COMP_EVT:btu_hcif_disconnection_comp_evt(p);break;case HCI_AUTHENTICATION_COMP_EVT:btu_hcif_authentication_comp_evt(p);break;case HCI_RMT_NAME_REQUEST_COMP_EVT:btu_hcif_rmt_name_request_comp_evt(p, hci_evt_len);break;case HCI_ENCRYPTION_CHANGE_EVT:btu_hcif_encryption_change_evt(p);break;case HCI_ENCRYPTION_KEY_REFRESH_COMP_EVT:btu_hcif_encryption_key_refresh_cmpl_evt(p);break;case HCI_READ_RMT_EXT_FEATURES_COMP_EVT:btu_hcif_read_rmt_ext_features_comp_evt(p, hci_evt_len);break;case HCI_COMMAND_COMPLETE_EVT:LOG_ERROR("%s should not have received a command complete event. ""Someone didn't go through the hci transmit_command function.",__func__);break;case HCI_COMMAND_STATUS_EVT:LOG_ERROR("%s should not have received a command status event. ""Someone didn't go through the hci transmit_command function.",__func__);break;case HCI_HARDWARE_ERROR_EVT:btu_hcif_hardware_error_evt(p);break;case HCI_MODE_CHANGE_EVT:btu_hcif_mode_change_evt(p);break;case HCI_PIN_CODE_REQUEST_EVT:btm_sec_pin_code_request(p);break;case HCI_LINK_KEY_REQUEST_EVT:btm_sec_link_key_request(p);break;case HCI_LINK_KEY_NOTIFICATION_EVT:btu_hcif_link_key_notification_evt(p);break;case HCI_READ_CLOCK_OFF_COMP_EVT:btu_hcif_read_clock_off_comp_evt(p);break;case HCI_ESCO_CONNECTION_COMP_EVT:btu_hcif_esco_connection_comp_evt(p);break;case HCI_ESCO_CONNECTION_CHANGED_EVT:btu_hcif_esco_connection_chg_evt(p);break;case HCI_SNIFF_SUB_RATE_EVT:btm_pm_proc_ssr_evt(p, hci_evt_len);break;case HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT:btm_sec_rmt_host_support_feat_evt(p);break;case HCI_IO_CAPABILITY_REQUEST_EVT:btu_hcif_io_cap_request_evt(p);break;case HCI_IO_CAPABILITY_RESPONSE_EVT:btm_io_capabilities_rsp(p);break;case HCI_USER_CONFIRMATION_REQUEST_EVT:btm_proc_sp_req_evt(BTM_SP_CFM_REQ_EVT, p);break;case HCI_USER_PASSKEY_REQUEST_EVT:btm_proc_sp_req_evt(BTM_SP_KEY_REQ_EVT, p);break;case HCI_REMOTE_OOB_DATA_REQUEST_EVT:btm_rem_oob_req(p);break;case HCI_SIMPLE_PAIRING_COMPLETE_EVT:btm_simple_pair_complete(p);break;case HCI_USER_PASSKEY_NOTIFY_EVT:btm_proc_sp_req_evt(BTM_SP_KEY_NOTIF_EVT, p);break;case HCI_BLE_EVENT: {STREAM_TO_UINT8(ble_sub_code, p);uint8_t ble_evt_len = hci_evt_len - 1;switch (ble_sub_code) {case HCI_BLE_ADV_PKT_RPT_EVT: /* result of inquiry */btm_ble_process_adv_pkt(ble_evt_len, p);break;case HCI_BLE_LL_CONN_PARAM_UPD_EVT:btu_ble_ll_conn_param_upd_evt(p, ble_evt_len);break;case HCI_BLE_READ_REMOTE_FEAT_CMPL_EVT:btm_ble_read_remote_features_complete(p, ble_evt_len);break;case HCI_BLE_LTK_REQ_EVT: /* received only at peripheral device */btu_ble_proc_ltk_req(p, ble_evt_len);break;case HCI_BLE_RC_PARAM_REQ_EVT:btu_ble_rc_param_req_evt(p, ble_evt_len);break;case HCI_BLE_DATA_LENGTH_CHANGE_EVT:btu_ble_data_length_change_evt(p, hci_evt_len);break;case HCI_BLE_PHY_UPDATE_COMPLETE_EVT:btm_ble_process_phy_update_pkt(ble_evt_len, p);break;case HCI_LE_EXTENDED_ADVERTISING_REPORT_EVT:btm_ble_process_ext_adv_pkt(hci_evt_len, p);break;case HCI_LE_ADVERTISING_SET_TERMINATED_EVT:btm_le_on_advertising_set_terminated(p, hci_evt_len);break;case HCI_BLE_REQ_PEER_SCA_CPL_EVT:btm_acl_process_sca_cmpl_pkt(ble_evt_len, p);break;case HCI_BLE_PERIODIC_ADV_SYNC_EST_EVT:btm_ble_process_periodic_adv_sync_est_evt(ble_evt_len, const_cast<const uint8_t*>(p));break;case HCI_BLE_PERIODIC_ADV_REPORT_EVT:btm_ble_process_periodic_adv_pkt(ble_evt_len,const_cast<const uint8_t*>(p));break;case HCI_BLE_PERIODIC_ADV_SYNC_LOST_EVT:btm_ble_process_periodic_adv_sync_lost_evt(ble_evt_len, p);break;case HCI_BLE_CIS_EST_EVT:case HCI_BLE_CREATE_BIG_CPL_EVT:case HCI_BLE_TERM_BIG_CPL_EVT:case HCI_BLE_CIS_REQ_EVT:case HCI_BLE_BIG_SYNC_EST_EVT:case HCI_BLE_BIG_SYNC_LOST_EVT:IsoManager::GetInstance()->HandleHciEvent(ble_sub_code, p,ble_evt_len);break;case HCI_LE_PERIODIC_ADV_SYNC_TRANSFERE_RECEIVED_EVT:btm_ble_periodic_adv_sync_tx_rcvd(p, hci_evt_len);break;case HCI_LE_BIGINFO_ADVERTISING_REPORT_EVT:btm_ble_biginfo_adv_report_rcvd(p, hci_evt_len);break;// Events are now captured by gd/hci/le_acl_connection_interface.hcase HCI_BLE_CONN_COMPLETE_EVT:  // SubeventCode::CONNECTION_COMPLETEcase HCI_BLE_ENHANCED_CONN_COMPLETE_EVT:  // SubeventCode::ENHANCED_CONNECTION_COMPLETEdefault:LOG_ERROR("Unexpectedly received LE sub_event_code:0x%02x that should not ""be handled here",ble_sub_code);break;}} break;case HCI_VENDOR_SPECIFIC_EVT:btm_vendor_specific_evt(const_cast<const uint8_t*>(p), hci_evt_len);break;// Events now captured by gd::hci_layer modulecase HCI_NUM_COMPL_DATA_PKTS_EVT:  // EventCode::NUMBER_OF_COMPLETED_PACKETScase HCI_CONNECTION_COMP_EVT:  // EventCode::CONNECTION_COMPLETEcase HCI_READ_RMT_FEATURES_COMP_EVT:  // EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETEcase HCI_READ_RMT_VERSION_COMP_EVT:  // EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETEcase HCI_ROLE_CHANGE_EVT:            // EventCode::ROLE_CHANGEdefault:LOG_ERROR("Unexpectedly received event_code:0x%02x that should not be ""handled here",hci_evt_code);break;}
}

這里不再展開講解了, 后面如果有機會介紹 某一個特定事件時, 在展開講述。


📢 寫到這里,已經掏心掏肺了,如果你看到這,說明你真的很有耐心!

如果這篇文章對你有一點點啟發、哪怕只是讓你少踩了一個坑,歡迎點個贊支持一下,讓我知道這些分享是有價值的!

有疑問?有不同看法?或者有更騷的姿勢?評論區歡迎你開麥!

順手轉發給你的同行、朋友、搭檔、實習生、老板,沒準哪天就用上了!

別光看不留言、別光學不點贊——不然你都不好意思從我博客頁面退出啊,真的😉

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/92159.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/92159.shtml
英文地址,請注明出處:http://en.pswp.cn/web/92159.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

小實驗--震動點燈

1.實驗目的 使用中斷的方法&#xff0c;震動傳感器檢測到震動時&#xff0c;LED1點亮2秒&#xff0c;之后熄滅。 2.硬件清單 震動傳感器STM32開發板ST-Link 3.硬件連接STM32震動傳感器PA4DO3V3VCCGNDGND4.代碼 4.1exti.c #include "exti.h" #include "sys.h&quo…

vcpkg: 一款免費開源的C++包管理器

目錄 1.簡介 2.安裝 3.常用命令 4.與項目集成 5.vcpkg的工作原理 5.1.包索引&#xff1a;ports 系統&#xff08;定義庫的 “元信息”&#xff09; 5.2.源碼獲取&#xff1a;從 “地址” 到 “本地緩存” 5.3.編譯構建&#xff1a;按 “triplet” 定制目標 5.4.安裝布…

WinCC通過無線Modbus TCP監控S7-1200/200SMT PLC實例詳解

工業自動化系統中&#xff0c;車間內通常部署多臺PLC設備并需通過中央監控平臺實現集中管控。考慮到工業現場設備間距普遍在數十至數百米范圍&#xff0c;傳統有線以太網雖能保障傳輸速率&#xff0c;但其施工需面臨電纜溝開挖或復雜布線工程&#xff0c;既增加線材采購、人力投…

【AI智能編程】Trae-IDE工具學習

什么是Trae&#xff1f; Trae與 AI 深度集成&#xff0c;提供智能問答、代碼自動補全以及基于 Agent 的 AI 自動編程能力。使用 Trae 開發項目時&#xff0c;你可以與 AI 靈活協作&#xff0c;提升開發效率。提供傳統的 IDE 功能&#xff0c;包括代碼編寫、項目管理、插件管理…

智能駕駛再提速!批量蘇州金龍L4級自動駕駛巴士交付杭州臨平區

近日&#xff0c;由蘇州金龍海格客車研發的“清源”L4級自動駕駛巴士現身杭州市臨平區并投入測試。這是臨平區引進的首批L4級自動駕駛巴士&#xff0c;標志著臨平區智能交通建設邁入新階段。此次投入測試的“清源”小巴采用一級踏步設計&#xff0c;車身延續了海格蔚藍巴士的經…

Spring_事務

在mysql階段的文章中&#xff0c;已經介紹過事務了。本篇文章是對mysql事務的總結和對使用Spring框架來實現事務操作的講解。事務回顧什么是事務事務時一組操作的集合&#xff0c;是一個不可分割的操作。事務會把所有操作作為一個整體&#xff0c;一起向數據庫提交或者撤銷操作…

事務管理介紹

為什么要用事務管理在我們同時操作兩個或更多個數據庫時&#xff0c;可能因為網絡等各方面原因導致中間出現異常。造成像對第一個數據庫的操作成功了&#xff0c;但是對第二個數據庫的操作沒有成功。這樣數據的完整性就被破壞了。事務&#xff1a;是一組操作的集合&#xff0c;…

Android 之 ViewBinding 實現更安全、高效的視圖綁定

??一、配置說明????作用位置??需在模塊級 build.gradle或 build.gradle.kts文件的 android {}塊內添加&#xff1a;android {buildFeatures {viewBinding true // Kotlin DSL 語法} }android {buildFeatures {viewBinding true // Groovy 語法} }??生成規則??為每…

全球首款Java專用AI開發助手實測:一句話生成完整工程代碼——飛算 JavaAI

&#x1f31f; 嗨&#xff0c;我是Lethehong&#xff01;&#x1f31f;&#x1f30d; 立志在堅不欲說&#xff0c;成功在久不在速&#x1f30d;&#x1f680; 歡迎關注&#xff1a;&#x1f44d;點贊??留言收藏&#x1f680;&#x1f340;歡迎使用&#xff1a;小智初學計算機…

Shader開發(七)創建第一個Shader項目

在前面的章節中&#xff0c;我們已經了解了Shader的基本概念和渲染管線的工作原理。現在&#xff0c;是時候動手實踐了&#xff01;本章將帶您一步步創建第一個Shader項目&#xff0c;開啟真正的Shader開發之旅。 為什么選擇openFrameworks&#xff1f; 與其他文章不同&#x…

IAR軟件中測量函數執行時間

通常在調試代碼中需要直到某個函數或者某段代碼的實際執行時間&#xff0c;在IAR中可以直接借助軟件提供的工具來計算代碼執行時間。 第一種方法 進入仿真調試界面&#xff0c;在需要測量的代碼前面打斷點。工具欄中選擇 ST-LINK — Data Log Summary在 Data Log Summary 窗口中…

Java 字節碼文件(.class)的組成詳解

文章目錄基礎信息常量池字段方法屬性字節碼文件內容說明案例文件基本信息類的基本信息常量池字段信息構造方法實例方法主方法源文件信息字節碼文件由五部分組成&#xff0c;分別是基礎信息、常量池、字段、方法、屬性。案例&#xff1a; public class Main implements Interfa…

C++之vector類的代碼及其邏輯詳解 (下)

1. insert()這個就是在指定位置插入一個元素&#xff0c;首先計算要插入的這個位置和開頭之間的距離&#xff0c;接著判斷那個_finish 有沒有碰到_endofstorage 或者_endofstorage 是不是為0&#xff0c;如果滿足條件&#xff0c;那就進行擴容&#xff0c;然后接著重新計算距離…

【自動化測試】Python Selenium 自動化測試元素定位專業教程

1. 引言&#xff1a;元素定位在 Selenium 中的核心地位 元素定位是 Selenium 自動化測試的基礎&#xff0c;所有用戶交互操作&#xff08;如點擊、輸入、選擇&#xff09;都依賴于準確識別頁面元素。Selenium WebDriver 提供了多種定位策略&#xff0c;從簡單的 ID 定位到復雜…

通用代碼自用

多文件上傳public int save(Role role, RequestParam("nfile") MultipartFile nfile, HttpServletRequest request) {System.out.println(nfile.getOriginalFilename());String path request.getSession().getServletContext().getRealPath("/upload");Fi…

生成式AI如何顛覆我們的工作和生活

原問題&#xff1a; ?你覺得生成式AI未來會如何改變普通人的工作和生活&#xff1f;? 做過一個對比國外和國內工業化產品制造的簡單調研&#xff0c;類似一款定制化的臺燈或者語音音響&#xff0c;從零到原型實物&#xff0c; 美國至少需要20萬美刀&#xff0c;國內成本大概…

K8S、Docker安全漏洞靶場

1 介紹 一個脆弱基礎設施自動化構建框架,主要用于快速、自動化搭建從簡單到復雜的脆弱云原生靶機環境。 1.1 項目的緣起 在研究漏洞時,我們經常會發現“環境搭建”這一步驟本身就會占用大量的時間,與之相比,真正測試PoC、ExP的時間可能非常短。由于許多官方鏡像在國內的…

使用Nginx部署前后端分離項目

使用Nginx部署前后端分離項目&#xff1a;用戶中心系統實踐指南 部署前的關鍵準備 在正式部署前&#xff0c;務必確保前后端在生產環境能正常運行&#xff1a; 前端&#xff1a;測試所有API請求路徑和生產環境配置后端&#xff1a;驗證數據庫連接、環境變量和外部服務集成完整流…

當前就業形勢下,軟件測試工程師職業發展與自我提升的必要性

軟件測試行業正處于深刻變革期&#xff0c;2025年的市場已超越400億美元規模&#xff0c;預計2027年將增長7% 。在這個技術驅動、效率至上的時代&#xff0c;測試工程師若想保持競爭力&#xff0c;必須主動擁抱變革&#xff0c;系統性提升技能。通過深入分析行業現狀與人才需求…

java 之 繼承

一、繼承 1.1 、什么是繼承&#xff1f; 繼承就是把所有的類的公共部分&#xff08;相同的成員&#xff09;提取出來&#xff0c;放到一個類中繼承需要使用 extends 關鍵字 public class Animal{ public String name&#xff1b; } public class Dog extends Animal{}Dog 是 An…