【android bluetooth 协议分析 01】【HCI 层介绍 1】【hci_packets.pdl 介绍】

在 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) {}
  • 双绑定机制

    1. op_code :协议规范定义的原始值(如 0x0C03

    2. 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

  1. 输入.pdl 文件定义协议格式(字段、长度、类型等)

  2. 处理bluetooth_packetgen 工具解析描述文件

  3. 输出:生成类型安全的 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_ */) {}
};
相关推荐
_一条咸鱼_3 小时前
大厂Android面试秘籍:Activity 结果回调处理(八)
android·面试·android jetpack
_一条咸鱼_3 小时前
大厂Android面试秘籍:Activity 与 Fragment 交互(九)
android·面试·android jetpack
青山渺渺5 小时前
简单记录一下Android四大组件
android
每次的天空6 小时前
Android学习总结之OKHttp拦截器和缓存
android·学习·okhttp
aaajj7 小时前
【Android】ContentResolver的使用
android
时光少年7 小时前
Android ExoPlayer版本升级遇上系统的”瓜“
android·前端
你说你说你来说9 小时前
安卓布局详解
android·笔记
奔跑吧 android9 小时前
【android bluetooth 框架分析 02】【Module详解 3】【HciHal 模块介绍】
android·bluetooth·bt·gd·aosp13·hcihal
好学人10 小时前
Activity的四种启动模型
android
好学人10 小时前
一文了解 Android MVI 架构
android