概述 : Android studio 断点调试技巧分享
1 断点简介
1.1断点种类
- 普通断点
- 方法断点
- 字段断点
- 条件断点
- 异常断点
1.2断点执行方法
-
step over F6(单步跳过)
-
Step Into F5:单步执行,遇到子函数就进入并且继续单步执行(简而言之,进入子函数)。
-
Force step into:强制进入,在调试的时候能进入任何方法。
-
Drop Frame:回退到被调用方法处. 当需要知道当前断点的上一层调用源时,可以使用这个步骤;或是希望重新执行前面的程序,可以回退到前面的方法。
-
step out F7: 当单步执行到子函数内时,用step out就可以执行完子函数余下部分,并返回到上一层函数.与Drop Frame相似,但有区别。 (1)Step Out回退到上一层调用方法
(2)回退之后,原先的变量值不能回退,变量值是执行完调用方法后的值。
(3)回退之后,再按F5也不会进入到getString()方法,因为已经执行完了。
(4)F7等价于F5+F6 (5)Drop Frame执行后,再按F6还会继续执行,而step out会直接跳到下一步。 -
Run to Cursor:跳转到光标所在位置
1.3断点辅助信息
1.3.1断点日志
在断点执行后,在控制台输出日志。备注:不是在logcat窗口,是在Debug的Console窗口。
1.3.2断点堆栈信息
在断点执行后,在控制台输出日志,日志内容是执行断点所在代码的堆栈信息。备注:堆栈信息中不包含时间,需要看执行时间可以断点日志中增加.
示例:
Breakpoint reached
at com.example.test2.TActivity.onResume(TActivity.java:75)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1472)
at android.app.Activity.performResume(Activity.java:8351)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:5068)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:5121)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:190)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:105)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2613)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:219)
at android.app.ActivityThread.main(ActivityThread.java:8668)
at java.lang.reflect.Method.invoke(Method.java:-1)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109)
1.3.3断点执行信息
在断点执行后,在控制台输出该断点的简单描述日志。
示例:
Breakpoint reached at com.example.test2.TActivity.onResume(TActivity.java:75)
2 Android Studio Debug调试功能
2.1 Android Studio菜单栏Debug功能
上图所示:
- debug模式重新安装运行。 应用场景:一般需要在程序启动时就需要进入debug,例如在MyApplication, main函数等。
- 进入Debug模式。点击之后会弹窗,然后选择进程。示例如下: 备注:非特殊情况,一般使用这种方法进入debug。因为debug过程中,程序运行较慢,影响调试速度,在打开程序进入特定界面后,再执行此操作进入Deubg模式。另外,建议开发者对该功能添加快捷键,非常实用,可以快速进入debug模式。 快捷键对应功能名称: Main menu | Run | Attach Debugger to Android Process
3. 结束debug模式。
备注:多数情况下会结束进程
2.2 Android StudioDebug菜单图解
- 1:studio 底部debug菜单功能按钮
- 2:StepOver
- 3: Step Into
- 4: Force Step Into
- 5: Step Out
- 6: Drop Frame
- 7: Run to Cursor
- 8: Evalute Expression 调试窗口
- 9:debug Console窗口(debug日志在这里显示)
- 10:Add To Watcehes
- 11:恢复Debug调试
- 12:结束Deubg调试
- 13:断点管理窗口
- 14:过滤所有断点
- 15:获取内存Deump
2.3 Breakpoints 菜单
进入方法:选择断点,点击点键》More
- 1:普通断点区域
- 2:方法断点区域
- 3:异常断点区域
- 4:异常断点区域
- 5:添加断点
- 6:删除断点
- 7:断点开关。可关闭和打开断点,默认是打开
- 8:断点暂停属性开关。默认勾选,非勾选状态下,程序执行到断点不会停留。
- 9:Condition窗口。添加断点执行条件。
- 10:执行到断点时打印堆栈信息
- 11:执行到断点时打印断点信息
- 12:打印自定义日志,日志都在Deubg控制台窗口显示
- 13:设置当前断点在某断点执行之后才会执行
备注:方法断点,默认是进入和退出都会执行,这样日志会打印两次。
3 Android Studio Debug功能详解
3.1 Evalute Expression 调试窗口
打开后可在Evalute窗口输入要执行的代码,可以得到对应的结果,单行代码可省略return 示例:
快捷键对应的功能名称: Main menu | Run | Debugging Actions | Evaluate Expression...
在AS中位置如下图
使用场景: 在debug过程中,需要得到某些函数的值,且不是一直需要,可以此功能;另外,如果已经知道某些程序执行会发生异常,可以在该窗口中执行,得到的结果是一个Exception,通过查找这个异常的堆栈信息来找到造成异常的原因,同时还保证了debug不会中断,这样就不用重新写try catch问题代码。
3.2 Add To Watches
添加执行代码块。在某断点处添加了该功能,那么每次执行到该断点时都会的执行。
使用方法:选中要执行的代码段,右键》点击Add To Watches; 或者在Variables窗口点击加号,再手动输入要执行的代码。
使用场景:在调试过程需要知道某个函数的执行结果或是要执行某个方法,或者需要修改某个字段的值。
实践一:进入H5Activity,需要修改url,在onCreate方法中,获取url后,添加断点,然后使用Add To Watches功能,添加代码段 url = "new url...."。这样就可以在不修改后台数据、不重启、不修改代码的前提下快速调试
实践二:在某断点处需要长期知道某些方法的值。
3.2 Set Value
设置值。修改某断点执行时,在Variables窗口中某字段的值。
备注:只有一次有效,断点再次执行时,不会生效。
使用方法:在Variables窗口中选中要修改的字段,点击右键,点击Set Value,即可修改该字段的值。
3.3 Resume Program 和 Pause Program
恢复debug程序和暂停debug程序 使用场景:当想暂停debug时,可使用Pause Program,它与 Mute BreakPoints 的区别是前者暂停Deubg程序,后者只是关闭断点,但还在debug程序中。\
使用方法:
3.4 Mute Breakpionts
关闭所有断点
3.5 增加断点
方法一:常见增加断点的方式是在代码左侧单击左键,添加后效果如下图。
方法二:在Breakpionts窗口手动添加断点。可以添加方法断点、字段断点和异常断点。
3.6 暂停断点
默认情况下程序执行到断点会暂停,但也可以将暂停取消。这样程序照样执行,同时断点日志、堆栈信息可以正常打印。这样可以通过日志去了解程序执行情况。
3.7 断点状态
3.7.1 无效断点
ine 5250 in Secure.getString() (android.provider.Settings) No executable code found at line 5,250 in class android.provider.Settings$Secure Suspend: thread
翻译:在类android.provider的第5250行没有发现可执行代码。设置$安全暂停:线程
3.7.2 断点关闭
关闭断点
3.7.2 断点暂停关闭
正常断点会在程序执行到断点时会暂停,等待开发者操作,把暂停属性关闭,则程序执行到断点时不会暂停。
3.8 在系统源码中打断点
方法一:通过手动添加方法断点,将系统方法添加断点。这样只能添加方法断点,且影响调试过程中运行速度。
方法二:使用Android Studio自带的模拟器,模拟器的API与APP工程中compileSdkVersion 版本要一致。因为很多手机厂商定制系统或是因为手机系统版本与工程中compileSdkVersion 版本不一致,导致无法在源码中打断点。提示断点无效。
示例在使用系统方法获取Android ID和TextView.setTextSize()方法中打断点。
4 实践
4.1 在系统方法中打断点。统计APP运行过程中获取Android Id的调用源和次数
应用场景:根据隐私协议要求,获取用户敏感信息需要申报。APP内有较多SDK和业务代码获取用户敏感信息。第三方(如梆梆、爱加密)采集这些信息是通过将APP安装在有root权限系统的手机上,通过hook对应的系统方法,打印日志来统计,而这个对一般开发者有一定门槛。
实现方法一:通过手动添加方法断点,将对应的系统方法添加断点,然后增加断点日志,打印执行时间和对应的TAG,同时打印断点信息和堆栈信息,另外要将该断点的暂停开关关闭,不需要暂时,让其正常运行。
获取Android ID API
String ANDROID_ID = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);
4.2 APP运行过程中动态添加代码执行块
应用场景:在调试过程中,需要增加一些代码,重新编译运行代价较大。可以打断点,然后在断点的Condition窗口增加执行代码块和执行条件。相当于条件断点中,增加了代码执行块。Add To Weacth只能增加一行代码,并不能增加更多代码。 示例:在某断点处添加代码块并执行