使用Android Studio对Debug包进行断点调试比较简单,这里介绍一下如何对release包进行断点调试。
背景什么的就不谈了,为什么要对着release包断点调试,debug包他不香吗?身不由己,不提也罢。
前提
- 一台root过的手机
- 应用源码,至少要有部分未混淆的源码。
- release包打包时保留了代码行数信息
- 应用release安装包。
将release包安装到root手机上,打开开发环境,开始对release包的断点调试之旅!
我这里有一台root手机,打开logcat可以看到当前正在运行的所有的进程,包括系统进程。
打开调试窗口,可以看到我们的应用进程。(注意IDE内源码应用的包名必须与待调试应用一致)
要在release包中保留源码的行数信息,只需要在防混淆代码中添加下面两句
-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile
在IDE自动添加的默认proguard-rules.pro中,这两句话是以注释的形式存在的,同时也包含了对这两句话作用的注释说明。
断点,找准位置!
要进行断点,首先要找到一个未被混淆的位置。诚然,可以在proguard-rules中添加防混淆代码,禁止混淆待调试的代码,但是这样就违背了混淆代码的初衷了,通常情况下并不可取。
但是即使不添加额外的代码,也是有很多地方没有被混淆的,这就是Activity、Service等四大组件以及自定义View类等需要使用反射进行调用的代码。
这里我选择了一个Activity的onCreate方法:
打开Activity,成功停在了onCreate上!
单步调试已混淆代码
能断点就能单步调试,到了这里已经解决了很大的问题了。但是我们要调试的代码可能已经被混淆了,怎么办呢?
我们来看一个单步调试深入混淆代码的例子:
当前断点停留在了已混淆的代码上。因为是通过单步进入这里的,所以实际上是知道这一行对应的源码的,并且从断点信息上也可以看到这个类名被修改为了g,而行数在91行。
此时,仍然可以对着代码行数继续进行单步调试。但是为了更直观的进行断点跟踪,或者跟踪代码中的异步操作流程,可以通过修改类名,这样就可以继续在源码上进行单步了。
下面我将源码类名修改为g,可以看到成功的断在了91行。
如果手里有编译时的mapping文件,可以将类名直接修改为混淆后的名称,然后愉快的在代码中进行断点,如果没有,就从Activity、View等入口处乖乖的单步调试找类名吧。
非阻塞断点
使用某为手机,在Activity的生命周期方法上断点的时,如果中断时间超过10秒,应用会直接崩溃退出。(这是手机自身的问题,作为Android开发者,一定也了解蓝绿厂手机对于开发者的恶意。在这里强烈推荐某米,这是我用过的对开发者最友好的手机。)
虽然手机不行,但是问题还是要解决的。阻塞断点不可行,可以修改为非阻塞断点。在断点上右击,取消勾选Suspend选项,断点就变成非阻塞的了。
非阻塞断点有什么用?可以输出log,可以执行任意代码!
首先勾选"Evaluate and log",并在下面的框里面输入 “非阻塞断点!”
每次代码执行到这一行的时候,都会在debug窗口的Console标签下输出"非阻塞断点":
除了输出文本log,也可以输出当前运行时的各种变量信息、也可以修改各种变量的值,只要你能拿到变量的正常名称。也可以执行各种代码,值得一提的是,在这里可以直接调用私有方法、修改私有变量,而不需要使用反射。使用方法很简单,就不再废话了。
当然阻塞断点也是可以执行代码与输出log的。关于断点的其他选项功能,可以自己探索一下,很简单,但是可以体会到探索的乐趣,何乐而不为!