重点内容
转载。 http://blog.csdn.net/cjpx00008/article/details/60474883
硬件环境要求
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 8 | jdk 8u45 or newer |
Android 5.x (Lollipop) - Android 6.0 (Marshmallow) | OpenJDK 7 | jdk-7u71-macosx-x64.dmg |
Android 2.3.x (Gingerbread) - Android 4.4.x (KitKat) | Java JDK 6 | Java 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及以上版本的话,直接运行如下指令即可直接安装:
$ sudo apt-get update
$ sudo apt-get install openjdk-8-jdk
- 1
- 2
Ubuntu 14.04
如果你使用的是Ubuntu 14.04版本,现在并没有专门针对14.0.4可用的open jdk8的包,
但是Ubuntu 15.04 OpenJDK 8的包可以在14.0.4上成功地运行,所以我们下载Ubuntu 15.04 OpenJDK 8的安装包来手动安装:
从 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安装.deb包
先运行apt-get指令更新软件列表
sudo apt-get update
- 1
接着依次对上面下载的三个deb文件运行如下指令进行安装:
sudo dpkg -i 下载的文件地址
- 1
最后运行 apt-get -f 指令修复安装依赖的包
sudo apt-get -f install
- 1
- 更新系统默认使用的JDK版本
如果你的系统安装了多个版本的JDK,可以通过下面的指令执行切换,会弹出可选的JDK版本,根据你的需要选择对应的版本就可以了:
sudo update-alternatives --config java
sudo update-alternatives --config javac
- 1
- 2
2.安装所需要的工具包
Ubuntu 14.04
我们编译过程中会用到下面的依赖包,执行如下指令统一安装:
sudo apt-get install git-core gnupg flex bison gperf build-essential \
zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 \
lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache \
libgl1-mesa-dev libxml2-utils xsltproc unzip
- 1
- 2
- 3
- 4
3.设置源码编译输出路径
默认情况下,编译好的系统源码会在源码所在目录的out文件夹下,
如果你希望调整输出目录的路径,可以执行下面的指令指定输出目录:
export OUT_DIR_COMMON_BASE=<path-to-your-out-directory>
- 1
4.设置USB接口访问设备
在linux下,默认情况是不允许普通用户直接通过USB接口来访问设备的.
推荐方法是以根用户身份在 /etc/udev/rules.d/51-android.rules
路径创建文件。
我们可以通过如下指令来实现(注意用你的系统username替换指令中的):
wget -S -O - http://source.android.com/source/51-android.rules | sed "s/<username>/$USER/" | sudo tee >/dev/null /etc/udev/rules.d/51-android.rules; sudo udevadm control --reload-rules
- 1
设置Mac OS系统编译环境
Mac OS的文件系统默认情况下保留了大小写实际上却又不区分大小写。
目前的git指令无法支持这样的文件系统,会导致一些莫名其妙的错误,所以在Mac OS上编译Android系统源码,我们必须先创建一块区分大小写的磁盘镜像。
创建一块区分大小写的磁盘镜像
这里我们直接通过命令行来创建:
hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 40g ~/android.dmg
- 1
该指令会在系统根目录下生成一个android.dmg或是android.dmg.sparseimage文件,一旦挂载,将被作为支持Android开发所需格式的驱动镜像分区。
如果之后你需要更大的空间,你可以通过下面的指令进行空间调整:
hdiutil resize -size <new-size-you-want>g ~/android.dmg.sparseimage
- 1
你还可以在 ~/.bash_profile
文件中,添加帮助函数来挂载跟取消挂载:
# mount the android file image
function mountAndroid { hdiutil attach ~/android.dmg -mountpoint /Volumes/android; }
#如果创建dmg文件时生成的是android.dmg.sparseimage文件,则使用
function mountAndroid { hdiutil attach ~
/android.dmg.sparseimage -mountpoint /Volumes/android; }
- 1
- 2
- 3
- 4
- 5
# unmount the android file image
function umountAndroid() { hdiutil detach /Volumes/android; }
- 1
- 2
之后我们就可以通过执行mountAndroid指令来执行挂载镜像,通过umountAndroid指令来取消挂载。
安装JDK
安装工具依赖包
1. 安装xcode命令行工具
$ xcode-select --install
- 1
对于老版本的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
- 1
注意:如果根目录下没有
.bash_profile
文件,那就手动创建一个
3. 通过macports安装make, git以及GPG
$ POSIXLY_CORRECT=1 sudo port install gmake libsdl git gnupg
- 1
如果使用的是Mac OS X v10.4版本的系统,还需要安装bison:
$ POSIXLY_CORRECT=1 sudo port install bison
- 1
注意:如果是编译Android 4.0.x及以下版本的系统,gmake 3.8.2版本存在一个bug,需要还原到gmake 3.8.1
优化编译环境(可选)
设置ccache
我们可以自由选择是否开启ccache编译工具。
ccache是一个高速编译缓存工具,它通过将头文件高速缓存到源文件之中而改进了构建性能,因而通过减少每一步编译时添加头文件所需要的时间而提高了C\C++的构建速度。
从编译的全过程来看,不使用ccache的情况下,编译过程中会多次解析相同的头文件,浪费了处理器周期,更重要的是浪费了开发者的时间,因为他们要等待这一过程的完成。在一个团队中,这一影响可能会更为明显,因为团队成员可能会反复编译解析相同的头文件。
所以,一般对于专门用来编译系统的服务器或是大容量的生产环境,这个功能比较有用,它可以加速重新编译的速度。
注意:如果你只是个人开发者,不是专门的编译服务器,不需要进行增量构建的话,那么使用ccache可能会因为高速缓存缺失而降低你的构建速度。
开启ccache
要开启ccache,在源码树的根路径下执行下面的指令:
$ export USE_CCACHE=1
$ export CCACHE_DIR=/<path_of_your_choice>/.ccache
$ prebuilts/misc/linux-x86/ccache/ccache -M 50G
- 1
- 2
- 3
缓存的大小一般设置为50G-100G
接着在 .bashrc (或者etc/profile)中添加下面的指令
export USE_CCACHE=1
- 1
默认情况下,缓存会存在home根目录的~/.ccache中,但是如果你使用的是NFS或者其他的非本地文件系统,那么你同样需要在.bashrc指定缓存目录地址
在Mac OS的系统中,你需要将linux-x86替换成darwin-x86:
prebuilts/misc/darwin-x86/ccache/ccache -M 50G
- 1
当编译的Android系统是4.0.x或者更老的版本,ccache的缓存路径会有所不同
prebuilt/linux-x86/ccache/ccache -M 50G
- 1
这个设置会一直存储在CCACHE_DIR中。
在Linux上,你可以通过以下指令开启对ccache的监听:
$ watch -n1 -d prebuilts/misc/linux-x86/ccache/ccache -s
- 1
下载源码
编译环境配置好之后,我们就可以开始下载我们的源码了
安装Repo
Repo是google用python写的一个脚本工具,Android使用git作为代码管理工具,一个Android系统由N多个git库构成,如果手动进行一个个下载,那简直是一件非常痛苦的事,而repo就是用来对这些git库进行维护管理跟下载的。
通过Repo工具,我们可以轻松地完成Android系统源码的下载。
1.在系统home根路径下创建bin目录并且添加到path路径中:
#创建bin目录
$ mkdir ~/bin
#把bin目录的路径添加到PATH中
$ PATH=~/bin:$PATH
- 1
- 2
- 3
- 4
- 5
2.下载repo工具并设置其可执行
#curl是个开源文件传输工具,在这里是把远程的repo文件下载到指定的~/bin/repo路径
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
#修改repo对所有人可执行
$ chmod a+x ~/bin/repo
- 1
- 2
- 3
- 4
- 5
初始化Repo客户端
1.创建一个空目录用来存放我们的Android系统源码,名字自己随便定
#创建名为WORKING_DIRECTORY的目录
$ mkdir WORKING_DIRECTORY
#进入到创建的目录中
$ cd WORKING_DIRECTORY
- 1
- 2
- 3
- 4
- 5
2.初始化repo仓库
从主干master下载源码,目前最新版本
$ repo init -u https://android.googlesource.com/platform/manifest
- 1
如果需要下载某个特定版本系统的分支,可以在上述命令后加-b 版本分支号,这里我指定Android 7.0的版本分支
$ repo init -u https://android.googlesource.com/platform/manifest -b android-7.1.0_r7
- 1
具体的版本分支号可以到这个地址查看(需要翻墙):
Android系统个版本分支号
3.同步源码到本地
这时执行sync指令便可以自动下载源码到本地了
$ repo sync
- 1
使用国内镜像下载源码
由于国内网络的问题,上述操作的源码下载需要翻墙才能进行,速度会受到很大影响,几十G的系统源码可能需要花上上周的时间才能下完,
因此我们可以选择国内的镜像进行源码下载:
清华大学的镜像站
参照页面上的描述对上面的指令稍作调整便可以了,站点上写得比较详细,这里我们就不作赘述了。
根据网速的不同,一般一天之内能够下载完毕。
对于下载下来的源码,我们并不能直接刷到我们的目标设备上或者是使用模拟器运行,我们必须对源码进行编译生成对应的image二进制镜像文件,
当然你也可以直接从官网下载对应系统版本的镜像文件(需翻墙):
Google’s Nexus driver page
Binaries Preview for Nexus Devices
这里我们还是自己来编译下源码,熟悉下整个编译过程。
源码编译
首先我们通过命令行进入到源码目录中,我这里目录的名称是aosp
cd aosp
- 1
清空输出目录
为了确保我们编译生成的文件不受之前build构建的文件影响,我们在源码目录中执行下面的指令,该指令会清空out输出目录中的所有文件
$ make clobber
- 1
设置编译环境
首先我们通过源码build目录中的 envsetup.sh
脚本文件初始化我们的编译环境,执行
$ source build/envsetup.sh
- 1
或
$ . build/envsetup.sh
- 1
这两个指令的效果是一样的,会初始化一些有用的命令工具
我们后面执行的一些指令必须在初始化 envsetup
之后才能执行
选择编译目标
接着我们通过 lunch
指令来选择我们需要编译的目标
执行lunch指令
$ lunch
- 1
会弹出可选目标项:
所有的构建目标由BUILD-BUILDTYPE的形式组成:
BUILD对应codename
这是官方提供的一份对照表:
Device | Code name | Build configuration |
---|---|---|
Pixel XL | marlin | aosp_marlin-userdebug |
Pixel | sailfish | aosp_sailfish-userdebug |
HiKey | hikey | hikey-userdebug |
Nexus 6P | angler | aosp_angler-userdebug |
Nexus 5X | bullhead | aosp_bullhead-userdebug |
Nexus 6 | shamu | aosp_shamu-userdebug |
Nexus Player | fugu | aosp_fugu-userdebug |
Nexus 9 | volantis (flounder) | aosp_flounder-userdebug |
Nexus 5 (GSM/LTE) | hammerhead | aosp_hammerhead-userdebug |
Nexus 7 (Wi-Fi) | razor (flo) | aosp_flo-userdebug |
Nexus 7 (Mobile) | razorg (deb) | aosp_deb-userdebug |
Nexus 10 | mantaray (manta) | full_manta-userdebug |
Nexus 4 | occam (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) | wingray | full_wingray-userdebug |
Nexus S | soju (crespo) | full_crespo-userdebug |
Nexus S 4G | sojus (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
- 1
输出的值如果是大于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
- 1
如果在安装KVM的过程中有什么疑问的话,可以访问下面这个网址查找方法:https://help.ubuntu.com/community/KVM/Installation
这样,在编译完目标intel cpu的镜像文件后,我们运行模拟器就会自动进行加速了。
编译源码
好了,一切就绪,我们可以开始编译我们的源码了,
我们在源码路径下通过 make -jN
指令来进行源码编译,这里的N一般建议设置为cpu核心线程数的1-2倍。
$ make -j4
- 1
一般情况下,我们等待源码编译完成就可以了,不过从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"
- 1
然后进入到输出路径的bin目录下:
cd /home/cjpx00008/aosp/out/host/linux-x86/bin
- 1
执行下面的指令重启Jack服务
./jack-admin stop-server
./jack-admin start-server
- 1
- 2
- 3
我改了service大小,同时增加了内存,后来编译的过程中没有发生其他问题。
有办法关闭Jack编译吗?
既然Jack有问题,那我们可以关闭Jack编译吗?
目前来说我还没有找到如何在Android 7.0编译的时候关闭Jack,如果有知道的小伙伴欢迎留言告诉我哈,感激不尽!!
运行编译出的image镜像
经过漫长的等待,我们的源码终于编译结束了,是时候来运行编译出的image镜像了。
这时我们只要在源码目录下执行 emulator
指令即可运行模拟器
$ emulator
- 1
第一次启动时间可能会有点长,耐心等待即可
运行成功了,是不是有点小激动呢!
注意:如果你的命令行窗口关闭重开了,那emulator指令可能会提示找不到命令,我们可以在源码根目录环境下,通过envsetup.sh重新初始化命令,运行lunch指令选择编译目标,这个时候你再运行emulator就不会提示找不到指令了(每次关闭命令行窗口都需要重新运行如下指令才能执行emulator)
也可以通过配置环境变量来设置emulator指令,不过我没有成功,哈哈
$ source build/envsetup.sh
$ lunch
$ emulator
- 1
- 2
- 3
好啦,到此,我们的源码就编译完毕啦,下一篇我们来聊聊如何使用Android Studio导入Android系统源码,并通过AS进行Java源码调试,以及使用GDB来调试系统Native C\C++源码。
$(".MathJax").remove();