概述
转载请注明出处:https://blog.csdn.net/wangzaieee/article/details/83895089
我们知道Android Framework层不仅仅是只有java代码,还有许多c/c++代码,比如init进程和MediaPlayerService,CameraService等本地系统服务,都是用c和c++实现的。这个时候我们要分析问题和追踪代码最好的方式就是调试。如果想要了解Framework Java的调试方法,请看本文。
今天我们主要讲解两种情况下的native代码调试:
- 调试运行中的native进程(以CameraService connect方法为例)
- 调试native进程的启动 (以init进程的启动为例)
调试CameraService connect方法
准备条件
- 有已经编译好的安卓源码(debug版)
- 使用上述镜像的debug设备
调试步骤
调试CameraService的connect方法,流程如下:
- 初始化调试环境(进入源码根目录执行)
# 运行shell脚本,配置环境
$ source build/envsetup.sh
# 然后选择自己要调试的编译版本
$ lunch
- 将设备连接上服务器(如果服务器是远程服务器呢?见下面思考1)
- 查看要调试的进程ID
# CameraService运行在mediaserver进程,获得其进程id
$ adb shell ps | grep mediaserver
- 然后链接gdb调试该进程。
$ adb root #否则gdbserver(64)没有足够的权限attach到mediaserver进程
$ gdbclient [mediaserver的进程id]
# 这个时候进入了gdb调试模式
# 给CameraService的connect方法打断点
# c++方法需要加上前面的命名空间
(gdb) b android::CameraService::connect
(gdb) i b #查看当前的断点
#打开摄像头,这个时候会黑屏,因为之前打的断点
(gdb) c #运行到断点
(gdb) bt #查看当前函数栈(可以看到栈顶是connect方法)
(gdb) n #单步调试(nexti 单步指令,l 查看当前的代码,p status打印status的值)
(gdb) c #继续执行至下一个断点(没断点就直接执行完成)
以上就是所有的调试步骤。
调试Init进程的启动
init进程是用户空间的第一个进程,init进程的启动流程可以查看这篇文章。接下来我们来看看这么调试init进程呢?
准备条件
- 有已经编译好的安卓源码(debug版)
- 使用上述镜像的debug设备
调试步骤
- 初始化调试环境(同上)
- 将设备连上服务器(同上)
- 启动要调试的进程(如果是wifi调试,就在设备端执行)
$ adb root #否则gdbserver(64)没有足够的权限运行init进程
$ adb shell gdbserver(64) :5039 ./init #Init进程会启动,并且会打印对应的进程id
并且init进程在本机的5039的端口监听之下。
- 转发端口(如果是wifi调试,在服务端执行)
#将设备的端口转发的服务器的端口(6.0以后不用执行,gdbclient的脚本会执行)
$ adb forward tcp:5039 tcp:5039
这个时候gdb只要连接本地的5039端口,就相当于连接上了设备的5039端口,gdb就间接通过gdbserver连接上init进程。
- gdb开始调试init进程的启动
$ gdbclient <PID> #<PID>表示init的进程id
- 进入gdb调试模式
(gdb) b main #给init.c(pp)的main方法打断点
(gdb) c #执行到断点
(gdb) ni #向下走一条指令
(gdb) n #向下走一条代码
step(进入函数体),fin(退出当前函数体),还有很多GDB的指令,有兴趣的可以使用
man gdb
查看相关参数
思考1: 如果源码在远程服务器上,这个时候应该怎么调试呢?
通过wifi调试,设备连接wifi,保证服务器和设备在同一个局域网内
$ adb tcpip 5555 #在设备端运行
$ adb connect <设备ip地址> #在服务端运行
思考2: gdbclient是什么,做了哪些操作呢?
#(要求Android 6.0及以上,5.0在build/envsetup.sh中找gdbclient()方法即可)
$ which gdbclient
# 可以看到gdbclient脚本的位置
然后我们查看里面的代码就可以发现,它做了如下几个操作:
1.设置端口转发(adb forward)
2.启动gdbserver,并将gdbserver attach到想要调试的进程
3.gdb 连接上gdbserver进行调试
PS:
gdbclient [pid]
如果连接过程中报错,也可以分析gdbclient源码来解决哦
总结
调试运行中的进程和调试本地进程的启动,操作步骤大致相同,都是先通过gdbserver进行监听,然后设置端口转发,gdb通过gdbserver进行远程调试。调试技巧对于分析源码,了解执行流程都起到了至关重要的作用。
以上就是Framework Native代码的调试流程,如果觉得对你有帮助请留下一个赞吧~ 觉得写的不好也请批评指出~
参考资料:
使用GDB