一、MTD分区:
BOOT: boot.img,Linux kernel (within normal ramdisk)
MISC: bootloader message struct
RECOVERY: recovery.img,Linux kernel (within recovery ramdisk)
SYSTEM: system.img
DATA: userdata.img
CACHE: some cache files


二、 三个部分、两个接口
Recovery的工作需要整个软件平台的配合,从架构角度看,有三个部分
1) Main system:用boot.img启动的Linux系统,Android的正常工作模式。

2) Recovery:用recovery.img启动的Linux系统,主要是运行Recovery程序。

3) Bootloader:除了加载、启动系统,还会通过读取flash的MISC分区获得来自Main system和Recovery的消息,并以此决定做何种操作。

在Recovery的工作流程中,上述三个实体的通信必不可少。通信的接口有以下两个:

1. 接口1: CACHE分区中的三个文件:/cache/recovery/…

Recovery通过/cache/recovery里的文件与main system通信,有三个文件:
1) /cache/recovery/command (Main System-->Recovery)
Main system传给Recovery的命令行,每一行有一个命令,支持以下几种:
--send_intent=anystring - write the text out to recovery.intent
--update_package=path - verify install an OTA package file
--wipe_data - erase user data (and cache), then reboot
--wipe_cache - wipe cache (but not user data), then reboot
--set_encrypted_filesystem=on|off - enables / diasables encrypted fs

2) /cache/recovery/log(Recovery写的log文件)
Recovery的log输出,在recovery运行过程中,stdout及stderr会重定位到/tmp/recovery.log文件,Recovery退出之前会将其转储到/cache/recovery/log中,也就是cache分区的recovery/log。

3) /cache/recovery/intent(Recovery-->Main system)
Recovery传给Main system的信息

2. 接口2: BCB (bootloader control block)即bootloader_message

[cpp] view plain copy print ?
  1. struct bootloader_message {
  2. char command[32];
  3. char status[32];
  4. char recovery[1024];
  5. };

BCB是Bootloader与Recovery的通信接口,也是Bootloader与Main system的通信接口,存储在flash中的MISC分区,占用三个page,各成员意义如下:

• command:
当Main system(Linux)想要重启进入recovery模式,或升级radio/bootloader firmware时,会更新这个域。当firmware更新完毕,为了启动后进入recovery做最终的清除,bootloader还会修改它。

•status:
update-radio或update-hboot完成后,bootloader会写入相应的信息,一般是一些状态或执行结果。

• recovery:
仅被Main system(Linux)写入,用于向Recovery发送消息,必须以“recovery\n”开头,否则这个域的所有内容会被忽略。这一项的内容中“recovery/\n”以后的部分,是/cache/recovery/command支持的命令,可以认为这是在Recovery操作过程中,对命令操作的备份。Recovery也会更新这个域的信息,执行某操作前把该操作命令写到recovery域,并更新command域,操作完成后再清空recovery域及command域,这样在进入Main system之前,就能确保操作被执行。

如下图所示,Main system、Recovery与Bootloader通过上述接口通信,通信逻辑依不同的目的而不同,在后面介绍具体工作流程中还会详细介绍。

Android Bootloader - Main system - Recovery_第1张图片

三、从Main system进入Recovery的方法
从Main system进入到Recovery,要修改misc分区的数据并重启,从而告诉Bootloader是用boot.img还是用recovery.img启动。

/system/core/init/signal_handler.c里的wait_for_one_process函数中有如下代码:

android_reboot(ANDROID_RB_RESTART2, 0, "recovery")->

__reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,

LINUX_REBOOT_CMD_RESTART2, “recovery”);

一些关键的进程运行异常,会重启进入recovery模式,这里用__reboot函数进入recovery。跟踪这个函数,由系统调用处理函数,到kernel_restart(char *cmd),最终调用machine_restart使用体系结构相关的代码完成重启。

Android中没有给出如何处理“recovery”重启。不过可以断定,在重启之前会向BCB中写入信息,以告知bootloader如何启动,具体操作是这样的:

向command域中写入“boot-recovery” // 此操作必做

向recovery域写入“recovery\n” // 此操作也可不做

这些操作很可能在kernel_restart(char *cmd)中完成,因为这一部分与体系结构无关,如果要实现完整的Recovery,这部分工作是必须做的。

Bootloader得到进入Recovery模式的指示,用recovery.img启动,进入Recovery模式,init.rc (bootable/recovery/etc/init.rc)的内容比Main system的要短的多,最重要的是把recovery程序作为服务启动:

service recovery /sbin/recovery

四、Android Recovery: 总体流程
根据Recovery的initrc,kernel启动完成后,启动recovery服务,这是一个C程序,入口在/bootable/recovery/recovery.c中,main函数结构清晰,主要流程如图:

Android Bootloader - Main system - Recovery_第2张图片

1. get_args

首先调用get_args获取参数,主要流程如下:

Android Bootloader - Main system - Recovery_第3张图片

get_args不仅传回获取到的参数,还会将其写入misc分区中的BCB,这样,一旦升级或擦除数据的过程中出现错误,重启之后依然进入Recovery并做相同操作。

2. install_package

或install_rkimage

或wipe_data

或wipe_cache

3. finish_recovery

离开Recovery进入Main system的必经之路,流程如下:

Android Bootloader - Main system - Recovery_第4张图片

• intent内容作为参数传进来,如果有intent需要告知Main system,将其写入/cache/recovery/intent;
• 将所有log信息转储到/cache/recovery/log文件,以供Main system读取;
• 清除BCB,也就是告知Bootloader启动进入Main system;
• 删除/cache/recovery/command;
以上是整体流程中的几个函数,关于安装升级包、升级firmware等操作将在具体流程中介绍。

五、Android Recovery: Factory data reset流程
如果系统不稳定,可以尝试恢复出厂设置,该操作会擦除DATA分区及CACHE分区,有两种恢复方式,下面分别介绍:
1. 通过Setting程序发起Facory data reset
Android Bootloader - Main system - Recovery_第5张图片

1) 在应用程序Setting中选择factory data reset

2) Main system向/cache/recovery/command写入”–wipe_data”

3) Main system重启进入recovery模式(方法:修改BCB)

4) Recovery向BCB写入”boot-recevory”和”recovery\n–wipe_data\n”

5) 擦除DATA分区,里面是用户数据,擦除CACHE分区

6) finish_recovery函数

7) 重启,回到Main system

第4) 步骤,Recovery向BCB写入boot-recovery和–wipe_data,这是为了保证后面几个步骤的完整执行。如,在擦除DATA分区或CACHE分区过程中,如果发生了重启、关机等操作,导致没有擦除成功,那么再次用常规方式开机后,Bootloader会依据misc分区中BCB的指示,引导进入Recovery,并重新擦除这两个分区。擦完DATA分区与CACHE分区后,调用finish_recovery,做返回Main system前最后的工作,最终要的是擦除BCB,即MISC分区。此后,用常规方式重新开机,系统会进入Main system。

阅读Android的代码,发现Setting通过RPC调用Checkin Service的masterClear()启动这个过程,然而在Android中并没有找到masterClear()的实现,相关代码需要在产品化的过程中加入。从ICheckinService.aidl的注释可以了解到这个函数的作用:

/** Reboot into the recovery system and wipe all user data. */

代码位置:

/packages/apps/Settings/src/com/android/settings/MasterClear.java

/frameworks/base/core/java/android/os/ICheckinService.aidl

2. 通过HOME+POWER组合键进入Recovery,再按ALT+W启动Factory data reset

过程比较简单,而且与上一种方式类似,结合总体流程,步骤如下:

1) 捕获按键Alt + W。

2) 擦除DATA分区、擦除CACHE分区。

3a) 若激活了log显示(ALT+L:toggle log text display),调用finish_recovery函数重启,回到Main system。

3b) 若没有激活log显示,继续接收按键,可用HOME+BACK重启回到Main system。

六、Android Recovery: Update流程

1. update.zip

update操作需要升级包,该升级包是文件名是*.zip,但观察包内结构会发现其实就是JAR包,JAR包是具有特定目录和文件结构的ZIP压缩包,因此可以作为ZIP包解开。

• MANIFEST.MF:这个manifest文件定义了与包相关数据。

• XXX.SF:这是JAR文件的签名文件,占位符xxx标识签名者,如CERT。

• XXX.DSA:与签名文件相关联的签名程序块文件,它存储了用于签名JAR文件的公共签名。

• 在META-INF/com/google/android目录下有updater-script文件,内容就是update要做的操作,也就是前面提到过的command序列。

出于安全性及版本控制的考虑,JAR包要求必须有完整性以及合法性签名。可以看出这是Android确保安全的策略。JAR相关内容参见http://www.ibm.com/developerworks/cn/java/j-jar/,这里就不再详细介绍。

2. Main system部分
通过Android系统下载升级包并启动升级操作,需要上层应用Updater的支持,它是Java程序,代码位置android/packages/apps/Updater。大致流程:

系统启动后,如果存在网络连接,则检查是否存在升级包;
如果存在升级包,则下载至/cache目录;
调用Updater程序来提示是否升级;
如果Updater程序进程不存在,则自动启动此程序;
没有在代码中找到开始升级后执行哪些操作。不过由recovery.c的注释部分可以肯定一定需要重启进入Recovery,重启前要更新/cache/recovery/command,以告知Recovery进行升级:
–update_package=root:path

3. update流程

update有两种方式,第一种是上面提到的由Android启动的自动update过程,升级包在cache/下,升级包的名字在/cache/recovery/command文件中指定。第二种是手动进入Recovery模式,然后输入Alt + S,安装/sdcard/update.zip升级包。两种方式不同的只是安装包的位置以及传递参数给Recovery的方法,update过程都是一样的,工作流程如下图所示:

Android Bootloader - Main system - Recovery_第6张图片

1) install_package @ android/bootable/recovery/install.c
得到安装包信息,如“–update_package=CACHE:update.zip”,进入install_package函数,流程如下左图。mount安装包所在的分区,然后打开zip压缩包,进入handle_update_package(Android4.0: try_update_binary,它从zip包中提取并运行update-binary程序,update-binary由/bootable/recovery/updater/updater.c编译生成,update-binary负责解释updater-script脚本并执行脚本中的命令)开始升级:

Android Bootloader - Main system - Recovery_第7张图片

4. Bootloader

每次启动,Bootloader都会读取位于misc分区的bootloader_message,并检查command区域以\0结尾,还要考虑flash存在坏块的情况。然后根据读取的命令,启动系统或者更新firmware。工作流程如下:

Android Bootloader - Main system - Recovery_第8张图片

升级之后,无论升级成功是否,Bootloader都会进入recovery完成最后的收尾工作,并带着status以告知是否成功。如果更新hboot(尚不知道为什么叫这个名字,不过可以确定它就是bootloader firmware),一旦失败,若原有的bootloader遭到破坏,那么系统将不能boot。

转自:http://www.codingguy.net/?p=49

更多相关文章

  1. android input系统如何导入kl文件
  2. Android创建XMl文件
  3. android 读取SD卡或者其他地方文件功能函数
  4. android通过servlet服务器保存文件到手机
  5. Android 文件选择器,单选,多选
  6. 【转载】Using SQLite from Shell in Android(在shell 下使用sqli
  7. Android利用TTF文件设置字体
  8. android 保存bitmap到指定文件

随机推荐

  1. Android应用程序目录结构分析
  2. Android伸手党系列之五:Android(安卓)UI相
  3. Android(安卓)线程池来管理线程
  4. Android(安卓)基本的UI布局
  5. Android中的人脸检测(静态和动态)
  6. Android(安卓)學習之旅!(2)
  7. Android读取文件
  8. ubuntu下android内核编译
  9. freetype 在android编译时上的一个makefi
  10. Android面试系列文章2018之Android部分Se