1.1.1. Android设备中的img文件
uboot.img
boot.img
recovery.img
userdata.img
system.img
Android系统包含boot.img、system.img、userdata.img
uboot.img android启动时第一个加载的镜像,初始化硬件和基本输入出系统。
Recovery系统仅包含一个recovery.img
boot.img和recovery.img一样,都包含了kernel和ramdisk,两者使用的kernel是一样的,区别在于ramdisk,最重要的区别是ramdisk中的init.rc,决定启动后运行的是Recovery还是Android
boot.img文件结构在源码system/core/mkbootimg/bootimg.h中声明
系统在启动的时候,会先去执行BootLoader中的代码,判断按键是否按下,来进入不同的启动模式,如果按键没有按下的话再去读取MISC分区中BCB的值,来进入相应标志位标志的启动模式。
\Android系统OTA原理**
Recovery的工作需要整个软件平台的配合,从通信架构上来看,主要有三个部分:
1、MainSystem:即上面提到的正常启动模式(无有效按键按下,BCB中无命令),是用boot.img启动的系统,更新时,在这种模式中我们的上层操作就是使用OTA或从SD卡中拿到update.zip包。在重启进入Recovery模式之前,会向BCB中写入命令,以便在重启后告诉bootloader进入Recovery模式。
2、Recovery:系统进入Recovery模式后会装载Recovery分区,该分区包含recovery.img(同boot.img相同,包含了标准的内核和根文件系统)。进入该模式后主要是运行Recovery服务(/sbin/recovery)来做相应的操作(重启、升级update.zip、擦除cache分区等)。
3、Bootloader:先做一些初始化,然后根据组合键做不同的事情,如果没有按键按下会读取位于MISC分区的启动控制信息块BCB(Bootloader Control Block)中的标志位获得来至Main system和Recovery的消息,判断进入Fastboot、Recovery还是正常启动系统。这个过程内核没有加载,机器知识在按顺序执行指令。 除了正常的加载启动系统之外,还会通过读取MISC分区(BCB)获得来至Main system和Recovery的消息。
其中通信的方式又分为两种:
1、通过/cache/recovery/目录下的三个文件进行通信
(1)/cache/recovery/command:这个文件保存着Main system传给Recovery的命令行,每一行就是一条命令,支持一下几种的组合。
send_intent=anystring(write the text out to recovery/intent)在Recovery结束时在finish_recovery函数中将定义的intent字符串作为参数传进来,并写入到/cache/recovery/intent中
update_package=root:path(verify install an OTA package file)Main system将这条命令写入时,代表系统需要升级,在进入Recovery模式后,将该文件中的命令读取并写入BCB中,然后进行相应的更新update.zip包的操作。
wipe_data(erase user data(and cache),then reboot)擦除用户数据。擦除data分区时必须要擦除cache分区。
wipe_cache(wipe cache(but not user data),then reboot)擦除cache分区。
(2)/cache/recovery/log:Recovery模式在工作中的log打印。在recovery服务运行过程中,stdout以及stderr会重定位到/tmp/recovery.log在recovery退出之前会将其转存到/cache/recovery/log中,供查看。
(3)/cache/recovery/intent:Recovery传递给Main system的信息。
2、MISC分区的启动控制信息块BCB(Bootloader Control Block)
BCB是Bootloader与Recovery的通信接口,也是Bootloader与Main system之间的通信接口。存储在flash中的MISC分区,占用三个page,其本身就是一个结构体,具体成员以及各成员含义如下:
struct bootloader_message{
char command[32];
char status[32];
char recovery[1024];
};
(1)command成员:当我们想要在重启进入Recovery模式时,会更新这个成员的值。另外在成功更新后结束Recovery时,会清除这个成员的值,防止重启时再次进入Recovery模式。
(2)status:在完成相应的更新后,Bootloader会将执行结果写入到这个字段。
(3)recovery:可被Main System写入,也可被Recovery服务程序写入。存储的就是一个字符串,必须以recovery\n开头,否则这个字段的所有内容域会被忽略。“recovery\n”之后的部分,是/cache/recovery/command支持的命令。可以将其理解为Recovery操作过程中对命令操作的备份。Recovery对其操作的过程为:先读取BCB然后读取/cache/recovery/command,然后将二者重新写回BCB,这样在进入Main system之前,确保操作被执行。在操作之后进入Main system之前,Recovery又会清空BCB的command域和recovery域,这样确保重启后不再进入Recovery模式。
打开update.zip,有一个升级脚本META-INF/com/google/android/updater-script。Android就是根据这个脚本进行升级的,升级失败了,最好从这个脚本中找原因,因为这个文件会打印升级过程中的信息。通过adb shell,进入/tmp目录,有个文件记录了升级过程的信息,可通过这个文件查看升级失败的原因。
升级执行的具体过程
①比较时间戳:如果升级包较旧则终止脚本的执行。
②匹配设备信息:如果和当前的设备信息不一致,则停止脚本的执行。
③显示进度条:如果以上两步匹配则开始显示升级进度条。
④格式化system分区并挂载。
⑤提取包中的recovery以及system目录下的内容到系统的/system下。
⑥为/system/bin/下的命令文件建立符号连接。
⑦设置/system/下目录以及文件的属性。
⑧将包中的boot.img提取到/tmp/boot.img。
⑨将/tmp/boot.img镜像文件写入到boot分区。
⑩完成后卸载/system。
需要注意的是执行过程中,并未将升级包另外解压到一个地方,而是需要什么提取什么。在操作的过程中,并未删除或改变update.zip包中的任何内容。在实际的更新完成后,update.zip包确实还存在于原来的位置