本节书摘来自华章出版社《深入理解Android》一书中的第1章,第1.4节,作者孟德国 王耀龙 周金利 黎欢,更多章节内容可以访问云栖社区“华章计算机”公众号查看
1.4 WebKit代码调试
Android平台WebKit的调试分析的常用手段包括打印log、remote gdb调试以及分析crash dump等,下面分别介绍。
(1)打印log,将系统的运行信息输出到log系统
WebKit 代码量较大,很多逻辑非常复杂,单纯的断点调试,很难直观看到想要观察的数据。一方面对于一些嵌套非常强的逻辑,如递归等,使用断点调试很难直观看到相互关系。WebKit中一个典型的递归应用就是对Render树等树形结构的遍历,如果我们要打印出一棵Render树的各个节点,要直观地看到其结构,就需要使用log。另一方面WebKit中很多对象巨大,变量隐藏很深,可能有多个基类包含多次继承,并且还有智能指针的包裹,使得使用动态调试观看非常麻烦,所以传统的log打印对于我们来说仍然必要。在Android系统下,打印log函数是__android_log_print,其输出的log通过adb logcat查看。一般使用定义宏:
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG,__VA_ARGS__)
// 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG,__VA_ARGS__)
// 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG,__VA_ARGS__)
// 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__)
// 定义LOGE类型
在使用__android_log_print 前,先要在WebKit的Android.mk中加上liblog.so库的连接依赖,具体如下:
LOCAL_LDLIBS+= -L$(SYSROOT)/usr/lib -llog
(2)通过ndk-stack查看webkit native crash时导出的栈信息
当程序崩溃时,需要知道crash 发生在哪里,crash时函数的调用栈细节等信息。 Android程序崩溃时,会通过log系统输出crash时的寄存器和栈信息,部分机器会在/data/tombstones目录产生crash日志文件。将crash时产生的stack dump信息保存在crash.txt中,通过如下命令查看crash 时栈的dump信息:
ndk-stack -sym $SYMBOL_SO_PATH -dump crash.txt
SYMBOL_SO_PATH是符号库目录,在Android源码中是out/target/product/xx/symbol/system/lib。
关于Android crash dump产生的原理可参考3.3节。
(3) 通过remote gdb直接动态调试运行中的浏览器
如果需要断点调试,单步跟踪,查看线程栈,此时就要使用gdb。Android源码本身提供脚本gdbclient连接设备上的gdbserver。将gdbserver push目标设备的特定目录(gdbserver可在Android源代码的prebuilt目录下找到,也可以从NDK中获取),赋予其可执行权限。在shell中启动设备上的gdbserver 并attach到browser线程:
$adb shell ps |grep com.android.browser #找到浏览器进程pid,需要先启动浏览器
$adb shell gdbserver :5039 --attach PID
其中5039为端口号,也可以自定义为其他端口。在另一个shell中启动端口映射:
$sudo adb forward tcp:5039 tcp:5039
启动gdbclient:
arm-eabi-gdb out/target/product/xx/symbols/system/bin/app_process
看到gdb的命令提示符“(gdb )”后,输入如下命令以载入符号库:
set solib-absolute-prefix out/target/product/xx/symbols/system/lib/
set solib-search-path out/target/product/xx/symbols/system/lib/
target remote:5039
等到各个lib加载完毕,就能看到gdb顺利启动起来,并再次显示命令提示符(gdb)。此后可以根据需要输入相应命令,比如设置断点:
b FrameLoaderClientAndroid.cpp:868
执行c,访问一个网址,就可以看到gdb断点了。此后就是我们熟悉的gdb命令了。