工欲善其事,必先利其器之—命令行下使用jdb调试android应用(MAC环境)

前提说明

  • 先关闭Eclipse,Android Studio这类的IDE,否则jdb attach到应用时出现如下异常,jdb连接中断
java.io.IOException: handshake failed - connection prematurally closed
    at com.sun.tools.jdi.SocketTransportService.handshake(SocketTransportService.java:136)
    at com.sun.tools.jdi.SocketTransportService.attach(SocketTransportService.java:232)
    at com.sun.tools.jdi.GenericAttachingConnector.attach(GenericAttachingConnector.java:116)
    at com.sun.tools.jdi.SocketAttachingConnector.attach(SocketAttachingConnector.java:90)
    at com.sun.tools.example.debug.tty.VMConnection.attachTarget(VMConnection.java:519)
    at com.sun.tools.example.debug.tty.VMConnection.open(VMConnection.java:328)
    at com.sun.tools.example.debug.tty.Env.init(Env.java:63)
    at com.sun.tools.example.debug.tty.TTY.main(TTY.java:1082)
  • 这种很原始调试手段,我一般是想看android系统库的真实代码运行情况(IDE上debug时Android系统类库的代码行数与运行时是不一致的)

调试三步曲

获取应用的进程Id

adb shell ps | grep 应用包名

重定向步端口

adb forward tcp:7701 jdwp:进程Id
//7701可以换行本地未被占用的port,可以使用 netstat -nlt ,查看本地端口的使用情况

运行jdb

jdb  -attach 127.0.0.1:7701

成功attach后,help一下,可以看到断点如何下等命令,注意class id 包括类的包名的!

luogw@luogw-MacBook-Pro temp$ jdb  -attach 127.0.0.1:7703
设置未捕获的java.lang.Throwable
设置延迟的未捕获的java.lang.Throwable
正在初始化jdb...
> help
** 命令列表 **
connectors                -- 列出此 VM 中可用的连接器和传输

run [class [args]]        -- 开始执行应用程序的主类

threads [threadgroup]     -- 列出线程
thread <thread id>        -- 设置默认线程
suspend [thread id(s)]    -- 挂起线程 (默认值: all)
resume [thread id(s)]     -- 恢复线程 (默认值: all)
where [<thread id> | all] -- 转储线程的堆栈
wherei [<thread id> | all]-- 转储线程的堆栈, 以及 pc 信息
up [n frames]             -- 上移线程的堆栈
down [n frames]           -- 下移线程的堆栈
kill <thread id> <expr>   -- 终止具有给定的异常错误对象的线程
interrupt <thread id>     -- 中断线程

print <expr>              -- 输出表达式的值
dump <expr>               -- 输出所有对象信息
eval <expr>               -- 对表达式求值 (与 print 相同)
set <lvalue> = <expr>     -- 向字段/变量/数组元素分配新值
locals                    -- 输出当前堆栈帧中的所有本地变量

classes                   -- 列出当前已知的类
class <class id>          -- 显示已命名类的详细资料
methods <class id>        -- 列出类的方法
fields <class id>         -- 列出类的字段

threadgroups              -- 列出线程组
threadgroup <name>        -- 设置当前线程组

stop in <class id>.<method>[(argument_type,...)]
                          -- 在方法中设置断点
stop at <class id>:<line> -- 在行中设置断点
clear <class id>.<method>[(argument_type,...)]
                          -- 清除方法中的断点
clear <class id>:<line>   -- 清除行中的断点
clear                     -- 列出断点
catch [uncaught|caught|all] <class id>|<class pattern>
                          -- 出现指定的异常错误时中断
ignore [uncaught|caught|all] <class id>|<class pattern>
                          -- 对于指定的异常错误, 取消 'catch'
watch [access|all] <class id>.<field name>
                          -- 监视对字段的访问/修改
unwatch [access|all] <class id>.<field name>
                          -- 停止监视对字段的访问/修改
trace [go] methods [thread]
                          -- 跟踪方法进入和退出。
                          -- 除非指定 'go', 否则挂起所有线程
trace [go] method exit | exits [thread]
                          -- 跟踪当前方法的退出, 或者所有方法的退出
                          -- 除非指定 'go', 否则挂起所有线程
untrace [methods]         -- 停止跟踪方法进入和/或退出
step                      -- 执行当前行
step up                   -- 一直执行, 直到当前方法返回到其调用方
stepi                     -- 执行当前指令
下一步                      -- 步进一行 (步过调用)
cont                      -- 从断点处继续执行

list [line number|method] -- 输出源代码
use (或 sourcepath) [source file path]
                          -- 显示或更改源路径
exclude [<class pattern>, ... | "none"]
                          -- 对于指定的类, 不报告步骤或方法事件
classpath                 -- 从目标 VM 输出类路径信息

monitor <command>         -- 每次程序停止时执行命令
monitor                   -- 列出监视器
unmonitor <monitor#>      -- 删除监视器
read <filename>           -- 读取并执行命令文件

lock <expr>               -- 输出对象的锁信息
threadlocks [thread id]   -- 输出线程的锁信息

pop                       -- 通过当前帧出栈, 且包含当前帧
reenter                   -- 与 pop 相同, 但重新进入当前帧
redefine <class id> <class file name>
                          -- 重新定义类的代码

disablegc <expr>          -- 禁止对象的垃圾收集
enablegc <expr>           -- 允许对象的垃圾收集

!!                        -- 重复执行最后一个命令
<n> <command>             -- 将命令重复执行 n 次
# <command>               -- 放弃 (无操作)
help (或 ?)               -- 列出命令
version                   -- 输出版本信息
exit (或 quit)            -- 退出调试器

<class id>: 带有程序包限定符的完整类名
<class pattern>: 带有前导或尾随通配符 ('*') 的类名
<thread id>: 'threads' 命令中报告的线程编号
<expr>: Java(TM) 编程语言表达式。
支持大多数常见语法。

可以将启动命令置于 "jdb.ini"".jdbrc" 中
位于 user.home 或 user.dir 中

进阶1:导入系统类库

jdb的sourcepatch选项

启动jdb时设置源文件的目录,即通过-sourcepatch参数设置
jdb的选项如下

uogw@luogw-MacBook-Pro ~$ jdb --help
选项无效: --help

用法: jdb <options> <class> <arguments>

其中, 选项包括:
    -help             输出此消息并退出
    -sourcepath <由 ":" 分隔的目录>
                      要在其中查找源文件的目录
    -attach <address>
                      使用标准连接器附加到指定地址处正在运行的 VM
    -listen <address>
                      等待正在运行的 VM 使用标准连接器在指定地址处连接
    -listenany
                      等待正在运行的 VM 使用标准连接器在任何可用地址处连接
    -launch
                      立即启动 VM 而不是等待 'run' 命令
    -listconnectors   列出此 VM 中的可用连接器
    -connect <connector-name>:<name1>=<value1>,...
                      使用所列参数值通过指定的连接器连接到目标 VM
    -dbgtrace [flags] 输出信息供调试jdb
    -tclient          在 HotSpot(TM) 客户机编译器中运行应用程序
    -tserver          在 HotSpot(TM) 服务器编译器中运行应用程序

转发到被调试进程的选项:
    -v -verbose[:class|gc|jni]
                      启用详细模式
    -D<name>=<value>  设置系统属性
    -classpath <由 ":" 分隔的目录>
                      列出要在其中查找类的目录
    -X<option>        非标准目标 VM 选项

<class> 是要开始调试的类的名称
<arguments> 是传递到 <class> 的 main() 方法的参数

要获得命令的帮助, 请在jdb提示下键入 'help'

导出手机上的系统类库(java类库)

手机系统类库的位置在 /system/framework
现在很多手机包括原生rom framework.jar里边是没有类文件了,已经转成odex,并存放在dalvik-cache目录了
使用adb pull命令,如下示例

luogw@luogw-MacBook-Pro Downloads$ adb pull /system/framework/framework.jaar
/system/framework/: 88 files pulled. 5.2 MB/s (105698190 bytes in 19.387s)
luogw@luogw-MacBook-Pro Downloads$ ll
total 16
drwx------+  5 luogw  staff   170  8 10 14:30 ./
drwxr-xr-x+ 67 luogw  staff  2278  8  9 17:45 ../
-rw-r--r--@  1 luogw  staff  6148  8  8 18:11 .DS_Store
-rw-------   1 luogw  staff     0  5 14 11:11 .localized
drwxr-xr-x  54 luogw  staff  1836  8 10 14:30 framework.jar

jdb时设置源码位置,指向导出的系统类库

framework目录是framework.jar反编译后的java代码

jdb  -sourcepath framework -attach 127.0.0.1:7701

猜你喜欢

转载自blog.csdn.net/SCHOLAR_II/article/details/81562459