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 接入。