Android源码介绍编译
AOSP Android Open Source Project
Android是一种为各种不同外形设备而开发的开源软件栈。 Android的主要目的是为运营商,OEM和开发人员创建一个开放的软件平台,使他们的创新理念成为现实,并引入一个成功的现实世界产品,改善用户的移动体验。
部分版本对应的分支以及支持的设备列表(详细):
Build | Branch | Version | Supported devices |
---|---|---|---|
N2G47O | android-7.1.2_r8 | Nougat | Nexus 5X, Nexus 6P, Pixel XL, Pixel, Pixel C |
MRA58K | android-6.0.0_r1 | Marshmallow | Nexus 5, Nexus 6, Nexus 7 (flo/deb), Nexus 9 (volantis/volantisg), Nexus Player |
LRX22C | android-5.0.1_r1 | Lollipop | Nexus 4, Nexus 5, Nexus 6 (shamu), Nexus 7 (flo), Nexus 9 (volantis/volantisg), Nexus 10 |
KTU84Q | android-4.4.4_r2 | KitKat | Nexus 5 (hammerhead) (For 2Degrees/NZ, Telstra/AUS and India ONLY) |
IMM76L | android-4.0.4_r2.1 | Ice Cream Sandwich |
Android开源项目的首选许可证是Apache软件许可证2.0版(“Apache 2.0”),大多数Android软件都使用Apache 2.0授权。 虽然该项目将努力遵守首选许可证,但可能会有例外情况将根据具体情况处理。 例如,Linux内核修补程序在GPLv2许可证下,系统异常,可以在kernel.org上找到。
常见许可证:
1. ASL Apache Software License Apache软件许可证
ASL是一种不设限的许可证,允许软件的商业性开发和垄断式发布。简单来说就是修改后可以不开源。
2. GPL General Public License 自由软件基金会通用开放许可证
GPL是一种CopyLeft许可证,规定所有对源码的修改和衍生都必须公开,并以类似的许可证发布。
3. BSD Berkly Software Distribution 与ASL类似,在修改源码可以不开源。
Android编译环境要求
硬件要求
- 编译2.3.x及以后的版本需要64位系统,之前的版本需要32位系统
- 检出代码需要100GB磁盘,单个系统构建需要150G磁盘空间,多个系统构建需要200GB及更多的空间。如果开启ccache,那就更多了
- 如果在虚拟机中运行Linux,则至少徐亚16GB的RAM交换
软件要求
操作系统
Android通常使用GNU / Linux或Mac OS操作系统构建。 也可以在不支持的系统(如Windows)上的虚拟机中构建Android。
GUN/Linux
- Android 6.0 (Marshmallow) - AOSP master: 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(Intel/x86)
- Android 6.0 (Marshmallow) - AOSP master: 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
JDK
Ubuntu14.04之后的版本不再支持OpenJdk8,需要手动下载。
下面是编译各个Android系统版本所需对应的JDK版本。
* AOSP主分支:Ubuntu - OpenJDK 8, Mac OS - jdk 8u45 or newer
* Android 5.x(Lollipop) - Android 6.0(Marshmallow):Ubuntu-OpenJDK 7,Mac OS - jdk-7u71-macosx-x64.dmg
* Android 2.3.X(GingerBread) - Android 4.4.x(KitKat):Ubuntu - Java JDK 6, Mac OS - Java JDK 6
* Android 1.5 (Cupcake) - Android 2.2.x (Froyo): Ubuntu - Java JDK 5
关键包
- Python 2.6 – 2.7 from python.org
- GNU Make 3.81 – 3.82 from gnu.org(Android 3.2.x和更早的版本需要从3.82回退到旧版本,以避免构建错误)
- Git 1.7 or newer from git-scm.com
设备二进制文件
- 工厂二进制镜像文件地址Factory Images
- OTA二进制镜像文件地址Full OTA Images
- 二进制硬件驱动文件地址Driver Binaries
- 支持Nexus设备的二进制预览文件Preview binaries(blobs)
创建构建环境
目前只支持Linux和Mac OS系统,不支持Windows系统。
在准备环境之前需要了解三个工具:Git,Repo,Gerrit。
- Git
开源的分布式版本控制系统,支持本地分支、提交、编辑、差异等。 - Repo
Repo是我们在Git之上构建的存储库管理工具。 Repo在必要时统一了许多Git存储库,上传到我们的版本控制系统,并自动部署了Android开发工作流程。 Repo并不意味着取代Git,只是为了在Android的上下文中更容易使用Git。 repo命令是可执行的Python脚本,您可以将其放在路径的任何位置。 在使用Android源文件时,您将使用Repo进行跨网络操作。 例如,使用单个Repo命令,您可以将文件从多个存储库下载到本地工作目录。 - Gerrit
Gerrit是使用git的项目的基于Web的代码审查系统。 Gerrit鼓励更多的集中使用Git,方法是允许所有授权用户提交更改,如果通过代码审查,这些更改将自动合并。 此外,Gerrit通过在浏览器中并排显示更改并启用内联注释来更轻松地进行审阅。
由于笔者使用的mac系统,所以只翻译Mac上的环境搭建,Linux系统可自行查看原文。
MacOS环境搭建
在默认安装中,Mac OS运行在保护大小写但不区分大小写的文件系统上。 git不支持这种类型的文件系统,并会导致一些git命令(如git状态)异常地出现。 因此,我们建议您始终在区分大小写的文件系统上使用AOSP源文件。 这可以很容易地使用磁盘映像完成,如下所述。
一旦正确的文件系统可用,在现代Mac OS环境中构建主分支是非常简单的。 早期的分支机构需要一些额外的工具和SDK。
创建区分大小写的磁盘镜像
您可以使用磁盘映像在现有Mac OS环境中创建区分大小写的文件系统。 要创建映像,请启动磁盘工具并选择“新建映像”。 25GB的大小是完成构建的最小值; 更大的数字更加面向未来。 使用稀疏图像可以节省空间,同时允许随着需要而增长。 确保选择“区分大小写,记录日志”作为卷格式。
也可以通过shell使用一下命令来创建镜像:
# hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 40g ~/android.dmg
这将创建一个.dmg(或可能的.dmg.sparseimage)文件,一旦安装,它将作为一个驱动器,具有Android开发所需的格式。
如果需要变更镜像大小,可以使用以下命令:
# hdiutil resize -size <new-size-you-want>g ~/android.dmg.sparseimage
为了方便挂载和卸载android.dmg磁盘镜像,可以在~/.bash_profile文件中添加帮助函数。
挂载镜像
# mount the android file image function mountAndroid { hdiutil attach ~/android.dmg -mountpoint /Volumes/android; }
卸载镜像
# unmount the android file image function umountAndroid() { hdiutil detach /Volumes/android; }
安装JDK
编辑不同版本的Android源码需要不同版本的JDK,详情请查看“Android介绍及环境要求”
安装所需软件包
安装Xcode命令行工具
$ xcode-select --install
从macports.org安装MacPorts
export PATH=/opt/local/bin:$PATH
注意:请确保在~/.bash_profile文件中,/opt/local/bin路径在 /usr/bin路径之前
通过MacPosts安装make,git和GPG
$ POSIXLY_CORRECT=1 sudo port install gmake libsdl git gnupg
如果是Mac OS v10.4,还需要安装bison:
$ POSIXLY_CORRECT=1 sudo port install biso
从make3.82退回
在Android4.0.x和更早版本,使用gmake3.82在构建Android源码时存在一个bug,需要使用MacPorts下载3.81版本。步骤如下:
编辑 /opt/local/etc/macports/sources.conf,添加如下内容
file:///Users/Shared/dports
然后创建对应目录:
$ mkdir /Users/Shared/dports
在新的 dports 目录下,运行如下命令:
$ svn co --revision 50980 http://svn.macports.org/repository/macports/trunk/dports/devel/gmake/ devel/gmake/
为新的本地仓库创建端口索引
$ portindex /Users/Shared/dports
下载旧版的gmake
$ sudo port install gmake @3.81
设置文件描述符限制
在Mac OS上,打开并行的文件描述符数量的默认限制太低,高度并行的构建过程可能会超出此限制。
为了提高这个限制,可以在~/.bash_profile文件中添加如下配置:
# set the number of open files to be 1024
ulimit -S -n 1024
优化构建环境
设置ccache
您可以选择告诉构建使用ccache编译工具,它是C和C ++的编译器缓存,可帮助构建更快。 它对于构建服务器和其他大批量生产环境特别有用。 Ccache作为可用于加速重建的编译器缓存。 如果您经常使用make clean,或者如果您经常在不同的构建产品之间切换,这样做效果非常好。
如果您改为执行增量版本(例如单个开发人员而不是构建服务器),则ccache可能会通过让您支付高速缓存未命中的费用来减慢您的构建速度。
要使用ccache,请在源代码树的根目录中发出这些命令。
$ export USE_CCACHE=1
$ export CCACHE_DIR=/<path_of_your_choice>/.ccache
$ prebuilts/misc/linux-x86/ccache/ccache -M 50G
建议缓存大小是50-100G
将以下内容放在.bashrc(或等效的文件)
export USE_CCACHE=1
默认情况下,缓存将存储在〜/ .ccache中。 如果您的主目录位于NFS或其他非本地文件系统上,那么您还需要在.bashrc文件中指定目录。
在Mac OS上,应当将linux-x86替换为darwin-x86:
prebuilts/misc/darwin-x86/ccache/ccache -M 50G
在构建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
确保在home目录下有bin/目录,并且已经添加到环境变量中。
$ mkdir ~/bin
$ PATH = ~/bin:$PATH
下载Repo工具,并确保可执行
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
$ chmod a+x ~/bin/repo
初始化Repo
创建存放工作文件的空目录。如果使用的是MacOS,这一步需要在大小写区分的文件系统中。向下面这样;
$ mkdir WORKING_DIRECTORY
$ cd WORKING_DIRRECTORY
配置真实的名称和邮件地址。为了使用Gerrit代码检查工具,需要设置一个邮件地址来连接一个已注册的Google账户。配置的名称则会展示在你的代码提交中。
$ git config --global user.name 'Your Name'
$ git config --global user.email 'you.@example.com'
执行 repo init 来下载Repo的最新版本。你必须指定manifest的URL,这个URL指定了Android源码中包含的各种仓库。
$ repo init -u https://android.googlesource.com/platform/manifest
如果想要检出非master分支,可以通过-b参数指定分支名称。具体分名称可见Source Code Tags and Builds。
$ repo init -u https://android.googlesource.com/platform/manifest -b android-4.0.1_r1
初始化成功后,你的客户端目录会包含一个.repo目录,里面包含了manifest等文件。
下载Android源码树
拉取Android源码到工作目录。
repo sync
Android源码目录结构详解:
目录 | 解释 |
---|---|
abi | 应用二进制接口。不同的操作系统,应用二进制接口不同。因此linux上的二进制可执行文件在windows上无法执行。 |
art | art虚拟机 |
bionic | C库,Android没有使用标准的glibc库,而是自己实现的一套 |
bootable | 包含两个工程,recovery和bootloader。刷机或者系统升级都是由recovery完成的。 |
build | Android编译系统核心代码都存在该目录 |
cts | Android兼容性测试套件 |
dalvik | dalvik虚拟机 |
developers | |
development | 开发相关的一些源码,如sdk、ndk工具 |
device | 硬件模块代码,不同设备,内容也不同 |
docs | |
external | 包含所有开源项目的源码,如sqlite、webkit、zxing等 |
frameworks | Android框架源码。这里找到Android最核心的实现。 |
hardware | 硬件相关源码。如Android硬件抽象层的实现和规范,还包括所涉及的通信模块实现 |
libcore | 核心Java库,大部分取自于Apache Harmony的类库子集。(Apache Harmony虚拟机间接催生了Dalvik虚拟机) |
libnativehelper | JNI使用的帮助函数 |
Out | 运行make后生成的一些文件 |
ndk | |
packages | 包含系统默认应用的源码,如联系人、日历、浏览器等 |
pdk | |
prebuilts | 为方便提前编译好的二进制文件 |
sdk | |
system | Android系统核心的源码文件。这是在Dalvik虚拟机和所有java启动前所能运行的最小Linux系统。包含init进程、默认的init.rc脚本等 |
tools | 不同IDE工具 |
遇到的问题
repo init -u https://android.googlesource.com/a/platform/manifest
fatal: Cannot get https://gerrit.googlesource.com/git-repo/clone.bundle
fatal: error [Errno 65] No route to host
使用proxyChains工具添加命令行翻墙功能后,访问超时
fatal: unable to access 'https://gerrit.googlesource.com/git-repo/': Failed to connect to gerrit.googlesource.com port 443: Operation timed out
折腾好久还是没有解决,只能用国内的镜像源替代了(清华大学开源软件镜像站)。
使用时将 https://android.googlesource.com/ 全部使用 https://aosp.tuna.tsinghua.edu.cn/ 代替即可
使用认证
默认情况下,访问Android源码是匿名的,为了保护服务器免受频繁的使用,每一个IP会有定额的访问限制。
当和他人使用共享IP时,尽管是正常使用,也会触发保护限制。
在这种情况下,应当使用认证访问方式。这种方式将限制策略由IP限制改成账户限制。
第一步,使用 the password generator来创建密码。
第二步,使用下面的manifest URI(https://android.googlesource.com/a/platform/manifest)进行强制认证访问。
$ repo init -u https://android.googlesource.com/a/platform/manifest
解决网络问题
当使用代理下载时,需要明确指定Repo使用的代理。一般在企业环境中比较常见
$ export HTTP_PROXY=http://<proxy_user_id>:<proxy_password>@<proxy_server>:<proxy_port>
$ export HTTPS_PROXY=http://<proxy_user_id>:<proxy_password>@<proxy_server>:<proxy_port>
$ unset HTTPS_PROXY 取消代理
使用本地镜像
当使用多个客户端时,特别是在带宽不足的情况下,最好创建整个服务器内容的本地镜像,并从该镜像(不需要网络访问)同步客户端。 整个镜像的下载小于下载两个客户端,同时包含更多的信息。
假设本地镜像目录为/usr/local/aosp/mirror。第一步就是创建并同步镜像本身。使用–mirror标识来创建新的客户端:
$ mkdir -p /usr/local/aosp/mirror
$ cd /usr/local/aosp/mirror
$ repo init -u https://android.googlesource.com/mirror/manifest --mirror
$ repo sync
一旦镜像同步完成后,就可以从中创建新的客户端。注意一定指定一个绝对路径:
$ mkdir -p /usr/local/aosp/master
$ cd /usr/local/aosp/master
$ repo init -u /usr/loca/aosp/mirror/platform/manifest.git
$ repo sync
最终,基于服务器同步镜像,其他的客户端基于镜像。
$ cd /usr/local/aosp/mirror
$ repo sync
$ cd /usr/local/aosp/master
$ repo sync
可以将镜像存储在LAN服务器上,并通过NFS,SSH或Git进行访问。也可以将其存储在可移动驱动器上,并将该驱动器传递到用户之间或机器之间。
验证Git标签
加载下面公开的秘钥到你的GnuPG秘钥数据库中,秘钥用于签署代表版本的注释标签。
$ gpg --import
复制并粘贴下面的秘钥,然后输入EOF(Ctrl-D)来结束输入并处理秘钥。
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.2.2 (GNU/Linux)
mQGiBEnnWD4RBACt9/h4v9xnnGDou13y3dvOx6/t43LPPIxeJ8eX9WB+8LLuROSV
lFhpHawsVAcFlmi7f7jdSRF+OvtZL9ShPKdLfwBJMNkU66/TZmPewS4m782ndtw7
8tR1cXb197Ob8kOfQB3A9yk2XZ4ei4ZC3i6wVdqHLRxABdncwu5hOF9KXwCgkxMD
u4PVgChaAJzTYJ1EG+UYBIUEAJmfearb0qRAN7dEoff0FeXsEaUA6U90sEoVks0Z
wNj96SA8BL+a1OoEUUfpMhiHyLuQSftxisJxTh+2QclzDviDyaTrkANjdYY7p2cq
/HMdOY7LJlHaqtXmZxXjjtw5Uc2QG8UY8aziU3IE9nTjSwCXeJnuyvoizl9/I1S5
jU5SA/9WwIps4SC84ielIXiGWEqq6i6/sk4I9q1YemZF2XVVKnmI1F4iCMtNKsR4
MGSa1gA8s4iQbsKNWPgp7M3a51JCVCu6l/8zTpA+uUGapw4tWCp4o0dpIvDPBEa9
b/aF/ygcR8mh5hgUfpF9IpXdknOsbKCvM9lSSfRciETykZc4wrRCVGhlIEFuZHJv
aWQgT3BlbiBTb3VyY2UgUHJvamVjdCA8aW5pdGlhbC1jb250cmlidXRpb25AYW5k
cm9pZC5jb20+iGAEExECACAFAknnWD4CGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIX
gAAKCRDorT+BmrEOeNr+AJ42Xy6tEW7r3KzrJxnRX8mij9z8tgCdFfQYiHpYngkI
2t09Ed+9Bm4gmEO5Ag0ESedYRBAIAKVW1JcMBWvV/0Bo9WiByJ9WJ5swMN36/vAl
QN4mWRhfzDOk/Rosdb0csAO/l8Kz0gKQPOfObtyYjvI8JMC3rmi+LIvSUT9806Up
hisyEmmHv6U8gUb/xHLIanXGxwhYzjgeuAXVCsv+EvoPIHbY4L/KvP5x+oCJIDbk
C2b1TvVk9PryzmE4BPIQL/NtgR1oLWm/uWR9zRUFtBnE411aMAN3qnAHBBMZzKMX
LWBGWE0znfRrnczI5p49i2YZJAjyX1P2WzmScK49CV82dzLo71MnrF6fj+Udtb5+
OgTg7Cow+8PRaTkJEW5Y2JIZpnRUq0CYxAmHYX79EMKHDSThf/8AAwUIAJPWsB/M
pK+KMs/s3r6nJrnYLTfdZhtmQXimpoDMJg1zxmL8UfNUKiQZ6esoAWtDgpqt7Y7s
KZ8laHRARonte394hidZzM5nb6hQvpPjt2OlPRsyqVxw4c/KsjADtAuKW9/d8phb
N8bTyOJo856qg4oOEzKG9eeF7oaZTYBy33BTL0408sEBxiMior6b8LrZrAhkqDjA
vUXRwm/fFKgpsOysxC6xi553CxBUCH2omNV6Ka1LNMwzSp9ILz8jEGqmUtkBszwo
G1S8fXgE0Lq3cdDM/GJ4QXP/p6LiwNF99faDMTV3+2SAOGvytOX6KjKVzKOSsfJQ
hN0DlsIw8hqJc0WISQQYEQIACQUCSedYRAIbDAAKCRDorT+BmrEOeCUOAJ9qmR0l
EXzeoxcdoafxqf6gZlJZlACgkWF7wi2YLW3Oa+jv2QSTlrx4KLM=
=Wi5D
-----END PGP PUBLIC KEY BLOCK-----
导入秘钥后,就可以使用下面命令验证任何标签了。
$ git tag -v TAG_NAME
准备构建
注:如果编译Android6.0和之后的版本,需要使用Jack工具,一种新的默认的工具链,后面会介绍。
获取专用的二进制文件
从AOSP上下载的源码不能单独编译,需要一些额外的硬件相关的专用库文件。例如硬件图形加速,详细请查看二进制硬件驱动文件地址Driver Binaries
下载
提取
每一组二进制文件作为压缩档案中的自解压脚本。 解压缩每个存档,从源代码树的根目录运行附带的自解压缩脚本,然后确认您同意附带的许可协议的条款。 二进制文件及其匹配的makefile将安装在源代码树的供应商/层次结构中。
清理
为了确保新安装的二进制文件被正确的提取,请使用以下命令删除任何以前版本的现有输出:
$ make clobber
设置环境
使用envsetup.sh脚本初始化环境。 请注意,用.(一个点)可以减少几个字符,简写在文档中更常用。
$ source build/envsetup.sh
or
$ . build/envsetup.sh
选择构建类型
使用 lunch 命令选择构建类型,额外的配置可通过参数传递。例:
$ lunch aosp_arm-eng
若是为模拟器完整的构建,应启动所有调试。
如果不添加任何参数,lunch会通过菜单提示你来选择编译类型。
所有构建目标采用BUILD-BUILDTYPE形式,其中BUILD是引用特定功能组合的代号。BUILDTYPE是下面列表中的一个:
Buildtype | Use |
---|---|
user | 限制访问,适合生产部署 |
userdebug | 和user类似,但是拥有root权限和可调试的,适合调试部署 |
eng | 可使用额外的调试工具作为开发配置 |
更多关于构建和运行在实际硬件设备的信息,后面讲到。
编译代码
用make构建一切。 GNU make可以使用-jN参数来处理并行任务,并且通常使用一些任务N,该数目是用于构建的计算机上的硬件线程数的1到2倍。 例如,在双E5520机器(2个CPU,每个CPU 4个内核,每个核心2个线程)上,最快的版本是通过make -j16和make -j32之间的命令进行的。
$ make -j4
运行
您可以在仿真器上运行构建程序,也可以将其部署在真实设备上。 请注意,您已经使用lunch选择了您的构建目标,并且不太可能运行在与其构建的目标不同的目标上。
使用fastboot刷设备
要刷新设备,您将需要使用fastboot,该应用程序在成功构建后应包含在路径中。详情参考https://source.android.com/source/running.html#flashing-a-device
模拟Android设备
在构建过程中,模拟器已经自动添加到你的路径中了。执行下面的命令运行模拟器:
$ emulator
常见构建错误解决
错误的Java版本
在构建过程中使用不匹配的Java版本,make会终止并输出一下信息:
************************************************************
You are attempting to build with the incorrect version
of java.
Your version is: WRONG_VERSION.
The correct version is: RIGHT_VERSION.
Please follow the machine setup instructions at
https://source.android.com/source/initializing.html
************************************************************
可能引起的原因:
- 没有按照要求下载正确的JDK版本。
- 在环境变量里有之前下载的JDK。
Python版本为3
Repo是基于Python2.x的特定功能构建,不与Python3兼容,为了使用repo,请安装Python2.x
$ apt-get install python
大小写敏感的文件系统
如果您基于Mac OS上的HFS文件系统构建,您可能会遇到诸如此类的错误
************************************************************
You are building on a case-insensitive filesystem.
Please move your source tree to a case-sensitive filesystem.
************************************************************
解决方法请查看创建构建系统部分
没有USB权限
在大多数Linux系统上,默认情况下,无特权用户无法访问USB端口。 如果您看到权限被拒绝的错误,请按照说明初始化构建环境以配置USB访问。
如果adb已经运行,并且在设置好这些规则后无法连接到设备,则可以使用adb kill-server进行杀死。 这将导致adb使用新配置重新启动。
使用Jack编译
根据本公告,Jack工具链已被弃用。 但是,您可以继续使用它来启用Java 8语言功能,直到发布可用的替代品。
Jack工具链
Jack是一个新的Android工具链,将Java源代码编译成Android dex字节码。 它替代了以前的Android工具链,它由多个工具组成,如javac,ProGuard,jarjar和dx。
Jack工具链具有以下优势:
* 完全开源
在AOSP上可用
* 加速编译
Jack使用特殊的支持来减少编译时间,包括预先dex转换、增量编译和Jack编译服务器
* 解决压缩、混淆、重新打包、多dex
不再使用单独的软件包,例如Proguard
从Android7.0(N)开始,Jack支持使用JaCoCo统计代码覆盖率。详情查看JaCoCo代码覆盖率和Java8语言特性
Jack概览
Jack库文件格式
杰克有自己的.jack文件格式,其中包含预编译的dex代码库,允许更快的编译(pre-dex)。
Jack库文件内容
Jill
Jill工具将已有的.jar库转换成新的库文件格式。
转换已有的.jar库文件流程
在Android编译过程中使用Jack
使用Jack编译Android7.0及以后版本请移步Jack服务端文档
Jack是Android M上默认的编译工具链。你不需要做任何更改就可以使用标砖的makefile命令去编译源码树或你的工程。
第一使用Jack是,会在你的电脑上启动一个本地的Jack编译服务器。
- 该服务器带来内在加速,因为它避免启动新的宿主JRE JVM,加载Jack代码,初始化Jack并在每次编译时加热JIT。 它也在小编译期间提供非常好的编译时间(例如在增量模式下)。
- 该服务器也是一个短期解决方案,用于控制并行Jack编译的数量,因此避免计算机(内存或磁盘问题)过载,因为它限制了并行编译的数量。
Jack服务器在空闲时间后自动关闭,无需任何编译。 它在localhost接口上使用两个TCP端口,因此外部不可用。 可以通过编辑$ HOME / .jack文件修改所有这些参数(并行编译次数,超时时间,端口号等)。
$HOME/.jack file
$HOME/.jack文件包含了Jack服务端的变量设置,采用完整的bash语法。
下面是这些变量的设置,包含定义和默认值。
- SERVER=true 启动Jack服务端特性
- SERVER_PORT_SERVICE=8072 设置服务端编译的TCP端口号
- SERVER_PORT_ADMIN=8073 设置服务端管理的TCP端口号
- SERVER_COUNT=1 目前没有使用
- SERVER_NB_COMPILE=4 允许的最大并行编译数量
- SERVER_TIMEOUT=60 服务端在没有编译任务后,等待关闭自己的空闲时长。
- SERVER_LOG={SERVER_LOG:=SERVER_DIR/jack-$SERVER_PORT_SERVICE.log} 服务器日志文件所在目录。默认情况下,可以被环境变量覆盖。
- JACK_VM_COMMAND=${JACK_VM_COMMAND:java} 启动JVM的默认命令。默认情况下,可以被环境变量覆盖。
Jack问题解决
编译过程中电脑无响应或编译失败“Out of memory error”
通过修改$HOME/.jack文件中的SERVER_NB_COMPILE值,来降低并行编译数量编译失败“Cannot launch background server”
首先可能是端口占用,修改SERVER_PORT_SERVICE和SERVER_PORT_ADMIN的值。如果不能解决问题,就只能关闭Jack编译服务(SERVER=false),并上报Jack日志。
如果编译没有任何进展就卡住了
上报日志病提供额外的信息:- 卡在了哪一条命令
- 命令行输出
- jack-admin server-stat命令的输出
- $HOME/.jack文件
服务端状态转储的日志内容
- 执行jack-admin list-server命令找出Jack后台服务进程
- 发送kill -3命令来存储服务端状态到日志文件
- 定位服务端日志文件,后面会说到
执行 ls -lR TMPDIR/jack− USER的结果
- 执行 ps j -U $USER的结果
你应该能够通过杀死Jack后台服务(jack-admin kill-server)来解除锁定,然后删除jack-$USER下的临时目录。
其他问题
访问http://b.android.com来上报错误或请求新特性找到Jack日志文件
- 如果是执行make命令, Jack日志文件位于$ANDROID_BUILD_TOP/out/dist/logs/jack-server.log
- 否则的话可以通过执行jack-admin server-log 来找到它
为了可以复现Jack失败,你可以获取更详细的日志通过设置一个变量:
$ export ANDROID_JACK_EXTRA_ARGS="--verbose debug --sanity-checks on -Dsched.runner=single-threaded"
然后使用标准的makefile命令来编译源码树或工程,并附加其标准输出和错误。
使用以下命令移除详细的构建日志:
$ unset ANDROID_JACK_EXTRA_ARGS
Jack的限制
默认情况下,Jack服务器是单用户的,因此只能由计算机上的一个用户使用。 如果不是这样,请为每个用户选择不同的端口号,并相应调整SERVER_NB_COMPILE。 您还可以通过在$ HOME / .jack中设置SERVER = false来禁用Jack服务器。
由于目前的vm-tests-tf集成,CTS(兼容测试套件)编译速度很慢。
- 不支持字节码操作工具如JaCoCo
使用Jack特性
Jack支持Java1.7和集成了额外的特性
预先Dex
第三方库文件是以class文件形式存在,Jack会将这些文件预先dex编译。
当生成Jack库文件时,会生成.dex文件并以pre-dex的形式存储在.jack库文件中。
当编译时,Jack会从每一个库文件中重用pre-dex。
所有的库文件都会被预先dex。
限制
目前,如果在编译过程中启用了混淆、重新打包、压缩资源,Jack不会重用pre-dex
启动增量编译
增量编译默认不会启动,如果想要增量构建,需要在工程下Android.mk文件中添加如下配置:
LOCAL_JACK_ENABLED := incremental
注:如果在第一次使用Jack构建时,缺少一些依赖。先使用mma构建他们,然后再使用标准的构建命令
资源压缩和混淆
Jack通过使用混淆配置文件来启动资源法索和混淆。下面是支持和忽略的选项:
支持的一般选项
- @
- -include
- -basedirectory
- -injars
- -outjars // only 1 output jar supported
- -libraryjars
- -keep
- -keepclassmembers
- -keepclasseswithmembers
- -keepnames
- -keepclassmembernames
- -keepclasseswithmembernames
- -printseeds
支持的资源压缩选项
- -dontshrink
支持的混淆选项
- -dontobfuscate
- -printmapping
- -applymapping
- -obfuscationdictionary
- -classobfuscationdictionary
- -packageobfuscationdictionary
- -useuniqueclassmembernames
- -dontusemixedcaseclassnames
- -keeppackagenames
- -flattenpackagehierarchy
- -repackageclasses
- -keepattributes
- -adaptclassstrings
忽略的选项
- -dontoptimize // Jack does not optimize
- -dontpreverify // Jack does not preverify
- -skipnonpubliclibraryclasses
- -dontskipnonpubliclibraryclasses
- -dontskipnonpubliclibraryclassmembers
- -keepdirectories
- -target
- -forceprocessing
- -printusage
- -whyareyoukeeping
- -optimizations
- -optimizationpasses
- -assumenosideeffects
- -allowaccessmodification
- -mergeinterfacesaggressively
- -overloadaggressively
- -microedition
- -verbose
- -dontnote
- -dontwarn
- -ignorewarnings
- -printconfiguration
- -dump
重新打包
Jack使用jarjar配置文件做重新打包。
多dex支持
Jack提供原生的和遗留的多dex支持。