ota 升级
recovery
Recovery的源代码在bootable/recovery/目录。
Recovery在init进程中被启动,启动过程定义在/etc/init.rc中:
在bootable/recovery/etc/init.rc中有下面的服务定义:
service recovery /sbin/recovery seclabel u:r:recovery:s0 |
升级流程
升级主流程在recovery.cpp中实现。
- 加载分区表(load_volume_table,默认挂载内存文件系统/tmp)
- 保存老的日志:last_log > last_log.1 > last_log.2(rotate_last_logs)
- 读取recovery参数(get_args)
- 如果没有启动命令行参数,读取boot.recovery作为参数
- 如果没有,读取/cache/recovery/command
- 将参数写回boot.recovery
- 初始化升级device,ui
- 如果有升级包参数update_package,安装升级包(install_package)
- 挂载、卸载分区(setup_install_mounts,挂载/tmp、/cache,其他卸载)
- 真正的升级过程(really_install_package)
- 更新UI
- 验证安装包
- 启动updater,执行安装脚本(try_update_binary)
- 否则处理wipe_data,wipe_cache
- 如果升级失败,输出菜单,处理用户选择(prompt_and_wait)
- 通过finish_recovery保存日志等信息
- 更新背景图像
- 获取用户选择(get_menu_selection)
- ui->FlushKeys()
- 循环处理用户按键
- 根据用户选择,进行相应动作
- 如果用户选择从外部存储(/sdcard)或者缓存目录(/cache)选择升级包,那么列出文件列表供用户选择(update_directory)
- 可能递归进入子目录,最终拷贝选中文件到/tmp/sideload/package.zip(copy_sideloaded_package)并安装升级包(install_package)
- 完成升级(finish_recovery)
- 保存intent,locale
- 复制日志
-
- /tmp/recovery.log >> /cache/recovery/log (追加)
- /tmp/recovery.log > /cache/recovery/last_log
- /tmp/last_install > /cache/recovery/last_install
-
- 清除bootloader message
- 取消挂载/cache/recovery/command和/cache
辅助功能
ui.cpp
RecoveryUI类,定义了一系列虚接口,同时处理键击事件。通过一个线程读取键击事件,并插入队列。
screen_ui.cpp
ScreenRecoveryUI类,负责图形界面绘制和菜单管理。启动了一个线程定期跟新界面。
default_device.cpp
定义了DefaultDevice、DefaultUI。Device定义了升级操作列表。DefaultUI继承ScreenRecoveryUI。
roots.cpp
管理分区挂载映射。分区配置文件:/etc/recovery.fstab。
bootloader.cpp
读写bootloader control block,/misc分区。支持mtd,emmc存储系统。
verifier.cpp
验证安装包。
验证密钥文件位于/res/keys。
参考:
install.cpp
启动updater进程(下一节介绍),并与其通过管道通信,接受updater反馈的进度等信息。
#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary" // If the package contains an update binary, extract it and run it. static int try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache); |
接受的信息格式为:
- progress <frac> <secs>
- set_progress <frac>
- ui_print <string>
- wipe_cache
- clear_display
adb_install.cpp
通过adb sideload命令输入升级包升级。启动一个recovery子进程,指定“—adbd”参数。子进程将升级包存放在/tmp/update.zip。
#define ADB_SIDELOAD_FILENAME "/tmp/update.zip" |
updater
Updater 就是升级包里面的 META-INF/com/google/android/update-binary 程序,在升级过程中被执行来解析执行升级脚本。
Updater 在recovery的install.cpp中被调用:
在升级过程中,update-binary 被解压到/tmp/update_binary执行,命令行参数格式为:
- update_binary <version> <fd> <name>
Updater 进程与父进程之间通过管道通信,向父进程汇报升级状态和进度。汇报格式为:
Updater 的源代码在 bootable/recovery/updater/ 目录。
脚本文件的名称写死在update.c 中:
#define SCRIPT_NAME "META-INF/com/google/android/updater-script" |
脚本里面使用时函数都定义在 install.c 中:
void RegisterInstallFunctions() { RegisterFunction("mount", MountFn); RegisterFunction("is_mounted", IsMountedFn); RegisterFunction("unmount", UnmountFn); RegisterFunction("format", FormatFn); …… RegisterFunction("ui_print", UIPrintFn); RegisterFunction("run_program", RunProgramFn); } |
applypatch
工具applypatch和imgdiff。
其他辅助库
libmtdutils
处理分区挂载的函数库;
mtdutils.c:处理mtd分区挂载、读写,mtd分区表从/proc/mtd获取。
mounts.c:获取已经挂载节点列表,处理remount或者umount,列表从/proc/mounts获取。
MTD(memory technology device内存技术设备)是用于访问memory设备(ROM、flash)的Linux的子系统。
参考:
libminzip
小型zip解压库。
libmincrypt
小型加密库。
libminadbd
小型adbd,只支持usb连接,少量命令。
libminui
小型UI库,通过opengl api绘图,并支持键盘事件输入。
libedify
一个升级脚本语言,替代amend。基于yacc语法解析器实现,内置了简单的字符串、逻辑运算符号支持,可以通过外部函数扩展功能。
参考:
libapplypatch
libminelf
framework/base/core/java/android/app/ContextImpl.java: ------------------------------------------------------------------------- static { // …… registerService(AUDIO_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return new AudioManager(ctx); }}); // …… } |