查看原文
其他

Android FrameWork学习(二)Android系统源码调试

2017-03-31 香辣牛肉面 终端研发部



前言介绍


新的一天,祝愿大家工作愉快。

如果对于Android7.0系统源码的下载和编译不太熟悉的童鞋们请先阅读

 这篇文章来自于面哥大神(香辣牛肉面)Android系统源码调试<二>关于Android7.0系统源码的编译及调试进一步深入的去学习。

香辣牛肉面博客地址:


正文



最近计划着研究下 7.0的系统源码,之前也没做过什么记录,这次正好将学习的内容记录下来,方便以后复习巩固。

通过上一篇 Android FrameWork学习(一)Android 7.0系统源码下载\编译 我们了解了如何进行系统源码的下载和编译工作。

为了更进一步地学习跟研究  系统源码,今天我们来讲讲如何进行 Android 系统源码的调试,只有学会了如何进行系统源码的调试,才能帮助我们更高效地阅读跟理解源码。

我们知道,Android Framework 的代码主要由、C\C++等代码组成,因此,对于系统源码的调试,我们这里将其分为了两部分

1. Java 相关代码的调试

2. C\C++ Native 相关代码的调试


一、Java 相关代码的调试

对于 Java 相关代码的调试,这里我们主要使用 Android Studio 开发工具来进行。

导入源码到 Android Studio

要在 Android Studio 中调试源码,那第一步自然是导入系统源码到 Android Studio 中了。

1. 编译 idegen

对于 Android 源码的导入, Google 官方给我们提供了一个很方便的工具 idegen

它位于我们所下载的系统源码路径中:

developement/tools/idegen

引用 README 的一句话

IDEGen automatically generates Android IDE configurations for IntelliJ IDEA 
and Eclipse.

idegen 工具会自动生成针对 Android 开发工具(Android Studio和Eclipse)的配置文件。

既然如此,那我们就来使用 idegen 工具生成导入源码所需的配置文件。

首先打开命令行工具,cd 进入到源码路径下,

执行如下指令:

#初始化命令工具soruce build/envsetup.sh #编译 idegen 模块,生成idegen.jarmmm development/tools/idegen/#生成针对 Android 开发工具的配置文件 sudo ./development/tools/idegen/idegen.sh

在执行完上述指令后,会在源码路径下生成下面三个文件

android.ipr:工程相关的设置,比如编译器配置、入口,相关的libraries等。

android.iml:描述了modules,比如modules的路径,依赖关系等。

android.iws:包含了一些个人工作区的设置。

2. 导入源码

接下来我们可以开始导入源码了.

如果你是第一次导入源码, Android Studio 可能需要占用大量的内存,我们需要设置下我们的 VM 选项。

 设备的话在 Android Studio 的 bin/studio64.vmoptions 文件中添加-Xms748m -Xmx748m

如果你使用的是 Mac ,那么在 AS 目录的 Contents/Info.plist 目录中进行添加。

由于 Android 的系统源码非常庞大,一次性导入 Android Studio 的话需要加载非常长的时间

因此,在正式开始导入前,我们可以打开 android.iml 文件根据自己需要调整要加载的源码。

这里 <excludeFolder> 表示不需要加载的目录,我们根据自己的需要使用 <excludeFolder> 标签添加对应的目录地址即可。

接着,选择 File -> open 选中 android.ipr 文件,打开

这时 Android Studio 就会开始加载源码了

在没有添加修改 <excludeFolder> 的情况下,这个加载的时间会比较长,经过一段时间的等待后,代码就加载完毕了,如图:

这里红色的目录代表被 exclude 排除了,代码加载 scan index 的时候会过滤掉该目录。

在加载完源码后,我们也可以在 Project Structure 中的 Module 选项中右键 exclude 来排除不需要加载的源码目录,如图:

3. 配置代码依赖,确保代码跳转正确

为了阅读和调试代码的时候能够保证代码跳转正确,我们需要配置下相关依赖。

首先是 AOSP 源码的跳转,我们通过 File -> Project Structure 打开 Module,然后选中 Dependencies, 保留 JDK 跟 Module Source 项,并添加源码的 external 和 frameworks 依赖,如图:

然后是 SDK 的设置,确保关联对应版本的 SDK 于系统版本一直

开始调试源码

调试前要设置 Project 的 SDK , File -> Project 下打开 Project Structure,选中 Project 设置对应版本的 SDK,于系统版本一致:

确保 Android Studio 允许 ADB 调试

接着我们参照上一篇文章中讲的方法打开 Android 模拟器

此时点击 Android Studio 工具栏的 attach debugger to Android process 按钮,会打开 Choose Process 窗口,我们根据自己需要调试的代码选择对应的进程:

这里假设我们要调试 Android 自带浏览器的源码,如图,我们在它的入口文件 WebViewBrowserActivity 中的 loadUrlFromUrlBar 方法中打上断点。

点击 WebViewBrowser 打开 app

打开之后,点击 attach to Android process 按钮打开 choose Process,可以看到 webViewBrowser 运行的进程,选中,ok

然后我们在 app 的 url 输入栏输入 网址进行跳转

如图所示我们可以看到,代码成功进入了断点,然后我们就可以随心所欲地调试我们想要的调试的 Java 代码了。


二、Native C\C++ 相关代码调试

对于 Framework Native 代码,我们这里使用 GDB 工具来进行调试。

什么是 GDB 呢?

它是一款 GNU 项目调试工具,它的功能非常强大,可以用来调试 C 、C++、Object-C、Pascal 等语言编写的项目。

对于使用习惯了可视化 IDE 的同学们来说,它最大的缺点可能就是它不支持图形化了

但是 GDB 提供的指令非常灵活,通过指令我们 
* 可以随心所欲地启动程序, 
* 可以根据自己的需要设置断点, 
* 可以查看断点处的变量,代码信息 
* 可以查看程序运行的调用栈

一旦你熟悉了它,你便可以玩得飞起!

一般情况下,使用 gdb 来调试 Android 源码需要在 Android 设备上安装 gbdserver attach 关联我们需要调试的进程,再使用 gdb 指令去连接 gdbserver 进行调试

不过官方给我们提供了 gdbclient 工具,可以让我们方便地进行 gdb 调试。

开始 GDB 调试

这里我们就基于 gdbclient 来进行实际的 gdb 调试演示:

跟上面 Java 调试一样,我们这里还是以系统自带的浏览器为例。

1. 点击启动图标打开浏览器 app:

2. 打开一个命令行终端,cd 进入到系统源码目录(我的源码路径为 aosp),初始化命令工具:

#进入源码路径cd aosp#初始化命令工具source build/envsetup.sh#选择编译的源码的版本,参考上一篇文章lunch

3. 通过 adb 指令来查找要调试进程的 PID

#通过 shell ps 指令查找相关进程,grep 搜索过滤 webview 进程adb shell ps -A | grep webview

如图,2157 为系统自带浏览器 app 所在进程的 PID

4. 使用 gdbclient 命令工具启用 gdb 调试 PID 对应进程

# gdbclient <app pid> 可以启用 gdb 调试对应 PID 进程gdbclient 2157

等待进入 gdb 调试命令界面

5. 使用 GDB b 命令打断点

在 gdb 指令中,我们使用b <代码文件>:行号 来设置断点.

这里我们选择 frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp 代码文件的 drawFrame 方法打上断点,位于文件 71 行:

该方法主要用于绘制帧,当浏览器 app 的界面发生变化时会触发该方法。

我们输入设置断点命令:

b frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp:71

输入指令后显示 
Breakpoint 2 at 0x7f69e9892c11: file frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp, line 71. 
说明我们的断点设置成功了。

6. 在命令行输入c 开始监听

c 即 continue,此时界面上出现 Continuing 说明开始监听进程了

我们点开模拟器,随意操作,触发界面变化时,便会进入绘制帧的代码断点了:

如图,显示进入断点,这样代表我们的代码调试成功了。


这里我们只是演示了一个大概流程,

gdb 代码的调试需要你对源码有一定的熟悉,知道哪个进程会调用哪个文件方法。

同时,我们还需要熟悉 gdb 的各种命令,这里给大家推荐一篇不错的入门文章,可以快速入门:

这里补充一点,如果你希望在某个进程启动时就监听,可以使用下面的指令关联目录,得到 pid,再通过 gdbclient 来进行调试

adb shell gdbserver :5039 /system/bin/my_test_app Process my_test_app created; pid = 3460Listening on port 5039gdbclient <app pid>

如果你希望通过 Android Studio 来调试 Framework 的 C\C++ 代码的话,也可以参考下面的两篇文章,不过个人觉得这种方法有一定的局限性。


结语

正如文章开头所说,只有学会了如何调试 Framework 源码,才能帮助我们更好地学习 Android Framework,希望这篇文章能给大家一些帮助,如果有更好地调试方法,欢迎大家给我留言咯!

本来来自面哥大神(香辣牛肉面)的投稿,想学习更多,请参考面哥的博客。

香辣牛肉面博客地址:

如果你觉得此文对您有所帮助,欢迎入群 QQ交流群 :232203809 微信公众号:终端研发部





            

Hello,伙伴们

长按二维码就可以关注我们啦!





您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存