11 - 调试与验证手段
本篇讲开发阶段如何无车调试信号功能:注入假信号、查配置、看日志、定位”信号不生效/收不到”。
1. 调试入口总览
| 目的 | 工具 | 命令 |
|---|---|---|
| 查信号配置(是否支持/取值范围) | 框架属性服务 | dumpsys micar_property |
| 真实读写车端 | VHAL 直连 | dumpsys android.hardware.automotive.vehicle.IVehicle/micar --get/--set |
| 注入假信号(模拟车端上报) | VHAL 直连 | ... --mock_from_car <PROP> -i <VAL> --stat 0 |
| CarService 层注入 | car_service | dumpsys car_service publish-vhal-event |
| 开 Mock 模式 | settings | settings put global mi_vehicle_mock_data 1 |
| 开调试日志 | settings | settings put global vehicle_debug_enable 1 |
| 看车端原始信号 | milogcat | adb shell milogcat -s CARSIGNAL |
| 按 propId 搜日志 | logcat | `adb logcat |
2. 查信号配置(是否支持)
框架属性层(推荐)——服务名 micar_property:
adb shell dumpsys micar_property子命令:
dumpsys micar_property list-vhal-props # 列全部约 3951 个 VehiclePropConfig
dumpsys micar_property get-carpropertyconfig <0xPROP> # 查某信号的配置(access/changeMode/areaType/取值范围)
dumpsys micar_property get-property-value <0xPROP> # 读当前值
dumpsys micar_property check-fake-vhal # 是否在 mock 模式
dumpsys micar_property get-vhal-backend # VHAL 后端类型这一步能确认”这台车到底支不支持这个信号、支持到什么程度”。如果
get-carpropertyconfig查不到,说明该机型不支持,UI 应隐藏。
3. VHAL 直连(真实读写车端 + 注入假信号)
服务名:android.hardware.automotive.vehicle.IVehicle/micar(AIDL 平台,newton/yu7/海外)或 @2.0::IVehicle(HIDL 平台,Android 12/CN)。
判定平台:
adb shell service list | grep automotive.vehicle
# IVehicle(无版本号)= AIDL → 用 /micar
# @2.0::IVehicle = HIDL调试三子命令(源码 MiVehicleClient.cpp:501-516,只支持这三个):
3.1 --get 读
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar \
--get 0x66403101
# 自动遍历所有 area3.2 --set 真实下发
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar \
--set 0x65404101 -i 1 -a 1
# -i int 值;-i64 long;-f float;-s string;-b byte;-a area;-t 多值
# ⚠️ --set 会真实写入并下发车端3.3 --mock_from_car 注入假上报(开发自测首选)
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar \
--mock_from_car 0x65404101 -i 1 -a 1 --stat 0
# 不真写源、只扇出给订阅者,模拟"车端上报"
# --stat 0/1/2 = AVAILABLE / UNAVAILABLE / ERROR这是无车调试的核心:用
--mock_from_car模拟车端上报,验证 App 的onPropertyChanged是否触发、UI 是否刷新。
已废弃命令(别用):--mock_set_enable、--log_optional_enable、--manager、--rebuild_connection、-h/--help(永远空输出)。
4. CarService 层注入
# 下行(模拟 App 下发)
adb shell dumpsys car_service publish-vhal-event <PROP> <AREA> <VALUE>
# 读值
adb shell dumpsys car_service get-property-value <PROP> <AREA>
# 注入(模拟车端上报到 CarService 层)
adb shell dumpsys car_service inject-vhal-event <PROP> <AREA> <VALUE>⚠️ user 版限制:
cmd car_service的 get/set 在 user 版会被SecurityException拦截(需 userdebug/eng)。VHAL dumpsys 不受限。
5. Mock 模式开关
# 开 Mock(开机默认关闭;8295 默认关,pad 默认开)
adb shell settings put global mi_vehicle_mock_data 1
# 开调试日志
adb shell settings put global vehicle_debug_enable 16. 日志定位
6.1 按 propId 搜日志(最有效)
propId 在日志里以 0x<hex> 或十进制出现。按 hex 搜能同时看到 VHAL 和 CarService 两层:
adb logcat | grep 0x654041016.2 关键 Tag
| Tag | 层 | 内容 |
|---|---|---|
MiVehicleClient | VHAL(C++) | 底层 get/set/mock |
MiCarPropertyService | CarService | onPropertyChange: CarPropertyValue{...} / setProperty: CarPropertyValue{...} |
PropServer-* | MiCar 服务端 | mi_property 链路 |
PropSDK-* | MiCar SDK 端 | MiCarPropertySDK 链路 |
VehicleControlManager | App(项目) | set 是否打印 |
CarPropertyCacheManager | App(项目) | 上报是否到达、注册去重 |
SettingsCarPropertyEventCallback | App(项目) | 信号回弹分发 |
CARSIGNAL | 车端原始 | adb shell milogcat -s CARSIGNAL |
6.3 MiCarPropertyService 日志格式
MiCarPropertyService: onPropertyChange: CarPropertyValue{name=…, mPropertyId=…, mAreaId=…, mStatus=…, mTimestamp=…, mValue=…}
MiCarPropertyService: setProperty: CarPropertyValue{…}
6.4 项目内的常见警告(踩坑信号)
| 警告 | 原因 |
|---|---|
"un-excepted observe propId" | propId 没注册进 observedSet,onPropertyChanged 不回调(见 02 篇 §6.6) |
| 超时日志 | 下发后超时未回弹,检查 VehiclePropertyConfig.sCustomTimeoutValue 阈值 |
7. status 枚举(小米扩展)
读日志时识别 status:
| 值 | 含义 |
|---|---|
| 0 | STATUS_AVAILABLE(可用) |
| 1 | STATUS_UNAVAILABLE(不可用) |
| 2 | STATUS_ERROR(错误) |
| 4 | STATUS_TIMEOUT(小米新增) |
| 5 | STATUS_TIMEOUT_UNAVAILABLE(小米新增) |
原生 AAOS 把 timeout 和 unavailable 合并了,E4 起区分。判断可用必须
== 0,不要!= 1。
8. 无车自检流程(端到端验证)
新写了一个信号功能,没车怎么验证?
1. 编译通过(dcd + xcd 两个 flavor)
./gradlew :app:assembleDcdDebug
./gradlew :app:assembleXcdDebug
2. 安装到设备/模拟器,进入目标页面
3. 确认 Controller 实例化
adb logcat | grep <ControllerName>
→ 看到 onCreateInternal
4. 确认 CarService 连接
adb logcat | grep onPropertyManagerPrepared
→ 看到 ready
5. 确认注册成功
adb logcat | grep CarPropertyCacheManager
→ 看到 propId 注册
6. 注入假信号(模拟车端上报)
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar \
--mock_from_car 0x<PROP> -i <VAL> --stat 0
→ 观察 UI 是否刷新到 VAL
7. 点击 UI(模拟用户下发)
adb logcat | grep VehicleControlManager
→ 看到 set 打印
→ 如果有车端回弹,观察 CarPropertyCacheManager 是否收到
8. 验证超时回滚
下发后不注入回弹,等超时
→ UI 应自动回退到上一态(restorePropertyToPrevious)
9. 常见问题诊断
9.1 信号收不到
| 排查 | 方法 |
|---|---|
| 机型是否支持 | dumpsys micar_property get-carpropertyconfig 0x<PROP> |
| propId 是否在 observedSet | 搜 "un-excepted observe propId" 警告 |
| CarService 是否 ready | 搜 onPropertyManagerPrepared |
| 注册是否成功 | 搜 CarPropertyCacheManager |
| 下行/上行 ID 是否一致 | 检查 VehiclePropertyConfig.sTimeoutSignalMapping |
9.2 下发不生效
| 排查 | 方法 |
|---|---|
| 是否被超时回滚 | 搜 onSetPropertyTimeout |
| 权限是否够 | user 版 cmd car_service 会被拦 |
| 车端是否真的收到 | milogcat -s CARSIGNAL |
| 值是否合法 | 对照 sSpecialSupportedPropValues 白名单 |
9.3 UI 闪烁/首帧错误
| 排查 | 方法 |
|---|---|
| 是否吃了首帧缓存 | VehiclePermanentListener.getCachePropertyValue 是否返回初值 |
| 首次 get 是否做了 | getPropValueForFirstCache 兜底前提 |
| 多 Controller 互相干扰 | 检查 areaId 过滤 |
10. 关键命令速查卡
# ===== 查配置 =====
adb shell dumpsys micar_property get-carpropertyconfig 0x<PROP>
# ===== 注入假信号(开发自测首选)=====
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar \
--mock_from_car 0x<PROP> -i <VAL> -a <AREA> --stat 0
# ===== 真实下发(慎用)=====
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar \
--set 0x<PROP> -i <VAL> -a <AREA>
# ===== 开 Mock / 日志 =====
adb shell settings put global mi_vehicle_mock_data 1
adb shell settings put global vehicle_debug_enable 1
# ===== 搜日志 =====
adb logcat | grep 0x<PROP>
adb shell milogcat -s CARSIGNAL
# ===== 判定平台 =====
adb shell service list | grep automotive.vehicle