Android 7系统编译与刷机(一)源码环境搭建与完整编译流程
系列目录:Android 7系统编译与刷机(一):源码环境搭建与完整编译流程 | (二):Image镜像生成机制深度解析 | (三):从编译产物到高通刷机包 | (四):QFIL刷机工具详解 | (五):特定分区镜像的单独导出 | (六):特定分区刷入实战
一、为什么要学编译流程
你可能会问:现在满大街都是刷机包,直接下载一个刷进去不就行了?为什么还要自己编译?
三个场景,你大概率遇到过至少一个:
- 场景一:你改了
Settings里的一行代码,发现make全编要跑两个小时,只想验证这一个 APK 的改动——怎么只编译一个模块? - 场景二:你拿到了一个第三方 ROM,发现
build.prop里有个参数不对劲,想改完重新打包一个system.img——但不知道这个.img到底是怎么从一堆文件夹变成单个文件的。 - 场景三:你刷了机发现
data分区大小不对,想重新分区——但不知道分区表是怎么定义的,也不知道编译参数BOARD_SYSTEMIMAGE_PARTITION_SIZE和最终的system.img之间是什么关系。
这些问题,网上搜到的答案要么是"执行 make -j8 就行了",要么是"用 make_ext4fs 命令"。但为什么是这个命令?参数从哪来?编译系统的 Makefile 是怎么串联起来的?没有人讲清楚。
本系列的目标就是把从源码到刷机的完整链路讲透,让读者不仅知道"怎么做",更知道"为什么这样做"。
二、编译环境准备
2.1 硬件要求
AOSP 7(Android Nougat)源码加上编译产物,建议硬盘空间至少预留 150GB。内存建议 16GB 以上,否则 jack-server 很容易 OOM。
关键:Android 7 的编译工具链是最后一次大规模使用
jack(Java Android Compiler Kit)的版本,jack-server默认最大堆内存只有 4GB,编译大型项目时很容易挂掉。建议在~/.jack-settings中调大JACK_SERVER_VM_ARGUMENTS。
2.2 操作系统与依赖
Android 7 官方推荐 Ubuntu 14.04 / 16.04(64 位)。虽然更高版本也能兼容,但编译中可能出现 glibc 版本导致的不兼容问题。
# 安装必要依赖包(Ubuntu 16.04)
sudo apt-get install -y 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 \
libgl1-mesa-dev libxml2-utils xsltproc unzip
2.3 JDK 版本
Android 7 需要 OpenJDK 8。注意:Android 6 及之前用 JDK 7,Android 8 及之后用 JDK 9+,版本错一个就会编译失败。
sudo apt-get install -y openjdk-8-jdk
# 确认版本
java -version # 应输出 1.8.0_xxx
三、源码下载:Repo 工具与国内镜像
3.1 Repo 工具是什么
Repo 是 Google 为管理 AOSP 这种多 Git 仓库项目开发的工具。它本身是一个 Python 脚本,通过一个 default.xml 清单文件描述所有子仓库的地址和分支。
aosp/
├── .repo/ ← repo 元数据,清单文件在这里
│ └── manifests/
├── build/ ← 构建系统(独立 git 仓库)
├── frameworks/ ← 框架层(独立 git 仓库)
├── packages/ ← 应用层(独立 git 仓库)
├── system/ ← 系统核心(独立 git 仓库)
└── ... ← 200+ 个子仓库
3.2 使用清华镜像
直接从 Google 源下载速度极慢,推荐使用清华大学镜像站。
# 1. 下载 repo 工具
mkdir ~/bin
curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o ~/bin/repo
chmod +x ~/bin/repo
export PATH=~/bin:$PATH
# 2. 初始化仓库(指定 Android 7.1.2 分支)
mkdir aosp7 && cd aosp7
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest \
-b android-7.1.2_r36
# 3. 同步源码(根据网络情况,耗时 2~8 小时)
repo sync -j4
注意:
-j4控制并发下载数,清华镜像站对并发连接有限制,开太高反而会被限速。建议先从-j4开始,稳定后再调高。
四、编译三部曲:envsetup → lunch → make
这是每个 Android 开发者都背过的三行命令:
source build/envsetup.sh
lunch
make -j8
但背后发生了什么?我们来拆解。
4.1 source build/envsetup.sh — 环境初始化
源码路径:build/envsetup.sh
这个脚本做三件事:
- 注入 shell 函数到当前会话:
lunch、m、mm、mmm、croot、godir等 - 加载设备相关的
vendorsetup.sh(如果有的话) - 设置环境变量
BUILD_SYSTEM,指向build/core/
# 核心逻辑(简化)
function m() {
# 一键编译,相当于 make
local T=$(gettop)
if [ "$T" ]; then
make -C "$T" $@
fi
}
function mm() {
# 编译当前目录下的模块
local T=$(gettop)
local SUBDIR=`pwd | sed "s,$T/?,,"`
local BUILD_ID=""
if [ -f "${SUBDIR}/Android.mk" ]; then
BUILD_ID="$SUBDIR:all"
fi
make ${BUILD_ID} $@
}
关键设计:
envsetup.sh不执行任何编译,只是在 shell 环境中注入函数。这意味着source之后你可以在任何目录下直接敲m、mm、mmm,而不需要切回源码根目录。
4.2 lunch — 选择编译目标
lunch 命令会列出所有可用的编译目标,格式为 产品名-编译类型。
You're building on Linux
Lunch menu... pick a combo:
1. aosp_arm-eng
2. aosp_arm64-eng
3. aosp_mips-eng
4. aosp_mips64-eng
5. aosp_x86-eng
6. aosp_x86_64-eng
...
以下表格对比了三种编译类型的区别:
| 编译类型 | 说明 | 典型用途 |
|---|---|---|
eng | 工程版本,包含所有调试工具,adb root 默认可用 | 日常开发 |
userdebug | 用户调试版本,adb root 需手动开启 | 测试验证 |
user | 正式发布版本,无 root 权限 | 量产发布 |
lunch 执行后,会设置以下关键环境变量:
TARGET_PRODUCT=aosp_arm64 # 目标产品
TARGET_BUILD_VARIANT=eng # 编译类型
TARGET_BUILD_TYPE=release # 构建类型
PRODUCT_OUT=out/target/product/aosp_arm64 # 产物输出目录
4.3 make -j8 — 编译入口
make 不带参数时,默认目标是 droid,定义在 build/core/main.mk 中。
源码路径:build/core/main.mk
# 默认目标(必须第一个声明)
.PHONY: droid
DEFAULT_GOAL := droid
$(DEFAULT_GOAL): droid_targets
# droid_targets 聚合所有构建目标
.PHONY: droid_targets
droid_targets: droidcore dist_files
# 构成 droidcore 的镜像目标($(PRODUCT_OUT) = out/target/product/<设备名>)
droidcore: files \
systemimage \
$(PRODUCT_OUT)/boot.img \
$(PRODUCT_OUT)/recovery.img \
$(PRODUCT_OUT)/userdata.img \
$(PRODUCT_OUT)/cache.img \
$(PRODUCT_OUT)/vendor.img \
$(PRODUCT_OUT)/system_other.img \
$(PRODUCT_OUT)/installed-files.txt \
$(PRODUCT_OUT)/installed-files-vendor.txt \
$(PRODUCT_OUT)/installed-files-system-other.txt
关键设计:
droid→droid_targets→droidcore,三层递进。droid_targets是droid的实际工作层,droidcore是核心聚合目标,把systemimage、bootimage、userdataimage等作为依赖。Make 在解析时发现这些依赖不存在,就会递归去构建它们。这就是"执行make就能生成所有镜像"的底层原理。
整个编译流程如下:
make (默认目标: droid)
│
├── droid_targets
│ └── droidcore(聚合目标)
│
├── bootimage
│ ├── 编译 kernel ← 内核源码
│ ├── 生成 ramdisk ← 系统启动所需的 init、init.rc 等
│ └── mkbootimg ← 打包成 boot.img
│
├── systemimage
│ ├── 编译所有 Java 代码 ← javac + jack
│ ├── 编译所有 C/C++ 代码 ← clang / gcc
│ ├── 编译所有资源文件 ← aapt
│ ├── 收集所有模块产物到 system/ 目录
│ └── make_ext4fs ← 生成 system.img
│
├── userdataimage
│ └── make_ext4fs ← 生成空的 userdata.img
│
└── recoveryimage
└── mkbootimg ← 生成 recovery.img
五、关键源码文件索引
以下表格汇总了本篇涉及的核心源码文件:
| 文件 | 作用 |
|---|---|
build/envsetup.sh | 注入 lunch、m、mm 等函数,环境初始化 |
build/core/main.mk | 编译入口,定义 droid 默认目标 |
build/core/Makefile | 各镜像的生成规则,system.img、boot.img 等 |
build/core/config.mk | 编译配置,路径、编译选项等 |
build/core/product.mk | 产品配置,继承关系 |
build/tools/releasetools/build_image.py | 镜像生成脚本,调用 make_ext4fs |
system/core/libsparse/ | sparse image 相关工具源码 |
system/extras/ext4_utils/ | make_ext4fs 工具源码 |
六、本篇总结
本篇覆盖了从零搭建编译环境到完成首次全编的完整流程,核心要点:
- 环境准备:Ubuntu 16.04 + OpenJDK 8 + 150GB 硬盘
- 源码下载:Repo 工具 + 清华镜像站,
repo init -b android-7.1.2_r36 - 编译三部曲:
envsetup.sh注入函数 →lunch选择目标 →make触发droidcore构建所有镜像 - 编译产物:最终在
out/target/product/<设备名>/下生成boot.img、system.img、userdata.img等
下一篇我们将深入 build/core/Makefile,逐行拆解 system.img 的生成规则——从 make_ext4fs 的调用到 sparse image 格式的转换,搞清楚一个文件夹到底是怎么变成 .img 文件的。
本系列基于 AOSP 7.1(Android Nougat)源码,代码路径以 AOSP 7.1 为准。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐
所有评论(0)