2. 基础知识
好,我们正式开始第二讲。上一章我们聊了为什么要把 Android Automotive 和 QNX 放在一起,这一章我们来看看它们到底是怎么「住」在同一个硬件上的。
说白了,整个系统的核心就三件事:怎么隔离、怎么分层、怎么启动。我当年第一次接触这种混合架构时,脑子里也是一团浆糊——又是 Hypervisor 又是 IPC,Android 和 QNX 到底谁先跑?别急,我们一层层剥开。
2.1 硬件隔离层:Hypervisor 与 IPC
先问一个问题:为什么不能让 Android 和 QNX 直接跑在同一个 CPU 上?
答案很简单——安全。QNX 负责仪表盘、刹车、转向这些功能安全等级 ASIL-D 的系统,而 Android 负责娱乐、导航、语音这些非安全域。如果 Android 崩溃了,不能把 QNX 也拖下水。所以我们需要一个「硬隔离」。
这个隔离层,就是 Hypervisor(虚拟机监视器)。
核心概念:Hypervisor 是一个极小的软件层,直接跑在硬件上。它把 CPU、内存、外设等资源「切」成多个虚拟机,每个虚拟机里跑一个独立的操作系统。两个系统互相看不见对方的物理内存,也抢不了对方的 CPU 时间片。
我在项目中用过几种主流的 Hypervisor:
- QNX Hypervisor(也叫 QNX Hypervisor for Safety)—— 自带功能安全认证,和 QNX 生态无缝集成
- ACRN(由 Intel 开源)—— 专门为嵌入式 IoT 和汽车设计,轻量级
- Jailhouse(由 Siemens 开源)—— 分区型 Hypervisor,静态分配资源
- Xen / KVM —— 通用型,但在汽车领域用得少,因为安全认证成本高
但光有隔离还不够。两个系统之间总得通信吧?比如 Android 要读取车速,或者 QNX 要显示 Android 的导航画面。这时候就需要 IPC(进程间通信)。
在 QNX 里,IPC 是天生的强项——它的微内核架构就是靠消息传递来工作的。Android 和 QNX 之间的 IPC 通常走 虚拟以太网 或 共享内存 + 信号量 的方式。我个人习惯用共享内存做大数据传输(比如视频流),用虚拟以太网做控制命令。
避坑指南:我曾经在一个项目里直接用共享内存传控制消息,结果发现消息丢失率很高。后来才意识到——共享内存本身没有同步机制,必须配合信号量或事件通知。嗯,这个坑我替你们踩过了。
下面这张图展示了典型的硬件隔离层架构:
2.2 软件分层:从硬件到应用
隔离层搞定了,接下来看软件怎么分层。你想想看,一个车载系统里既有实时控制又有复杂应用,如果不分层,代码会乱成一锅粥。
我习惯把整个软件栈分成四层:
| 层级 | 包含内容 | 运行在哪个 OS | 功能安全等级 |
|---|---|---|---|
| 应用层 | HMI、导航、语音、影音、设置 | Android Automotive | QM(非安全) |
| 服务层 | Car Service、Audio Policy、Vehicle HAL | Android Automotive | QM |
| 安全服务层 | 仪表渲染、车身控制、ADAS 决策 | QNX | ASIL-B / ASIL-D |
| 内核与驱动层 | QNX 微内核 / Linux 内核、设备驱动 | QNX + Android | ASIL-D(QNX 侧) |
这里有个关键点:Android 的 Vehicle HAL 并不直接操作硬件。它通过 IPC 把请求发给 QNX 侧的硬件抽象层,由 QNX 去控制真正的 CAN 总线、GPIO、PWM 等外设。这样做的好处是——即使 Android 崩溃了,QNX 依然能控制车辆。
注意:千万不要在 Android 侧直接操作硬件寄存器!我见过一个团队为了省事,让 Android 直接读写 SPI 总线,结果一次 Android OTA 升级后驱动不兼容,整个仪表盘黑屏了。嗯,这个教训很深刻。
2.3 启动流程总览:谁先醒?
好,现在到了最核心的部分——系统启动。很多人问我:「Android 和 QNX 到底谁先启动?」
答案是:QNX 先启动,Android 后启动。
为什么?因为 QNX 负责安全关键功能,它必须在 Android 启动之前就把仪表盘、刹车、转向等系统初始化好。万一 Android 启动失败了,QNX 还能保证车辆可以安全行驶。
完整的启动流程大致分 6 步:
- BootROM → SPL → U-Boot:硬件上电,BootROM 加载 SPL(Secondary Program Loader),SPL 初始化 DDR 和时钟,然后加载 U-Boot。
- U-Boot 启动 Hypervisor:U-Boot 把 Hypervisor 镜像加载到内存,跳转到 Hypervisor 入口。
- Hypervisor 初始化虚拟机:Hypervisor 创建两个虚拟机——VM1(QNX)和 VM2(Android),分配 CPU 核心、内存区域、中断控制器等资源。
- QNX 启动:VM1 启动 QNX 微内核,然后启动安全服务(仪表、车身、ADAS)。QNX 启动完成后,通过 IPC 通知 Hypervisor:「我准备好了」。
- Android 启动:Hypervisor 收到 QNX 的就绪信号后,启动 VM2 中的 Android。Android 走标准的 Bootloader → Kernel → Init → Zygote → System Server 流程。
- 跨域通信建立:Android 启动完成后,QNX 侧的 IPC 服务与 Android 侧的 Vehicle HAL 建立连接,开始交换数据。
下面这张流程图把启动顺序画得更清楚:
这个流程里有一个容易被忽略的细节:QNX 启动完成后,会等待 Android 就绪。如果 Android 在规定时间内没有启动成功,QNX 会进入「降级模式」——仪表盘正常显示,但娱乐功能不可用。我记得在某个项目中,Android 因为存储分区损坏导致反复重启,QNX 侧一直收不到就绪信号,最后触发了降级策略。嗯,这个降级逻辑一定要在项目早期就设计好。
个人经验:我建议在 QNX 侧实现一个「看门狗定时器」,监控 Android 的启动状态。如果 Android 启动超时,QNX 可以主动重启 Android 虚拟机,而不是一直死等。这个机制在量产项目中救过我们好几次。
2.4 本章小结
这一章我们覆盖了三块内容:
- 硬件隔离层:Hypervisor 提供硬隔离,IPC 提供跨域通信,两者配合实现「安全域 + 娱乐域」的共存
- 软件分层:四层架构——应用层、服务层、安全服务层、内核与驱动层,QNX 控制硬件,Android 通过 IPC 间接访问
- 启动流程:QNX 先启动 → Android 后启动 → 跨域通信建立,降级策略保证安全