1. 引言
Android,中文名称“安卓”,是一种自由开放源代码的操作系统,主要使用于诸如智能手机、平板电脑、电视、数码相机和游戏机等的移动设备。它最初由美国的软件工程师Andy Rubin开发,后来被Google公司收购。之后,Google公司与硬件制造商、软件开发商及电信营运商组建一个开放手机联盟,以Apache开源许可证的授权方式发布Android的源代码,大家可以共同研发。目前,采用Android系统的设备数量不断上升,研发队伍也在不断壮大,这套系统也越来越好,也越来越被大众喜爱。作为众多爱好者之一,近来开始热衷于Ubuntu系统下的Android源码编译,遇到各种各样的问题。网上有关这方面的介绍很多,各有优点,可是,地点变了,时间变了,系统环境不一样了,这些介绍都有这样那样的问题。为了让其他喜好者少走弯路,本文介绍Ubuntu系统和Java [1] [2] 软件下载和安装、以及Android的源码下载和编译,并对可能出现的常见问题提出相应的解决方案。不同版本Ubuntu系统中的gcc编译器、Java编译器和Android之间的兼容性尤为重要,在下载安装时要特别注意。本文的工作之一就是解决了这三者间的兼容性。Android编译仿真时的环境变量设置也很重要,给出这些变量的合理设置便是本文的工作之二。另外,还解决了部分Android源码中的64进制编译问题,用sed命令语句直接修改部分Android源码。
这种安装编译还是需要一定的硬件要求的。一般来说,奔腾或AMD的 CPU都行,内存最低512MB,硬盘最低30 GB,当然,CPU配制越高,编译运行就越快,存储容量越大就越好。这次在老旧的型号为Thinkpad R51e的笔记本电脑上进行实验,硬件配置相对现在的科技来说很低,参见列表1。
另外,还准备了一个8 GB的U盘,用于制作Ubuntu系统安装U盘。
除了硬件要求之外,大家还需要会操作Linux系统的基本命令,比如,Linux的sed用法往往在修改文件内容时很有用,能编写shell脚本就更好了。推荐大家参见美国Richard Blum和Christine Bresnahan编著的书 [3] ,这本书已于2012年由武海峰翻译成中文,中文书名为《Linux命令行与shell脚本编程大全》 [4] 。如果具备有关Android系统的基本知识 [5] - [14] ,那就更好了。
通过实验,可以掌握Ubuntu系统、Java软件和Android源码的下载安装以及Android源码编译的基本技能,领会Android源码编译与Ubuntu系统和Java软件之间的兼容性,缺少其中任何环节都不行。Android源码编译可谓是个庞大的系统工程,在这基础上,可以进行更加广泛的软件开发。
2. 系统软件安装和环境变量设置
Android的源码是基于Linux系统的。为此,首先要下载并安装一个Linux系统。由于电脑CPU不

Table 1. The hardware configuration of the Thinkpad R51e laptop
表1. Thinkpad R51e笔记本电脑的硬件配置
支持64进制,所以本次实验选用的是32进制的Ubuntu系统。如CPU支持64进制,就选用64进制的系统。Ubuntu系统有许多的镜像网址,最好选个国内的网址。从如下的Sohu镜像网址:
http://mirrors.sohu.com/ubuntu-releases/10.04.4/release/
就可下载ubuntu-10.04.4-dvd-i386.iso,然后用UltraISO或电脑店软件将这个映像文件刻录到U盘,最后用这个装有Ubuntu系统安装软件的U盘将32进制的Ubuntu系统安装到电脑。实验发现这个版本的Ubuntu系统更适合编译Android源码。
启动电脑,进入Ubuntu系统,设置好网络配置,联网。接着,还需要安装下载和编译Android源码所需的相关软件。为此,先在终端执行
sudo apt-get update
去对Ubuntu系统的升级包更新,如果不执行此更新,就无法进行接下来的软件安装。再在终端执行如下命令行:
sudo apt-get install git-core curl
sudo apt-get install gnupg flex bison gperf build-essential zip
sudo apt-get install tofrodos pngcrush schedtool squashfs-tools
sudo apt-get install g++-multilib python-markdown mingw32
sudo apt-get install libxml2-utils xsltproc zlib1g-dev libc6-dev
sudo apt-get install libncurses5-dev libreadline5-dev libz-dev
sudo apt-get install libsdl1.2-dev libesd0-dev libwxgtk2.6-dev
sudo apt-get install zlib1g-dev libgl1-mesa-dev libx11-dev
sudo apt-get install lib64z1-dev x11proto-core-dev
其中,第一行是下载Android源码所需的工具,其它行是编译Android源码所需的软件。另外,还要下载Java。大家可以从网上获取jdk-6u45-linux-i586.bin并保存在目录~/下,在终端执行:
chmod a+x ~/jdk-6u45-linux-i586.bin & sudo ~/jdk-6u45-linux-i586.bin
就把Java安装在Ubuntu系统上了,Java就在目录~/jdk1.6.0_45下。Java官方网址如下:
http://www.oracle.com/technetwork/java/javase/downloads/index.html
从此可以获取最新版本,不过,最新版本不支持较早的Android源码编译。获取旧版的Java的网址很多,比如,http://ghaffarian.net/downloads/Java/JDK/,这个网址上还有其他版本,可自由下载。为了能正常运行Java,还需设置Java运行的环境变量,并把这些变量存放在文件jdk.bashrc中。为此,可在终端执行如下命令:
echo export JAVA_HOME=$HOME/jdk1.6.0_45 >> jdk.bashrc
echo export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib/dt.jar >> jdk.bashrc
echo export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib/tools.jar >> jdk.bashrc
echo export PATH=$HOME/bin:$JAVA_HOME/bin:$PATH >>jdk.bashrc
source jdk.bashrc
其中前4行将环境变量写入文件jdk.bashrc中;JAVA_HOME是指向jdk的安装目录的环境变量,Java编译器通过搜索JAVA_HOME变量来找到并使用安装好的jdk;CLASSPATH环境变量指定类搜索路径,Java编译器通过CLASSPATH来寻找已经编写好的类;PATH环境变量指定命令搜索路径;最后一行使得这些变量生效。在终端运行java -version,如显示Java版本号,就说明安装设置成功。到这里,相关软件安装准备就绪。如果不设置这些环境,Android源码环境变量安装时就会出错停止,显示要求安装Java 1.6。
3. Android源码下载、编译和仿真
有了前面的准备工作,下面就可以下载和编译Android的源码了。
国内Android的源码镜像有,下载下来的都无法编译,不是缺这就是缺那。上Google公司网址google.com嘛,连接不上,据说被封了,至于被谁封,那就搞不清了。就连gmail.com同样连接不上。上网查询一下,发现可以通过第三方的镜像网址下载。下面就讲述具体的下载步骤。
要下载Android的源码,首先需要下载repo,它只是google用Python脚本写的调用git的一个脚本,主要是用来下载和管理Android项目的软件仓库[15] 。由于无法连接android.git.kernel.org和git-repo.googlecode.com等google网址,所以只能通过第三方获取。先在用户根目录下新建一个子目录bin,并设置好路径,然后用curl从一个第三方连接网址中获取repo,为此,在终端运行如下命令就可下载:
mkdir -p ~/bin & export PATH=~/bin:$PATH
curl http://php.webtutor.pl/en/wp-content/uploads/2011/09/repo >~/bin/repo
chmod a+x ~/bin/repo
其中最后一行命令改变repo的属性,使得repo成为一个可以执行的脚本。如果原先有这个脚本,那就不需要这些步骤了。接着,同样在用户根目录下新建一个子目录work,并在这个子目录work下开始下载Android的源码。为此,可在终端运行如下命令:
mkdir -p ~/work & cd ~/work
repo init -u git://git.omapzoom.org/platform/manifest.git -b android-2.3.3_r1
cd ~/work/.repo/manifests & cp default.xml default.xml.bk
sed -i -e 's/fetch=../fetch=git:\/\/git.omapzoom.org\//g' default.xml
cd ~/work & repo sync –j8
其中,执行第3行和第4行命令的目的就是要修改google默认网址为第三方网址,最后一行命令指的是回到这个子目录work来执行同步下载Android源码。特别要说明的是,在执行第2行命令的过程中,还需要gmail的账户和密码。如果没有,就得借助第三方软件登入gmail.com网址注册一个用户。再到google下载Android源码的网址去用自己的gmail.com信箱注册获得下载许可,并把下载许可的账户名和密码按要求的格式存放在一个文本文件中,其存放格式如下:
machine android.googlesource.com login git-***.gmail.com password *$*
machine android-review.googlesource.com login git-***.gmail.com password *$*
其中,***表示下载许可的账户名,*$*表示密码。而且这个文件必须以.netrc为名存放在用户根目录下。这步是必须的,需要在开始下载Android源码之前完成。如果一切顺利,那就等待下载完吧。
以上命令是下载版本号为2.3.3_r1的Android源码。如果不知道那种版本可以下载,那就执行如下命令:
cd ~/work & repo init -u git://git.omapzoom.org/platform/manifest.git
cd ~/work/.repo/manifests & git branch -a > ~/android-branch.txt
这时,在用户目录下就有一个文本文件android-branch.txt,打开查看即可。
由于我们采用32进制Ubuntu系统,所以还得将版本号为2.3.3_r1的Android源码中设定的64进制编译选项改为32进制的编译选项,这些选项就在5个文件中。在子目录work下,只需在终端作如下命令:
sed -i -e '74a ifneq (0,0)' -e '81a endif' ./build/core/main.mk
sed -i -e 's/FLAGS += -m64/FLAGS += -m32/' ./external/clearsilver/cgi/Android.mk
sed -i -e 's/FLAGS += -m64/FLAGS += -m32/' ./external/clearsilver/cs/Android.mk
sed -i -e 's/FLAGS += -m64/FLAGS += -m32/' ./external/clearsilver/java-jni/Android.mk
sed -i -e 's/FLAGS += -m64/FLAGS += -m32/' ./external/clearsilver/util/Android.mk
就对这些文件完成了32进制的编译设置。如果Ubuntu系统是64进制的,这些文件就不需要修改了。
有了前面的准备,就可以进行Android源码编译,终端执行下列命令即可:
cd ~/work & source ~/jdk.bashrc & source ./build/envsetup.sh
lunch generic-eng & make -j8
这里就不多解释了。耐心等待编译完成之后,终端出现如图1所示的结果,这表明已成功编译好了。
接着,就可以仿真显示了。终端运行如下命令:
export ANDROID_PRODUCT_OUT=~/work/out/target/product/generic
ANDROID_PRODUCT_OUT_BIN=~/work/out/host/linux-x86/bin
export PATH=${PATH}:${ANDROID_PRODUCT_OUT_BIN}
export PATH=${PATH}:${ANDROID_PRODUCT_OUT}
cd ${ANDROID_PRODUCT_OUT}
emulator -system system.img -data userdata.img -ramdisk ramdisk.img
这里,前4行是设置仿真的环境变量,ANDROID_PRODUCT_OUT指向Android系统映像文件所在的目录,ANDROID_PRODUCT_OUT_BIN指向Android系统的仿真执行文件所在的目录;第5行转入Android系统映像文件所在的目录;第6行仿真运行Android系统。如果不把ANDROID_PRODUCT_OUT和ANDROID_PRODUCT_OUT_BIN添加到命令搜索路径PATH中,执行第6行时就会出错,显示没有

Figure 1. The screenshot of a terminal where the Android source codes are successfully compiled
图1. Android源码编译成功的终端截图
emulator命令。值得提一下的是,如果不知道如何设置仿真的环境变量,那么前4行设置仿真环境变量的命令也可用如下命令行代替:
cd ~/work & source ./build/envsetup.sh & lunch generic-eng
这里,它还包含了编译环境变量的设置。仿真运行成功后,进入系统设置,选择中文语言,然后去查看系统信息,就可以找到如图2所示的信息。图2展示了一个仿真运行Android系统的截图。
4. 问题处理
一般来说,按以上介绍,Android的下载编译仿真就没有问题。在整个实验过程中,如果遇到问题,我们如何处理呢?首先查看硬件是否符合要求,然后查看软件的兼容性是否有问题。硬件方面的常见问题就是硬盘空间不足或者内存不够,更换大硬盘和大内存条就行。编译出现的问题往往就是因为编译器gcc和java与Android源码不兼容,或者因为make的版本较低,或者因为选用Linux系统的进制与Android源码设置的进制不匹配。为此,在终端通过如下命令:
gcc -v
java -version
make -version
就可以分别查看Linux系统中安装的编译器gcc和java的版本以及make的版本。版本为2.3和4 系列的Android源码要求的java版本为1.6,就版本为5系列的Android源码而言,要求的java版本为1.7。版本为2.3系列的Android源码要求的gcc版本为4.4.3,而版本为4 和5系列的Android源码所要求的gcc版本为4.6或4.7。这三种版本的Android源码要求的make版本都为3.81或更高。依次排查,如果不符合要求,就得更换成相符的版本。

Figure 2. The screenshot of emulating the Android system
图2.仿真运行Android系统的截图
5. 小结
Android系统用户逐年增加,这方面的研究和开发很有意义。通过Android源码编译,我们不仅加深了对这个系统的基本原理的认识,而且还认识了它与其他系统的兼容性。整个下载编译仿真的过程还可以从Ubuntu Linux系统推广到Cynwin Linux系统或Mac OSX系统,其变化无非就是设置环境变量的方式不同而已,这个工作将另文公布。我们还可以把这个过程写成一个shell脚本,通过这个脚本来完成整个任务。
致谢
作者感谢评审人对本文给予许多很有价值的修改建议!也感谢众多的无名网友提供有关Android源代码的各种各样的编译介绍!这个工作还得到国家自然科学基金(NSFC 11171356)和国家基础科学人才培养基金资助。