Android FrameWork 学习之Android 系统源码调试

这是很久以前访问掘金的时候 无意间看到的一个关于Android的文章,作者更细心,分阶段的将学习步骤记录在自己博客中,我觉得很有用,想作为分享同时也是留下自己知识的一些欠缺收藏起来,今后做项目的时候会用到。

好了,废话不多说了。直接来吧。。

Android 7.0系统源码下载\编译:http://blog.csdn.net/cjpx00008/article/details/67185045(这个链接并不是下载地址,而是对安卓系统编码的一个阐述,源码官网可以下载的)

这是Android 7.0系统源码下载\编译

原文

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

既然要学习我们的系统源码,那我们第一步要做的就是下载源码并进行编译了。

硬件环境要求

1. 编译环境

按照官方的说法,编译Android 2.3.x及以上版本的系统源码需要64位的系统运行环境来支持,而编译2.3.x以下的版本则需要32位的系统运行环境。

2. 硬盘空间

官方建议最好预留100G的磁盘空间来下载源码,150G的磁盘空间用来编译源码,如果使用了ccache(一个高速编译缓存工具,可以大幅加快gcc的编译速度),那么则需要更大的空间来支持。

所以尽可能地保证自己的磁盘空间够大吧,之前就因为磁盘空间预留不够导致源码编译过程中空间不足,狠狠地把自己坑了一把。

3. 内存空间

如果你是在虚拟机上跑Linux,官方建议至少需要16G的内存空间,我的机器只有8G的内存空间跑虚拟机,目前跑起来也没太大问题,就是编译源码的过程非常漫长,不知道是否跟内存大小有关。

软件环境要求

1. 操作系统

Android系统的源码的编译支持Linux跟Mac OS两种操作系统,一般情况下,Android系统源码都是在Linux Ubuntu系统上进行开发与测试的,所以如果你准备使用Linux系统来进行源码编译,那一般推荐安装Ubuntu版本的Linux。

下面列出了各Android版本与编译系统版本的对应关系

Linux:

Android版本GNU/Linux
Android 6.0 (Marshmallow) - Android最新版本Ubuntu 14.04 (Trusty)
Android 2.3.x (Gingerbread) - Android 5.x (Lollipop)Ubuntu 12.04 (Precise)
Android 1.5 (Cupcake) - Android 2.2.x (Froyo)Ubuntu 10.04 (Lucid)

Mac OS

Android版本Mac OS (Intel/x86)
Android 6.0 (Marshmallow) - Android最新版本Mac OS v10.10 (Yosemite) or later with Xcode 4.5.2 and Command Line Tools
Android 5.x (Lollipop)Mac OS v10.8 (Mountain Lion) with Xcode 4.5.2 and Command Line Tools
Android 4.1.x-4.3.x (Jelly Bean) - Android 4.4.x (KitKat)Mac OS v10.6 (Snow Leopard) or Mac OS X v10.7 (Lion) and Xcode 4.2 (Apple’s Developer Tools)
Android 1.5 (Cupcake) - Android 4.0.x (Ice Cream Sandwich)Mac OS v10.5 (Leopard) or Mac OS X v10.6 (Snow Leopard) and the Mac OS X v10.5 SDK

2.JDK 版本要求

不同的Android版本编译也需要对应的JDK环境,这里列出了各版本之间的对应关系

Android版本JDK版本(Ubuntu)JDK版本(Mac OS)
Android目前最新版本OpenJDK 8jdk 8u45 or newer
Android 5.x (Lollipop) - Android 6.0 (Marshmallow)OpenJDK 7jdk-7u71-macosx-x64.dmg
Android 2.3.x (Gingerbread) - Android 4.4.x (KitKat)Java JDK 6Java JDK 6
Android 1.5 (Cupcake) - Android 2.2.x (Froyo)Java JDK 5 

搭建编译环境

据上面列出的软硬件要求,我们可以根据自己要编译的Android版本以及自己的设备来选择合适的系统及JDK,接下来我们就来说说如何搭建编译环境。

这里我们主要针对Android 7.0的需要的编译环境分别对Linux和Mac OS进行配置:

设置Linux系统编译环境

1.安装JDK

Android 7.0目前需要openJDK 8的JDK环境

Ubuntu 15.04+

如果你的系统是Ubuntu 15.04及以上版本的话,直接运行如下指令即可直接安装:

 

Ubuntu 14.04

如果你使用的是Ubuntu 14.04版本,现在并没有专门针对14.0.4可用的open jdk8的包,

但是Ubuntu 15.04 OpenJDK 8的包可以在14.0.4上成功地运行,所以我们下载Ubuntu 15.04 OpenJDK 8的安装包来手动安装:

  1. 从 archive.ubuntu.com上依次下载下面列出的64位的open JDK 8 的.deb安装包 
    openjdk-8-jre-headless_8u45-b14-1_amd64.deb 
    openjdk-8-jre_8u45-b14-1_amd64.deb 
    openjdk-8-jdk_8u45-b14-1_amd64.deb

  2. 安装.deb包 
    先运行apt-get指令更新软件列表

      sudo apt-get update

      接着依次对上面下载的三个deb文件运行如下指令进行安装:

 

      sudo dpkg -i 下载的文件地址

     最后运行 apt-get -f 指令修复安装依赖的包

 

      sudo apt-get -f install

 

  1. 更新系统默认使用的JDK版本 
    如果你的系统安装了多个版本的JDK,可以通过下面的指令执行切换,会弹出可选的JDK版本,根据你的需要选择对应的版本就可以了:

2.安装所需要的工具包
Ubuntu 14.04

我们编译过程中会用到下面的依赖包,执行如下指令统一安装:

3.设置源码编译输出路径

默认情况下,编译好的系统源码会在源码所在目录的out文件夹下, 
如果你希望调整输出目录的路径,可以执行下面的指令指定输出目录:

4.设置USB接口访问设备

在linux下,默认情况是不允许普通用户直接通过USB接口来访问设备的.

推荐方法是以根用户身份在 /etc/udev/rules.d/51-android.rules 路径创建文件。

我们可以通过如下指令来实现(注意用你的系统username替换指令中的):

设置Mac OS系统编译环境

Mac OS的文件系统默认情况下保留了大小写实际上却又不区分大小写。 
目前的Git指令无法支持这样的文件系统,会导致一些莫名其妙的错误,所以在Mac OS上编译Android系统源码,我们必须先创建一块区分大小写的磁盘镜像。

创建一块区分大小写的磁盘镜像

这里我们直接通过命令行来创建:

该指令会在系统根目录下生成一个android.dmg或是android.dmg.sparseimage文件,一旦挂载,将被作为支持Android开发所需格式的驱动镜像分区。

如果之后你需要更大的空间,你可以通过下面的指令进行空间调整:

你还可以在 ~/.bash_profile 文件中,添加帮助函数来挂载跟取消挂载:

之后我们就可以通过执行mountAndroid指令来执行挂载镜像,通过umountAndroid指令来取消挂载。

安装JDK

安装工具依赖包
1. 安装xcode命令行工具
$ xcode-select --install

对于老版本的Mac OS系统(10.8或者10.8之前的),我们需要到苹果开发者站点进行下载安装. 
如果你还没有注册成为苹果开发者,你需要先注册一个苹果账号来进行下载.

2. 到 macports.org 上下载对应Mac OS版本的macports(类似于Linux下的apt-get,用来帮助你安装其他应用程序)

注意:确保 /opt/local/bin 在路径 /usr/bin前,如果没有,在 ~/.bash_profile 文件中进行添加

export PATH=/opt/local/bin:$PATH

注意:如果根目录下没有 .bash_profile 文件,那就手动创建一个

3. 通过macports安装make, git以及GPG
$ POSIXLY_CORRECT=1 sudo port install gmake libsdl git gnupg

如果使用的是Mac OS X v10.4版本的系统,还需要安装bison:

$ POSIXLY_CORRECT=1 sudo port install bison

注意:如果是编译Android 4.0.x及以下版本的系统,gmake 3.8.2版本存在一个bug,需要还原到gmake 3.8.1

优化编译环境(可选)

设置ccache

我们可以自由选择是否开启ccache编译工具。

ccache是一个高速编译缓存工具,它通过将头文件高速缓存到源文件之中而改进了构建性能,因而通过减少每一步编译时添加头文件所需要的时间而提高了C\C++的构建速度。

从编译的全过程来看,不使用ccache的情况下,编译过程中会多次解析相同的头文件,浪费了处理器周期,更重要的是浪费了开发者的时间,因为他们要等待这一过程的完成。在一个团队中,这一影响可能会更为明显,因为团队成员可能会反复编译解析相同的头文件。

所以,一般对于专门用来编译系统的服务器或是大容量的生产环境,这个功能比较有用,它可以加速重新编译的速度。

注意:如果你只是个人开发者,不是专门的编译服务器,不需要进行增量构建的话,那么使用ccache可能会因为高速缓存缺失而降低你的构建速度。

开启ccache

要开启ccache,在源码树的根路径下执行下面的指令:

缓存的大小一般设置为50G-100G

接着在 .bashrc (或者etc/profile)中添加下面的指令

export USE_CCACHE=1

默认情况下,缓存会存在home根目录的~/.ccache中,但是如果你使用的是NFS或者其他的非本地文件系统,那么你同样需要在.bashrc指定缓存目录地址

在Mac OS的系统中,你需要将linux-x86替换成darwin-x86:

prebuilts/misc/darwin-x86/ccache/ccache -M 50G

当编译的Android系统是4.0.x或者更老的版本,ccache的缓存路径会有所不同

prebuilt/linux-x86/ccache/ccache -M 50G

这个设置会一直存储在CCACHE_DIR中。

在Linux上,你可以通过以下指令开启对ccache的监听:

$ watch -n1 -d prebuilts/misc/linux-x86/ccache/ccache -s

下载源码

编译环境配置好之后,我们就可以开始下载我们的源码了

安装Repo

Repo是google用Python写的一个脚本工具,Android使用git作为代码管理工具,一个Android系统由N多个git库构成,如果手动进行一个个下载,那简直是一件非常痛苦的事,而repo就是用来对这些git库进行维护管理跟下载的。

通过Repo工具,我们可以轻松地完成Android系统源码的下载。

1.在系统home根路径下创建bin目录并且添加到path路径中:

2.下载repo工具并设置其可执行

初始化Repo客户端

1.创建一个空目录用来存放我们的Android系统源码,名字自己随便定

2.初始化repo仓库

从主干master下载源码,目前最新版本

如果需要下载某个特定版本系统的分支,可以在上述命令后加-b 版本分支号,这里我指定Android 7.0的版本分支

 

 

具体的版本分支号可以到这个地址查看(需要翻墙): 
Android系统个版本分支号

3.同步源码到本地

这时执行sync指令便可以自动下载源码到本地了

使用国内镜像下载源码

由于国内网络的问题,上述操作的源码下载需要翻墙才能进行,速度会受到很大影响,几十G的系统源码可能需要花上上周的时间才能下完,

因此我们可以选择国内的镜像进行源码下载:

清华大学的镜像站 
参照页面上的描述对上面的指令稍作调整便可以了,站点上写得比较详细,这里我们就不作赘述了。

根据网速的不同,一般一天之内能够下载完毕。

对于下载下来的源码,我们并不能直接刷到我们的目标设备上或者是使用模拟器运行,我们必须对源码进行编译生成对应的image二进制镜像文件, 
当然你也可以直接从官网下载对应系统版本的镜像文件:

里我们还是自己来编译下源码,熟悉下整个编译过程。

源码编译

首先我们通过命令行进入到源码目录中,我这里目录的名称是aosp

 

cd aosp

清空输出目录

为了确保我们编译生成的文件不受之前build构建的文件影响,我们在源码目录中执行下面的指令,该指令会清空out输出目录中的所有文件

$ make clobber

设置编译环境

首先我们通过源码build目录中的 envsetup.sh 脚本文件初始化我们的编译环境,执行

$ source build/envsetup.sh

$ . build/envsetup.sh

这两个指令的效果是一样的,会初始化一些有用的命令工具

我们后面执行的一些指令必须在初始化 envsetup之后才能执行

选择编译目标

接着我们通过 lunch 指令来选择我们需要编译的目标 
执行lunch指令

$ lunch

会弹出可选目标项:

所有的构建目标由BUILD-BUILDTYPE的形式组成: 
BUILD对应codename

这是官方提供的一份对照表:

这是官方提供的一份对照表:

DeviceCode nameBuild configuration
Pixel XLmarlinaosp_marlin-userdebug
Pixelsailfishaosp_sailfish-userdebug
HiKeyhikeyhikey-userdebug
Nexus 6Pangleraosp_angler-userdebug
Nexus 5Xbullheadaosp_bullhead-userdebug
Nexus 6shamuaosp_shamu-userdebug
Nexus Playerfuguaosp_fugu-userdebug
Nexus 9volantis (flounder)aosp_flounder-userdebug
Nexus 5 (GSM/LTE)hammerheadaosp_hammerhead-userdebug
Nexus 7 (Wi-Fi)razor (flo)aosp_flo-userdebug
Nexus 7 (Mobile)razorg (deb)aosp_deb-userdebug
Nexus 10mantaray (manta)full_manta-userdebug
Nexus 4occam (mako)full_mako-userdebug
Nexus 7 (Wi-Fi)nakasi (grouper)full_grouper-userdebug
Nexus 7 (Mobile)nakasig (tilapia)full_tilapia-userdebug
Galaxy Nexus (GSM/HSPA+)yakju (maguro)full_maguro-userdebug
Galaxy Nexus (Verizon)mysid (toro)aosp_toro-userdebug
Galaxy Nexus (Experimental)mysidspr (toroplus)aosp_toroplus-userdebug
Motorola Xoom (U.S. Wi-Fi)wingrayfull_wingray-userdebug
Nexus Ssoju (crespo)full_crespo-userdebug
Nexus S 4Gsojus (crespo4g)full_crespo4g-userdebug

BUILD_TYPE 对照表:

构建类型用途
user有限的访问权限,主要用于发布正式产品,没有root跟调试权限
userdebug跟user类型差不多,但是多了root跟debug调试权限
eng拥有各种调试工具的开发版设置,拥有root跟debug权限

如果作为开发使用的话,那我们一般都是选 -eng

这里我自己是准备在模拟器上运行编译的image镜像,并且我电脑的cpu是intel x86的,所以我选择了 6. aosp_x86-eng

我们可以根据自己的需要选择对应的cpu类型。

注意:我们知道,Android官方的模拟器速度很慢, 
Intel特意提供了一个叫HAXM的虚拟硬件加速技术,全称为:Intel Hardware Accelerated Execution Manager.

只要你的CPU是intel的产品并且支持VT(virtualization Technology)就可以使用HAXM技术将你的模拟器的速度提升至真机的水平。

目前Intel只提供了windows版和MAC版,Linux系统只有通过安装KVM来达到这个效果。

安装KVM

首先我们检测下自己的cpu是否支持 hardware virtualization(硬件虚拟化)

egrep -c '(vmx|svm)' /proc/cpuinfo

输出的值如果是大于0的,则表明你的cpu支持

如果你使用的是vmware虚拟机安装的linux,注意要设置下虚拟机的cpu来支持硬件虚拟化,先关闭虚拟机,然后右键虚拟机=》设置,选中cpu,勾选虚拟化Intel VT项,这样就能支持KVM了。

对于Ubuntu 10.0.4以上的版本,我们通过下面的指令安装KVM即可

sudo apt-get install qemu-kvm libvirt-bin ubuntu-vm-builder bridge-utils

如果在安装KVM的过程中有什么疑问的话,可以访问下面这个网址查找方法:https://help.ubuntu.com/community/KVM/Installation

这样,在编译完目标intel cpu的镜像文件后,我们运行模拟器就会自动进行加速了。

编译源码

好了,一切就绪,我们可以开始编译我们的源码了, 
我们在源码路径下通过 make -jN 指令来进行源码编译,这里的N一般建议设置为cpu核心线程数的1-2倍。

$ make -j4

一般情况下,我们等待源码编译完成就可以了,不过从Android 7.0 N开始,make指令默认会开启Jack编译工具链来进行Java代码的编译,这个过程中可能会出现一些问题。

什么是Jack编译工具链(The Jack toolchain)?

我们知道,我们平时编译Android代码的时候会先将Java代码编译成.class文件,最终再转换成.dex文件,如图:

而Jack编译工具链则跳过了编译成.class文件这一过程,直接将Java代码编译成.dex文件

它的优势:

  • 完全开放源码 
    源码均在AOSP中,合作伙伴可贡献源码

  • 加快编译源码 
    Jack 提供特殊的配置,减少编译时间:pre-dexing, 增量编译和Jack编译服务器.

  • 支持代码压缩,混淆,重打包和multidex

  • 不在使用额外单独的包,例如ProGuard。

如果想进一步了解Jack,可以访问Compiling with Jack(需翻墙),这里就不作太多解释了。

按照官方的说法Jack可以加快编译速度

但实际编译过程中,在我的设备上Jack会占用大量内存,并且拖慢编译速度,还会报错,而且官方文档上写的配置方式对Jack并不起作用。

Jack编译过程中遇到的问题
编译过程中报Out of memory error并中断编译

在执行make指令后,当第一次编译Java代码的时候,Jack会被启用,这个时候经常会卡住,并且一段时间后报错Out of memory error

按照官方的说法,Jack并行编译的时候占用的资源太大导致内存溢出了

可以通过在 $HOME/.jack 文件中减小 SERVER_NB_COMPILE 的值来减小并行编译数量, SERVER_NB_COMPILE 的值默认为4

但实际情况是Jack没有在根路径下生成 .jack 文件,并且手动创建设置 SERVER_NB_COMPILE 后重启Jack服务也没有效果。

经测试发现make编译过程中当Jack第一次被启用时会在home根路径下生成.jack-server目录

可以通过修改该目录中config.properties文件里的 
.jack.server.max-service
值来设置并发线程数。

同时,你也可以设置增加Jack的内存容量来解决这个问题,指令如下

export JACK_SERVER_VM_ARGUMENTS="-Dfile.encoding=UTF-8 -XX:+TieredCompilation -Xmx4096m"

然后进入到输出路径的bin目录下:

cd /home/cjpx00008/aosp/out/host/linux-x86/bin

执行下面的指令重启Jack服务

./jack-admin stop-server./jack-admin start-server

我改了service大小,同时增加了内存,后来编译的过程中没有发生其他问题。

有办法关闭Jack编译吗?

既然Jack有问题,那我们可以关闭Jack编译吗?

目前来说我还没有找到如何在Android 7.0编译的时候关闭Jack,如果有知道的小伙伴欢迎留言告诉我哈,感激不尽!!

运行编译出的image镜像

经过漫长的等待,我们的源码终于编译结束了,是时候来运行编译出的image镜像了。

这时我们只要在源码目录下执行 emulator 指令即可运行模拟器

$ emulator

第一次启动时间可能会有点长,耐心等待即可 

运行成功了,是不是有点小激动呢!

注意:如果你的命令行窗口关闭重开了,那emulator指令可能会提示找不到命令,我们可以在源码根目录环境下,通过envsetup.sh重新初始化命令,运行lunch指令选择编译目标,这个时候你再运行emulator就不会提示找不到指令了(每次关闭命令行窗口都需要重新运行如下指令才能执行emulator)

也可以通过配置环境变量来设置emulator指令,不过我没有成功,哈哈

$ source build/envsetup.sh$ lunch$ emulator

好啦,到此,我们的源码就编译完毕啦,下一篇我们来聊聊如何使用Android Studio导入Android系统源码,并通过AS进行Java源码调试,以及使用GDB来调试系统Native C\C++源码。

 

到了这里,就是一长篇文章告一段落了,之后对Java代码调试,通过命令行实现。  (*打个星号)

开始...

我们知道,Android Framework 的代码主要由Java、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.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 文件根据自己需要调整要加载的源码。

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

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

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

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

这里红色的目录代表被 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 的各种命令,这里给大家推荐一篇不错的入门文章,可以快速入门:

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++ 代码的话,也可以参考下面的两篇文章,不过个人觉得这种方法有一定的局限性。

 

 两篇文章先到这里结束,技术文章很多,但是真正使用起来又可以总结出新的结论和技术操作上的更新。

转载出自:https://juejin.im/entry/5934cfd8fe88c20061ccc63e   谢谢提供!

转载于:https://www.cnblogs.com/liumce/p/8027559.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值