作为有点点小追求的 Android Developer,应该都需要拥有一套自己的 Android 源码吧,一方面方便自己对源码的理解,另一方面也方便自己验证自己的很多猜想。本文主要记录一下源码从下载到编译成功的一整套完整过程,以便以后自己在其他地方搭环境或者其他朋友搭建有借鉴的地方。

在 Windows 上从零开始搭建环境我理解分为以下几个步骤:

  • 搭建 Linux 运行环境,详见第一章
  • 安装下载和编译需要的各种工具,详见第二章
  • 下载源码
  • 构建编译环境
  • 编译源码
  • 运行

下面我就一个一个的记录所有的操作,尽量细致哈,哈哈哈哈

1. 安装 VMWare 和 Ubuntu

参见

2. 安装下载和编译需要的工具

参见

3. 下载源码

由于国内种种原因,我们访问 qiang 外的网站非常慢,甚至无法访问,导致下载源码真是要折磨死人。
好在各大高校提供了国内的镜像源,可以供国内的小伙伴们一起学习交流,目前中国科学技术大学和清华大学的比较稳定,其具体使用都差不多,我就以清华源的镜像进行一步一步搭建吧。(科大源清华源

3.1 创建源目录

创建源代码目录,主要用于将所有源代码,以后编译出来的中间产物等都放着这里面方便管理。
这个源文件目录随便创建,但是方便看,我们就在自己用户目录下创建 source 目录吧。

3.1.1 创建目录

java
1
2
mkdir ~/work_directory
cd ~/work_directory

3.1.2 初始化仓库

java
1
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest

如果执行该命令的过程中,如果提示无法连接到 gerrit.googlesource.com,那么我们只需要编辑~/bin/repo 文件,找到 REPO_URL 这一行,然后将其内容修改为:

java
1
REPO_URL = 'https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'

修改repo.png

修改 repo.png

PS: 由于我希望下 Android P 的代码,使用 - b 参数来指定哪个分支,所有我的初始化仓库为:

java
1
2
3
4
repo init -u git://mirrors.ustc.edu.cn/aosp/platform/manifest -b android-9.0.0_r33

//坑点:大家不要下清华源的android-9.0.0_r1,访问我同步下来是编不过的。
// 如果下载Android9的话,建议下载:android-9.0.0_r8或者android-9.0.0_r33,亲测可以编过

具体 Android 版本 (列表)

3.1.3 同步代码到本地

java
1
repo sync

!!!一直!!!使用以上代码即可完成代码同步。

同步代码是一个非常耗费人力的事情,反正我睡前开始第一步同步,半夜起来同步了几次,第二天一直守着电脑,一旦出现:repo sync has finished successfully. 我就再用 repo sync 再次看看同步结果没有,结果还要无休止的同步……. 大家耐心等待吧,至少折磨一天,反正目前我到了这一步还在同步,一天了….

一直等此次同步结束,然后再执行 repo sync….. 如此往复就行了。

此次同步结束.png

此次同步结束.png

3.1.4 自动化脚本

是不是看了 3.1.3 然后自己一直 repo sync,等,repo sync…… 如此循环都快绝望了。别绝望,下面介绍一个脚本,自动下载。

首先,在工作目录下创建一个 python 脚本

shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//step1 创建脚本文件
vim ~/download.sh

// step2 在脚本中输入
echo "======start repo sync======"
repo sync
while [ $? == 1 ]; do
echo "======sync failed, re-sync again======"
sleep 30
repo sync
done

// step3 赋权限
chmod a+x download.sh

// step4 执行即可
./download.sh

可以洗洗睡了,第二天看看下完没有吧,准备开始编译吧。

4. 构建编译环境

源码下载完成后,就可以构建编译环境了。在开始之前,我们先来看看一些编译要求:

4.1 硬件要求:
64 位的操作系统只能编译 2.3.x 以上的版本,如果你想要编译 2.3.x 以下的,那么需要 32 位的操作系统.
磁盘空间越多越好,至少在 100GB 以上。意思就是,你可以去买个大点的硬盘了啊
如果你想要在是在虚拟机运行 linux, 那么至少需要 16GB 的 RAM/swap.
(实际上,我非常不推荐在虚拟机中编译 2.3.x 以上的代码.)

4.2 软件要求:
1. 操作系统要求
AOSP 开源中,主分支使用 Ubuntu 长期版本开发和测试的,因此也建议你使用 Ubuntu 进行编译,下面我们列出不同版本的的 Ubuntu 能够编译那些 android 版本:

Android 版本 编译要求的 Ubuntu 最低版本
Android 6.0 至 AOSP master Ubuntu 14.04
Android 2.3.x 至 Android 5.x Ubuntu 12.04
Android 1.5 至 Android 2.2.x Ubuntu 10.04

2. JDK 版本要求
除了操作系统版本这个问题外,我们还需要关注 JDK 版本问题,为了方便,同样我们也列出的不同 Android 版本的源码需要用到的 JDK 版本:

Android 版本 编译要求的 JDK 版本
AOSP 的 Android 主线 OpenJDK 8
Android 5.x 至 android 6.0 OpenJDK 7
Android 2.3.x 至 Android 4.4.x Oracle JDK 6
Android 1.5 至 Android 2.2.x Oracle JDK 5

更具体的可以参看:Google 源码编译要求

我现在在 Ubuntu 16.04 下编译 AOSP 主线代码,因此需要安装 OpenJDK 8, 执行命令如下:
sudo apt-get install openjdk-8-jdk
如果你需要在 Ubuntu 14.04 下编译 AOSP 主线代码,同样需要安装 OpenJDK 8, 此时需要执行如下命令:

csharp
1
2
sudo apt-get update
sudo apt-get install openjdk-8-jdk

如果你要编译的是 Android 5.x 到 android 6.0 之间的系统版本,需要采用 openjdk7. 但是在 Ubuntu 15.04 及之后的版本的在线安装库中只支持 openjdk8 和 openjdk9 的安装。因此,如果你想要安装 openjdk 7 需要首先设置 ppa:

csharp
1
2
sudo add-apt-repository ppa:openjdk-r/ppa 
sudo apt-get update

然后再执行安装命令:

csharp
1
sudo apt-get install openjdk-7-jdk 

有时候,我们需要编译不同版本的 android 系统,就可能使用不同的 jdk 版本。关于 jdk 版本切换,可以使用如下命令:

Code
1
2
sudo update-alternative --config java
sudo update-alternative --config javac

3. 其他要求

Google 官方构建编译环境指南中已经说明了 Ubuntu14.04,Ubuntu 12.04,Ubuntu 10.04 需要添加的依赖,这里我们就不做介绍了。我原先以为,Ubuntu16.04 的设置和 Ubuntu14.04 的依赖设置应该差不多,但是只能说 too young too simple.
下面是 Ubuntu16.04 中的依赖设置:

swift
1
2
3
4
5
6
7
8
9
10
sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib 
sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386
sudo apt-get install tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386
sudo apt-get install dpkg-dev libsdl1.2-dev libesd0-dev
sudo apt-get install git-core gnupg flex bison gperf build-essential
sudo apt-get install zip curl zlib1g-dev gcc-multilib g++-multilib
sudo apt-get install libc6-dev-i386
sudo apt-get install lib32ncurses5-dev x11proto-core-dev libx11-dev
sudo apt-get install libgl1-mesa-dev libxml2-utils xsltproc unzip m4
sudo apt-get install lib32z-dev ccache

(其中几个命令中参数是重复的,但不妨碍我们)

5. 编译系统

5.1 初始化编译环境

在工作目录使用以下指令初始化编译环境

shell
1
source build/envsetup.sh

执行命令之后:

初始化编译环境.png

初始化编译环境.png

不难发现该命令只是引入了其他执行脚本,至于这些脚本做什么,目前不在本文中细说。该命令执行成功后,我们会得到了一些有用的命令,比如最下面要用到的 lunch 命令.

5.2 选择编译目标

使用 lunch 指令选择编译目标。

shell
1
lunch

选择编译目标.png

选择编译目标.png

使用 lunch 指令之后会出现上图的结果,让我们选择要编译的目标系统。因为我希望编译车机的系统,我选择 10,于是输入 “10”,然后回车。会出现如下结果。

编译车机系统.png

编译车机系统.png

5.3 开始编译

通过 make 指令进行代码编译,该指令通过 -j 参数来设置参与编译的线程数量,以提高编译速度。比如这里我们设置 8 个线程同时编译:

shell
1
make -j8

需要注意的是,参与编译的线程并不是越多越好,通常是根据你机器 cup 的核心来确定:core*2, 即当前 cpu 的核心的 2 倍。比如,我现在的笔记本是双核四线程的,因此根据公式,最快速的编译可以 make -j8.
(通过 cat /proc/cpuinfo 查看相关 cpu 信息)

注意:使用 j8 参数一定要注意,最好电脑配置要高,反正我笔记本使用 j8 开始报 oom,然后直接卡死…..

建议直接使用 make 指令。

shell
1
make

如果一切顺利,出现:***#### build completed successfully (06:43 (mm:ss)) ####***

那就恭喜你,编程完成了。

编译成功.png

编译成功.png

6 其他

XH 分支

  • repo 环境配置:
    mkdir /home/xxx/bin && cp repo /home/xxx/bin
    export PATH= /home/xxx/bin:$PATH

  • 代码下载:
    mkdir a55 && cd a55
    repo init -u ssh://xxx@10.5.20.68:29418/8155_a55/manifest.git -b master –repo-url=https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/
    repo sync

  • 代码编译
    ./build_target.sh msmnile_gvmq -a