第一章 源码下载、编译与调试

第一章 源码下载、编译与调试

**注意:**做为Android开发人员,心里多少有对源码的向往,研究源码能够说是开发人员的荣耀,彰显了对系统的认知度,本文适用于Ubuntu 16.04上编译Android 6.0.*及以上版本,其余状况请酌情处理,自行参考官网,源码针对系统8.0分析。python

@(源码系列)linux

##摘要 android源码编译的四个流程:android

  • 源码下载
  • 构建编译环境
  • 编译源码
  • 运行

下文也将按照该流程讲述.git

##1.源码下载 因为墙的缘由,不少人采用国内的镜像源进行下载。不过笔者经过设置hosts能够在官方地址上下载源码,配置项以下:shell

110.4.24.178    www.googlesource.com
110.4.24.178    android.googlesource.com
110.4.24.178    dl-ssl.google.com
110.4.24.178    gerrit.googlesource.com
110.4.24.178    www.google.com
110.4.24.178    google.com
110.4.24.178    google.com.hk
110.4.24.178    www.google.com.hk
110.4.24.178    chromium.googlesource.com

地址查询来源,参考google代理hosts查询,按期更新,用起来很是方便。 在ubuntu下,下载代码仍是比较简单的,步骤分为4步:ubuntu

1.下载repo toolapi

mkdir ~/bin
PATH=~/bin:$PATH 
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo

2.初始化repo下载代码,须要注册谷歌帐号,与本身git配置相对应,注意姓名的排序,lastName在前。bash

mkdir WORKING_DIRECTORY
cd WORKING_DIRECTORY
git config --global user.name "Your Name"
git config --global user.email "you@example.com"

3.repo初始化,选择须要下载的分支markdown

repo init -u https://android.googlesource.com/platform/manifest
# 若是不填写分支默认下载master或经过-b切换至对应的分支
repo init -u https://android.googlesource.com/platform/manifest -b android-6.0.1_r1

4.同步android源码网络

repo sync

**提示:**这里,来简单的介绍下repo工具,咱们知道AOSP项目由不一样的子项目组成,为了方便进行管理,Google采用Git对AOSP项目进行多仓库管理。AOSP项目当前全部的分支列表参看分支列表

之后若是须要同步最新的远程代码到本地,也只须要执行该命令便可。在同步过程当中,若是由于网络缘由中断,使用该命令继续同步便可。不出意外,5个小时即可以将所有源码同步到本地。

**提示:**必定要肯定代码彻底同步了,否则在下面编译过程出现的错误会让你痛不欲生,不肯定的童鞋能够多用repo sync同步几回。

因为网络缘由,在使用repo sync同步代码的过程当中会屡次出错,总不能时时刻刻刻盯着,能不能在同步失败的状况下,自动重试呢?固然能够,咱们能够写一个简单的shell脚本:

#!/bin/bash
#FileName source_asyn.sh
PATH=~/bin:$PATH
# 注意修改为你要编译的版本,固然也能够不填
repo init -u https://android.googlesource.com/platform/manifest
repo sync
while [$? = 1]: do
echo "=========download failed,again============"
sleep 5
repo sync
done

将该文件保存在源码目录下,也就是咱们的source目录,而后执行该脚本便可,如今能够安心的等待源码下载完成了。

注意:因为.repo目录是隐藏目录,所以在下载完成以前你是不看到啥东西的。

##2.源码编译 ###2.1编译环境 源码下载完成后,就能够构建编译环境了。在开始以前,咱们先来看看一些编译要求:

硬件

磁盘空间越多越好,至少在100GB以上

软件

|Android版本| 编译要求的Ubuntu最低版本| 编译要求的JDK版本| |--| |Android 6.0至AOSP master| Ubuntu 14.04|OpenJDK 8| |Android 5.x至AOSP 6.0| Ubuntu 12.04|OpenJDK 7| |Android 2.3.x至Android 5.0| Ubuntu 12.04|Oracle JDK 6| |Android 1.5至Android 2.2.x| Ubuntu 10.04|Oracle JDK 5|

更具体的能够参看:Google源码编译要求

我如今在Ubuntu 16.04下编译AOSP主线代码,所以须要安装OpenJDK 8,执行命令以下:

sudo apt-get install openjdk-8-jdk

其它需求

sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib 
sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386 
sudo apt-get install tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386 
sudo apt-get install dpkg-dev libsdl1.2-dev libesd0-dev
sudo apt-get install git-core gnupg flex bison gperf build-essential  
sudo apt-get install zip curl zlib1g-dev gcc-multilib g++-multilib 
sudo apt-get install libc6-dev-i386 
sudo apt-get install lib32ncurses5-dev x11proto-core-dev libx11-dev 
sudo apt-get install libgl1-mesa-dev libxml2-utils xsltproc unzip m4
sudo apt-get install lib32z-dev ccache

###2.2初始化编译 首先初始化编译环境,确保上述过程完整完成,接下来咱们须要初始化编译环境,命令以下:

source build/envsetup.sh

不难发现该命令只是引入了其余执行脚本,至于这些脚本作什么,目前不在本文中细说.。该命令执行成功后,咱们会获得了一些有用的命令,好比最下面要用到的lunch命令。

###2.3编译源码 初始化编译环境以后,就进入源码编译阶段。这个阶段又包括两个阶段:选择编译目标和执行编译。 ####2.3.1选择编译目标 经过lunch指令设置编译目标,所谓的编译目标就是生成的镜像要运行在什么样的设备上。这里咱们设置的编译目标是aosp_arm64-eng,所以执行指令:

lunch aosp_arm64-eng

编译目标格式说明 编译目标的格式:BUILD-BUILDTYPE,好比上面的aosp_arm-eng的BUILD是aosp_arm,BUILDTYPE是eng

什么是BUILD

BUILD指的是特定功能的组合的特定名称,即表示编译出的镜像能够运行在什么环境。其中aosp(Android Open Source Project)表明Android开源项目;arm表示系统是运行在arm架构的处理器上;arm64则是指64位arm架构;处理器x86则表示x86架构的处理器;此外,还有一些单词表明了特定的Nexus设备,下面是经常使用的设备代码和编译目标,更多参考官方文档

|受型号| 设备代码| 编译目标| |:--| |Nexus 6P| angler| aosp_angler-userdebug| |Nexus 5X| bullhead| aosp_bullhead-userdebug| |Nexus 6| shamu| aosp_shamu-userdebug| |Nexus 5| hammerhead| aosp_hammerhead-userdebug|

提示:若是你没有Nexus设备,那么一般选择arm或者x86便可

什么是BUILDTYPE

BUILD TYPE则指的是编译类型,一般有三种:

  • user:表明这是编译出的系统镜像是能够用来正式发布到市场的版本,其权限是被限制的(如没有root权限,不包含dedug等)
  • userdebug:在user版本的基础上开放了root权限和debug权限。
  • eng:表明engineer,也就是所谓的开发工程师的版本,拥有最大的权限(root等),此外还附带了许多debug工具

了解编译目标的组成以后,咱们就能够根据本身目前的状况选择了。那不知道编译目标怎么办?咱们只须要执行不带参数的lunch指令,稍后控制台会列出全部的编译目标,以下:

接着咱们只须要输入相应的数字便可。 来举个例子:你没有Nexus设备,只想编译完后运行看看,那么就能够选择aosp_arm-eng。(我在ubuntu 16.04(64位)中编译完成后启动虚拟机时,卡在黑屏,尝试编译aosp_arm64-eng解决。所以这里我使用了aosp_arm64-eng)

####2.3.2开始编译 经过make指令进行代码编译,该指令经过-j参数来设置参与编译的线程数量,以提升编译速度。好比这里咱们设置8个线程同时编译:

make -j8

须要注意的是,参与编译的线程并非越多越好,一般是根据你机器cup的核心来肯定:core*2,即当前cpu的核心的2倍。好比我如今的笔记本是双核四线程的,所以根据公式,最快速的编译能够make -j8

经过cat /proc/cpuinfo查看相关cpu信息

若是一切顺利的化,在几个小时以后,即可以编译完成。看到

### make completed successfully (04:16:38(hh:mm:ss)) ###

表示你编译成功了。

###2.4运行模拟器 在编译完成以后,就能够经过如下命令运行Android虚拟机了,命令以下:

source build/envsetup.sh
lunch(选择刚才你设置的目标版本,好比这里了我选择的是2)
emulator

若是你是在编译完后马上运行虚拟机,因为咱们以前已经执行过source及lunch命令了,所以如今你只须要执行命令就能够运行虚拟机:

emulator

不出意外,在等待一会以后,你会看到运行界面: 运行界面

**补充:**既然谈到了模拟器运行,这里咱们顺便介绍模拟器运行所须要四个文件: Linux Kernelsystem.imguserdate.imgramdisk.img 若是你在使用 lunch命令时选择的是aosp_arm-eng,那么在执行不带参数的emualtor命令时,Linux Kernel默认使用的是/source/prebuilds/qemu-kernel/arm/kernel-qemu目录下的kernel-qemu文件;而android镜像文件则是默认使用source/out/target/product/generic目录下的system.imguserdata.imgramdisk.img,也就是咱们刚刚编译出来的镜像文件。

上面我在使用lunch命令时选择的是aosp_arm64-eng,所以linux默认使用的/source/prebuilds/qemu-kernel/arm64/kernel-qemu下的kernel-qemu,而其余文件则是使用的source/out/target/product/generic64目录下的system.imguserdata.imgramdisk.img

固然emulator指令容许你经过参数制定使用不一样的文件,具体用法能够经过emulator --help查看。

###2.5模块编译 除了经过make命令编译能够整个android源码外,Google也为咱们提供了相应的命令来支持单独模块的编译。编译环境初始化(即执行source build/envsetup.sh)以后,咱们能够获得一些有用的指令,除了上边用到的lunch,还有如下:

- croot: Changes directory to the top of the tree.
 - m: Makes from the top of the tree.
 - mm: Builds all of the modules in the current directory.
 - mmm: Builds all of the modules in the supplied directories.
 - cgrep: Greps on all local C/C++ files.
 - jgrep: Greps on all local Java files.
 - resgrep: Greps on all local res/*.xml files.
 - godir: Go to the directory containing a file.

其中mmm指令就是用来编译指定目录。一般来讲,每一个目录只包含一个模块。好比这里咱们要编译Launcher2模块,执行指令:

mmm packages/apps/Launcher2/

稍等一会以后,若是提示:

### make completed success fully ###

即表示编译完成,此时在out/target/product/gereric/system/app就能够看到编译的Launcher2.apk文件了。

从新打包系统镜像

编译好指定模块后,若是咱们想要将该模块对应的apk集成到系统镜像中,须要借助make snod指令从新打包系统镜像,这样咱们新生成的system.img中就包含了刚才编译的Launcher2模块了,重启模拟器以后生效。

单独安装模块

咱们在不断的修改某些模块,总不能每次编译完成后都要从新打包system.img,而后重启手机吧?有没有什么简单的方法呢? 在编译完后,借助adb install命令直接将生成的apk文件安装到设备上便可,相比使用make snod,会节省不少事件。

补充:咱们来介绍out/target/product/generic/system目录下的内容: 系统自带apk文件:out/target/product/generic/system/apk目录下; 系统可执行文件:out/target/product/generic/system/bin目录下; 动态连接库:out/target/product/generic/system/lib目录下; 硬件抽象层文件:out/targer/product/generic/system/lib/hw目录下。

###2.6错误合集 1. 提示:error processing archive /var/cache/apt/archives/lib32z1-dev_

在安装依赖的时候有一个依赖不能顺利安装:

sudo apt-get install lib32z-dev ccache

这里笔者也是安装你们推荐的依赖安装,若是出现任何不能安装的依赖都会去解决一下,解决办法为:

sudo dpkg -i --force-overwrite <filename>
# 以下例
sudo dpkg -i --force-overwrite /var/cache/apt/archives/lib32z1-dev_1%3a1.2.8.dfsg-2ubtuntu4_amd64.deb
# 而后执行
sudo apt-get -f install

问题顺利解决。

##3.源码调试 咱们已经描述了Android源码在Ubuntu 16.0.4上下载和编译的过程,目前咱们已经顺利的编译出android的成果文件:

下载源码初衷咱们是为了调试代码,查看其中的运行机制和关键过程,理解其精髓。好比咱们对PMS过程不是很了解,如何打个断点查看一下,亦或是根据本身思想改进一下,都是很是值得尝试的。下面咱们来讲说如何调试源码,一样这里的工做平台仍是ubuntu 16.04和Android Studio。

**参考:**源码中developent/tools/idegen/README文档

###3.1调试准备 在源码中,存在idegen模块,该模块专门用来为idea工具生成系统源码的project。在开始调试以前,须要确保当前已经编译过Android源码了,若是没有,跳转至第二章编译源码,时间大概4-5个小时。准备过程分为以下几个过程:

  1. 工程文件生成android.iprandroid.iml
  2. 修改android.iml文件提升as启动速度
  3. 设置jdk和sdk,导入源码

1.工程文件生成

检查out/host/Linux-x86/framework/目录下是否存在idegen.jar文件,存在则说明你已经编译过该模块,若是没有编译过则须要编译。执行以下命令便可:

source build/envsetup.sh
mmm development/tools/idegen/

其中mmm development/tools/idegen/执行完成后会生成idegen.jar,在已经编译过idegen模块后,执行:

sudo ./development/tools/idegen/idegen.sh

会在源码目录下生成IEDA工程配置文件:android.iprandroid.iml文件,文件什么做用呢?

  • android.ipr:一般是保存工程相关的设置,好比编译器配置入口相关的libraries等
  • android.iml:则是主要是描述了modules,好比modules的路径,依赖关系等

2.修改android.iml

android源码的体量仍是很大的,若是直接使用Android Studio导入工程,须要漫长的等待时间,看代码仍是选择source Insight。这就要求咱们有选择的导入模块,选择须要导入。在导入前修改android.iml文件,经过添加配置的方式告诉AS不导入某些模块,好比如今我不想导入art模块,那么就在android.iml文件中添加:

<excludeFloder url="file://$MODULE_DIR$"/abi>

格式为:<excludeFloder url="file://$MODULE_DIR$"/模块名> ,这里只保留了framworks和packages模块,将其余模块所有排除了,所以在android.iml中添加了如下配置:

<excludeFolder url="file://$MODULE_DIR$/.repo" />
<excludeFolder url="file://$MODULE_DIR$/abi" />
<excludeFolder url="file://$MODULE_DIR$/art" />
<excludeFolder url="file://$MODULE_DIR$/bionic" />
<excludeFolder url="file://$MODULE_DIR$/bootable" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/cts" />
<excludeFolder url="file://$MODULE_DIR$/dalvik" />
<excludeFolder url="file://$MODULE_DIR$/developers" />
<excludeFolder url="file://$MODULE_DIR$/development" />
<excludeFolder url="file://$MODULE_DIR$/device" />
<excludeFolder url="file://$MODULE_DIR$/docs" />
<excludeFolder url="file://$MODULE_DIR$/external" />
<excludeFolder url="file://$MODULE_DIR$/hardware" />
<excludeFolder url="file://$MODULE_DIR$/libcore" />
<excludeFolder url="file://$MODULE_DIR$/libnativehelper" />
<excludeFolder url="file://$MODULE_DIR$/ndk" />
<excludeFolder url="file://$MODULE_DIR$/out" />
<excludeFolder url="file://$MODULE_DIR$/pdk" />
<excludeFolder url="file://$MODULE_DIR$/prebuilt" />
<excludeFolder url="file://$MODULE_DIR$/prebuilts" />
<excludeFolder url="file://$MODULE_DIR$/sdk" />
<excludeFolder url="file://$MODULE_DIR$/system" />
<excludeFolder url="file://$MODULE_DIR$/tools" />

3.设置jdk和sdk,导入源码

在完成android.iml文件的修改后,将源码工程导入至AS,以下图所示:

源码工程导入至AS

图3.1 源码工程导入至AS

导入时间会比较长,要耐心等待,若是已经将所有项目导入到AS中,而又想排除一些模块该怎么办呢? 此时能够在Project Scureture的Mobules中进行排除。 为了排除android sdudio的Sdk中依赖的干扰,须要改进当前的jdk和sdk,让代码跳转也在源码的文件中,而不能在依赖于外部的sdk项目,点击Project Structure进入到项目配置页面: 设置jdk

图3.2 设置工程的jdk

选择新建,新建一个jdk,将其classpath标签下的内容通通删除,选择Android API 25 Platform将当前新建的JDK配置给它。 jdk配置

图3.3 jdk配置给Android API 25 Platform

###3.2调试源码 搞定上面以后,如今咱们来看看如何用Android Studio一步一步调试代码。首先使用emulator命令启动咱们的虚拟机,启动完虚拟机后,运行的是咱们源码编译的最新的系统。接下来打开android studio,打开源码工程,选择Attache debugger to Android process选项,在弹出的Choose Process框内必须选择Show all processes,不然看不到相关的进程,能够看到系统的不少进程。如system_process、com.android.systemui、com.android.settings等不少进程。

**注意:**在虚拟机或设备运行了咱们编译的系统后,拥有的是root权限,能够查看全部进程,这与咱们前面说的BUILDTYPE为eng相关,方便开发和调试

选择任意一个进程,这里以com.android.settings进程为例,并在包名为com.android.settings的SettingsActivity的onCreate()函数上打上断点,打开虚拟机的设置,源码会在onCreate()函数上中止,此时能够对源码进行断点调试。

##参考

本身动手编译最新Android源码及SDK 本身动手调试Android源码 android源码-下载与管理

相关文章
相关标签/搜索