2、Recovery模式源码结构:源码目录结构、关键文件介绍、编译环境搭建

好,咱们直接进入正题。这一章我带你看看 Recovery 模式的源码到底长什么样。说实话,我第一次打开这个目录的时候,也被里面的文件数量吓了一跳。但别慌,核心的东西其实就那么几个。

2.1 源码目录结构

Recovery 模式的源码,藏在 AOSP 源码树的 bootable/recovery 目录下。我习惯先看顶层结构,心里有个地图,后面才不会迷路。

bootable/recovery/
├── Android.bp          # 构建配置文件
├── applypatch/         # 差分升级相关
├── bootloader_message/ # 与 bootloader 通信的数据结构
├── edify/              # 升级脚本解析器
├── fuse/               # 文件系统挂载相关
├── minadbd/            # 精简版 adbd,用于 sideload
├── minui/              # 极简 UI 框架
├── minzip/             # zip 文件操作
├── recovery.cpp        # 主入口文件
├── recovery-persist.cpp
├── recovery-refresh.cpp
├── screen_ui.cpp       # 屏幕 UI 实现
├── device.cpp          # 设备抽象层
├── install.cpp         # 升级安装逻辑
├── ui.cpp              # UI 基础组件
├── tests/              # 单元测试
└── updater/            # 升级脚本执行引擎

嗯,这里要注意,不同 Android 版本的结构会有些微调。比如 Android 10 之后,minuiminzip 被移到了 system/core 下。但核心逻辑没变。

2.2 关键文件介绍

这么多文件,哪些是必须啃下来的?我按重要程度排个序。

2.2.1 recovery.cpp — 程序入口

这是整个 Recovery 的 main 函数所在地。说白了,系统启动后第一个执行的就是它。我当年为了搞清楚启动流程,在这文件里打了不下 50 个 log。

它的核心逻辑其实很简单:

// 伪代码,帮你理解流程
int main() {
    // 1. 解析启动参数(从 misc 分区读取)
    // 2. 初始化 UI
    // 3. 根据参数执行对应操作(升级、清数据、重启等)
    // 4. 循环等待用户操作(按键或触摸)
    // 5. 执行完毕后重启
}

你想想看,整个 Recovery 模式就靠这一个文件撑起来。是不是比想象中简单?

2.2.2 screen_ui.cpp — 界面渲染

Recovery 的 UI 很简陋,但五脏俱全。screen_ui.cpp 负责把文字、进度条、菜单画到屏幕上。它用的是 minui 提供的绘图接口,说白了就是直接操作 framebuffer。

我曾经在某个项目里,客户要求 Recovery 界面显示公司 Logo。我就是在 screen_ui.cppDrawTextInfo() 函数里加了一段绘制图片的逻辑。嗯,效果还不错。

2.2.3 install.cpp — 升级核心

这个文件负责执行真正的升级操作。它会解析 META-INF/com/google/android/update-binary 这个脚本,然后调用 updater 里的函数去执行。

说白了,你看到的 OTA 升级包,最终就是被这个文件里的逻辑一步步解包、校验、写入分区的。

2.2.4 device.cpp — 设备适配层

不同手机的按键、屏幕、存储分区都不一样。这个文件就是用来做适配的。比如你的手机用音量键选择,用电源键确认,这些映射关系就在 device.cpp 里定义。

我建议你拿到一个新平台时,第一个要改的就是这个文件。不改的话,按键可能完全没反应。

2.3 编译环境搭建

好,理论说完了,咱们动手。搭建编译环境其实就三步。

2.3.1 准备 AOSP 源码

首先你得有一套完整的 AOSP 源码。我推荐用 Android 10 或 11 的版本,比较稳定,资料也多。

# 下载 AOSP(以 android-11.0.0_r48 为例)
repo init -u https://android.googlesource.com/platform/manifest -b android-11.0.0_r48
repo sync -j8

这个过程比较漫长,我建议你晚上睡觉前跑,第二天起来就好了。

2.3.2 配置编译环境

源码下载完后,需要配置环境变量和编译工具链。

# 进入源码根目录
cd ~/aosp

# 加载编译环境
source build/envsetup.sh

# 选择编译目标(以 Pixel 3 为例)
lunch aosp_blueline-userdebug

这里有个坑:lunch 后面的参数取决于你的设备。如果你没有真机,可以用模拟器:lunch sdk_phone_x86_64-userdebug

2.3.3 单独编译 Recovery

全量编译太慢了,我们只编译 Recovery 模块。

# 编译 recovery 镜像
make recoveryimage -j$(nproc)

编译完成后,生成的镜像在 out/target/product/<设备名>/recovery.img。你可以用 fastboot 刷入测试。

小技巧: 如果你只想编译 Recovery 相关的二进制文件,可以用 make recovery -j$(nproc)。这样更快,大概 2-3 分钟就能搞定。

2.4 避坑指南

最后,分享几个我踩过的坑。

注意: 编译前一定要确认你的 Python 版本。AOSP 10 之后要求 Python 3.x,如果你系统默认是 Python 2,编译会报错。我当初因为这个折腾了一下午。

还有一个常见问题:编译时提示缺少 libncurses 之类的库。别慌,用包管理器安装就行:

# Ubuntu/Debian
sudo apt-get install libncurses5-dev

# macOS(用 brew)
brew install ncurses

嗯,这一章的内容就这些。说白了,Recovery 的源码结构并不复杂,关键文件也就那么几个。编译环境搭好后,你就可以开始动手修改了。下一章,我会带你深入 recovery.cpp,看看启动流程到底是怎么跑的。