Android FrameWork学习(二)Android系统源码调试
通过上一篇 Android FrameWork学习(一)Android 7.0系统源码下载\编译 我们了解了如何进行系统源码的下载和编译工作。
为了更进一步地学习跟研究 Android 系统源码,今天我们来讲讲如何进行 Android 系统源码的调试,只有学会了如何进行系统源码的调试,才能帮助我们更高效地阅读跟理解源码。
我们知道,Android Framework 的代码主要由Java、C\C++等代码组成,因此,对于系统源码的调试,我们这里将其分为了两部分
- Java 相关代码的调试
- 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.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 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 = 3460
Listening on port 5039
复制代码
gdbclient <app pid>
复制代码
如果你希望通过 Android Studio 来调试 Framework 的 C\C++ 代码的话,也可以参考下面的两篇文章,不过个人觉得这种方法有一定的局限性。
#结语
正如文章开头所说,只有学会了如何调试 Framework 源码,才能帮助我们更好地学习 Android Framework,希望这篇文章能给大家一些帮助,如果有更好地调试方法,欢迎大家给我留言咯!
Android FrameWork学习(二)Android系统源码调试的更多相关文章
- Android FrameWork 学习之Android 系统源码调试
这是很久以前访问掘金的时候 无意间看到的一个关于Android的文章,作者更细心,分阶段的将学习步骤记录在自己博客中,我觉得很有用,想作为分享同时也是留下自己知识的一些欠缺收藏起来,今后做项目的时候会 ...
- [spring源码学习]二、IOC源码——配置文件读取
一.环境准备 对于学习源码来讲,拿到一大堆的代码,脑袋里肯定是嗡嗡的,所以从代码实例进行跟踪调试未尝不是一种好的办法,此处,我们准备了一个小例子: package com.zjl; public cl ...
- Android开发学习之路-Volley源码解析
从简单的StringRequest入手看看Volley的工作机制. 先简单说下Volley的用法: ① 获取一个RequestQueue mRequestQueue = Volley.newReque ...
- Android进阶:二、从源码角度看透 HandlerThread 和 IntentService 本质
上篇文章我们讲日志的存储策略的时候用到了HandlerThread,它适合处理"多而小的任务"的耗时任务的时候,避免产生太多线程影响性能,那这个HandlerThread的原理到底 ...
- mybatis源码学习(二)--mybatis+spring源码学习
这篇笔记主要来就,mybatis是如何利用spring的扩展点来实现和spring的整合 1.mybatis和spring整合之后,我们就不需要使用sqlSession.selectOne()这种方式 ...
- Android开发学习之路-SimpleAdapter源码分析学习
今天在课堂上,老师用到了SimpleAdapter,然后女神在边上问我为什么这个SimpleAdapter不能做到我app那种带有进度条的效果,言语说不清,然后就开始看源代码,发现这个Adapter的 ...
- Redis学习之对象系统源码分析
背景知识: Redis并没有直接使用sds,双端链表,字典,压缩列表,跳表等这些数据结构来直接实现键值对数据库,而是基于这些对象创建了一个对象系统,这个对象系统包含5个对象:字符串对象,列表对象,哈希 ...
- 【转】编译Android系统源码和内核源码
原文网址:http://blog.csdn.net/jiangwei0910410003/article/details/37988637 好长时间没有写blog了,之所以没有写,主要还是工作上的事, ...
- 【安卓本卓】Android系统源码篇之(一)源码获取、源码目录结构及源码阅读工具简介
前言 古人常说,“熟读唐诗三百首,不会作诗也会吟”,说明了大量阅读诗歌名篇对学习作诗有非常大的帮助.做开发也一样,Android源码是全世界最优秀的Android工程师编写的代码,也是A ...
随机推荐
- python--一些知识点
一. ==和is的区别 1. ==意为左右两端的值是否相等 2. is意为,左边是否就是右边,python会检测左右两边的引用位置,相等才是True(注:一定范围内的数字,左右两边为True) 二. ...
- 【JavaScript】js02
正则对象. 声明: //var reg = new RegExp('', '');// i,g 修正符. // i,不区分大小写,g 全局匹配. //var reg = /\w/i; 方法: //ex ...
- 【PHP】流程控制
一. 顺序结构 a) PHP的脚本从上到下,从左往右的执行顺序就是顺序结构! 二. 分支结构 a) 单一的分支结构 If ( 条件表达式 ) { 程序体: } 执行过程 ...
- flask-文件上传的使用
flask-文件上传 在flask中使用request.files.get来获取文件对象 对获取到的文件对象可以使用save(filepath)方法来保存文件 上传的文件在保存前需要对文件名做一个过滤 ...
- python部署-Flask+uwsgi+Nginx
一.Flask部分(app.py) flask即Python代码:部分参考代码如下,相信很多人如果看到这篇文章一定有flask的代码能力. from app import create_app fro ...
- Linux网络安全篇,配置Yum源(二),阿里Yum源
官网教程: https://opsx.alibaba.com/mirror 1.下载配置文件到 /etc/yum.repos.d 目录 wget -O /etc/yum.repos.d/CentOS- ...
- Linux中vim编辑器 的 快捷键 --- 常用 的 都比较全
Linux中vim编辑器的功能非常强大,许多常用快捷键用起来非常方便,这里将我学vim入门时学的一些常用的快捷键分享给大家一下,希望可以帮助你们. 这个是我将鸟哥书上的进行了一下整理的,希望不要涉及到 ...
- ViewStub
在书上了解了ViewStub,但只是带过两笔,没能了解.在网上搜索了一些资料,虽然很多文章都讲得比较完善,但是觉得可能是表达的原因,导致某个点上我理解错误,慢慢的才算比较清楚的认识ViewStub. ...
- 绕过XSS过滤姿势总结
0x01 弹窗关键字检测绕过 基本WAF都针对常用的弹窗函数做了拦截,如alert().prompt().confirm(),另外还有代码执行函数eval(),想要绕过去也比较简单,我们以alert( ...
- JUC并发编程基石AQS源码之结构篇
前言 AQS(AbstractQueuedSynchronizer)算是JUC包中最重要的一个类了,如果你想了解JUC提供的并发编程工具类的代码逻辑,这个类绝对是你绕不过的.我相信如果你是第一次看AQ ...