Files
MAG160C/analysis/magcx_official_flow.md
T

6.0 KiB
Raw Blame History

MAG160C 官方 MAG-Cx 完整逆向结论(2026-09-10jadx + Ghidra 全量解包)

产物来源:

  • Java 层:analysis/sdk_re/android_app/jadx_magcx/(jadx 1.5.1 反编译官方普通版 MAG-Cx.apk 全量源码)
  • Native 层:analysis/sdk_re/android_app/libcxsdk_decomp.txt Ghidra 11.3.2 headless 全量反编译 lib/armeabi/libcxsdk.so1290 函数)
  • libcoresdk(arm64) 反编译已在 analysis/sdk_re/android_app/(专业版/网络路径)
  • 本文结论全部来自以上反编译源码,与真机日志交叉验证(vivo V2509A, Android 16)。

1. USB 协议权威版(以官方 Java UsbCommunication.java 为准)

1.1 端点与超时

端点 方向 用途 超时
0x03 OUT 命令(4B 小端 magic;FFC/激光/帧率带参数) 800ms
0x82 IN 命令响应/ack(读 ≤64B 800ms
0x81 IN 图像流(28B 头 + 38400B + 28B 尾) 800ms
0x84 IN 标定文件下载(16KB 块) 800ms/块
0x05 OUT 向相机发送标定(SendCaliFile 上传方向,本项目暂不用) 800ms

全部 800ms(官方 TIMEOUT 常量)。响应缓冲 64B。

1.2 命令集(P2DCmd,全部 4 字节小端)

官方名 说明
0x6BB6B66B GetParameter1 → 0x5BB5B55B BasePara160B
0x6BB6B66C GetParameter2 → 0x5BB5B55C BasePara260B
0x6BB6B66D SetParameter1 带 ack64B 读)
0x6BB6B66E SetParameter2 带 ack
0x6BB6B66F GetCaliInfo → 0x5BB5B55E {i32 size, i32 reserved, i64 date}
0x6BB6B670 GetCaliFile ack 0x5BB5B55D,随后相机在 0x84 推标定文件
0x6BB6B671 SendCaliFile 上传方向(配 0x05 OUT
0x6BB6B672 SetShutterState FFC8B {magic LE, u32 on LE}
0x6BB6B673 StartTransferImg 开始推流,带 ack
0x6BB6B674 StopTransferImg 停流,带 ack
0x6BB6B675 GetLifeTime → 0x5BB5B561 {magic, i32 开机毫秒}
0x6BB6B676 SetLaserState 8B(激光,非省电!)
0x6BB6B677 PowerSave 8B
0x6BB6B678 GetFPAState → 0x5BB5B562
0x6BB6B679 SetFrameRate 12B {magic, i32 interFrame, i32 interLine}

D2P 响应魔数:5B=SendParameter1、5C=SendParameter2、5D=SendCaliFile、 5E=SendCaliInfo、61=SendLifeTime(均在 0x5BB5B5xx 空间)。

注意0x6BB6B66B 是回文数(字节对称),因此历史上"66b 有响应、其余全无" 正是字节序反了的特征——非回文命令全部变成无效字节。MagProtocolTest 已锁死。

1.3 BasePara10x5BB5B55B payload14×i32 = 56B

int[0] serialNumberint[1] hwVersion(低24位)|devType(高8位) int[2] swVersionint[4] fpaWidthint[5] fpaHeightint[6] fps int[8] fpaGainint[9] fpaFlipint[10] interFrameint[11] interLine。 devType0=c1, 1=c3, 2=c3p, 3=core160(MAG160C), 5=c1pro, 6=c1prolite。

1.4 官方连接序列(connect() + startTransfer()

1. write GetParameter1 → read 64B → BasePara1(失败则整个 connect 放弃)
2. write GetParameter2 → read → BasePara2
3. write GetCaliInfo   → read → {size, reserved, date}
4. 缓存判定:{caliDir}/{productType}.{serial}.{date} 存在且长度==size
   ├─ 命中:直接 startTransfer()
   └─ 未命中:启动 ThreadCaliRecv0x84 连续读,16KB/块,无数据 5s 放弃)
      → sleep 50ms → write GetCaliFile(670)waitForCmdAck 读 ack
      → 收满 size 字节存盘 → startTransfer(caliPath)
5. startTransfer
   a. native startProcess(w, h, serial, devType, shutterClose/OpenSpeed,
      ffcTriggerFrame, ffcTriggerTemperature, paletteIndex, baseLineAcc,
      caliPath)   ← libcxsdk Controller::StartProcess → LoadCalibrationTable
      (caliPath),加载失败即 startProcess 失败并删除缓存文件
   b. native setEX / getExtParameter+setExtParameter(dwFlip) / setAutoEnlarge
      (全部 native,不占 USB
   c. 启动 ThreadImgRecv + ThreadImgProcess → sleep 5ms
      → write StartTransferImg(673)waitForCmdAck 读 ack

1.5 图像流帧结构(与 FrameStream/管线一致)

28B 头:0x1BB1B11B, frameIndex, dataLen(=wh2), type(0/1), period, 保留×3。 38400B u16LE 像素。 28B 尾:0x1BB1B11C, frameIndex, fpaTemp, intDrop(=type), reserved[2]。 官方 ThreadImgRecv:搜头→凑满 frameBytes→校验尾→drop∈{0,1} 才交给处理线程; fpaTemp 在尾 +8devType0/5/6/3),camTemp=fpaTemp-500。

1.6 FFC 触发(官方逻辑)

  • 双击/消息(MSG_TRIGGER_FFC)→ SetShutterState(672)
  • 每 16 帧查 GetLifeTime(675)devType1/2 按 6.5s/13s/19.5s/26s 档位触发 FFC devType0/5/6/3(含 core160)该路径不自动 FFC(仅温度稳定标志)。
  • 本项目管线内部 FFC 调度(onFfc→672)为等效实现,且 672 相机随时接受。

2. 本项目复刻状态(IrSession.kt = 官方 UsbCommunication 等价物)

  • 连接序列 1-5 已逐行复刻(含 0x84 拉取、缓存 files/cali/{product}.{serial}.{date});
  • 命令打包小端(与官方 intToByteArray 一致)——历史上 cmd4/cmd8 用 ByteBuffer.putInt 默认大端导致非回文命令全部反转16 轮黑屏的根因, MagProtocolTest 锁死);
  • usfs 坑:bulk 读超时后端点被标 halted,后续传输全部瞬间失败,须每次失败后 CLEAR_HALTIrSession.diagnoseEndpoint);
  • 会话互斥(同一时刻仅一个 IrSession 持有相机)+ DETACHED 释放 + 去抖。

3. 工具与环境(2026-09-10 本机)

  • jadx 1.5.1C:\Tools\jadx-1.5.1(反编译产物 C:\Tools\jadx-out,已拷贝入库 analysis/sdk_re/android_app/jadx_magcx/
  • Ghidra 11.3.2C:\Tools\ghidra_11.3.2_PUBLIC;工程 C:\Tools\ghidra_proj\MagCX 全量反编译脚本 C:\Tools\ghidra_scripts_user\DumpAllDecomp.java
  • 重跑命令(PowerShell/cmd): set JAVA_HOME=C:\Tools\jdk-21&& C:\Tools\ghidra_11.3.2_PUBLIC\support\analyzeHeadless.bat C:\Tools\ghidra_proj MagCX -process libcxsdk.so -scriptPath C:\Tools\ghidra_scripts_user -postScript DumpAllDecomp.java <输出文件>