深入高通QMI的‘黑匣子’:用QXDM和日志分析一次失败的通信

深入高通QMI的‘黑匣子’:用QXDM和日志分析一次失败的通信

高通QMI通信故障排查实战:从QXDM日志到TLV解析的完整指南

当AP与Modem之间的QMI通信突然中断时,工程师的终端上往往只显示"发送超时"或"解析错误"这类模糊提示。本文将以一次真实的WDS服务连接故障为例,演示如何像侦探一样通过QXDM抓包、TLV结构分析和代码级日志追踪,定位问题根源。

1. 搭建QMI调试环境

在开始排查前,需要准备以下工具链:

  • QXDM Professional:高通官方诊断工具(需License)
  • QPST Configuration:用于建立诊断端口连接
  • 十六进制分析工具:如HxD或010 Editor
  • 自定义日志模块:在AP/CP代码中添加的详细日志打印

典型的连接配置参数:

# 通过ADB激活诊断端口 adb shell "echo 1 > /sys/class/android_usb/f_diag/on" adb shell "setprop sys.usb.config diag,serial_cdev,rmnet,adb"

注意:确保设备已启用Diag权限,部分厂商系统可能需要签名驱动

2. 捕获并分析QXDM原始数据

当客户端调用qmi_client_send_msg_sync()超时后,按以下步骤抓取日志:

  1. 在QXDM中启用QMI消息过滤:

    • 导航到View → New → Common → QMI
    • 右键勾选Enable All Messages
  2. 关键字段解析技巧:

    • Control Flags:第1字节,0x00表示请求,0x02表示响应
    • Transaction ID:2-3字节,用于匹配请求响应对
    • Message ID:4-5字节,如0x0022代表WDS_START_NETWORK_INTERFACE_REQ
    • TLV段:从第8字节开始

示例故障消息的十六进制dump:

00 01 23 00 22 00 10 00 01 02 00 04 00 00 00 01 03 01 00 01 00

对应TLV解析:

  • Type 0x01:2字节长度,值0x00000001(APN类型)
  • Type 0x03:1字节长度,值0x00(鉴权类型)

3. 交叉验证AP/CP两端日志

3.1 AP侧编码检查

在发送函数前添加结构体打印:

void dump_req_msg(qmi_test_req_msg_v01 *req) { printf("APN: %s\n", req->apn); printf("Auth: %d\n", req->auth_type); }

常见编码问题:

  1. 可选字段未设置valid标志位
  2. 可变长度数组的length字段与实际不符
  3. 字节序错误(特别是多字节字段)

3.2 CP侧解码验证

在Modem处理函数中添加TLV解析日志:

qmi_csi_cb_error handle_wds_req( void *conn_handle, void *req_c_struct, unsigned int req_c_struct_len) { uint8_t *tlv_ptr = (uint8_t *)req_c_struct + 8; while(tlv_ptr < req_c_struct + req_c_struct_len) { uint8_t type = *tlv_ptr++; uint16_t length = *(uint16_t *)tlv_ptr; tlv_ptr += 2; printf("TLV Type:0x%02X Len:%d\n", type, length); tlv_ptr += length; } }

4. 典型故障模式与解决方案

4.1 无响应故障树

graph TD A[QMI无响应] --> B{QXDM可见请求?} B -->|否| C[AP侧发送问题] C --> C1[SMD通道未初始化] C --> C2[消息编码失败] B -->|是| D{CP有响应日志?} D -->|否| E[CP处理超时] D -->|是| F[响应传输中断]

4.2 TLV编码异常案例

某次实际调试中出现的异常TLV:

01 FF 00 04 41 42 43 44

问题特征:

  • Type为0x01(必选字段)
  • Length为0x00FF(明显过大)
  • 实际数据只有4字节

根本原因:

// 错误的结构体定义 typedef struct { uint8_t data_len; // 本应是uint16_t char data[256]; } payload_type;

5. 高级调试技巧

5.1 强制重传测试

通过修改QPST配置注入错误:

# 模拟SMD传输错误 def corrupt_packet(packet): if packet[0] == 0x00: # 请求消息 packet[-1] ^= 0xFF # 翻转最后字节 return packet

5.2 性能分析

使用QXDM的QMI时序统计功能:

  1. 开启Log → Statistics → QMI Transaction Timing
  2. 重点关注:
    • 请求到响应的延迟
    • CP处理耗时分布
    • 重传次数统计

6. 自动化测试方案

建议搭建的CI检查项:

#!/bin/bash # 自动QMI测试脚本 run_test_case() { send_qmi_request "WDS_START_NETWORK" \ --apn "test.apn" \ --auth "PAP" verify_qxdm_log "WDS_START_NETWORK_RESP" \ --timeout 2000 \ --field "result=0x0000" }

在最近一次项目迭代中,我们发现当TLV中包含嵌套结构时,Modem侧的类型表索引偏移计算存在边界错误。通过对比三个版本的IDL文件差异,最终定位到是类型表版本号未同步更新导致。