05 - DDS / SOA 调试工具

小米除主通道 CarProperty 外,还有第二通道 RTI Connext DDS(仅 8295 平台充电曲线/充电报告等高频流)。DDS 信号 dumpsys 不可达、无现成 mock 命令——这是 P10(DDS 无注入入口)的根源。本篇给出”无 RTI license 也能 mock”的落地路径。

解决痛点:P10 第二通道无注入入口

⭐ 本篇直接读了项目代码,结论全部基于仓库事实。


1. 小米 DDS 现状(代码核实)

事实源码
Domain IDDOMAIN_VEHICLE = 1settingsCommon/rtiLib/.../RTISignalMgr.java:33
RTI 商业 jar已随仓库附带:nddsjava.jar/rticonnextmsg.jar/rtiroutingservice.jarsettingsCommon/rtiLib/libs/
充电 TopicHvChargingPowerInOneCycleTopic(101 float,500ms)/ ChrgnReportDataTopicmicarChargeSettings/.../RTISignalConstants.java
IDL 生成版本rtiddsgen 3.1.2(RTI Connext 6.x/7.x)HvChargingPowerInOneCycle.java:7
DataWriter 类已存在可复用(rtiddsgen 自动生成)micarChargeSettings/.../HvChargingPowerInOneCycleDataWriter.java
充电报告 jarcharge-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

关键判断

  1. 写 Mock publisher 的全部依赖已在仓库——nddsjava.jar + rtiddsgen 生成的 DataWriter/TypeSupport + QoS Profile 路径。普通 dev 不需要 RTI license
  2. Security 当前关闭 → 开源 DDS(Fast-DDS/Cyclone)理论可接入小米 Domain=1 总线互通。

2. 商业工具(RTI,部分小米在用)

工具定位license
rtiddsspyCLI 抓 DDS 总线数据(=ros2 topic echo+list)Pro 收费
Admin ConsoleGUI 可视化 Domain/Participant/Topic 发现树Pro 收费
Recording Service录制/回放 DDS 数据(jar 已在仓库 rtiroutingservice.jarPro 收费,缺 license+XML 配置
Routing ServiceDDS↔DDS/Kafka 桥接(jar 已在仓库)Pro 收费
RTI Connext Express2025 新免费版(无超时,仅实体数限制),含 rtiddsspy+Admin Console免费

强烈推荐:普通 dev 立刻申请 RTI Connext Express 免费版,调试充电曲线(1 Participant + 1 DataWriter)完全够用。


3. 开源工具(无 license 方案)

工具定位对小米可用性
Fast-DDS SpyCLI 抓 RTPS 包(跨 DDS 实现)中(Security 关则可行,需喂 IDL)
Cyclone DDS InsightGUI 看拓扑/发现(不需 IDL)中(看”谁在发/谁在订”很实用)
cyclonedds-pythonPython 绑定,10 行发一个 sample高(PC 端 Mock 备选)
Fast-DDS MonitorGUI 监控(只看 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 RTPS0
看拓扑/发现(谁在发谁在订)RTI Express 免费版 Admin Console,或 Cyclone Insight0
驱动订阅链路端到端调试(核心痛点)⭐方案 A:复用 nddsjava.jar + DataWriter,写 MockHvChargingPublisher0.5 人日
录制充电过程回放Recording Service(jar 已在仓库,缺 license+XML);无 license 则自写录制器
实时曲线可视化不推荐 Foxglove/MCAP(太重),直接 App 内加 Debug Fragment 画 Canvas

6. 风险与局限

  1. DDS Security 启用/data/vendor/rtidds/SOASecurityEnable.cfg)会让所有开源互通方案失效——需持续跟踪。
  2. Mock publisher 只能 mock 发布端(模拟车端 SOA 推数据),消费端(App 订阅)逻辑仍要靠真实数据或 Mock 驱动。
  3. 充电报告走 AIDL HAL 路径时,用 dumpsys 即可调试,不必走 DDS Mock——先确认走哪条路径。

7. 立即 Action Items

  1. ⭐ adb pull MICAR_QOS_PROFILES.xml 到工程 debug 资源(0)
  2. micarChargeSettingssrc/debug/MockHvChargingPublisher(0.5 人日)——解决 P10
  3. 加隐藏 Debug Activity 触发 Mock(仅 xcdDebug flavor)(0.5 人日)
  4. 下载 RTI Connext Express 免费版(0)
  5. PC 装 Wireshark 验证 RTPS 抓包通路(0.5 小时)

一句话:小米已把 Mock publisher 所需全部依赖打进工程,普通 dev 无需 RTI license,加 ~50 行 Kotlin 即可解决”DDS 信号无法 mock”痛点。