2. Android Automotive 平台架构:AAOS 系统架构概览、核心服务与 HAL 层、车载应用框架

好,咱们进入正题。这一章我打算聊聊 Android Automotive 的底层骨架。说白了,就是 AAOS 到底是怎么搭起来的。很多做上层应用的朋友,可能一辈子都不用碰 HAL 层,但理解了这个架构,你写代码时心里会更有底。

我个人习惯把 AAOS 的架构想象成一栋楼。地基是 Linux 内核,往上盖的是 HAL 层,再往上就是各种核心服务,最顶层才是咱们开发者接触最多的应用框架。嗯,咱们一层层来看。

2.1 AAOS 系统架构概览

先看一张宏观图(当然,这里没有图,我用文字给你画出来)。AAOS 的架构其实和手机上的 Android 很像,但针对车载场景做了大量定制。

它主要分这么几层:

  • 应用层:你写的那些车载应用,比如音乐、导航、设置,都在这一层。
  • 应用框架层:这是 Google 提供的一套 API,帮你管理界面、生命周期、资源等等。
  • 系统服务层:这是 AAOS 的核心。像 CarService、VehicleService 这些大管家,都住在这里。
  • HAL 层:硬件抽象层。它把底层的硬件差异给屏蔽了。你想想看,不同车厂的空调、车窗、方向盘按键,接口千奇百怪,但到了 HAL 层,都变成了统一的接口。
  • Linux 内核层:最底层,负责和硬件打交道,比如驱动、内存管理、进程调度。

我在项目中遇到过一个问题:有个第三方应用直接去读底层的 CAN 总线数据,结果系统直接崩溃了。为什么?因为它绕过了 HAL 层,没有权限控制。所以,千万别想着跳过 HAL 层直接操作硬件,这是大忌。

警告: 千万不要在应用层直接访问硬件资源。所有硬件操作必须通过 Vehicle HAL 或 CarService 进行。我曾经见过一个团队,为了图方便,在应用里直接打开了串口去读 GPS 数据,结果导致系统不稳定,最后全部返工。

2.2 核心服务与 HAL 层

这一节是重点。AAOS 的核心服务,说白了就是几个关键的进程,它们一直在后台跑着,管理着车辆的一切。

2.2.1 CarService

CarService 是车载系统的总管家。它负责管理车辆的状态,比如车门、车窗、空调、座椅等等。它通过 Vehicle HAL 和底层硬件通信。

它的工作流程大概是这样的:

  1. 应用调用 CarService 的 API,比如“打开空调”。
  2. CarService 把这个请求转给 Vehicle HAL。
  3. Vehicle HAL 通过 CAN 总线或者别的协议,告诉空调控制器“该干活了”。
  4. 空调控制器执行操作,然后返回状态。
  5. 状态再原路返回给应用。

你看,这一来一回,CarService 起到了承上启下的作用。它不直接操作硬件,但它是所有车载功能的入口。

2.2.2 Vehicle HAL

Vehicle HAL 是硬件抽象层。它的核心接口是 IVehicle。这个接口定义了你能够对车辆做哪些操作,比如获取车速、控制车窗、读取方向盘角度等等。

每个车厂都需要实现自己的 Vehicle HAL。为什么?因为不同车厂的硬件不一样。有的车用 CAN 总线,有的车用 LIN 总线,还有的用以太网。Vehicle HAL 就是把这些差异都封装起来。

我建议你在实现 Vehicle HAL 时,注意以下几点:

  • 属性定义要清晰:每个车辆属性(比如车速、油量)都要有唯一的 ID 和类型。
  • 错误处理要完善:硬件可能会出问题,比如传感器坏了。你的 HAL 要能优雅地处理这些错误,而不是直接崩溃。
  • 性能要达标:有些属性,比如车速,需要高频更新。你的 HAL 实现要能扛得住。
核心要点: Vehicle HAL 是 AAOS 和车辆硬件之间的桥梁。它的质量直接决定了整个车载系统的稳定性和性能。我曾经在一个项目中,因为 Vehicle HAL 里一个属性值类型定义错了,导致整个 CarService 频繁重启,排查了整整两天才找到问题。

2.2.3 其他核心服务

除了 CarService,还有几个重要的服务:

  • UserManagerService:管理用户账户。咱们这门课的主题,就是围绕它展开的。
  • AudioService:管理音频焦点。车载音频很复杂,导航、电话、音乐、提示音,它们之间不能打架。
  • PowerService:管理电源。车载系统的电源管理比手机复杂得多,涉及到休眠、唤醒、ACC 信号等等。

2.3 车载应用框架

应用框架,就是咱们开发者直接打交道的那一层。AAOS 在标准 Android 框架的基础上,增加了一些车载专用的组件。

2.3.1 Car API

Car API 是 Google 提供的一套接口,让应用能够访问车辆数据。比如,你想知道当前车速,可以调用 Car.getCarInfoManager().getVehicleSpeed()

这些 API 都是通过 CarService 来间接访问硬件的。所以,你的应用不需要关心底层是 CAN 还是 LIN,只需要调用 API 就行了。

举个例子,获取车辆信息的代码大概长这样:

// 获取 Car 实例
Car car = Car.createCar(context);
// 获取车辆信息管理器
CarInfoManager infoManager = (CarInfoManager) car.getCarManager(Car.INFO_SERVICE);
// 获取车速
float speed = infoManager.getVehicleSpeed();
// 获取油量
float fuelLevel = infoManager.getFuelLevel();

你看,代码很简单。但要注意,这些 API 可能不是实时更新的。有些属性,比如车速,是高频更新的;有些属性,比如油量,是低频更新的。你的应用要根据实际情况来处理。

2.3.2 车载 UI 组件

AAOS 还提供了一些车载专用的 UI 组件。比如:

  • CarUiRecyclerView:针对车载触摸屏优化的列表控件。
  • CarDrawerLayout:侧滑菜单,适合在驾驶场景下快速切换功能。
  • CarToolbar:顶部的工具栏,通常包含返回按钮、标题和操作按钮。

这些组件都考虑了驾驶安全。比如,按钮的尺寸更大,触摸区域更宽,防止误触。我建议你在开发车载应用时,尽量使用这些组件,而不是自己从头造轮子。

小技巧: 车载应用的 UI 设计,核心原则是“少即是多”。不要堆砌信息,不要让驾驶员分心。我在做导航应用时,就只显示最重要的信息:当前道路、下一个转弯、剩余距离。其他信息都折叠起来,需要时才展开。

2.3.3 多用户与多显示

车载系统的一个特点是多用户和多显示。一辆车可能有好几个屏幕:中控屏、仪表盘、副驾屏、后排屏。每个屏幕可能属于不同的用户。

AAOS 的应用框架支持这种场景。每个用户都有自己的应用栈和设置。比如,驾驶员登录后,中控屏显示导航;副驾登录后,副驾屏显示视频。

这里有个坑:不同屏幕之间的应用状态管理。我曾经遇到过一个情况:驾驶员在中控屏上打开了音乐应用,然后副驾在副驾屏上也打开了同一个音乐应用。结果两个屏幕上的播放状态不一致,音乐一会播放一会暂停。后来我们通过为每个用户分配独立的进程,才解决了这个问题。

嗯,这一章的内容就到这里。总结一下:AAOS 的架构是分层的,核心服务通过 HAL 层和硬件打交道,应用框架则提供了方便的 API 和 UI 组件。理解了这个架构,你就能更好地设计你的车载应用了。