JDWP远程方法调用伪代码

基于 JDWP 协议实现 ViewDebug.dump 的伪代码流程,展示了调试器如何一步步与目标 Android App 通信、定位并调用 ViewDebug.dump() 方法并回收数据。

JDWP View dump 调用伪代码

// 假设当前你是调试器端(如自己实现一个 JDWP 客户端)

// ① 通过 ADB 建立 JDWP 通道(实际在命令行中执行)
adb jdwp                      // 获取目标进程 PID
adb forward tcp:8700 jdwp:<pid>

// ② 与目标 JDWP 服务建立 Socket 连接
JDWPConnection conn = JDWP.connect("localhost", 8700);

// ③ 查询类 android.view.ViewDebug
ClassID viewDebugClassId = conn.send(
    JDWPCommand.VirtualMachine.ClassesByName("android.view.ViewDebug")
).getFirstClassId();

// ④ 查询方法 dump(View, OutputStream)
MethodID dumpMethodId = conn.send(
    JDWPCommand.ReferenceType.Methods(viewDebugClassId)
).findMethod("dump", "(Landroid/view/View;Ljava/io/OutputStream;)V");

// ⑤ 获取当前 Activity 的 DecorView(通过调用 getWindow().getDecorView())
ObjectID activityThread = conn.findStaticField("android.app.ActivityThread", "sCurrentActivityThread");
ObjectID activityClientRecord = conn.invokeMethod(activityThread, "getActivities", ...).getFirst();
ObjectID activity = conn.getField(activityClientRecord, "activity");
ObjectID window = conn.invokeMethod(activity, "getWindow", "()");
ObjectID decorView = conn.invokeMethod(window, "getDecorView", "()");

// ⑥ 创建 OutputStream(使用 java.io.PipedOutputStream 或自定义 wrapper)
ObjectID outputStream = conn.newObject("java.io.ByteArrayOutputStream");

// ⑦ 执行 ViewDebug.dump(rootView, outputStream)
conn.invokeMethod(
    viewDebugClassId,                 // class ref
    dumpMethodId,                     // method ref
    [decorView, outputStream],        // arguments
    options = SINGLE_THREADED         // optional flags
);

// ⑧ 获取 outputStream 中的内容
byte[] data = conn.invokeMethod(outputStream, "toByteArray", "()[B");

// ⑨ 解码 byte[] 得到文本内容
String layoutDump = new String(data, "UTF-8");

// ⑩ 解析 dump 数据并呈现
LayoutTree tree = LayoutParser.parse(layoutDump);
UI.render(tree);

补充说明

  • 上述是一个高层抽象逻辑,真实的 JDWP 通信使用的是二进制协议,需要使用 JDWP command set / command code 和编解码结构;
  • 类、字段、方法、对象在 JDWP 协议中都是通过 ID(数字)引用的;
  • 所有参数都需要包装为 Value 类型(如 ObjectReference、IntValue、StringValue);
  • invokeMethod 等指令必须考虑线程上下文、安全性与异常捕获;
  • 对于 OutputStream 的实现,可以用 ByteArrayOutputStream(简单)或 Pipe/Socket 输出到调试器(复杂但高效)。

你可以把这段伪代码理解为:

一个简化版的 Layout Inspector 所做的事情,用纯调试通信方式,远程执行 Java 方法,不需要修改 App 代码、不需要插桩或 SDK 接入。

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器