文章目录
  1. 1. 环境准备
  2. 2. 下载Android源码
  3. 3. 编译Android源码
  4. 4. 安装编译好的Android到模拟器
  5. 5. 参考

自诩为Android开发者已经很久了然而却没有自己编译安装过Android源码,怎么也说不过去。今天就编译安装,记录下来过程中需要注意的情况。

环境准备

  • 如果在中国大陆建议有一个能访问google的网络环境,官方的指导是最可靠最完善的。
  • Android编译不能在Windows系统上进行,所以你需要一个基于Linux的系统,Mac OS和Ubuntu都行,虚拟机的话需要16GB的swap空间。官方使用的是Ubuntu 14.04,我建议你也用这个版本(我用的是16.04)。
  • Android基于Java,最新的基于Java 8, 所以你需要安装JDK 1.8。
  • Android源码使用Git进行管理,并在外封装了一层叫Repo,所以你还要安装Git客户端。
  • 安装依赖包。
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  

下载Android源码

Android源码每个分支可能都要占用约22GB空间,官方建议磁盘空间至少25GB.我建议先选定一个版本的源码,进行下载。

  1. 下载repo工具。执行以下命令:

    1
    2
    3
    4
    5
    wget https://storage.googleapis.com/git-repo-downloads/repo
    chmod a+x repo
    mkdir ~/bin
    cp repo ~/bin/
    PATH=~/bin:$PATH
  2. 下载源码。执行以下命令:

    1
    2
    3
    4
    mkdidr AndroidSource
    cd AndroidSource
    repo init -u https://android.googlesource.com/platform/manifest -b android-4.4.1_r1 # -b是选择分支,不加则下载最新master分支。可以在网页上查看有哪些分支标签
    repo sync

然后就开始下载源码了,视网络状况这个过程可能会很长(我下了两天),中间还可能遇到下载错误,这时候重新执行repo sync就行了。

编译Android源码

Android用到的Makefile系统来编译源码,所以必要的相关知识会非常有帮助。以后涉及到单独模块的编译需要自己写makefile。
在源码根目录下执行make就可以编译源码。默认编译目标是droid,默认输出目录在/out,执行source build/envsetup.sh可以获得更多的编译命令,其中lunchmmm两个命令特别有用。
编译目标中,默认是droid前面已经说过,另外还有几个常用的编译目标,clean清理out目录,sdk编译SDK,clean-sdk清理SDK编译产物,all编译所有内容,snod从已经编译出的包快速重建系统镜像,dump-products显示所有产品的编译配置信息,bootimage recoveryiamge userdataimage cacheimage生成对应的.img。关于Build系统可以看这里

可能会遇到问题:
1.

1
2
You are using version x.x of make  
Android can only be built by versions 3.81 and 3.82

make的版本过低或过高,过低升级即可,过高则需要安装指定版本。我先remove了make 4.1,然后在http://packages.ubuntu.com/trusty/make 下载安装了make 3.81。
2.
You are attempting to build with an unsupported JDK.
很明显OpenJDK不被支持,需要Oracle JDK。另外,JDK版本也一定要与你要编译的版本相匹配,不能过高,否则提示You are attempting to build with the incorrect version of java.。比如我编译4.4源码用的JDK 1.8,就提示java版本错误,非常郁闷。
安装好JDK 6 之后终于开始了编译步骤。
官网上说AOSP光靠它的源码还不能工作,需要一些跟硬件有关的library,在http://source.android.com/source/requirements.html#binaries 最下面。另外提供了官方的Nexus系列的驱动在https://developers.google.com/android/nexus/blobs-previewhttps://developers.google.com/android/nexus/drivers 。安装步骤见http://source.android.com/source/building.html, 每个binary是一个自解压文件,在Android源码根目录运行这个自解压文件,然后相应的binary和makefile就会被安装在vendor目录。
编译没有错误的话就会生成Android系统了,根据主机配置不同这个过程可能比较久(我开始编译的时候没有注意,用了4小时…),可以在make的时候指定并发job数量来加速编译过程:make -j8
编译完成的out目录下应该有system.img ramdisk.img userdata.img三个文件。
接下来进行安装。

安装编译好的Android到模拟器

安装有两种选择:刷到设备里和安装到模拟器。其中刷到设备里需要设备和编译目标相匹配,否则可能无法成功启动,且需要用到fastboot工具,见flashing a device。这里我们选择安装到模拟器。
在build完成后把/out/host/linux-x86/bin/emulator添加到环境变量,这里需要执行的是这个emulator。加选项-kernel <PATH> -sysdir <PATH> -system <PATH> -data <PATH> -ramdisk <PATH>可以指定要用到的image文件。模拟器运行需要四个文件,分别是Linux Kernel镜像kernel-qemu(在$ANDROID_SOURCE/prebuilts/qemu-kernel中)、Android镜像system.imguserdata.imgramdisk.img
需要注意的是即使是模拟器平台也要跟编译目标相匹配,模拟器要求的内核最低版本必须低于所使用的内核版本。
今后就可以自己修改某个模块的代码,然后编译这个模块并重新打包到system.img来查看效果啦!
甚至可以自己定义新的模块,添加到系统镜像中。Android自带的App存放在out/target/product/generic/system/app,可执行文件存放在out/target/product/generic/system/bin,动态链接库存放在out/target/product/generic/system/lib,硬件抽象层(HAL)接口文件存放在out/target/product/generic/system/lib/hw

可能会遇到的问题:

  1. emulator: ERROR: Missing initial data partition file: (null) or 必须要指定一个虚拟机才能运行emulator。遇到这个可能是因为你使用了不合适的emulator,看一看which emulator,是不是使用了Sdk中的emulator。应该使用/out/host/linux-x86/bin/emulator

  2. qemu: could not load initrd 'ramdisk.img'。遇到这个问题可能是模拟器没有读取到正确的ramdisk.img文件。按网上说法使用绝对路径即可,也可以将ramdisk的父目录out/target/product/generic添加到环境变量。

  3. 启动模拟器后一直黑屏。可能是使用了错误的kernel,换一个kernel试试。我换成arm/kernel-qemu-armv7就可以启动了。

  4. emulator: WARNING: system partition size adjusted to match image file (550 MB > 200 MB)。这个WARNING好像不影响模拟器运行,但强迫症还是想弄懂为什么要WARNING,于是查了查。原来是所需空间不足,添加参数emulator -partition-size 1024 # 大于所需尺寸即可

  5. make: *** No rule to make target 'out/target/product/generic/root/file_contexts', needed by 'snod'. Stop. 或者启动模拟器后一直停留在开机画面,打开monitor发现logcat一直在循环刷错误(最近几天连续出现这个问题,虽然还没搞清楚原因,不过暂时在emulator之前执行lunch full-eng是有效果的,另外如果不执行lunch full-eng的话启动的模拟器默认连皮肤都没有,完全没有按键)。可能是模块编译目标与system.img目标不匹配。在编译模块前lunch full-eng# lunch的combo要和编译系统时lunch的combo一致,在make snodlunch full-eng,我是这么做的。

参考

本文参考了以下文章,排列不分先后:
Android编译系统环境初始化过程分析
深入理解Android输入系统
那两年练就的Android内功修养-老罗
在Ubuntu上下载、编译和安装Android最新源代码-老罗
如何单独编译Android源代码中的模块-老罗
理解Android Build系统

文章目录
  1. 1. 环境准备
  2. 2. 下载Android源码
  3. 3. 编译Android源码
  4. 4. 安装编译好的Android到模拟器
  5. 5. 参考