zoukankan      html  css  js  c++  java
  • Android FrameWork学习(二)Android系统源码调试

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

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

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

    • Java 相关代码的调试
    • CC++ 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.jar
    mmm development/tools/idegen/
    #生成针对 Android 开发工具的配置文件 
    sudo ./development/tools/idegen/idegen.sh
    复制代码

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

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

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

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

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

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

    Linux 设备的话在 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 CC++ 相关代码调试 对于 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 的各种命令,这里给大家推荐一篇不错的入门文章,可以快速入门:

    GDB十分钟教程

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

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

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

    如何调试Android Native Framework

    用Android Studio调试Framework层代码


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

  • 相关阅读:
    读《大道至简》第二章有感
    读大道至简之感
    C#学习笔记二:并行编程基础:在 PLINQ 和 TPL 中的 Lambda 表达式
    C#学习笔记一:委托、匿名函数、Lambda 表达式
    VS2013 最常用 和 不是最常用的快捷键备忘
    EntityFramework初上手
    C#的值类型,引用类型,栈,堆,ref,out
    python批量下载图片
    django部署for新浪SAE
    Linux下安装搜狗拼音输入法
  • 原文地址:https://www.cnblogs.com/twodog/p/12137673.html
Copyright © 2011-2022 走看看