3. AAOS系统架构与R-Car适配层

Android Automotive OS(AAOS)并不是把手机 Android 直接搬到车机上,而是在 AOSP 之上叠加了一整套面向车辆的总线抽象、服务框架与应用接口。R-Car 平台要跑通 AAOS,关键不在于“能不能点亮屏幕”,而在于从 Bootloader 到 CarService 的每一层是否与 R-Car 的硬件资源、BSP 驱动、HAL 接口正确对齐。本节按启动链自下而上梳理这条适配路径。

一、Android 系统启动链与 R-Car 的介入点

AAOS 的启动链可以概括为:BootROM → Bootloader(R-Car 上通常是 U-Boot 或厂商定制 SPL)→ Linux Kernel → init → 各类 native 服务 → Zygote → SystemServer → CarService → CarApp。R-Car 的适配工作几乎贯穿整条链,但介入方式各不相同。

Bootloader 阶段主要完成 DRAM 初始化、加载内核与设备树(DTB)。R-Car H3/M3/E3 等 SoC 的 DTB 中会描述 CPU 集群、GIC、SCIF/HSCIF 串口、I2C、GPIO、PCIe、显示控制器(DU)、视频输出等节点。内核启动后,init 依据 init.rc 与 init.<hardware>.rc 拉起服务。R-Car 平台通常需要新增或修改 init.rc 中的 import 项,把 BSP 提供的 init.rc 片段纳入启动流程,例如提前挂载 /vendor、启动 android.hardware.automotive.vehicle@2.0-service 等。

Zygote 启动后 fork 出 SystemServer,SystemServer 中会依次启动 ActivityManagerService、WindowManagerService、PackageManagerService 等,随后通过 SystemServiceManager 启动 CarServiceHelperService,由它绑定并拉起 CarService。CarService 再通过 VHAL 与车辆总线通信,最终把车辆信号暴露给 CarApp。这条链上任何一环的 SELinux 策略、权限、HAL 接口版本不匹配,都会导致 CarService 起不来或车辆属性读不到。

AAOS 启动链与 R-Car 适配层 BootROM / Bootloader DRAM 初始化 · 加载 DTB Linux Kernel DU / I2C / GPIO / PCIe 驱动 init 解析 init.rc · 挂载 /vendor Zygote / SystemServer AMS · WMS · PMS CarServiceHelperService 绑定并拉起 CarService CarService CarPropertyManager CarApp / 应用层 R-Car BSP 适配 • 设备树 DTB 节点 • 内核驱动(DU/I2C/GPIO) • init.rc 片段与 SELinux • 分区表与 vendor 镜像 HAL / VHAL 适配 • android.hardware.automotive.vehicle • VehicleProperty 映射 • CAN / LIN / 以太网信号 • Subscribe / Set 回调 CarService / CarApp 适配 • CarPropertyManager 读写 • CarAppService / CarActivity • 权限与 SELinux 标签 • 车辆属性订阅与回调 关键检查点 1. DTB 中 DU 节点与显示时序 2. init.rc 是否导入 BSP 片段 3. VHAL 服务是否注册成功 4. VehicleProperty 是否可读 5. CarService 是否绑定成功 6. SELinux 是否放行 HAL 访问 7. CarApp 权限是否声明 8. 车辆信号周期与超时 9. 分区镜像是否匹配 10. 内核日志 dmesg 异常 典型失败现象 • CarService 反复重启 • 车辆属性返回 NOT_AVAILABLE • 屏幕无输出或花屏 • SELinux denied 日志刷屏

二、HAL 与 VHAL:车辆信号的抽象边界

AAOS 中与车辆相关的 HAL 主要是 Vehicle HAL(VHAL)。它定义在 hardware/interfaces/automotive/vehicle/ 下,当前主流版本为 android.hardware.automotive.vehicle@2.0 或 @2.1。VHAL 的核心职责是把车辆总线上的物理信号抽象为 VehicleProperty,并提供 get、set、subscribe 三类操作。

R-Car 适配 VHAL 时,通常不会从零实现,而是基于 AOSP 的 VehicleHal 默认实现或芯片厂商提供的参考实现,替换其中的信号采集与下发部分。例如,车速信号可能来自 CAN 总线,空调温度来自 LIN 或私有总线,车门状态来自 GPIO。适配层需要把这些来源统一映射到 VHAL 的属性 ID 上。

一个典型的属性映射示例如下:

VehicleProperty::PERF_VEHICLE_SPEED  -> CAN ID 0x1A0, 字节 0-1, 系数 0.01, 单位 km/h
VehicleProperty::HVAC_TEMPERATURE_SET -> LIN 帧 0x22, 字节 2, 系数 0.5, 单位 ℃
VehicleProperty::DOOR_OPEN           -> GPIO 12, 高电平表示开门
VehicleProperty::GEAR_SELECTION      -> CAN ID 0x2B0, 字节 3, 枚举值 P/R/N/D

映射完成后,VHAL 服务需要以 android.hardware.automotive.vehicle@2.0-service 的形式注册到 hwservicemanager。CarService 启动时会通过 IVehicle::getService() 获取该服务,并建立订阅关系。如果 VHAL 服务没有注册成功,CarService 会在日志中报 Unable to get IVehicle,车辆属性全部不可用。

三、CarService 与 CarApp 框架

CarService 是 AAOS 中车辆功能的中枢。它内部包含 CarPropertyService、CarPowerManagementService、CarAudioService、CarPackageManagerService 等子服务。CarPropertyService 负责把 VHAL 的 VehicleProperty 封装为 CarPropertyManager 接口,供应用层调用。

应用层通过 CarPropertyManager 读写车辆属性,典型调用如下:

CarPropertyManager mgr = (CarPropertyManager) car.getCarManager(Car.PROPERTY_SERVICE);
// 读取车速
CarPropertyValue<Float> speed = mgr.getProperty(Float.class, VehiclePropertyIds.PERF_VEHICLE_SPEED, 0);
// 订阅车速变化
mgr.registerCallback(callback, VehiclePropertyIds.PERF_VEHICLE_SPEED, CarPropertyManager.SENSOR_RATE_ONCHANGE);

CarApp 框架则规定了车机应用的形态:CarAppService、CarActivity、CarLauncher 等。与手机应用不同,车机应用需要声明 android.car.permission.CAR_* 权限,并在 AndroidManifest.xml 中声明 android.software.car.templates_host 等特性。R-Car 平台上,CarApp 的显示输出依赖 DU 控制器与 SurfaceFlinger 的合成路径,如果显示时序配置错误,应用可能正常启动但画面无法输出。

四、R-Car BSP 与内核适配要点

R-Car BSP 通常以 Yocto 层的形式提供,包含内核补丁、设备树、U-Boot、驱动模块和固件。适配 AAOS 时,需要重点关注以下几点:

  • 设备树节点:确认 DU、VSP、I2C、GPIO、PCIe、以太网等节点与硬件原理图一致,尤其是显示输出接口(LVDS、HDMI、DP)的时序参数。
  • 内核配置:打开 CONFIG_DRM_RCAR_DU、CONFIG_I2C_RCAR、CONFIG_GPIO_RCAR、CONFIG_CAN_RCAR 等选项,并确保 Android 所需的 CONFIG_ANDROID_BINDER_IPC、CONFIG_ASHMEM 已启用。
  • init.rc 与 SELinux:把 BSP 的 init.rc 片段导入 Android 启动流程,并为 VHAL 服务、CAN 设备节点、GPIO 节点编写正确的 SELinux 策略,避免 avc: denied。
  • 分区与镜像:确认 boot、vendor、system、product 分区大小与镜像格式匹配,R-Car 上常用 eMMC 或 UFS,需在分区表中预留足够空间。
调试启动链时,优先看 dmesg 中的内核报错、logcat 中的 CarService 日志、以及 dumpsys car_service 输出的车辆属性状态。三者结合可以快速定位是驱动层、HAL 层还是框架层的问题。

整体来看,AAOS 在 R-Car 上的适配是一条从 Bootloader 到 CarApp 的纵向链路,每一层都有明确的接口与检查点。理解这条链路的层次关系与数据流向,比记住某个具体命令更重要——它决定了遇到问题时应该先看哪一层、再查哪一层。