在 AOSP 的蓝牙协议栈 (Gabeldorsche) 中,hci_packets.pdl
是一个 协议描述语言文件,用于定义 HCI (Host Controller Interface) 层的数据包结构和通信协议。以下是详细解析:
1. 文件作用
-
system/gd/hci/hci_packets.pdl
-
协议自动化生成 :通过
.pdl
文件定义蓝牙 HCI 命令/事件/数据包的二进制格式 -
跨语言支持:生成 C++/Java 等语言的协议解析/构建代码
-
保证一致性:避免手动编写协议代码导致的错误
关键定义示例:
OpCode 枚举定义
pdl
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)
-
-
pdl
enum OpCodeIndex : 16 {
RESET = 57, // 将 RESET 命令映射到索引 57
}
: 16
:索引值用 16 位整数存储(实际索引通常远小于此范围)RESET = 57
:表示RESET
命令在内部数组中的位置为 57
核心作用
-
二级映射 :将
OpCode
(如0x0C03
)转换为更紧凑的 数组索引 (如57
),优化内存和访问效率 -
快速查找:通过数字索引快速定位命令处理器(替代哈希表或线性搜索)
-
代码生成:为自动生成的代码提供命令编号与索引的映射关系
和 OpCode 的关系:
pdl
enum OpCode : 16 {
RESET = 0x0C03, // 规范定义的原始操作码
}
packet Reset : Command (op_code = RESET, op_code_index = RESET) {}
-
双绑定机制:
-
op_code
:协议规范定义的原始值(如0x0C03
) -
op_code_index
:内部优化的数组索引(如57
)
-
-
编译时关联:代码生成工具会确保两者正确匹配
pdl
packet Reset : Command (op_code = RESET) {
}
-
作用:声明 Reset 命令的数据结构
-
语法:
-
packet
声明一个协议数据包 -
: Command
表示这是 HCI 命令类型 -
(op_code = RESET)
绑定到前面定义的枚举值 -
空
{}
表示此命令无附加参数
-
pdl
test Reset {
"\x03\x0c\x00",
}
-
二进制解释:
-
03 0c
:小端格式的0x0C03
(Reset 命令码) -
00
:无参数填充
-
pdl
packet ResetComplete : CommandComplete (command_op_code = RESET) {
status : ErrorCode,
}
-
作用:定义命令完成事件的数据结构
-
语法:
-
: CommandComplete
表示这是命令完成事件 -
(command_op_code = RESET)
关联对应的命令 -
status : ErrorCode
:-
字段名
status
-
类型
ErrorCode
(通常是 8 位错误码枚举)
-
-
pdl
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
makefile
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 |
生成的头文件输出路径 |
Build System bluetooth_packetgen hci_packets.pdl l2cap_packets.pdl smp_packets.pdl genDir 调用工具 解析协议描述 解析协议描述 解析协议描述 生成 h/l2cap/smp_packets.h Build System bluetooth_packetgen hci_packets.pdl l2cap_packets.pdl smp_packets.pdl genDir
-
输入 :
.pdl
文件定义协议格式(字段、长度、类型等) -
处理 :
bluetooth_packetgen
工具解析描述文件 -
输出:生成类型安全的 C++ 头文件
其他模块通过 generated_headers
依赖这些生成的头文件:
makefile
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
生成的代码会包含:
c
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(); }
#endif
protected:
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_ */) {}
};