3. VHAL 核心概念
在 AAOS 的 Vehicle HAL(VHAL)体系中,所有对外暴露的车辆能力都被抽象为“车辆属性(Vehicle Property)”。VHAL 不是一组随意的方法集合,而是一套由属性 ID 驱动的、可枚举、可订阅、可权限控制的数据模型。理解属性、属性 ID、区域(Area)、属性类型、访问权限与配置标志这六个核心概念,是后续进行服务集成、信号映射和故障排查的基础。
一、核心原理:属性是 VHAL 的最小契约单元
一个车辆属性代表车辆上一个可被读取或写入的物理量或状态量,例如车速、档位、空调温度、车门锁状态、胎压、雨刷位置等。每个属性在编译期由 VehicleProperty 枚举定义,并携带一组元数据:属性 ID、数据类型、访问权限、区域支持、配置标志以及单位、取值范围等。VHAL 实现方(通常是供应商 HAL)负责把这些属性映射到真实 CAN/LIN/以太网信号,AAOS 框架层则通过 CarPropertyManager 向应用提供统一访问接口。
属性 ID 是一个 32 位整数,其位域结构决定了属性的全局唯一性和语义分类。典型布局如下:
VehicleProperty ID 位域(简化):
[31:24] 属性组 / 全局唯一编号高位
[23:16] 区域类型(Area Type)
[15:8] 属性组标识(Property Group)
[7:0] 组内序号
示例:
0x0100 | 0x0000 | 0x00 | 0x01 → PERF_VEHICLE_SPEED
0x0900 | 0x0100 | 0x00 | 0x02 → HVAC_TEMPERATURE_SET(支持区域)
属性 ID 的高位还隐含了“是否支持区域”“是否支持订阅”等语义。开发者不应硬编码魔法数字,而应始终使用 VehicleProperty 常量,避免因版本升级导致 ID 语义漂移。
二、区域(Area):同一属性的多实例寻址
许多车辆属性天然具有多个实例,例如四个车门、四个座椅、多个空调出风口、多个胎压传感器。VHAL 用“区域 ID(Area ID)”来区分同一属性下的不同实例。区域 ID 的编码方式由属性 ID 中的区域类型位决定,常见区域类型包括:
- GLOBAL:全局唯一,无区域概念,如车速、档位。
- WINDOW:按车窗位置编码,如左前、右前、左后、右后。
- SEAT:按座椅行列编码,如第 1 排左、第 2 排右。
- DOOR:按车门位置编码,与 WINDOW 类似但语义独立。
- MIRROR:按后视镜位置编码。
- WHEEL:按车轮位置编码,用于胎压。
- VENDOR:供应商自定义区域,需在 HAL 中显式声明。
区域 ID 不是简单的 0、1、2、3,而是按位域构造的复合值。例如座椅区域可能由“排号 + 位置”组合而成。应用层通过 CarPropertyManager.getCarPropertyConfig() 获取某属性支持的 Area ID 列表,再按需读写。若对不支持区域的属性传入 Area ID,HAL 会返回 StatusCode.INVALID_ARG。
三、属性类型与访问权限
属性类型决定数据在 HAL 与框架之间的序列化格式。VHAL 支持的基础类型包括:INT32、INT64、FLOAT、STRING、BOOLEAN、BYTES,以及它们的数组形式。此外还有复合类型如 INT32_VEC、FLOAT_VEC,用于一次传递多个值。类型必须与属性定义严格一致,否则会在 VehicleHal 校验阶段被拒绝。
访问权限由 VehiclePropertyAccess 定义,分为三类:
- READ:只读,如车速、发动机转速。
- WRITE:只写,较少见,如某些一次性命令。
- READ_WRITE:可读可写,如空调温度设定、座椅加热档位。
权限之外还有“变更模式(Change Mode)”,决定属性值变化时是否上报:STATIC 表示不变,ON_CHANGE 表示变化即上报,CONTINUOUS 表示按固定频率持续上报。车速通常为 CONTINUOUS,车门锁状态为 ON_CHANGE,VIN 码为 STATIC。
四、配置标志(Config Flags)与属性配置表
配置标志用于声明属性的附加行为,常见标志包括:
| 配置标志 | 含义 | 典型属性 |
|---|---|---|
| GLOBAL | 无区域,全局唯一 | PERF_VEHICLE_SPEED |
| POWER | 依赖电源状态,需唤醒管理 | HVAC_POWER_ON |
| SYSTEM | 系统级属性,普通应用不可见 | VEHICLE_CURB_WEIGHT |
| VENDOR | 供应商扩展属性 | 自定义诊断属性 |
| DISABLED | 当前不可用,需动态启用 | 可选配置项 |
每个属性在 VehiclePropertyConfig 中还会声明单位、最小/最大值、支持的区域列表、默认值等。这些配置在 VHAL 初始化时通过 getAllPropertyConfigs() 上报给框架,CarService 据此构建属性能力表,供应用查询。
关键理解:属性 ID 决定“是什么”,区域决定“哪一个”,类型决定“怎么传”,权限决定“谁能动”,配置标志决定“怎么用”。五者共同构成 VHAL 的属性契约,缺一不可。
五、案例场景:空调温度属性的完整定义
以 HVAC_TEMPERATURE_SET 为例,其属性定义大致如下:
Property ID : 0x0501 0x0100 0x00 0x02
Access : READ_WRITE
Change Mode : ON_CHANGE
Value Type : FLOAT
Area Type : SEAT
Config Flags : POWER
单位 : 摄氏度
范围 : 16.0 ~ 32.0
支持区域 : SEAT_ROW_1_LEFT, SEAT_ROW_1_RIGHT
应用层读取时需指定 Area ID:
CarPropertyManager mgr = car.getCarManager(CarPropertyManager.class);
float temp = mgr.getFloatProperty(
VehiclePropertyIds.HVAC_TEMPERATURE_SET,
VehicleAreaSeat.SEAT_ROW_1_LEFT);
若传入 SEAT_ROW_2_LEFT,而配置中未声明该区域,则返回 CarPropertyManager.STATUS_ERROR_INVALID_ARG。这正是区域与配置表联合校验的体现。
六、误区与复盘
误区一:把属性 ID 当作普通整数随意比较或拼接。属性 ID 是位域编码,不同属性组之间可能数值接近,但语义完全不同。
误区二:忽略区域类型,对所有属性都传 GLOBAL。只有声明为 GLOBAL 的属性才能省略区域,否则必须传合法 Area ID。
误区三:认为 READ_WRITE 属性可以任意写。写入还需通过权限校验、电源状态校验和范围校验,任一失败都会返回错误码。
误区四:把 CONTINUOUS 属性当 ON_CHANGE 用,导致高频回调拖垮应用。应按实际需求选择订阅频率或使用 getProperty 轮询。
复盘时建议建立一张“属性-区域-类型-权限-标志”对照表,在集成每个新属性前先核对配置,再编写读写代码。这样可以把大量运行时错误提前到设计阶段发现,显著降低 VHAL 集成调试成本。