• 前言
    • 夏虫不可语于冰

AOSP 调试工具 JDP 使用文档

一、概述

JDP(Java Debugger Protocol)是一种基于 JDWP(Java Debug Wire Protocol) 的调试协议,广泛应用于调试 Android Framework 和 SystemServer 进程。JDP 可通过 jdbAndroid StudioIDEA 等调试工具连接至目标虚拟机,实现设置断点、单步调试、查看堆栈、变量等功能。

在 AOSP(Android Open Source Project)开发中,利用 JDP 可以定位 SystemServer 中服务的初始化问题、Binder 调用异常等系统级问题。


二、JDP/JDWP 调试前提

  • 已开启 ro.debuggable=1
  • 目标进程支持 JDWP(SystemServer 默认支持)。
  • 可通过 ADB 通信。
  • 主机和设备间端口转发已配置。

三、连接调试步骤(以 SystemServer 为例)

步骤 1:确保设备开启调试模式

1
2
adb root
adb remount

确认 ro.debuggable 属性是否为 1

1
adb shell getprop ro.debuggable

若不是 1,需刷入 userdebug 或 eng 版系统。


步骤 2:查看支持 JDWP 的进程

1
adb jdwp

会输出类似:

1
2
3
5
1234
1632 ← SystemServer 的 PID

记录目标进程的 PID, 可以通过 ps -A | grep -insH "systemui" 查询对应的 PID。


步骤 3:设置端口转发

将本地端口(如 8800)映射到目标进程的 JDWP 接口:

1
adb forward tcp:8800 jdwp:<PID>

示例:

1
adb forward tcp:8800 jdwp:1632

步骤 4:使用调试器连接

方法一:使用 jdb 工具(推荐)

1
jdb -attach localhost:8800

若连接成功,控制台将进入 JDB 调试界面。

方法二:使用 Android Studio / IDEA

  1. 打开调试配置 > 添加 Remote JVM Debug。

  2. 设置:

    • Host: localhost
    • Port: 8800
    • Transport: Socket
  3. 点击连接。


四、常用 JDB 命令表

命令 说明
help 显示帮助命令列表
classes 显示已加载的类
methods <类名> 查看类中方法
stop in <类名>.<方法名> 在指定方法设置断点
clear <类名>:<行号> 清除指定行断点
run 启动程序(首次连接不用)
cont 继续执行
next 单步执行(不进入方法)
step 单步执行(进入方法)
print <变量> 打印变量值
where 打印当前线程堆栈
thread 显示线程信息
threads 显示所有线程
exit 退出调试器

  • 使用案例(Android P 分析 LayoutInflater.inflate )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#  查询可调试进程
adb jdwp

# 启动调试版系统镜像,并启用 JDWP
adb root
adb shell setprop service.jdwp.enable 1
adb shell stop && adb shell start


adb jdwp # 找到你的 App PID,比如 10456
adb forward tcp:8000 jdwp:3945

jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8000

# 指定源码(出现找不到的时候)
jdb -sourcepath $ANDROID_BUILD_TOP/frameworks/base/core/java \
-attach localhost:8000


# 调试方法
# 设置断点到 XmlPullParser 版本
stop in android.view.LayoutInflater.inflate(org.xmlpull.v1.XmlPullParser, android.view.ViewGroup, boolean)

stop at android.view.LayoutInflater:884


where # 查看当前栈帧
locals # 查看局部变量
print parser # 查看 parser 的类型或内容
print root
print attachToRoot

print root.getId() # 查看 root.getId() 调用结果

五、调试技巧与注意事项

1. SystemServer 多线程注意

  • SystemServer 内部启动多个服务线程,调试时应先用 threads 找到目标线程,使用 thread <id> 切换再打断点。

2. 设置断点位置建议

  • 推荐在 .java 文件中查找行号或方法名,然后在 JDB 中使用 stop instop at 设置断点。

3. 连接失败常见原因

问题 原因 解决方法
Unable to attach PID 不存在 / JDWP 不支持 确认使用的 PID 正确并支持 JDWP
无法进入 JDB 被防火墙阻断 / 未转发端口 关闭防火墙、确认 adb forward 正确
JDB 显示乱码 JDK 编码问题 设置 JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8

六、附录:如何让自定义服务支持 JDWP

若要调试自定义 native 服务或 Java 服务,可在启动代码中添加:

1
Debug.waitForDebugger(); // 启动时等待调试器连接

1
2
3
if (android.os.Debug.isDebuggerConnected()) {
Log.d(TAG, "Debugger connected");
}

并确保 ro.debuggable=1 和服务是以 app_process 启动的 Java 进程。


如需进一步集成 JDP 调试进 IDE,也可将 out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar 添加为依赖,获得完整调试符号。