19、测试与调试:模拟器(Emulator)使用,VHAL 模拟器调试,车载测试框架

说实话,做车载开发最头疼的是什么?不是代码写不出来,而是你写完了没法跑。车机不像手机,你不可能每次改个逻辑都去车上试。所以这一章,我重点聊聊怎么在模拟器上把活儿干利索。

我个人习惯,拿到一个新项目,第一件事不是看代码,而是先把模拟器跑起来。为什么?因为模拟器能帮你把环境问题提前暴露掉。你想想看,要是等到真车调试才发现环境不对,那代价就大了。

19.1 模拟器(Emulator)的使用

Android Automotive 的模拟器,说白了就是一套专门为车载场景定制的 AVD(Android Virtual Device)。它跟手机模拟器最大的区别在于:它模拟了车载特有的硬件接口,比如 VHAL、车载网络、多屏显示等。

19.1.1 创建车载模拟器

在 Android Studio 里创建车载模拟器,步骤其实不复杂:

  1. 打开 AVD Manager,点击 "Create Virtual Device"
  2. 在 Category 里选择 "Automotive"
  3. 选择一个合适的系统镜像(建议用 API 30 以上)
  4. 配置模拟器参数,比如内存、存储空间
我的小建议: 内存至少给 2GB,存储给 8GB 以上。车载系统比手机重,配置低了容易卡。

19.1.2 启动模拟器的常用命令

我一般不用 Android Studio 的图形界面启动,而是用命令行。为什么?因为命令行可以加很多调试参数。

# 启动车载模拟器
emulator -avd Automotive_AVD_API_30 \
  -netdelay none \
  -netspeed full \
  -gpu host \
  -memory 2048 \
  -wipe-data

# 带 VHAL 调试端口启动
emulator -avd Automotive_AVD_API_30 \
  -qemu -serial tcp::5554,server

这里有个坑,我曾经遇到过:如果不加 -gpu host,模拟器的渲染会非常慢,尤其是多屏场景下,卡得你怀疑人生。

19.2 VHAL 模拟器调试

VHAL(Vehicle Hardware Abstraction Layer)是车载系统的核心。说白了,它就是车机和硬件之间的翻译官。你在模拟器里调试 VHAL,其实就是模拟各种车辆信号。

19.2.1 VHAL 模拟器的工作原理

模拟器里的 VHAL 实现,其实是一个虚拟的硬件抽象层。它通过一个叫 VehicleHal 的接口,模拟了车辆的各种属性(Property)。比如车速、转向灯、空调温度等。

我画了一张图,帮你理解这个流程:

VHAL 模拟器调试流程 车载应用 CarService VHAL(模拟器实现) 虚拟车辆硬件 VHAL 调试工具 模拟信号注入

19.2.2 使用 VHAL 调试工具

Android 提供了一个叫 vhal_emulator 的工具,专门用来模拟车辆信号。我常用的命令是这样的:

# 启动 VHAL 模拟器调试模式
adb shell vhal_emulator

# 设置车速为 60 km/h
setprop vendor.vehicle.property.VEHICLE_SPEED 60

# 模拟转向灯开启
setprop vendor.vehicle.property.TURN_SIGNAL_ON 1
重要提醒: VHAL 的属性值是有范围限制的。比如车速不能超过 255 km/h,转向灯只有 0 和 1 两种状态。设置超出范围的值,系统会直接忽略。

19.2.3 调试 VHAL 的常见问题

我在项目里遇到过几个典型问题,分享给你:

  • 属性值不生效: 检查一下是不是权限问题。有些属性需要系统级权限才能修改。
  • 模拟器卡死: 多半是内存不够。我建议把模拟器的 heap 调到 512MB 以上。
  • 信号延迟: 模拟器毕竟不是真车,信号会有 100-200ms 的延迟。这个在调试时要注意。

19.3 车载测试框架

车载测试跟普通 App 测试不一样。你不仅要测功能,还要测各种车辆状态下的表现。比如车速变化时,导航界面会不会卡顿?空调温度调节时,动画是否流畅?

19.3.1 测试框架的层次结构

Android Automotive 的测试框架,大致分三层:

层次 测试内容 常用工具
单元测试 单个组件、单个方法 JUnit, Mockito
集成测试 组件间交互、VHAL 通信 Android Test, Espresso
系统测试 整车场景、多屏交互 CTS, VTS, 自定义脚本

19.3.2 编写车载测试用例

我写测试用例时,习惯先模拟车辆状态,再验证 UI 表现。举个例子:

@Test
public void testSpeedChangeUpdatesUI() {
    // 模拟车速变化
    VehicleHAL.setProperty(VehicleProperty.PERF_VEHICLE_SPEED, 80);

    // 等待 UI 更新
    onView(withId(R.id.speed_display))
        .check(matches(withText("80 km/h")));

    // 验证动画是否流畅
    assertTrue(isAnimationSmooth());
}
注意: 车载测试里,千万不要用 Thread.sleep() 来等待。车辆信号是异步的,用 IdlingResource 或者 CountDownLatch 更靠谱。

19.3.3 自动化测试脚本

我一般会写一套自动化脚本,用来跑回归测试。脚本里会模拟各种驾驶场景:

#!/bin/bash
# 车载自动化测试脚本

echo "开始测试:高速场景"
adb shell vhal_emulator --speed 120
sleep 2
# 检查导航是否正常
adb shell am instrument -w com.example.car.test/androidx.test.runner.AndroidJUnitRunner

echo "开始测试:停车场景"
adb shell vhal_emulator --speed 0
sleep 1
# 检查停车辅助功能
adb shell am instrument -w com.example.car.parking.test/androidx.test.runner.AndroidJUnitRunner

19.4 调试技巧与避坑指南

做车载调试这几年,我踩过不少坑。挑几个典型的说说:

  • 模拟器网络问题: 有时候模拟器连不上网,检查一下是不是代理设置的问题。我一般用 adb shell settings put global http_proxy :0 清掉代理。
  • 多屏调试: 车载系统通常有多个屏幕。调试时记得用 adb shell dumpsys display 查看屏幕信息。
  • 日志过滤: 车载系统的日志量很大。我习惯用 adb logcat -s CarService VehicleHal 只过滤关键模块。
我的小技巧: 调试 VHAL 时,可以开两个终端窗口。一个跑模拟器,一个跑日志。这样能实时看到属性变化对应的日志输出,排查问题快很多。

嗯,这一章的内容差不多就这些。模拟器调试和测试框架,说白了就是让你在没车的情况下也能干活。记住一点:模拟器能解决的问题,尽量不要等到真车上去试。成本差太多了。


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