# aosp编译

## 一、编译步骤

### 1.1 下载源码

如果网络允许，可以从Google直接下载源码。本节介绍如何使用国内的镜像源下载，清华源由于目前限速，所以选择中科大源。

首先下载谷歌的源码管理工具repo，该工具源于`depot_tool`，可以直接下载`depot_tool`并在`PATH`下建立符号链接，也可以仅下载repo的代码，这里以后者为例。

```bash
mkdir ~/bin
PATH=~/bin:$PATH
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
## 如果上述 URL 不可访问，可以用下面的：
## curl -sSL  'https://gerrit-googlesource.proxy.ustclug.org/git-repo/+/master/repo?format=TEXT' |base64 -d > ~/bin/repo
chmod a+x ~/bin/repo
```

建立源码目录并进入，以android 10代码为例。

```bash
mkdir android-10_r1 && cd android-10_r1
```

初始化源码仓库，其中`-b`选项用于设定要同步的Android版本，这里以Android 10的第一个发行版为例。完整的可选参数在[这里](https://source.android.com/setup/start/build-numbers#source-code-tags-and-builds)。类似于git，这一步执行完后会在该目录下生成`.repo`文件。

```bash
repo init -u git://mirrors.ustc.edu.cn/aosp/platform/manifest -b android-10.0.0_r1
## 如果提示无法连接到 gerrit.googlesource.com，可以编辑 ~/bin/repo，把 REPO_URL 一行替换成下面的：
## REPO_URL = 'https://gerrit-googlesource.proxy.ustclug.org/git-repo'
```

最后开始同步代码，选项`-j`用于表示同步的线程数，建议不要选择太大，4个线程足够，线程数太多可能会有同步失败的可能。

```bash
repo sync -j4
```

### 1.2 编译环境部署

**硬件要求:**

64位的操作系统只能编译 2.3.x 以上的版本，如果你想要编译 2.3.x 以下的，那么需要32位的操作系统.

磁盘空间越多越好，至少在 100GB 以上；如果你想要在是在虚拟机运行linux，那么至少需要16GB的 RAM/swap.

**软件要求:**

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  |

1. 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源码编译要求](https://source.android.com/source/requirements.html)

```
// 安装 jdk8
sudo add-apt-repository ppa:openjdk-r/ppa
sudo apt-get update
sudo apt-get install openjdk-8-jdk

// 安装 jdk7
sudo add-apt-repository ppa:openjdk-r/ppa
sudo apt-get update
sudo apt-get install openjdk-7-jdk

// 安装oracle jdk
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java6-installer

// jdk版本切换
sudo update-alternatives --config java
sudo update-alternatives --config javac
```

1. 其它要求

[Google官方构建编译环境指南](https://source.android.com/source/initializing.html)中已经说明了Ubuntu14.04，Ubuntu 12.04，Ubuntu 10.04需要添加的依赖（推荐使用ubuntu 14.04）

而Ubuntu16.04添加的依赖为：

```
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
```

1. 下载硬件驱动程序(刷入到真机时使用)

我们从google下载的源码编译后不能直接的刷入到我们的手机上，主要就是因为我们需要将设备对应的驱动放到源码里面一起编译，google旗下的nexus产品的驱动你可以通过以下的链接下载到： <https://developers.google.com/android/nexus/drivers> 将对应的三个文件下载下来，解压得到sh文件并放到Android源码根目录下。然后在终端中分别执行上述三个sh文件，即可在源码根目录下的 `vendor` 文件夹下自动释放相应文件

### 1.3 编译

**在使用Android源码之前,需要完整编译整个源码**

进入Android源码根目录：

```
source build/envsetup.sh    // 初始化编译环境
lunch    // 指定此次编译的目标设备以及编译类型
export LC_ALL=C //加入到bashrc或者zshrc中
make [-j4]    // 开始编译，默认为编译整个系统，其中 -j4 代表的是编译的job数量为4，即线程数
```

`lunch` 的作用是选择选择编译目标，编译目标的格式为：BUILD-BUILDTYPE

BUILD 指的是特定功能的组合的特定名称，即表示编译出的镜像可以运行在什么环境

* aosp(Android Open Source Project)代表Android开源项目
* arm 表示系统是运行在arm架构的处理器上
* arm64则是指64位arm架构处理器
* x86 则表示x86架构的处理器

BUILD TYPE 则指的是编译类型,通常有三种：

* `user` - 代表这是编译出的系统镜像是可以用来正式发布到市场的版本，其权限是被限制的(如：没有root权限,不能dedug等)
* `userdebug` - 在user版本的基础上开放了root权限和debug权限
* `eng` - 代表engineer，也就是所谓的开发工程师的版本，拥有最大的权限(root等)，此外还附带了许多debug工具

我们平时常用的设备代码和编译目标：

|   设备型号   |    设备代码    |            编译目标            |
| :------: | :--------: | :------------------------: |
|  Nexus 5 | hammerhead | aosp\_hammerhead-userdebug |
|  Nexus 6 |    shamu   |    aosp\_shamu-userdebug   |
| Nexus 5X |  bullhead  |  aosp\_bullhead-userdebug  |
| Nexus 6P |   angler   |   aosp\_angler-userdebug   |
| 公司的小辣椒手机 |            |   pxa1908sl\_tz-userdebug  |

更多参考：[官方文档](https://source.android.com/source/running.html#selecting-device-build)

**可以在编译前修改源文件中的 ro.secure，避免以后在adb shell中无法 remount 的情况。**

> 在文件 /build/core/main.mk 和 /build/core/build-system.html中，将 ro.secure = 1 改为 ro.secure = 0（两个文件中共有4个值）

## 二、单个编译编译

以反汇编作为case检测策略时，有时需要编译单个模块来获取汇编代码打补丁前后变化，常用指令如下。

|         编译指令         |          解释         |
| :------------------: | :-----------------: |
|           m          |     在源码树的根目录执行编译    |
|          mm          |  编译当前路径下所有模块，但不包含依赖 |
|  mmm \[module\_path] |  编译指定路径下所有模块，但不包含依赖 |
|          mma         |  编译当前路径下所有模块，且包含依赖  |
| mmma \[module\_path] |  编译指定路径下所有模块，且包含依赖  |
| make \[module\_name] | 无参数则表示编译整个Android代码 |

Tips:

* 对于m、mm、mmm、mma、mmma这些命令的实现都是通过make方式来完成的；
* mm/mmm 默认只会编译发生改变的部分，如果要编译模块的所有文件，需要 `-B` 选项
* mmm/mm编译的效率很高，而make/mma/mmma编译较缓慢；
* make/mma/mmma编译时会把所有的依赖模块一同编译，但mmm/mm不会;
* 建议：首次编译时采用make/mma/mmma编译；当依赖模块已经编译过的情况，则使用mmm/mm编译

## 三、代码刷入实机

1. 用USB将手机与PC连接；
2. `sudo adb reboot bootloader` 进入fastboot模式
3. 如果fastboot是锁定状态（屏幕下方有一个小锁），需要执行`fastboot oem unlock`
4. 在 out/target/product/xxx 目录下执行 `fastboot -w flashall`（需要先执行 `. build/envsetup.sh` 设置必要的环境变量），会将目录下的所有 .img 文件烧录到手机中

fastboot 的常用命令：

```
/* 擦除分区 */
fastboot erase {partition}
// 例：
fastboot erase boot
fastboot erase system

/* 烧写指定分区 */
fastboot flash {partition} {*.img}
// 例：
fastboot flash boot boot.img
fastboot flash system system.img

/* 烧写所有分区 */
fastboot flashall
// 注意：此命令会在当前目录中查找所有img文件，将这些img文件烧写到所有对应的分区中，并重新启动手机

/* 重启手机 */
fastboot reboot
fastboot reboot-bootloader    // 重启到 bootloader 刷机用
```

## 四、remount

将修改后的 xxx.so 文件写入手机:

```
adb push out/target/product/pxa1908sl/system/lib/xxx.so /data/local/tmp/
adb shell
mount -o rw,remount /system     # 需要root权限
cp /data/local/tmp/xxx.so /system/lib/
```

关于无法remount的问题

检查系统的ro.secure是否为0

```
adb shell getprop | grep "ro.secure"
```

如果不是，修改代码makefile，在build/core/main.mk 和 build/core/build-system.html将其中的ro.secure = 1 改为 ro.secure = 0，再full build
