Android 系统源码中自带 gdb 调试工具,下面举例示范如何使用 gdb 来调试 framework 的 native 代码。
前提条件:
1. Android 系统源码,要调试的代码需要编译。
2. Android 设备中运行的是上一条中的代码编译出来的程序,且编译的系统是 userdebug 版本的。
一、获取进程 PID
假设我们当前想要调试系统的媒体播放服务 MediaPlayerService,这个服务是在 mediaserver 进程中启动的,故需要先查找该进程的 PID。
设备连接到电脑并开启adb,在命令行中执行:
$ adb shell ps | grep mediaserver
可以获取到 mediaserver 进程的 PID:
上面的 525 就是该进程的pid。
二、启动 gdbserver
按理说这步可以省略,系统源码中提供的 gdbclient.py 脚本会自动执行这一步骤,但在我的调试机上操作好像没成功,故增加这一步,正常可以先跳过这一步,从下一步开始。
开启 gdbserver,打开一个终端进入adb shell,执行命令:
# gdbserver :5039 --attach 525
可以看到 gdbserver 已经 attach 到 525 进程,并且监听 5039 端口等待 gdb 的连接,该端口是默认使用的端口:
注意,这里要根据进程的类型选择 gdbserver ,如果是64位的使用 gdbserver64
三、启动 gdb 连接 gdbserver
Android 系统源码中提供了一个脚本 gdbclient.py 用于连接到设备的 gdbserver 进行调试,这个脚本其实就是封装了一些gdb的操作,便于使用。
首先需要重新开启一个终端窗口,刚才那个就保持不动。进入源代码的根目录,然后执行:
$ source build/envsetup.sh
$ lunch xxxx
这是常规的编译前操作,不懂的先去看编译流程。然后就可以开启运行 gdbclient.py 脚本, -p 指定刚才获取到的 pid:
$ gdbclient.py -p 525
运行输出如下:
看到这个输出电脑的 gdb 已经成功连接设备上的 gdbserver 了,此时设备上的 gdbserver 也会有输出:
四、开始调试
前面提到,我们想调试 MediaPlayerService,比如说现在要在 MediaPlayerService::Client::start() 方法上打一个断点,就可以输入:
(gdb) b android::MediaPlayerService::Client::start
可以看到输出,显示了断点的文件和位置:
注意此时该进程是卡住的,现在让它跑起来,输入:
(gdb) c
进程开始执行:
要让程序运行到断点的地方,因为是媒体播放服务,所以可以播放一段音乐,比如进入系统声音设置,点一下音量条之类的,就可以看到:
可以看到程序已经停在断点所在的地方,对应源码就是:
接下去就可以根据需要执行相应的调试,比如单步执行,打印变量值等,具体参考gdb的使用教程。