前言
记得当年刚接触Android的时候,就看有关老罗的文章倒是让我的安卓内功提升不少,但是由于工作都是停留在应用层的缘故,我几乎对这块并没有深入研究,最近公司的新产品对Framework层的开发有所涉及,需要制作自己的ROM包,我用一个星期来调研,查国内外的很多资料,发现国内的魔趣的开源项目是基于CM和AOSP来进行二次开发的,社区论坛也比较活跃,这里的Android ROM我就选择从魔趣的源码来进行编译开发了,刚好手里有一台红米5A手机,以下的开发过程就围绕这部手机型号来进行展开。
源码的下载
配置SSH长连接
我们的用户端和服务端链接过程中长时间不输入后会导致自动断开,我参考《解决SSH自动断开问题》进行配置,下载的时候,因为同步命令会记录上次下载的位置,所以可以继续执行。在编译的时候特别重要,因为断开后,他很多变量都是配置到当前会话中的,断开SSH会话后,编译命令无法找到,我们就需要重新的去编译源码。
选定源码版本
我们来看下魔趣官网中对于源码版本的选定
上面我在魔趣下载网站上对于5A机型ROM源码的查看,几乎每天都在更新,那么我们这里下载的肯定就是魔趣的8.1的源码了(MK8.1就是代表魔趣的ROM是基于8.1来进行开发的)。
安装repo
在这里我主要参考的是官网的repo安装,我在挂载的服务器硬盘路径中创建我们下载的文件夹,并且添加到环境变量中。
$ mkdir /var/android/rom/mokee/source
$ PATH=/var/android/rom/mokee/source:$PATH
使用魔趣的镜像下载repo
$ curl https://download.mokeedev.com/git-repo-downloads/repo > /var/android/rom/mokee/source/repo
$ chmod a+x /var/android/rom/mokee/source/repo
初始化repo分支
$ repo init -u https://github.com/MoKee/android -b mko-mr1
下载好后有一个.repo
的隐藏文件夹,cd进去:
$ ls
local_manifests manifests project-objects projects
manifest.xml manifests.git project.list repo
更改国内镜像地址
目前下载的时候,如果使用默认的http://android.googlesource.com/
需要我们进行翻墙操作,可能网速不稳定,这里就需要我们再.repo/manifest.xml
文件去修改我们的下载地址,通过这篇《魔趣开源项目定制版Repo-全程无需科学上网环境同步完整Android源码库》帖子,我们可以进行下载环境的搭建。这里我们就选择了清华大学镜像,改为https://aosp.tuna.tsinghua.edu.cn/
更改后初始化repo并且同步下载8.1的源码:
$ repo sync
来看一张下载完成后的效果图:
上面的红框是我在编译源码的过程中产生的,这里可以忽略掉,下载完成后是没有这些文件的。
安装编译环境
安装OpenJDK
在官网中要求,编译7.0和8.0版本源码我们这里就安装OpenJDK安装,参考这篇文章《CentOS7 使用yum命令安装Java SDK(openjdk)》。
安装所需的软件包
虽然官方给我们推荐的是Ubuntu,但是我们公司给我提供的服务器环境是centos 6.5
这里我找了些资料去安装我们的环境,我看了这篇文章CentOS7上编译Android系统执行了下面的命令。
$ sudo yum install -y gcc make libstdc++.i686 libstdc++-devel.i686 zlib-devel openssl-devel perl cpio expat-devel gettext-devel autoconf glibc.i686 glibc-devel.i686 zlib-devel.i686 libstdc++.i686 libX11-devel.i686 ncurses-devel.i686 ncurses-libs.i686 gperf flex gcc-c++ bison patch
编译中产生的问题
在小节内容都是我在编译中产生的问题,放在编译小结前面,主要是让大家先阅览产生印象,如果你在编译过程中也产生了类似的问题,可以参考我发的链接进行修改,目前编译的出现报错的问题我分为两类:
- 安装包的缺失和不适配问题
- 编译机器配置问题
安装包的问题
这里安装包的问题,我们可以提前的解决编译的时候,就可以节省很多时间,因为,我是自己摸索编译的相关资料很少,就自己采坑后重新编译。
-
Glibc 版本过旧的问题
在编译过程中,会提示我编译需要Glibc 2.15,由于我们当前的版本是2.13,达不到编译的要求会出现错误,这里我们参考看这篇文章进行版本升级和安装。 -
缺失ImageMagick软件包
============================================
ninja: no work to do.
ninja: no work to do.
/var/android/rom/mokee/source/out/build-mk_rolex.ninja is missing, regenerating...
[1070/1081] including ./vendor/mk/bootanimation/Android.mk ...
**********************************************
The boot animation could not be generated as
ImageMagick is not installed in your system.
Please install ImageMagick from this website:
https://imagemagick.org/script/binary-releases.php
**********************************************
这里我们参考这篇文章《Centos7安装ImageMagick》。
- Zlib版本不适配
FAILED:
/var/android/rom/mokee/source/out/host/linux-x86/bin/aapt:
/lib64/libz.so.1: version `ZLIB_1.2.3.4' not found (required by /var/android/rom/mokee/source/out/host/linux-x86/bin/aapt)
ninja: build stopped: subcommand failed.
参考《version ZLIB_1.2.3.4 not found 解决方法》按照这篇文章我的编译是成功的,但是我们需要注意一个点,修改后再次查看命令还是1.2.3
版本:
[mujf@pbx-test01 lib64]$ rpm -qa | grep zlib
zlib-1.2.3-29.el6.i686
zlib-devel-1.2.3-29.el6.x86_64
zlib-devel-1.2.3-29.el6.i686
zlib-1.2.3-29.el6.x86_64
也就是说使用文章的方法安装Zlib并没有覆盖原有的版本进行升级的效果,这里我暂时没有找到好的方案去升级。
编译机器配置问题
在官网的要求中,这需要16G的内存是标配,但是公司给的内存也就是8G所以常常会出现内存不足的情况,因为编译的时候是用的jack,这里我也是勉强的去使用,就需要更改下配置。
- 修改Jack内存配置
FAILED: /var/android/rom/mokee/source/out/soong/build.ninja
/var/android/rom/mokee/source/out/soong/.bootstrap/bin/soong_build -t -b /var/android/rom/mokee/source/out/soong -d /var/android/rom/mokee/source/out/soong/build.ninja.d -o /var/android/rom/mokee/source/out/soong/build.ninja Android.bp
fatal error: runtime: out of memory
编译的时候,显示log出错,内存不足,我查看本机的内存发现还有4个G。我参考了这篇文章《编译CM14.1 提示Jack “Out of memory error”错误》,配置适合本机的Jack内存为8G。
在上面的路径下找到我们的jack-admin
文件,按照下面的命令去修改
这里的修改命令,Xmx4096对应的内存是8G,修改后进行错误的重启。
#先停止服务
prebuilts/sdk/tools/jack-admin stop-server
#重新开始服务
prebuilts/sdk/tools/jack-admin start-server
效果图:
- JVM内存不足的问题
[ 83% 80128/96322] Docs droiddoc: /var/android/rom/mokee/source/out/target/common/docs/api-stubs
FAILED: /var/android/rom/mokee/source/out/target/common/docs/api-stubs-timestamp
/bin/bash /var/android/rom/mokee/source/out/target/common/docs/api-stubs-timestamp.rsp
OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000c4180000, 103809024, 0) failed; error='Cannot allocate memory' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 103809024 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /var/android/rom/mokee/source/hs_err_pid13087.log
ninja: build stopped: subcommand failed.
今天在编译到83%的时候,曝出上面的错误,看网上的文章应该是内存不够,本来我编译的时候只有8GB内存,编译8.1的源码肯定会出现问题。我参考了这篇文章创建swap(交换区)方案,当内存不够的时候使用交换空间去做临时方案。
编译源码
如果提前解决上面的问题,那么现在我们编译肯定是顺风顺水了,在魔趣论坛的《5行命令教你编译魔趣》这个帖子中,我了解到了一些流程,现在就动手实践一下:
source build/envsetup.sh
lunch mk_rolex-userdebug
mka bacon -j1 > make.log
PS:这里有个指令 make clobber 是清除编译缓存,简单说就是删掉out文件夹下面内容。
下面的source命令,就是初始化编译环境变量这些变量的设置只有在当前的会话中有用,如果出现断网后面的lunch
和mka
命令就无法执行,需要重新执行source
命令。
-
lunch命令
lunch
命令后的跟的是开发代号,这里我们可以在魔趣设备支持列表中找到红米5A
代号。
-
mka bacon -j1 > make.log
这里当上面命令完成后,我们将使用一个cpu去编译所有源码这里可以根据自身的配置,来使用-j[num]
来编译,数字代表使用几个cpu内核来编译,这里的log是我们编译中产生的日志信息。关于命令的的作用参考《Android编译系统详解(一)——build/envsetup.sh》
注意点
在编译过程中,我们可能会出现各种相对自己机子的报错,但是我们并不需要重新的去编译我们的文件,当我们解决当前报错的问题后,在SSH没有断开的情况下重新执行编译命令mka bacon -j1 > make.log
会继续我们上次报错的点来继续编译。
写到这里我们对命令的简单实用应该已经基本知晓了,但是正所谓知其所以然,我们要了解命令背后的含义还需要看一下老罗的这篇文章《Android编译系统环境初始化过程分析》。
编译完成
下面放一张编译完成后的效果图:
上面的镜像文件就是我们通常刷机时候需要的文件,我们再来看看MK81.0-rolex-201901191847-UNOFFICIAL.zip
文件内容。
在官方发布的rom每夜版MK81.0-rolex-201901211301-NIGHTLY.zip
中和我们编译后产生的zip包命名很类似,在这里我们应该已经猜测到了,每夜版本就是通过这种方式产生的,我们来看下官方发布的zip包中的内容证实一下。
文件名称完全是一样的,在这里我们就可以肯定,官方的代码也是通过我们的这种方式得到。
结束语
在编译的整个过程中,因为我是最低的配置去编译8.1的源码,总共就花费了将近20个小时。期间还出现了很多问题,不过总算是编译完成,其实有点幸运的成分在其中,毕竟我因为内存吃紧报错出现了很多问题了,都几度想放弃还是坚持下来了。编译只是第一步,下面我们需要将编译出来的魔趣OS刷机包刷入到手机中,这样我们才能进行后续的研发工作,感兴趣的可以看我的下一篇文章《定制ROM采坑之路(2):魔趣OS刷入小米5A手机过程详解》。