第19章 测试与仿真环境搭建

说实话,做车载OTA开发这几年,我踩过最大的坑就是——在真车上调试。有一次,一个简单的升级包解析错误,我抱着笔记本在测试车里蹲了整整一下午。车里的空调还坏了,那滋味...后来我学乖了,先把仿真环境搭得妥妥当当,再上真车。

这一章,我就把压箱底的环境搭建经验掏出来。从QEMU模拟器到Cuttlefish虚拟设备,再到HIL台架和Tradefed自动化框架,咱们一个一个说清楚。

核心观点:仿真环境不是替代品,而是加速器。好的仿真环境能覆盖80%的OTA测试场景,剩下20%留给真车验证。

19.1 QEMU模拟器配置

QEMU这东西,说白了就是一个硬件模拟器。你可以在PC上模拟出一台完整的ARM设备,跑Android系统。我刚开始用的时候,总觉得它慢,后来发现是配置没调对。

19.1.1 基础环境准备

先说说硬件要求。QEMU跑Android,CPU最好支持硬件虚拟化。Intel的VT-x或者AMD的AMD-V,都得在BIOS里打开。内存至少16GB,我建议32GB起步。磁盘空间?准备100GB吧,AOSP编译产物就占不少地方。

# 安装QEMU和相关工具
sudo apt-get install qemu-system-arm qemu-efi-aarch64
sudo apt-get install libvirt-daemon-system virt-manager

# 下载预编译的Android系统镜像
wget https://ci.android.com/builds/latest/branches/aosp-main/artifacts/aosp_cf_arm64_phone-userdebug/view/qemu-img.zip
unzip qemu-img.zip -d ~/android-qemu

19.1.2 启动脚本配置

我个人习惯写一个启动脚本,把参数都封装好。这样每次启动不用敲一长串命令。

#!/bin/bash
# start-qemu.sh - 启动Android QEMU模拟器

QEMU_SYSTEM=qemu-system-aarch64
KERNEL=~/android-qemu/kernel
RAMDISK=~/android-qemu/ramdisk.img
SYSTEM_IMG=~/android-qemu/system.img
USERDATA_IMG=~/android-qemu/userdata.img

$QEMU_SYSTEM \
  -machine virt,virtualization=true,gic-version=3 \
  -cpu cortex-a72 \
  -smp 4 \
  -m 4096 \
  -kernel $KERNEL \
  -initrd $RAMDISK \
  -append "console=ttyAMA0 androidboot.hardware=qemu" \
  -drive file=$SYSTEM_IMG,if=none,id=system,format=raw \
  -device virtio-blk-device,drive=system \
  -drive file=$USERDATA_IMG,if=none,id=userdata,format=raw \
  -device virtio-blk-device,drive=userdata \
  -netdev user,id=net0,hostfwd=tcp::5555-:5555 \
  -device virtio-net-device,netdev=net0 \
  -nographic

小技巧:加上-nographic参数后,模拟器不启动图形界面,只通过终端交互。这对CI/CD环境特别有用。我在做自动化OTA测试时,都是这么跑的。

19.1.3 网络桥接配置

OTA测试离不开网络。QEMU默认的user模式网络,说白了就是个NAT,模拟器能上网,但外部连不进来。我们需要桥接模式。

# 创建桥接网络
sudo brctl addbr br0
sudo brctl addif br0 eth0
sudo ip addr add 192.168.1.100/24 dev br0
sudo ip link set br0 up

# QEMU启动时指定桥接网络
-netdev tap,id=net0,ifname=tap0,script=no,downscript=no \
-device virtio-net-device,netdev=net0,mac=52:54:00:12:34:56

嗯,这里要注意。桥接模式需要root权限,而且会改变主机网络配置。我在项目中遇到过,有同事不小心把网络搞断了,整个团队都连不上服务器。建议在专用测试机上操作。

19.2 Cuttlefish虚拟设备

Cuttlefish是Google官方推荐的Android虚拟设备方案。跟QEMU比,它更贴近真机体验。为什么?因为它模拟了完整的硬件抽象层(HAL),包括摄像头、传感器、GPS等。

19.2.1 环境搭建

Cuttlefish需要Linux内核支持KVM,而且对内核版本有要求。我建议用Ubuntu 22.04 LTS,内核5.15以上。

# 安装Cuttlefish依赖
sudo apt-get install -y git devscripts config-package-dev debhelper-compat golang curl

# 下载Cuttlefish源码
git clone https://github.com/google/android-cuttlefish.git
cd android-cuttlefish

# 编译安装
make
sudo make install

# 启动Cuttlefish
sudo launch_cvd --daemon

19.2.2 OTA测试专用配置

Cuttlefish最牛的地方,是支持OTA更新包的直接推送。你想想看,在真机上测试OTA,每次都要刷机、重启、等待。在Cuttlefish上,一条命令搞定。

# 生成OTA包
ota_from_target_files \
  -i target_files_old.zip \
  -o ota_update.zip \
  target_files_new.zip

# 推送到Cuttlefish设备
adb connect 10.0.2.15:6520
adb push ota_update.zip /data/ota_package/
adb shell update_engine_client \
  --update \
  --payload=file:///data/ota_package/ota_update.zip \
  --metadata_size=65536 \
  --metadata_signature=... \
  --public_key=/etc/update_engine/update-payload-key.pub.pem

注意:Cuttlefish默认使用10.0.2.15这个IP地址。如果你在Docker里跑,需要做端口映射。我曾经因为忘记映射端口,折腾了两个小时才发现问题。

19.3 HIL(硬件在环)测试台架

HIL测试,说白了就是把真实的硬件(比如ECU、T-Box)接入仿真环境。软件跑在模拟器上,但通信走真实硬件。这样既能验证软件逻辑,又能检查硬件兼容性。

19.3.1 台架架构

我画了一张图,帮你理解HIL台架的整体架构:

HIL测试台架架构图 软件仿真层 QEMU/Cuttlefish Android OTA Client Test Scripts 模拟器实例 更新引擎 Tradefed 通信接口层 CAN Bus / Ethernet ADB / Fastboot 串口 / GPIO 真实硬件层 ECU T-Box IVI 网关 传感器 发动机控制 远程通信 车载娱乐 网络路由 环境感知

19.3.2 搭建步骤

搭建HIL台架,我总结了四个步骤:

  1. 硬件选型:根据测试需求选择ECU型号。我建议用开发板级别的硬件,比如NXP的S32G系列,接口丰富,调试方便。
  2. 接口适配:把硬件的CAN、以太网、串口等接口,通过USB转接板连接到主机。注意电平匹配,我曾经烧过一个ECU的串口,就是因为没注意3.3V和5V的区别。
  3. 通信中间件:写一个适配层,把硬件接口抽象成API。比如CAN消息的收发,封装成send_can_frame()和recv_can_frame()。
  4. 测试编排:用Python或Shell脚本,编排测试流程。比如:启动模拟器→连接ECU→推送OTA包→监控升级状态→验证结果。
# HIL测试脚本示例
#!/usr/bin/env python3
import can
import subprocess
import time

# 初始化CAN接口
bus = can.interface.Bus(channel='can0', bustype='socketcan')

# 启动Cuttlefish
subprocess.run(['launch_cvd', '--daemon'])

# 等待设备就绪
time.sleep(30)

# 推送OTA包
subprocess.run(['adb', 'push', 'ota_update.zip', '/data/ota_package/'])

# 监控升级过程中的CAN消息
def monitor_can():
    while True:
        msg = bus.recv()
        if msg.arbitration_id == 0x100:  # OTA状态消息
            print(f"OTA状态: {msg.data}")
            if msg.data[0] == 0xFF:  # 升级完成
                break

monitor_can()

19.4 自动化测试框架(Tradefed)

Tradefed是Android官方的自动化测试框架。说实话,刚开始接触的时候,我觉得它挺复杂的。但用顺手之后,发现它确实强大。尤其是做OTA回归测试,Tradefed可以帮你自动跑几百个测试用例。

19.4.1 框架结构

Tradefed的核心概念就三个:

组件 作用 我的理解
Test 单个测试用例 就是你要测的那个东西
Device 测试设备抽象 可以是真机、模拟器、Cuttlefish
Invocation 一次测试执行 从开始到结束的完整流程

19.4.2 OTA测试配置

写一个Tradefed的OTA测试配置,其实不复杂。关键是把升级流程拆解成几个步骤:准备、推送、升级、验证。

<?xml version="1.0" encoding="utf-8"?>
<configuration description="OTA升级测试配置">
    <device name="device">
        <option name="serial" value="emulator-5554"/>
        <option name="type" value="cuttlefish"/>
    </device>

    <test class="com.android.tradefed.testtype.OtaTest">
        <option name="ota-package" value="/data/ota_package/ota_update.zip"/>
        <option name="pre-ota-checks" value="check_battery,check_storage"/>
        <option name="post-ota-checks" value="check_version,check_apps"/>
        <option name="timeout" value="600000"/>  <!-- 10分钟超时 -->
    </test>

    <logger class="com.android.tradefed.log.FileLogger">
        <option name="log-level" value="VERBOSE"/>
        <option name="output-file" value="/tmp/ota_test_log.txt"/>
    </logger>
</configuration>

19.4.3 运行与结果分析

配置写好了,怎么跑?一条命令搞定:

# 运行OTA测试
tradefed run config ota_test.xml

# 查看测试结果
tradefed list results

# 重新运行失败的用例
tradefed run retry --previous-session-id 12345

经验之谈:Tradefed的日志非常详细,但也很啰嗦。我习惯用grep过滤关键信息:grep -E "(FAIL|PASS|ERROR)" test_log.txt。这样一眼就能看出哪些用例没过。

19.5 环境集成与最佳实践

把上面这些环境整合起来,形成一个完整的测试流水线。我画个图帮你理解:

代码提交 Git Push 编译构建 AOSP Build OTA打包 ota_from_target_files 测试执行 Tradefed 并行测试环境 QEMU模拟器 Cuttlefish HIL台架 真机

最后,分享几个我踩过的坑:

  • 磁盘空间:QEMU和Cuttlefish的镜像文件都很大,一个镜像动辄几个GB。我建议用LVM管理磁盘,方便扩容。
  • 网络隔离:测试环境最好跟办公网络隔离。OTA测试会频繁推送大文件,容易占满带宽。我吃过这个亏,整个团队都卡得不行。
  • 日志收集:每次测试都要自动收集日志。我写了个脚本,测试结束后自动打包logcat、kernel log、Tradefed报告,存到NAS上。出了问题,直接翻日志,不用再复现。

总结一下:仿真环境搭建,说白了就是「用软件模拟硬件,用自动化替代手动」。QEMU适合快速验证,Cuttlefish适合完整功能测试,HIL台架适合硬件兼容性验证,Tradefed负责把这一切串起来。把这四样玩转了,OTA测试的效率至少提升5倍。


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