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 集成调试成本。

VHAL 车辆属性核心概念关系 属性 ID · 区域 · 类型 · 权限 · 配置标志 共同构成属性契约 Vehicle Property 车辆属性(最小契约单元) 属性 ID 32 位位域编码 全局唯一 · 语义分类 区域 Area 同一属性多实例寻址 SEAT / DOOR / WINDOW 属性类型 INT32 / FLOAT / STRING 决定序列化格式 访问权限 READ / WRITE / READ_WRITE 变更模式:ON_CHANGE 等 配置标志 GLOBAL / POWER / SYSTEM VENDOR / DISABLED 示例:空调温度 HVAC_TEMPERATURE_SET FLOAT · READ_WRITE · SEAT 16.0 ~ 32.0 ℃ 属性 ID 决定“是什么” · 区域决定“哪一个” · 类型决定“怎么传” 权限决定“谁能动” · 配置标志决定“怎么用”