本节书摘来华章计算机出版社《深入理解Android:卷III A》一书中的第1章,第1.4节,作者:张大伟 更多章节内容可以访问云栖社区“华章计算机”公众号查看。1
1.4调试Android源代码
调试是分析问题与印证对代码的理解的最有效手段,对Android这种复杂而庞大的系统来说尤为如此。Android的源代码主要由Java代码以及C/C++代码构成,因此调试Android源代码需要从Java的调试以及C/C++的调试两个方面说起。
1.4.1使用Eclipse调试Android Java源代码
由于Android源代码是以一个普通的Java工程的方式导入的,于是在Eclipse中不能通过ADT所提供的DDMS直接对其进行远程调试。
1)首先需要通过DDMS获取调试进程的端口号。将设备通过USB连接PC,然后打开Eclipse的DDMS视图。在视图左侧Device进程列表中可以找到对应进程的调试端口号,如图1-7所示。
图 1-7获取调试目标进程的端口号
2)回到Java视图,在Package Explorer中,用右键点击Android源代码所在的项目,在菜单中依次选择“Debug As→Debug Configurations”。在弹出的对话框中通过双击Remote Java Application新建一个远程调试配置。编辑Host为“localhost”,Port为调试进程的端口号之后点击Apply按钮保存配置。最后点击Debug按钮即可将Eclipse调试器绑定到对应的进程上,如图1-8所示。
图1-8启动对目标进程的远程调试
完成上述步骤后就可以通过Eclipse的Debug视图调试进程了。
在点击Debug进行调试时,Eclipse可能会提示代码中存在错误(最常见的原因是注释掉了.classpatch中的代码路径而导致引用解析失败)。不过不用理会,直接点击Proceed按钮继续调试即可。
导入Eclipse中的源代码可能运行在任何一个进程中,这份源代码可以对设备中任何一个Java进程进行调试。本书所介绍的各种系统服务均运行在system_server进程中,而其他的内容如SystemUI、WallpaperService则运行在其他的进程里。因此,读者需要注意正确选择调试目标进程。
1.4.2使用gdb调试Android C/C++源代码
下面介绍使用gdb调试C/C++代码的步骤。
首先通过adb shell ps获取需要进行调试的进程号,比如795。然后通过执行adb shell进入手机端的shell。
输入gdbserver :5039 --attach 795并执行。其中5039是端口号,795是待调试的进程号。于是gdbserver便会绑定在795进程上,并通过5039端口与PC端的调试器进行通信。
保持gdbserver运行,然后回到PC端执行adb forward tcp:5039 tcp:5039。这个命令可以在设备上的5039端口与PC上的5039端口之间建立一个映射。于是PC端的调试器可以通过本机的5039端口与设备上的gdbserver进行通信。
接下来便需要运行Android源代码中附带的复合设备及其架构的gdb工具,并连接到本机的5039端口进行调试。对ARM架构来说,这个工具为prebuilts/gcc/linux-x86/arm/arm-eabi-4.X/bin/ arm-eabi-gdb。
Android源代码中提供了用于ARM、x86以及MIPS等目标机器架构的编译工具链。
倘若读者不清楚需要使用哪种机器架构下的编译工具链,可以先完成代码编译时source build/envsetup.sh以及choosecombo的执行以确定目标设备的类型。这样一来Android编译系统会将目标设备使用的机器架构对应的编译工具链所在的路径加入PATH环境变量中。然后就可以通过echo $PATH得知用于当前设备的编译工具链所在的路径,进而得知机器架构的类型。
进入gdb之后,依次执行如下命令:
连接本机的5039端口,进而连接到运行在设备中的gdbserver
target remote :5039
指定调试进程可执行文件的路径。注意需要选择编译结果中symbols路径下的文件。这些文件中保存了
用于进行调试的符号表
file out/target/product//symbols/system/bin/
设置用于搜索so文件的路径。注意需要选择编译结果中symbols路径下的so文件所在的路径。读者
可以从out/target/product//XXXgdb.cmds文件中的内容中得知这个路径
set solib-search-path ......
之后便可以开始使用gdb的命令调试795进程了。
倘若读者觉得使用上述步骤进行调试比较繁复,可以使用Android源代码中所提供的gdbclient工具。gdbclient是定义在build/envsetup.sh中的一个Shell函数,它会根据choosecombo的结果判断可执行文件的路径以及so文件的路径,并自动完成上文所述的工作。因此,使用它之前必须完成source build/envsetup以及choosecombo的执行。使用gdbclient调试一个进程的方法如下:
gdbclient <可执行文件名> :<端口号> <进程号>
例如,调试795的mediaserver进程可以使用如下命令:
gdbclient mediaserver :5039 795
另外,倘若使用gdb调试Java进程中的C/C++代码,需要使用app_process作为可执行文件进行调试。