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 通常走 虚拟以太网 或 共享内存 + 信号量 的方式。我个人习惯用共享内存做大数据传输(比如视频流),用虚拟以太网做控制命令。

避坑指南:我曾经在一个项目里直接用共享内存传控制消息,结果发现消息丢失率很高。后来才意识到——共享内存本身没有同步机制,必须配合信号量或事件通知。嗯,这个坑我替你们踩过了。

下面这张图展示了典型的硬件隔离层架构:

硬件隔离层架构图 物理硬件层(CPU / 内存 / 外设 / GPU / 存储) Hypervisor(QNX Hypervisor / ACRN / Jailhouse) VM 1:QNX 安全域 仪表盘 / 车身控制 / ADAS VM 2:Android 娱乐域 导航 / 语音 / 影音 / 应用 IPC 通信通道 共享内存 / 虚拟以太网 Hypervisor 提供硬件级隔离,IPC 提供跨域通信,两者缺一不可 QNX 安全域和 Android 娱乐域互不感知对方内存,通过 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 步:

  1. BootROM → SPL → U-Boot:硬件上电,BootROM 加载 SPL(Secondary Program Loader),SPL 初始化 DDR 和时钟,然后加载 U-Boot。
  2. U-Boot 启动 Hypervisor:U-Boot 把 Hypervisor 镜像加载到内存,跳转到 Hypervisor 入口。
  3. Hypervisor 初始化虚拟机:Hypervisor 创建两个虚拟机——VM1(QNX)和 VM2(Android),分配 CPU 核心、内存区域、中断控制器等资源。
  4. QNX 启动:VM1 启动 QNX 微内核,然后启动安全服务(仪表、车身、ADAS)。QNX 启动完成后,通过 IPC 通知 Hypervisor:「我准备好了」。
  5. Android 启动:Hypervisor 收到 QNX 的就绪信号后,启动 VM2 中的 Android。Android 走标准的 Bootloader → Kernel → Init → Zygote → System Server 流程。
  6. 跨域通信建立:Android 启动完成后,QNX 侧的 IPC 服务与 Android 侧的 Vehicle HAL 建立连接,开始交换数据。

下面这张流程图把启动顺序画得更清楚:

系统启动流程总览 ① BootROM → SPL → U-Boot ② U-Boot 启动 Hypervisor ③ Hypervisor 创建 VM1 / VM2 ④ QNX 微内核 + 安全服务启动 ⑤ Android Boot → Kernel → System Server ⑥ 跨域 IPC 通信建立(QNX ↔ Android) QNX 先启动保证安全,Android 后启动提供娱乐,Hypervisor 全程隔离

这个流程里有一个容易被忽略的细节:QNX 启动完成后,会等待 Android 就绪。如果 Android 在规定时间内没有启动成功,QNX 会进入「降级模式」——仪表盘正常显示,但娱乐功能不可用。我记得在某个项目中,Android 因为存储分区损坏导致反复重启,QNX 侧一直收不到就绪信号,最后触发了降级策略。嗯,这个降级逻辑一定要在项目早期就设计好。

个人经验:我建议在 QNX 侧实现一个「看门狗定时器」,监控 Android 的启动状态。如果 Android 启动超时,QNX 可以主动重启 Android 虚拟机,而不是一直死等。这个机制在量产项目中救过我们好几次。

2.4 本章小结

这一章我们覆盖了三块内容:

  • 硬件隔离层:Hypervisor 提供硬隔离,IPC 提供跨域通信,两者配合实现「安全域 + 娱乐域」的共存
  • 软件分层:四层架构——应用层、服务层、安全服务层、内核与驱动层,QNX 控制硬件,Android 通过 IPC 间接访问
  • 启动流程:QNX 先启动 → Android 后启动 → 跨域通信建立,降级策略保证安全