05 - DDS / SOA 调试工具
小米除主通道 CarProperty 外,还有第二通道 RTI Connext DDS(仅 8295 平台充电曲线/充电报告等高频流)。DDS 信号
dumpsys不可达、无现成 mock 命令——这是 P10(DDS 无注入入口)的根源。本篇给出”无 RTI license 也能 mock”的落地路径。解决痛点:P10 第二通道无注入入口。
⭐ 本篇直接读了项目代码,结论全部基于仓库事实。
1. 小米 DDS 现状(代码核实)
| 项 | 事实 | 源码 |
|---|---|---|
| Domain ID | DOMAIN_VEHICLE = 1 | settingsCommon/rtiLib/.../RTISignalMgr.java:33 |
| RTI 商业 jar | 已随仓库附带:nddsjava.jar/rticonnextmsg.jar/rtiroutingservice.jar 等 | settingsCommon/rtiLib/libs/ |
| 充电 Topic | HvChargingPowerInOneCycleTopic(101 float,500ms)/ ChrgnReportDataTopic | micarChargeSettings/.../RTISignalConstants.java |
| IDL 生成版本 | rtiddsgen 3.1.2(RTI Connext 6.x/7.x) | HvChargingPowerInOneCycle.java:7 |
| DataWriter 类 | 已存在可复用(rtiddsgen 自动生成) | micarChargeSettings/.../HvChargingPowerInOneCycleDataWriter.java |
| 充电报告 jar | charge-report-rti-0.0.2.jar(含 ChrgnReportData 全套 DataWriter/Reader/TypeSupport) | micarChargeSettings/libs/ |
| DDS Security | 基础设施已就绪但当前禁用(// if (isEnableSecurity())) | RtiSslDdsQosHelper.java:182-186 |
| 两条路径 | ① AIDL HAL(IChrgnReport binder,dumpsys 可达)② DDS 直连(dumpsys 不可达) | ChargingReportMgr.kt vs *Subscriber.kt |
关键判断:
- 写 Mock publisher 的全部依赖已在仓库——
nddsjava.jar+ rtiddsgen 生成的 DataWriter/TypeSupport + QoS Profile 路径。普通 dev 不需要 RTI license。 - Security 当前关闭 → 开源 DDS(Fast-DDS/Cyclone)理论可接入小米 Domain=1 总线互通。
2. 商业工具(RTI,部分小米在用)
| 工具 | 定位 | license |
|---|---|---|
| rtiddsspy | CLI 抓 DDS 总线数据(=ros2 topic echo+list) | Pro 收费 |
| Admin Console | GUI 可视化 Domain/Participant/Topic 发现树 | Pro 收费 |
| Recording Service | 录制/回放 DDS 数据(jar 已在仓库 rtiroutingservice.jar) | Pro 收费,缺 license+XML 配置 |
| Routing Service | DDS↔DDS/Kafka 桥接(jar 已在仓库) | Pro 收费 |
| ⭐RTI Connext Express | 2025 新免费版(无超时,仅实体数限制),含 rtiddsspy+Admin Console | 免费 |
强烈推荐:普通 dev 立刻申请 RTI Connext Express 免费版,调试充电曲线(1 Participant + 1 DataWriter)完全够用。
3. 开源工具(无 license 方案)
| 工具 | 定位 | 对小米可用性 |
|---|---|---|
| Fast-DDS Spy | CLI 抓 RTPS 包(跨 DDS 实现) | 中(Security 关则可行,需喂 IDL) |
| Cyclone DDS Insight | GUI 看拓扑/发现(不需 IDL) | 中(看”谁在发/谁在订”很实用) |
| cyclonedds-python | Python 绑定,10 行发一个 sample | 高(PC 端 Mock 备选) |
| Fast-DDS Monitor | GUI 监控 | 低(只看 Fast-DDS 自家 participant,听不到 RTI) |
| Wireshark RTPS dissector | 抓 DDS 网络包(内置) | 高(首选诊断:先确认 RTPS 包在不在) |
互通性结论:RTI/Fast-DDS/Cyclone 都走 OMG RTPS 标准;小米 Security 当前关闭 → 开源 DDS 可接入。风险:一旦启用 /data/vendor/rtidds/SOASecurityEnable.cfg,开源方案全失效。
4. ⭐ 最实用方案:自写 Mock 发布者(复用项目已有依赖)
核心思路:项目已带
nddsjava.jar,rtiddsgen 已生成HvChargingPowerInOneCycleDataWriter.java——直接组装,~50 行 Kotlin 即可驱动整个充电曲线订阅链路。
方案 A(强烈推荐):Kotlin/Java Mock,放 src/debug/
最小骨架(micarChargeSettings/src/debug/kotlin/.../MockHvChargingPublisher.kt):
object MockHvChargingPublisher {
private const val DOMAIN_ID = 1 // 与 RTISignalMgr.DOMAIN_VEHICLE 一致
private var writer: HvChargingPowerInOneCycleDataWriter? = null
fun start() {
val factory = DomainParticipantFactory.get_instance()
// ⚠️ 必须加载设备机 QoS:adb pull /vendor/etc/micar_mw_configs/rtidds_qos/MICAR_QOS_PROFILES.xml
val participant = factory.create_participant(
DOMAIN_ID, DomainParticipant.PARTICIPANT_QOS_DEFAULT,
null, StatusKind.STATUS_MASK_NONE)
HvChargingPowerInOneCycleTypeSupport.register_type(participant, null) // 复用 rtiddsgen 输出
val topic = participant.create_topic(
RTISignalConstants.TOPIC_HV_CHARGING_POWER_IN_ONE_CYCLE,
HvChargingPowerInOneCycleTypeSupport.get_type_name(), /*...*/)
val pub = participant.create_publisher(Publisher.PUBLISHER_QOS_DEFAULT, null, 0)
writer = pub.create_datawriter(topic, Publisher.DATAWRITER_QOS_DEFAULT, null, 0)
as HvChargingPowerInOneCycleDataWriter
}
/** 发一条假曲线:101 float 从 0 升到 100 */
fun publishFakeCurve() {
val sample = HvChargingPowerInOneCycle().apply {
vcuHVExtPortEgyTrfActPwr = FloatSeq(101)
for (i in 0 until 101) vcuHVExtPortEgyTrfActPwr.add(i * 1.0f)
}
writer!!.write(sample, InstanceHandle_t.HANDLE_NIL)
}
}注意事项:
- 必须加载设备机的
MICAR_QOS_PROFILES.xml(adb pull),否则 QoS 不匹配报INCONSISTENT_POLICY。 - 同进程自收自发问题:
RTISignalMgr.java:36注释提到订阅自己发布的 Topic 需用不同 DP。 - 写在
src/debug/避免进 release 包;配一个隐藏 Debug Activity 触发(仅 xcdDebug flavor)。
方案 B:Python + cyclonedds(PC 端发,设备机收)
pip install cyclonedds,需 IDL→Python 转换 + PC 与设备机网络互通。
5. 小米 DDS 调试推荐路径(按场景分流)
| 场景 | 方案 | 成本 |
|---|---|---|
| 快速确认”总线上有没有数据” | adb shell tcpdump -i any udp port 7400 -w dds.pcap + Wireshark RTPS | 0 |
| 看拓扑/发现(谁在发谁在订) | RTI Express 免费版 Admin Console,或 Cyclone Insight | 0 |
| 驱动订阅链路端到端调试(核心痛点) | ⭐方案 A:复用 nddsjava.jar + DataWriter,写 MockHvChargingPublisher | 0.5 人日 |
| 录制充电过程回放 | Recording Service(jar 已在仓库,缺 license+XML);无 license 则自写录制器 | 中 |
| 实时曲线可视化 | 不推荐 Foxglove/MCAP(太重),直接 App 内加 Debug Fragment 画 Canvas | 小 |
6. 风险与局限
- DDS Security 启用(
/data/vendor/rtidds/SOASecurityEnable.cfg)会让所有开源互通方案失效——需持续跟踪。 - Mock publisher 只能 mock 发布端(模拟车端 SOA 推数据),消费端(App 订阅)逻辑仍要靠真实数据或 Mock 驱动。
- 充电报告走 AIDL HAL 路径时,用
dumpsys即可调试,不必走 DDS Mock——先确认走哪条路径。
7. 立即 Action Items
- ⭐ adb pull
MICAR_QOS_PROFILES.xml到工程 debug 资源(0) - 在
micarChargeSettings加src/debug/写MockHvChargingPublisher(0.5 人日)——解决 P10 - 加隐藏 Debug Activity 触发 Mock(仅 xcdDebug flavor)(0.5 人日)
- 下载 RTI Connext Express 免费版(0)
- PC 装 Wireshark 验证 RTPS 抓包通路(0.5 小时)
一句话:小米已把 Mock publisher 所需全部依赖打进工程,普通 dev 无需 RTI license,加 ~50 行 Kotlin 即可解决”DDS 信号无法 mock”痛点。