通过上一篇 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 ...
随机推荐
-
Google Material Design的图标字体使用教程
使用教程 1. 打开Material icons下载页 2. 选择要下载的图标 (目前不能多选>_<) 3.选择要下载的格式即可 图标字体使用教程 [方法一] STEP 1: 引入字体文件 ...
-
dataguard不同步问题ora-16191解决
公司的11g的dataguard主备不同步,检查步骤如下: Primary:查询主库的最大日志 SQL> select max(sequence#) from v$archived_log;SQ ...
-
初见Gnuplot——时间序列的描述
研读一本书,<数据之魅:基于开源工具的数据分析>(Data Analysis with Open Source Tools),写的很好.这里,复述一下书中用Gnuplot分析时间序列数据的 ...
-
后台方庄List razor 循环
后台: //1.查询所有年卡类型 StringBuilder sqlStr = new StringBuilder(); sqlStr.Ap ...
-
QT5:C++实现基于multimedia的音乐播放器(一)
上一篇里简略的描述了一下播放器的实现,这一篇开始具体描述一下过程. 环境配置:Qt Creator 打开Qt Creator,创建一个new project,项目名称随你喜欢(我的是MusicPlay ...
-
【PY】Python3.7+Anaconda3 + PyQt5 + Eric6
Anaconda下载地址:https://www.continuum.io/downloads pip install pyenchant pip install QScintilla pip ins ...
-
Disable access to Windows Update
Disable access to Windows Update If this policy setting is enabled, all Windows Update features are ...
-
centos7部署phpipam(ip管理系统)
安装必要的软件 yum install httpd mariadb-server php php-cli php-gd php-common php-ldap php-pdo php-pear php ...
-
uva1416 dijkstra
大白书P330 这题比较麻烦 给出一个n个节点m条边的无向图,每条边上有一个正权.令c等于每对节点的最短路长度之和.例n=3时, c = d(1,1)+d(1,2)+d(1,3)+d(2,1)+d(2 ...
-
drupal中安装CKEditor文本编辑器,并配置图片上传功能 之 方法二
drupal中安装CKEditor文本编辑器,并配置图片上传功能 之 方法一 中介绍了ckeditor的安装和配置方法,其实还有另一种新方法,不用IMCE模块. 不过需要ckfinder的JS库,可以 ...