在 AOSP 的藍牙協議棧 (Gabeldorsche) 中,hci_packets.pdl
?是一個?協議描述語言文件,用于定義 HCI (Host Controller Interface) 層的數據包結構和通信協議。以下是詳細解析:
1. 文件作用
-
system/gd/hci/hci_packets.pdl
-
協議自動化生成:通過?
.pdl
?文件定義藍牙 HCI 命令/事件/數據包的二進制格式 -
跨語言支持:生成 C++/Java 等語言的協議解析/構建代碼
-
保證一致性:避免手動編寫協議代碼導致的錯誤
關鍵定義示例:
OpCode 枚舉定義
enum OpCode : 16 {RESET = 0x0C03, // 規范定義的原始操作碼
}
-
作用:定義 HCI 命令的操作碼(OpCode)
-
語法:
-
enum
?聲明枚舉類型 -
: 16
?表示用 16 位存儲(藍牙規范要求) -
RESET = 0x0C03
:-
0x0C03
?是藍牙規范定義的 Reset 命令碼 -
高 6 位?
0x03
?是 OGF(Opcode Group Field) -
低 10 位?
0x03
?是 OCF(Opcode Command Field)
-
-
enum OpCodeIndex : 16 {RESET = 57, // 將 RESET 命令映射到索引 57
}
: 16
:索引值用 16 位整數存儲(實際索引通常遠小于此范圍)RESET = 57
:表示?RESET
?命令在內部數組中的位置為 57
核心作用
-
二級映射:將?
OpCode
(如?0x0C03
)轉換為更緊湊的?數組索引(如?57
),優化內存和訪問效率 -
快速查找:通過數字索引快速定位命令處理器(替代哈希表或線性搜索)
-
代碼生成:為自動生成的代碼提供命令編號與索引的映射關系
和 OpCode 的關系:
enum OpCode : 16 {RESET = 0x0C03, // 規范定義的原始操作碼
}packet Reset : Command (op_code = RESET, op_code_index = RESET) {}
-
雙綁定機制:
-
op_code
:協議規范定義的原始值(如?0x0C03
) -
op_code_index
:內部優化的數組索引(如?57
)
-
-
編譯時關聯:代碼生成工具會確保兩者正確匹配
packet Reset : Command (op_code = RESET) {
}
-
作用:聲明 Reset 命令的數據結構
-
語法:
-
packet
?聲明一個協議數據包 -
: Command
?表示這是 HCI 命令類型 -
(op_code = RESET)
?綁定到前面定義的枚舉值 -
空?
{}
?表示此命令無附加參數
-
test Reset {"\x03\x0c\x00",
}
-
二進制解釋:
-
03 0c
:小端格式的?0x0C03
(Reset 命令碼) -
00
:無參數填充
-
packet ResetComplete : CommandComplete (command_op_code = RESET) {status : ErrorCode,
}
-
作用:定義命令完成事件的數據結構
-
語法:
-
: CommandComplete
?表示這是命令完成事件 -
(command_op_code = RESET)
?關聯對應的命令 -
status : ErrorCode
:-
字段名?
status
-
類型?
ErrorCode
(通常是 8 位錯誤碼枚舉)
-
-
test ResetComplete {"\x0e\x04\x01\x03\x0c\x00","\x0e\x04\x01\x03\x0c\x01", // unknown command
}
-
二進制解釋:
-
0e
:事件碼(Command Complete) -
04
:參數總長度 -
01
:允許發送的 HCI 命令數 -
03 0c
:對應的命令碼(小端) -
00/01
:狀態碼(成功/未知命令)
-
關鍵語法規則
語法元素 | 說明 |
---|---|
enum Name : bits | 定義枚舉類型,指定存儲位數 |
packet Name : Type | 定義數據包,繼承特定基類(Command/Event等) |
field : Type | 定義字段,類型可以是基礎類型或自定義枚舉 |
test | 定義二進制測試用例 |
(key=value) | 屬性綁定(如關聯命令與操作碼) |
2. 編譯流程
.pdl
?文件通過?Packet Framework?工具鏈處理,具體步驟:
編譯階段
system/gd/Android.bp
genrule {name: "BluetoothGeneratedPackets_h",tools: ["bluetooth_packetgen",],cmd: "$(location bluetooth_packetgen) --include=packages/modules/Bluetooth/system/gd --out=$(genDir) $(in)",srcs: ["hci/hci_packets.pdl","l2cap/l2cap_packets.pdl","security/smp_packets.pdl",],out: ["hci/hci_packets.h","l2cap/l2cap_packets.h","security/smp_packets.h",],
}
字段 | 說明 |
---|---|
name | 規則名稱:BluetoothGeneratedPackets_h |
tools | 使用的工具:bluetooth_packetgen ?(協議代碼生成器) |
cmd | 實際執行的命令,包含: ? 工具路徑? $(location) ? 輸入參數? --include ? 輸出目錄? --out ? 輸入文件? $(in) |
srcs | 輸入的協議描述文件: ? HCI 層 ( hci_packets.pdl ) ? L2CAP 層 ( l2cap_packets.pdl ) ? 安全層 ( smp_packets.pdl ) |
out | 生成的頭文件輸出路徑 |
-
輸入:
.pdl
?文件定義協議格式(字段、長度、類型等) -
處理:
bluetooth_packetgen
?工具解析描述文件 -
輸出:生成類型安全的 C++ 頭文件
其他模塊通過?generated_headers
?依賴這些生成的頭文件:
cc_library {name: "libbluetooth_gd",defaults: ["libbluetooth_gd_defaults", # 依賴它],apex_available: ["com.android.bluetooth",],min_sdk_version: "31",
}cc_defaults {name: "libbluetooth_gd_defaults",generated_headers: ["BluetoothGeneratedPackets_h", # 這里],
}
3. 生成代碼結構
- out/soong/.intermediates/packages/modules/Bluetooth/system/gd/BluetoothGeneratedPackets_h/gen/hci/hci_packets.h
生成的代碼會包含:
class ResetBuilder : public CommandBuilder
{
public:virtual ~ResetBuilder() = default;static std::unique_ptr<ResetBuilder> Create(){auto builder = std::unique_ptr<ResetBuilder>(new ResetBuilder());return builder;}#if defined(PACKET_FUZZ_TESTING) || defined(PACKET_TESTING) || defined(FUZZ_TARGET)static std::unique_ptr<ResetBuilder> FromView(ResetView view) { return ResetBuilder::Create(); }
#endifprotected:void SerializeHeader(BitInserter &i) const { CommandBuilder::SerializeHeader(i); }void SerializeFooter(BitInserter &i) const { CommandBuilder::SerializeFooter(i); }public:virtual void Serialize(BitInserter &i) const override{SerializeHeader(i);SerializeFooter(i);}protected:size_t BitsOfHeader() const { return 0 + CommandBuilder::BitsOfHeader(); }size_t BitsOfFooter() const { return 0 + CommandBuilder::BitsOfFooter(); }public:virtual size_t size() const override { return (BitsOfHeader() / 8) + (BitsOfFooter() / 8); }protected:explicit ResetBuilder() : CommandBuilder(OpCode::RESET /* op_code_ */) {}
};