Android平台debug完全解析

1,175 阅读6分钟

一:Java程序调试原理:

java这种上层语言编译结果是字节码,字节码需要jvm解释执行,那么调试java具体就是和jvm通信的问题,一般IDE中对Java程序的调试功能都是对jdb的包装,关于jvm调试体系网上有很多文章,比如:juejin.cn/post/688739… ,不赘述了

二:Native 程序调试原理:

native代码包含的是对应平台的cpu指令,是直接cpu跑的,对native代码调试需要cpu的支持(比如int3软中断指令),以及操作系统的协助(比如Linux的ptrace系统调用),lldb,gdb,IDA的android_server等调试器都是基于上面的功能实现的,具体网上有资料,比如:zhuanlan.zhihu.com/p/336922639 ,不赘述了

三:Class,Dex,Elf三种文件指令和源码对应关系描述结构:

1:class字节码和源码行号对应关系描述结构:

image.png

2:dex字节码和源码行号对应关系描述结构:

image.png

3:elf指令和源码行号对应关系描述结构:

image.png

4:小结

当class没有了行号,那只能反编译调试class指令

当dex没有了行号,那只能反编译调试smali指令

当elf没有了行号,那只能反汇编调试汇编指令

四:调试Android Studio

AS本质上是个Java程序,调试AS就是调试个Java程序

1:配置AS以Debug模式启动

dmg安装包安装后,可执行程序路径: /Applications/Android Studio.app/Contents/MacOS/studio 由于这是个mac下的可执行文件,此程序内部又启动java程序,并传入andorid studio相关的jar路径和参数,直接通过这个没法传递java参数,不过AS提供了个VM配置文件,启动时候会读取此文件的内容加入到java参数中 VM配置文件路径: Applications/Android Studio.app/Contents/bin/studio.vmoptions 加上:-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=6006 这里为方便观察,直接双击/Applications/Android Studio.app/Contents/MacOS/studio 程序启动AS,可观察到终端中输出: image.png

说明jvm已经准备好被调试器附加了

2:调试配置:

实现了JDWP协议的程序都可以作为调试器来用,当然没道理自己搞一个,用jdb则命令行操作太繁琐,手动管理源码也很费劲,不如使用包装完善的IDE,这里使用Idea,新建一个Remote JVM Debug 类型的configuration。配置如下图: image.png

3:导入代码

源码从哪来,你可以去下载下来,甚至可以自己编译个AS,参考:tools.android.com/build/studi… 但我们大多数时候只是想调试下,不想这么麻烦,可以直接导入AS的jar包到Idea中,利用Idea的反编译和Debug功能完成我们的目标,(AS的程序包的各个目录中有很多jar,需要哪个导入哪个,如下图):

image.png

导入Idea方式:Idea中新建个java项目,随便建个文件夹,把需要的jar复制过去,在jar上右键->Add as Library

image.png image.png

4:开始调试

首先要找到要调试的功能所涉及的类或者方法,寻找的方式可以通过在jar中搜索字符串,或者尝试在感觉相关名称的Class中断点,在 IDEA Plugin 框架体系中,大多数插件的功能入口都依赖 Action,那就可以在Action的一些方法中断点 image.png

五:调试Gradle

Gradle本质上是个Java程序,调试Gradle就是调试个Java程序

1:配置Gradle以Debug模式启动

gradle.properties中添加 org.gradle.jvmargs=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005

启动gradle,比如执行下assemble task,执行后下图所示,由于上面设置的suspend=y,启动后会等待调试器链接后再继续运行

image.png

2:调试配置

这里都使用Idea调试,配置和AS调试一样:

image.png

3:导入代码

源码从哪来,你可以去下载下来,甚至可以自己编译个Gradle,参考:github.com/gradle/grad… 但我们大多数时候只是想调试下,不想这么麻烦,可以直接导入Gradle的jar包到Idea中,利用Idea的反编译和Debug功能完成我们的目标,Gradle以及Gradle plugin的jar位置,如下图):

gradle程序位置

image.png

图中lib目录是编译后的jar,如果现在的是gradle-{version}-all类型的,则src目录中会对应的源码,可以导入源码调试

gradle plugin位置

在下图所示的文件夹中搜索目标插件:

image.png

比如我要搜索android gradle plugin:

image.png

导入Idea方式:Idea中新建个java项目,随便建个文件夹,把需要的jar复制过去,在jar上右键->Add as Library,和AS一样,不赘述了

4:开始调试

首先要找到要调试的功能所涉及的类或者方法,寻找的方式不多说了,自己摸索着来吧

image.png

六:调试任意App Java层

自己编个aosp刷机,类型选择userDebug或者Eng,这样的系统有root权限且全局可以调试,如何编译网上很多资料,中间若遇到问题也可以参考我写的aosp编译的坑点,不赘述

如果是第三方App,需要反编译dex为java源码导入AS调试,如果行号对不上老是调飞,说明行号信息被混淆了或去掉了,这时候可以考虑反编译成smali,使用AS+smalidea插件调试smali代码,网上有很多资料。比如:blog.csdn.net/YJJYXM/arti… 如果遇到AS无法对smali类型的文件下断点,就参考 blog.csdn.net/qq_43278826…

七:调试任意App Native层

自己编个aosp刷机,类型选择userDebug或者Eng,这样的系统有root权限且全局可以调试,如何编译网上很多资料,中间若遇到问题也可以参考我写的aosp编译的坑点,不赘述

由于第三方app中的so都是去除debug信息的,以及我们并没有对应源码,所以只能反汇编调试,我一般都是习惯使用IDA,网上有很多资料,比如: blog.csdn.net/Breeze_CAT/… IDA调试时候注意下这个坑: bbs.pediy.com/thread-2654…

八:调试Android系统Java层

自己编个aosp刷机,类型选择userDebug或者Eng,这样的系统有root权限且全局可以调试,如何编译网上很多资料,中间若遇到问题也可以参考我写的aosp编译的坑点,不赘述

导入编译的代码到AS中(可以参考www.jianshu.com/p/2ba5d6bd4… ),或者也可以按需要把android sdk中的源码替换为编译系统用的源码(我就是这样),注意targetSdk版本要和编译的系统版本一致

九:调试Android系统Native层

自己编个aosp刷机,类型选择userDebug或者Eng,这样的系统有root权限且全局可以调试,如何编译网上很多资料,中间若遇到问题也可以参考我写的aosp编译的坑点,不赘述

使用AS作为调试环境的话可以参考: weishu.me/2017/01/14/…