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 之后,minui 和 minzip 被移到了 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.cpp 的 DrawTextInfo() 函数里加了一段绘制图片的逻辑。嗯,效果还不错。
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 刷入测试。
make recovery -j$(nproc)。这样更快,大概 2-3 分钟就能搞定。
2.4 避坑指南
最后,分享几个我踩过的坑。
还有一个常见问题:编译时提示缺少 libncurses 之类的库。别慌,用包管理器安装就行:
# Ubuntu/Debian
sudo apt-get install libncurses5-dev
# macOS(用 brew)
brew install ncurses
嗯,这一章的内容就这些。说白了,Recovery 的源码结构并不复杂,关键文件也就那么几个。编译环境搭好后,你就可以开始动手修改了。下一章,我会带你深入 recovery.cpp,看看启动流程到底是怎么跑的。