recovery源码的入口位置为:bootable/recovery/recovery.cpp文件
int main(int argc, char **argv)
{
打印启动recovery的时间
printf("Starting recovery on %s", ctime(&start));
}
return 0;
}
if (mv) {
//已经被挂载
return 0;
}
if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "vfat") == 0) {
// ext4和vfat类型的分区调用mount函数进行挂载,挂载成功返回0,失败返回-1
result = mount(v->blk_device, v->mount_point, v->fs_type, MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
}
}
stage = strndup(boot.stage, sizeof(boot.stage));
FILE *fp = fopen_path(COMMAND_FILE, "r");
if (fp != NULL) {
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
if (!fgets(buf, sizeof(buf), fp)) break;
}
check_and_fclose(fp, COMMAND_FILE);
}
}
}
switch(arg) {
case 's': send_intent = optarg; break;
case 'u': update_package = optarg; break;
case 'w': wipe_data = wipe_cache = 1; break;
case 'c': wipe_cache = 1; break;
case 't': show_text = 1; break;
case 'x': just_exit = true; break;
case 'l': locale = optarg; break;
case 'p': shutdown_after = true; break;
case '?':
LOGE("Invalid command argument\n");
continue;
}
}
status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE){
err = verify_file(path, loadedKeys, numKeys);
}
int main(int argc, char **argv)
{
打印启动recovery的时间
printf("Starting recovery on %s", ctime(&start));
一、填充fstab结构体
load_volume_table(){1.1解析/etc/recovery.fstab配置文件,填充fstab结构体
fstab = fs_mgr_read_fstab("/etc/recovery.fstab");1.2在fstab结构体中增加/tmp分区
ret = fs_mgr_add_entry(fstab, "/tmp", "ramdisk", "ramdisk", 0);}
二、挂载cache分区
ensure_path_mounted(LAST_LOG_FILE){2.1这里是在fstab结构体中找到挂载点为/cache的fstab_recs
Volume* v = volume_for_path(path);2.2ramdisk类型的分区是一直挂载的。
if (strcmp(v->fs_type, "ramdisk") == 0) {return 0;
}
2.3当前分区是否被挂载
const MountedVolume* mv = find_mounted_volume_by_mount_point(v->mount_point);if (mv) {
//已经被挂载
return 0;
}
2.4具体的挂载过程
mkdir(v->mount_point, 0755);if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "vfat") == 0) {
// ext4和vfat类型的分区调用mount函数进行挂载,挂载成功返回0,失败返回-1
result = mount(v->blk_device, v->mount_point, v->fs_type, MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
}
}
三、获取Recovery命令参数
get_args(&argc, &argv){3.1首先从MISC分区中读取BCB数据块到boot变量中,可能存在为空的情况。
get_bootloader_message(&boot);stage = strndup(boot.stage, sizeof(boot.stage));
3.2从/cache/recovery/command获取参数,一般常用的ota升级做法。
if (*argc < 1) {FILE *fp = fopen_path(COMMAND_FILE, "r");
if (fp != NULL) {
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
if (!fgets(buf, sizeof(buf), fp)) break;
}
check_and_fclose(fp, COMMAND_FILE);
}
}
3.3将从/cache/recovery/command获取的参数写入到misc分区
...省略}
四、分析recovery命令
while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {switch(arg) {
case 's': send_intent = optarg; break;
case 'u': update_package = optarg; break;
case 'w': wipe_data = wipe_cache = 1; break;
case 'c': wipe_cache = 1; break;
case 't': show_text = 1; break;
case 'x': just_exit = true; break;
case 'l': locale = optarg; break;
case 'p': shutdown_after = true; break;
case '?':
LOGE("Invalid command argument\n");
continue;
}
}
五、升级install_package过程
if (update_package != NULL) {status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE){
5.1卸载除了/tmp和/cache的其他分区
setup_install_mounts()5.2ota升级的真正实现,这里去除掉跟UI显示相关的逻辑
result = really_install_package(path, wipe_cache){5.2.1确保zip包所在的目录是挂载的
if (ensure_path_mounted(path) != 0)5.2.2加载公钥源文件,根据公钥对zip包进行校验
Certificate* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);err = verify_file(path, loadedKeys, numKeys);
5.2.3打开升级包,并将相关的信息拷贝到一个临时的ZipArchinve变量中。这一步并未对我们的update.zip包解压。
err = mzOpenZipArchive(path, &zip);5.2.4真正fota升级的过程
return try_update_binary(path, &zip, wipe_cache);}
}
}}