恢复出厂设置模式—擦除分区
一、Android中的分区 2
二、恢复出厂设置 3
2.1、recovery模式下的init.rc 3
2.2、recovery.c(入口函数) 3
三、擦除data、cache分区 5
总结: 5
恢复出厂设置最终会进入Recovery模式,擦除data、cache分区之后,系统重启,开始正常的启动流程。
上层从点击事件开始—click“恢复出厂设置”,在底层判断节点之后进入恢复出厂设置模式。前面有写过关机流程的文章,当关机或重启的时候,一般都会向相关文件写入命令及原因。恢复出厂设置也不例外,它也会通过写入命令,再去执行相关操作。
此篇文档主要分析的是恢复出厂设置关于底层的流程。在进入主题之前,我们先来了解一下Android中的“分区”概念。
当判断出来恢复出厂设置的节点后,它会:1、进入Recovery模式(此模式下可以对内部数据或系统进行修改);2、读取/cache/recovery/command, 命令字段为"--wipe_data";3、按照读取的command,进行清除数据操作(擦除cache、data分区);4、清除成功后系统重启,重新使用system分区的内容完成开机初始化, 进入正常开机流程。
path:./bootable/recovery/etc/init.rc
service recovery /sbin/recovery
seclabel u:r:recovery:s0
service adbd /sbin/adbd --root_seclabel=u:r:su:s0 --device_banner=recovery
disabled
socket adbd stream 660 system system
seclabel u:r:adbd:s0
Note:实质是kernel加载recovery.img,kernel起来后执行的第一个进程就 是init,此进程会读入init.rc启动相应的服务。在recovery模式中,启动的服务是执行recovery可执行文件。
int main(int argc, char **argv) {
/* 如果二进制文件使用单个参数"--adbd"启动,而不是正常的recovery启动(不带参数即为正常启动)*/
if (argc == 2 && strcmp(argv[1], "--adbd") == 0) {
adb_main(0, DEFAULT_ADB_PORT);
return 0;
}
.............
load_volume_table(); //加载并建立分区表
.............
get_args(&argc, &argv); //从传入的参数或/cache/recovery/command文件中得到相应的命令
while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
switch (arg) {
/*循环解析command或者传入的参数,并把对应的功能设置为true或给相应的变量赋值*/
..............
case 'i': send_intent = optarg; break;
..............}
Device* device = make_device(); //初始化UI
ui = device->GetUI();
gCurrentUI = ui;
.............
ui->SetBackground(RecoveryUI::NONE);//设置recovery界面背景
.............
if (show_text) ui->ShowText(true); //设置界面上是否能够显示字符,使能ui->print函数开关
struct selinux_opt seopts[] = { // 设置selinux权限
{ SELABEL_OPT_PATH, "/file_contexts" }
};
//之后开始一些列的安装,清除的操作
status = install_package()//安装升级包
.....
}
Note: 1)、get_args()方法得到命令之后,先判断传进来的参数;如果有解析传入的命令,从/cache/recovery/command文件中解析命令。
(注意:此函数会先把struct bootloader_message boot写入到misc分区,目的是防止断电等原因导致关机,开机后lk会从misc分区中读取相关信息,如果发现是"boot-recovery"会再次进入recovery模式,misc分区会在退出recovery时被清除,以至于可以正常开机,如果手机每次都是进入recovery而不能正常开机,可以分析是否没有清除misc分区。)
2)、 install_package()流程:
1).设置ui界面,包括背景和进度条
2).检查是否挂在tmp和cache,tmp存放升级log,cache存放升级包
3).加载密钥并校验升级包,防止升级包被用户自己修改
.打开升级包,并执行升级包内的安装程序
注:关于Recovery的内容还有很多,这里只是简单的介绍了一些和恢复出厂设置时相关的重要函数而已。
最后:函数 get_args() 会读取 /cache/recovery/command 文件,并根据命令字段进行相应操作,所以它会擦除 data 和 cache 分区:
erase_volume() reformats /data
erase_volume() reformats /cache
//擦除data分区
bool wipe_data(int confirm, Device* device) {
return mt_wipe_data(confirm, device);
}
//擦除cache分区
static bool wipe_cache(bool should_confirm, Device* device) {
if (!has_cache) {
ui->Print("No /cache partition found.\n");
return false;
}
if (should_confirm && !yes_no(device, "Wipe cache?", " THIS CAN NOT BE UNDONE!")) {
return false;
}
modified_flash = true;
ui->Print("\n-- Wiping cache...\n");
bool success = erase_volume("/cache");
ui->Print("Cache wipe %s.\n", success ? "complete" : "failed");
return success;
}
总结:恢复出厂设置的流程大致下图所示~