车辆信号调试 Q&A — CarService 与 VHAL

📌 快速导航: 查看 Android 信号 Log 方法 查看 Qnx-CarService 信号 Log 方法

1、Android CarService 调试

1.1 辅助测试用 APP(代码仓库

📎 附件:CarDemo4Test.apk(见下文网盘地址,亦可从 Daily Build 获取)

adb install -t -g CarDemo4Test.apk
 
# APP 中打开 Mock 时候点击,和命令行注入等效
# 注入雨刮速度为 间歇高速 (Body#WIPER_SPEED_MODE)
adb shell dumpsys car_service inject-vhal-event 0x63401301 1 2
# 注入雨刮维修模式为 ON (Body#WIPER_SERVICE_MODE)
adb shell dumpsys car_service inject-vhal-event 0x63401302 1 1

开发人员可以直接拉取代码,来更新 App(代码仓库 更新 vehicle.support 版本即可,界面是依赖信号自动生成的)。

📷 [图片:CarDemo app 模块 build.gradle,dependencies 中 implementation ‘com.carveicle.support:0.1.1-SNAPSHOT’ 红色下划线标注]

  • 其他 Mock 功能仅适用于信号通路完成前,debug 使用,切勿在车辆设备上使用。8295 上默认 Mock 关闭,pad 上默认开启。目前所有设备在开机后会保持默认状态(以防有人忘了清理配置)(提交
# enable mock,仅为在通路不可用时,测试 APP 使用
adb shell settings put --user 0 GLOBAL vehicle_mock_data 1
# disable mock,切换至正常模式
adb shell settings put --user 0 GLOBAL vehicle_mock_data 0

网盘地址(可用附件):

1.2 通过 shell cmd 注入

# 下行 prop
# adb shell dumpsys car_service publish-vhal-event [propid] [areaid] [value]
# 例如,下发左一【areid=1】车门【prop=0x66403101】打开【value=1】
adb shell dumpsys car_service publish-vhal-event 0x66403101 1 1
 
# 如果信号为 global 类型,无 areaid,则 areaid 可不写,或填 0;
# 例如,打开【value=1】后视镜加热【prop= 0x61401106】
adb shell dumpsys car_service publish-vhal-event 0x61401106 1
adb shell dumpsys car_service publish-vhal-event 0x61401106 0 1
 
# geteventa
adb shell dumpsys car_service get-property-value 0x61401106 1

1.2.1 通过工具和 log 生成模拟注入命令

模拟信号脚本

📎 附件:LogPropMonitor.py(模拟信号脚本,见原文档附件)

# 解析 log,并执行模拟
python LogPropMonitor.py xxxx.log
# 将 log 中模拟命令转储为 cmd_list.sh 文件
python LogPropMonitor.py xxxx.log --save_only
# 将 log 中模拟命令转换为 cmd_list.sh 文件,并执行
python LogPropMonitor.py xxxx.log --output output.sh --exec

1.3 Android CarService Log

1.3.1 推荐!!查看 Android 信号完整链路 Log(AndroidCarService + VHAL)

# 通过信号 PropID(PropID 列),如:
# 查看整车电源模式,信号 PropID 为 0x61407207
adb logcat | grep -i 0x61407207

💡 如何正确找到 PropID? 可通过 DBC 定义的信号名在 SOA 表格里检索,比如: 整车电源模式的 DBC 信号名称为 “PwrModSts”,则在 SOA 表格搜索该名称,即可定位到 “Driving” sheet 中的一行,然后查看对应的 PropID 列即可。 如存在检索不到的,有可能是 SOA 表格更新不及时导致的,请联系 @宋自力 @姚鹏 @张佃伦 任何一位即可。

示例:

🍥 执行 adb logcat | grep 0x61407207 显示结果:

01-01 09:13:30.371   519   662 D vendor.micar.hardware.vehicle@1.0-service: [MiVehicleClient.cpp] onMiCarPropertyValue# On micar prop: {.timestamp=4402014747794, .prop=BASIC_INFO_POWER_MODE(0x61407207), .areaId=0x0, .status=AVAILABLE, .value={.int32Values = [1]{0}, .floatValues = [0]{}, .int64Values = [0]{}, .bytes = [0]{}, .stringValue = ""}}
01-01 09:13:30.379  1410  1502 I MiCarPropertyService: onPropertyChange: CarPropertyValue{name=Driving#POWER_MODE, mPropertyId=0x61407207, mAreaId=0x0, mStatus=0, mTimestamp=4402014747794, mValue=0}

其中 MiVehicleClient.cpp 为 VHAL 的 Log,MiCarPropertyService 为 AndroidCarService 的 Log。 Log 的具体释义:1.3.2 及 2.4 章节

1.3.2 查看 AndroidCarService Log

# 使用命令
adb logcat | grep MiCarPropertyService

🍥 下行 Log 例子

2022-08-29 17:53:34.050 1424-1773/com.android.car I/MiCarPropertyService: setProperty: CarPropertyValue{name=Body#COCKPIT_POWER_MODE_REPORT, mPropertyId=0x6141171a, mAreaId=0x0, mStatus=0, mTimestamp=0, mValue=[1, 0]}

上行 Log 例子

2022-08-29 17:53:37.491 1424-3436/com.android.car I/MiCarPropertyService: onPropertyChange: CarPropertyValue{name=Driving#NAVIGATE_VISION_OVER_SPEED_TRIGGER, mPropertyId=0x61407709, mAreaId=0x0, mStatus=0, mTimestamp=17065965565, mValue=0}

释义:

  • name 表示其 Java API
  • mPropertyIdmAreaId 是传输用的 propId 以及 areaId,均为 16 进制
  • mStatus 的取值范围为 STATUS_AVAILABLE(0) / STATUS_UNAVAILABLE(1) / STATUS_ERROR(2)
  • mValue 为具体值
  • mTimestamp 为该信号产生的开机纳秒时间(SystemClock#elapsedRealtimeNanos)

2、Android VHAL 调试

2.1 如何替换 VHAL

⚠️ 平台差异(2026-07 更新):VHAL 已从 HIDL 迁移到 AIDL,二进制名随平台不同:

  • 旧平台(E3 等,HIDL):vendor.micar.hardware.vehicle@1.0-service
  • 新平台(newton / YU7 等,AIDL):vendor.micar.hardware.vehicle@2.0-service

替换前务必先确认本机实际文件名,不要照抄版本号(newton 上不存在 @1.0-service)。

adb root
adb remount
# 先确认本机 VHAL 文件名(newton=@2.0-service,旧 E3=@1.0-service)
adb shell ls -la /vendor/bin/hw/vendor.micar.hardware.vehicle@*-service
 
# 以下以 newton(@2.0-service)为例:
adb shell mv /vendor/bin/hw/vendor.micar.hardware.vehicle@2.0-service /vendor/bin/hw/vendor.micar.hardware.vehicle@2.0-service-bak
adb push vendor.micar.hardware.vehicle@2.0-service /vendor/bin/hw
adb shell sync
adb reboot
# 重新上电
# 或者找到 vhal 的 pid,kill 后进程会重启

2.2 VHAL 调试命令(dumpsys)

⚠️ 重要变更(2026-07 更新,源码核实):新平台(newton / YU7 等)VHAL 已迁移到 AIDLlshal debug(HIDL 工具)已彻底失效。 实测 lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/...Invalid fully-qualified name——lshal 只认 HIDL 格式(pkg@ver::IFoo/inst),AIDL 接口从设计上就不走它。 调试入口改为 dumpsys android.hardware.automotive.vehicle.IVehicle/micar

先做平台判定

adb shell service list | grep automotive.vehicle
# 输出 android.hardware.automotive.vehicle.IVehicle        → AIDL(newton / 大多数新平台)→ 用 dumpsys
# 输出 android.hardware.automotive.vehicle@2.0::IVehicle   → HIDL(suiren / YU7 等老平台)→ 用 lshal
旧(HIDL,老平台)新(AIDL,newton / YU7)
lshal debug android.hardware.automotive.vehicle@2.0::IVehicle[/micar]dumpsys android.hardware.automotive.vehicle.IVehicle/micar

实例名:IVehicle/micar(micar 车控,3951 prop)/ IVehicle/default(AOSP 标准,223 prop)。车控调试用 /micar。 源码:子命令解析在 vendor/micar/.../hal-impl/service/common/MiVehicleClient.cpp:501-516只支持 3 个子命令

① 读 prop(--get,自动遍历所有 area,无副作用):

# 看 service 总览(属性数 / client 数 / 接口版本)
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar
# 读单个 prop(自动列出该 prop 所有 area 的值)
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar --get 1715482881
# 读多个 prop
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar --get 1715482881 289408000

② 下行设置 prop(--set,真实写入并下发到车端,谨慎使用):

#    -i / -i64 / -f 接多值(向量);-s / -b / -a / -t 各 1 个
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar --set 1715482881 -i 1 -a 16
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar --set 0x11400400 -i 1 2 3 -a 1
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar --set 0x12345678 -b 0xDEADBEEF -a 1

③ 上行注入伪造车端事件(--mock_from_car,不真写源,只扇出给订阅者):

#    每个 flag 只接 1 个值(多值需重复 flag);--stat 0=AVAILABLE / 1=UNAVAILABLE / 2=ERROR;timestamp 自动
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar --mock_from_car 1715482881 -i 1 -a 16 --stat 0
# bytes 数组
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar --mock_from_car 0x6170b40d -b 0x123456
# 多个 int32(重复 -i)
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar --mock_from_car 0x6141415c -i 1 -i 1

⚠️ --set--mock_from_car-i/-f 行为不同:前者接多值,后者每 flag 只接一值。 -h / --help 永远空输出(源码无 help 分支,未知子命令直接返回空)。 已废弃(AIDL 已删,勿用):--mock_set_enable--log_optional_enable--manager--rebuild_connection

dumpsys micar_property(推荐查配置,信息最全): 走框架属性层,dump 全部 ~3951 个 VehiclePropConfig(prop ID / access / area / 合法取值范围)。子命令:inject-vhal-event / get-property-value / set-property-value / list-vhal-props / get-carpropertyconfig(详见《MiCarPropertyService 接入文档》)。

⑤ 车端原始信号流:

adb shell milogcat -s CARSIGNAL    # milogcat 即 logcat 封装,过滤 CARSIGNAL tag

注:user 版系统下 cmd car_service 的交互式 get/set 会被 SecurityException 拦截(需 userdebug/eng 版);VHAL 层 dumpsys ... --get / --mock_from_car 不受此限。

2.3 native get/set/sub 例子

2.4 Android VHAL Log

  • 查看方法 1:

📷 [图片:查看 VHAL 服务进程及日志示例 — 上方 ps -e | grep micar 显示 vendor.micar.hardware.vehicle@1.0-service 进程,下方 logcat -pid 5407 输出该服务日志含初始化信息及各节点 GRPC 服务名称]

  • 查看方法 2:
# 执行命令;上行信号会过滤重复值,即只打印变化的信号
# VHAL 目前 LOG 默认等级为 D,可以更改为 V 来展示更多详情
adb shell setprop log.tag.MiVehicleClient V
adb logcat | grep -i MiVehicleClient

🍥 下行例子

08-30 15:18:23.782  1053  1053 D vendor.micar.hardware.vehicle@1.0-service: [MiVehicleClient.cpp] setProperty# Set micar prop: {.timestamp=191923783154, .prop=DOOR_STATE(0x66403101), .areaId=0x10, .status=AVAILABLE, .value={.int32Values = [1]{1}, .floatValues = [0]{}, .int64Values = [0]{}, .bytes = [0]{}, .stringValue = ""}}

上行例子

01-01 08:01:11.085   521  1018 V vendor.micar.hardware.vehicle@1.0-service: [MiVehicleClient.cpp] onPropertyValueReceived# Handle received prop: {.timestamp=62724916274, .prop=BASIC_INFO_POWER_MODE(0x61407207), .areaId=0x0, .status=AVAILABLE, .value={.int32Values = [1]{1}, .floatValues = [0]{}, .int64Values = [0]{}, .bytes = [0]{}, .stringValue = ""}}

释义:

  • .timestamp 表示其上行或下行触发时间
  • .prop 表示信号名以及 propId
  • .areaId 是传输用的 areaId,均为 16 进制
  • .status 的取值范围为 AVAILABLE(0) / UNAVAILABLE(1) / ERROR(2)
  • .value 为具体值

2.5 更多 LOG

# VHAL 收到 QNX 的消息可以通过以下命令打开,不会过滤重复信号
adb root
adb shell dumpsys android.hardware.automotive.vehicle.IVehicle/micar --log_optional_enable 1

🍥

01-01 08:01:11.085   521  1018 V vendor.micar.hardware.vehicle@1.0-service: [MiVehicleClient.cpp] onPropertyValueReceived# Prop received: {.timestamp=62724916274, .prop=BASIC_INFO_POWER_MODE(0x61407207), .areaId=0x0, .status=AVAILABLE, .value={.int32Values = [1]{1}, .floatValues = [0]{}, .int64Values = [0]{}, .bytes = [0]{}, .stringValue = ""}}

3、QNX CarService

3.1 替换 carservice

adb root
adb remount
adb push carservice /mnt/nfs
adb shell sync
 
# 登录到 qnx
adb shell
busybox telnet 192.168.8.1
 
# 备份原有 carservice,然后覆盖
mv /emmc/svp/bin/carservice /emmc/svp/bin/carservice-bak
mv /var/share/carservice /emmc/svp/bin
cd /emmc/svp/bin
chmod 755 carservice
 
# 重新上电,或者执行以下命令进行手动启动 carservice
slay carservice  # 杀掉原有进程
export LD_LIBRARY_PATH=/emmc/svp/lib:$LD_LIBRARY_PATH
./carservice

3.2 carservice log

qnx 下通过下面命令抓取 carservice 日志。

💡 注意:添加日志只允许添加 debug/warn/error

# 查看 carservice 的所有 Log
tail -f /var/log/qnx/slog2/high_rate/carservice_1.log | grep carservice
 
# 查看具体某个信号的相关 Log
tail -f /var/log/qnx/slog2/high_rate/carservice_1.log | grep -i 0x61407207

示例:

上行:

🍥

[carservice]: pps data received, messageid = 7353, function id = 254, command id = 6, data len = 3
[carservice]: [1, 0, 0]
[carservice]: PipelineParser find index:VCUPrpsnPwrForDisp,raw data size:2
[carservice]: process signal:VCUPrpsnPwrForDisp
[carservice]: func process--out value:65535,task size:1
[carservice]: proper id:7007742998922395648
[carservice]: PipelineParser int receive data,0,status:0
[carservice]: EnergyService publish prop=1631617313,area_id=0, value=0
[carservice]: PipelineParser find index:VCURgnPwrForDisp,raw data size:2
[carservice]: process signal:VCURgnPwrForDisp
[carservice]: func process--out value:65535,task size:1
[carservice]: proper id:7007743003217362944
[carservice]: PipelineParser int receive data,0,status:0
[carservice]: EnergyService publish prop=1631617314,area_id=0, value=0
[carservice]: PipelineParser find index:VCUSpdLimDisp,raw data size:2
[carservice]: process signal:VCUSpdLimDisp
[carservice]: func process--out value:255,task size:1
[carservice]: proper id:7007729800487895040
[carservice]: PipelineParser int receive data,255,status:0
[carservice]: DrivingService publish prop=0x61407520,area_id=0, value=255, status=0, value_size=1

下行:

🍥

[carservice]: ---------HandleVehicleRequest [prop = 1631614729 area_id= 0 value = 0]---------
[carservice]: transfer final signalName is:DCDTSASlifSpdDisp,value:0
[carservice]: PpsPubExecutor send to pps ok.

日志使用方式:

#include <log/logging.hpp>
 
INFO("start carservice process");
 
DEBUG("test %d",5);

4、XCD 替换 MiVehicleService 方式

  1. adb root
  2. adb remount
  3. adb shell
  4. umount -l /system/priv-app/ 如果失败,重启 xcd 然后继续
  5. adb push MiVehicleService.apk /system/priv-app/MiVehicleService/
  6. 重启