相信很多Android开发者都编译过android系统,我之前也编译过android系统,但是编译完后,打开虚拟机玩了玩。但是没法用来调试,如果编译的是arm版本运行速度又很慢,所以编译完后,基本就荒废了。
但是编译真机的系统的话,就可以通过定制一些系统选项,或者修改系统的源码,以方便开发或调试,比如:
android studio中包含一个GFX trace的GPU调试模式,但是这种模式必须在adbd以root运行的场景下才能使用,所以可以打开系统的选项来实现。
编译android系统的eng版本,eng版本顾名思义,就是工程版本,会将很多日志输出到logcat中,有时候可以加快查找BUG的速度。
打开linux的core dump功能,出售的机器自带的系统core dump功能都是关闭的,而core dump有时候对jni的crash很有帮助,因此打开它也是好选择。
本文拿nexus 5x来做实验,给它装上自己编译的系统。
1.先决条件
一台解锁后的nexus 5x(或者其他CM支持的手机)
一台ubuntu 64位系统的电脑,最好有8G左右内存,剩余空间大于100G
知道如何刷机
2.下载源码
首先创建源码下载的目录和编译的目录:
$ mkdir -p ~/bin
$ mkdir -p ~/android/system
下载 “repo”,并给它增加可执行权限:
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
$ chmod a+x ~/bin/repo
再将 ~/bin 加入到PATH里面,在最近的ubuntu系统中,~/bin 已经在PATH中了。
使用下面命令来初始化源码的下载目录:
注意:这里的分支一定是你想要编译的分支,并且支持你的设备
$ cd ~/android/system/
$ repo init -u https://github.com/CyanogenMod/android.git -b cm-13.0
然后就可以开始下载源码了:
$ repo sync
CM的manifests中已经有了针对repo的配置,所以建议直接使用(不要加任何其他参数给sync)。默认的参数值是-j 4和 -c,-j 4表示4个线程并行下载。如果你sync有问题的话,也可以降低成两个或者三个线程并行。-c表示需要repo只拉取当前分支,而不是整个CM的历史。
然后只需要等待下载完成就可以了。
3.安装编译所需要的组件
除了系统自带的组件,编译CM还需要一些其他的编译组件:
sudo apt-get install bison build-essential curl flex git gnupg gperf libesd0-dev liblz4-tool libncurses5-dev libsdl1.2-dev libwxgtk2.8-dev libxml2 libxml2-utils lzop maven openjdk-7-jdk pngcrush schedtool squashfs-tools xsltproc zip zlib1g-dev g++-multilib gcc-multilib lib32ncurses5-dev lib32readline-gplv2-dev lib32z1-dev
Ubuntu 15.10以及最新版系统将 lib32readline-gplv2-dev 替换为 lib32readline6-dev
Ubuntu 16.04以及最新系统将 libwxgtk2.8-dev 替换为 libwxgtk3.0-dev
由于Ubuntu 16.04中将OpenJDK 1.7从官方源中移除了,所以有两个选择:
从 openjdk-r PPA(https://launchpad.net/~openjdk-r/+archive/ubuntu/ppa) 下载OpenJDK 1.7
打开CM 13.0(旧版本没有)的OpenJDK 1.8的体验选项,需要将export EXPERIMENTAL_USE_JAVA8=true加到环境变量中。(我选的是这个)
4.准备好设备相关的配置
下载完代码以及组件后,切换到源码的根目录(cd ~/android/system),然后输入下面命令:
$ source build/envsetup.sh
$ breakfast bullhead
这两句会下载nexus 5x的配置文件以及内核源码。
5.提取设备私有的二进制文件
android除了需要有系统源码外,还有一些二进制文件是和设备相关的,需要由厂商提供。这一部分可能没有源码,所以需要从手机里面直接取出来。
这一步很关键,这个阶段一定不能出错,否则很容易出现编译问题。所以在执行这一步之前,需要先执行以下两个步骤:
将手机自带的系统刷回去(nexus 5x的系统可以从Google网站上找)
然后再刷入支持该设备的CM系统
然后再切换到 ~/android/system/device/lge/bullhead,执行 extract-files.sh 脚本:
$ ./extract-files.sh
然后就可以看到很多文件从手机复制到了 ~/android/system/vendor/lge 中。
6.配置缓存
设置缓存之后,可以加快后续编译的速度,建议设置下。首先将下面这句加到环境变量中:
export USE_CCACHE=1
然后调用ccache命令设置缓存的大小
prebuilts/misc/linux-x86/ccache/ccache -M 50G
ccache命令只需要执行一次,缓存大小建议为50G,增加或者缩小都可能会影响编译速度。
也可以通过以下命令设置缓存的位置和大小:
export ANDROID_CCACHE_DIR="$HOME/android/.ccache"
export ANDROID_CCACHE_SIZE="50G"
7.开始编译
编译只需要执行下面两句就可以了:
$ croot
$ brunch bullhead
编译完成后,就可以在 out/target/product/bullhead/ 中找到编译出来的zip包,正常的刷到手机上,就可以快乐的玩耍了。
8.后续
如果想编译一个eng版本的话,只需要将 brunch bullhead 换成 brunch bullhead eng 就可以了。
如果你修改了一个小模块,不想编译整个系统的话,可以通过 mm 命令来编译该模块。mm 可以在任何目录执行,如果它找不到编译的配置的话,就会向上级目录查找,直到找到编译配置文件(.mk)。
注:编译子模块的时候,mm会检查是否有变更,然后再决定是否需要编译。有些cpp会引入一些输入文件(如:gl2_api.in),这一类文件变更的时候,并不会导致重新编译,所以需要在相关文件中增加一些变更(空行或注释都可以),触发它编译。