3、AAOS系统架构详解:系统服务层、硬件抽象层(HAL)、内核层、应用框架层

好,我们直接切入正题。AAOS 这套系统,说白了就是 Android 在车机上的一个“定制版”。但它的架构,跟手机 Android 有本质区别。你想想看,手机死机了重启一下就行,车机要是死机了,那可是要出大事的。所以它的架构设计,核心就两个字:稳定

我个人习惯把 AAOS 的架构想象成一个四层蛋糕。从下往上分别是:内核层硬件抽象层(HAL)系统服务层应用框架层。每一层都各司其职,又互相隔离。今天我们就一层一层把它剥开来看。

核心观点: AAOS 架构的精髓在于“分层解耦”。每一层只对上层提供接口,下层的变化对上层透明。这样,车厂换硬件、改驱动,都不会影响到上层的应用。

应用框架层 (Application Framework) CarLauncher | CarSettings | 第三方车载应用 系统服务层 (System Services) CarService | VehicleService | 窗口管理 | 权限管理 核心:通过 Vehicle HAL 与硬件通信 硬件抽象层 (HAL) Vehicle HAL | Audio HAL | Camera HAL | 传感器 HAL 屏蔽硬件差异,提供统一接口 内核层 (Linux Kernel) 设备驱动 | 电源管理 | 内存管理 | 安全模块 基于 Linux 内核,增加车载专用驱动

1. 内核层:一切稳定的基石

最底层是 Linux 内核。嗯,这里要注意,AAOS 用的不是标准的 Linux 内核,而是经过 Google 和芯片厂商深度定制的。为什么?因为车机需要一些特殊功能,比如 车载网络管理(CAN bus)实时性保障安全隔离

我记得在做一个项目时,遇到过一个问题:车机在倒车时,摄像头画面会卡顿半秒。查到最后,发现是内核的 camera driver 中断优先级被其他进程抢占了。后来我们调整了内核的 IRQ 亲和性,把摄像头中断绑定到专用 CPU 核心上,问题才解决。你看,内核层的调优,直接决定了上层体验。

避坑指南: 我曾经在调试某个车型的蓝牙连接时,发现每次连接手机都会导致系统重启。最后定位到是内核的蓝牙驱动在内存分配时没有做 GFP_ATOMIC 标志,导致在中断上下文中睡眠了。所以,写内核驱动时,一定要搞清楚上下文环境。

2. 硬件抽象层(HAL):隔离变化的“防火墙”

HAL 层,说白了就是给上层一个“假象”。让系统服务层觉得所有硬件都是一样的,不管底下是博世的传感器还是大陆的屏幕。AAOS 里最重要的 HAL 就是 Vehicle HAL

Vehicle HAL 定义了车辆属性的标准接口,比如车速、转向灯状态、空调温度等。车厂只需要实现这些接口,上层 CarService 就能直接读取。你想想看,如果没有这一层,每个车厂都自己搞一套 API,那应用开发者不得疯掉?

// Vehicle HAL 核心接口示例 (简化)
// 定义车辆属性
typedef struct {
    int32_t prop_id;        // 属性ID,如 VEHICLE_PROPERTY_CURRENT_SPEED
    int32_t area_id;        // 区域ID,如驾驶座、副驾驶座
    int32_t value_type;     // 值类型:INT32, FLOAT, STRING 等
    union {
        int32_t int32_value;
        float   float_value;
        char    string_value[64];
    } value;
} VehiclePropValue;

// HAL 实现必须提供的函数
int32_t vehicle_hal_get_property(VehiclePropValue* out_value);
int32_t vehicle_hal_set_property(const VehiclePropValue* value);

我个人习惯在实现 Vehicle HAL 时,先写一个 模拟层。就是在没有真车硬件的情况下,用软件模拟车辆数据。这样上层开发可以并行进行,不用等硬件就绪。这个技巧在项目初期特别有用。

注意: HAL 层的稳定性至关重要。如果 HAL 层崩溃,整个 CarService 都会挂掉。所以一定要做好异常处理和超时保护。我曾经见过一个项目,因为 HAL 层在读取传感器时没有做超时判断,导致车辆在行驶中突然黑屏——嗯,那场面,你懂的。

3. 系统服务层:车机的“大脑”

系统服务层,是 AAOS 最核心的一层。它运行在 System Server 进程中,负责管理所有车载功能。这里面最重要的两个服务是:CarServiceVehicleService

  • CarService:面向应用层提供高层次的 API,比如获取当前车速、控制空调、切换音源等。它内部会调用 VehicleService 来与 HAL 通信。
  • VehicleService:直接与 Vehicle HAL 交互,负责订阅车辆属性变化、处理属性设置请求。它还会做权限校验,确保只有授权的应用才能控制车辆。

为什么要把它们分开?我刚开始做 AAOS 时也不理解。后来在项目中踩了坑才明白:CarService 可能会被频繁重启(比如应用崩溃),但 VehicleService 必须保持稳定,因为它直接控制车辆。分层之后,即使 CarService 挂了,VehicleService 还能继续工作,保证车辆安全。

关键点: 系统服务层是 AAOS 的“安全边界”。所有对车辆硬件的操作,都必须经过这一层的权限检查。应用层不能直接访问 HAL,只能通过系统服务提供的接口。

4. 应用框架层:用户看到的“面子”

最上面一层,就是用户直接接触的应用了。比如车载桌面(CarLauncher)、设置应用、地图导航、音乐播放器等。这一层其实跟普通 Android 应用开发差别不大,只是多了一些车载特有的 API。

举个例子,你想在应用中显示当前车速,只需要调用 Car.getCarInstrumentClusterInfo() 或者订阅 CarSpeedEvent。底层怎么跟硬件通信的,应用开发者完全不用关心。这就是分层架构的好处。

// 应用层获取车速示例 (Kotlin)
val car = Car.createCar(context)
val vehicleStore = car.getVehicleStore()

// 订阅车速变化
vehicleStore.subscribeProperty(
    VehiclePropertyIds.CURRENT_SPEED,
    VehicleZone.ROOF_TOP,
    { speedValue ->
        val speed = speedValue.value.floatValue
        textView.text = "当前车速: $speed km/h"
    }
)

不过,这里有个坑。应用层虽然开发简单,但性能要求很高。车机屏幕通常分辨率高,而且要求 60fps 流畅。我建议在应用层尽量少做耗时操作,比如网络请求、数据库读写,都放到后台线程去做。否则,一旦 UI 线程卡顿,用户就会觉得“这车机好卡”。

个人经验: 我在做车载地图应用时,发现每次导航转弯提示都会掉帧。后来用 Systrace 一查,发现是布局嵌套太深,导致 measure 阶段耗时过长。优化成扁平化布局后,帧率就稳定了。所以,应用层的性能优化,往往从布局开始。

各层之间的协作:一个完整的流程

为了让你更直观地理解,我们来看一个实际场景:用户按下方向盘上的“音量+”按钮

  1. 内核层:按钮按下产生一个硬件中断,内核的 GPIO 驱动检测到电平变化,上报一个输入事件。
  2. HAL 层:Input HAL 接收到事件,将其转换为标准的 KeyEvent,并上报给上层。
  3. 系统服务层:Window Manager 接收到按键事件,判断是“音量+”键,然后调用 AudioServiceadjustVolume() 方法。
  4. 应用框架层:AudioService 更新音量状态,并发送广播通知当前正在播放音乐的应用(如 Spotify)更新 UI。

整个过程,从硬件到应用,经过了四层。每一层都只做自己分内的事,互不干扰。这就是 AAOS 架构设计的精髓。

层级 核心职责 关键组件 常见问题
应用框架层 提供用户界面和交互 CarLauncher, CarSettings UI 卡顿、内存泄漏
系统服务层 管理车辆功能、权限控制 CarService, VehicleService 服务崩溃、权限绕过
硬件抽象层 屏蔽硬件差异、提供统一接口 Vehicle HAL, Audio HAL 接口不兼容、超时无响应
内核层 硬件驱动、资源管理、安全 Linux Kernel, 车载驱动 驱动死锁、中断延迟

好了,AAOS 的四层架构就讲到这里。每一层都有很多细节,但核心思想就是“分层”和“解耦”。你只要记住:下层提供能力,上层使用能力,中间通过标准接口通信。这个思路,贯穿了整个 AAOS 开发。

公众号:蓝海资料掘金营,微信 deep3321