Android系统Recovery工做原理之使用update.zip升级过程分析(五)---u...

  Android系统Recovery工做原理之使用update.zip升级过程分析(五)---update.zip包从上层进入Recovery服务


               文章开头咱们就提到update.zip包来源有两种,一个是OTA在线下载(通常下载到/CACHE分区),一个是手动拷贝到SD卡中。不管是哪一种方式得到update.zip包,在进入Recovery模式前,都未对这个zip包作处理。只是在重启以前将zip包的路径告诉了Recovery服务(经过将--update_package=CACHE:some_filename.zip或--update_package=SDCARD:update.zip命令写入到/cache/recovery/command中)。在这里咱们假设update.zip包已经制做好并拷贝到了SD卡中,并以Settings-->About Phone-->System Update-->Installed From SDCARD方式升级。java

         咱们的测试开发板是TCC8800,使用的Android源码是gingerbread0919,在这种方式下升级的源码位于gingerbread/device/telechips/common/apps/TelechipsSystemUpdater/src/com/telechips/android/systemupdater/下。         下面咱们具体分析这种升级方式下,咱们的update.zip是怎样从上层一步步进入到Recovery模式的。android


1、从System Update到Rebootsql


        当咱们依次选择Settings-->About Phone-->System Update-->Installed From SDCARD后会弹出一个对话框,提示已有update.zip包是否如今更新,咱们从这个地方跟踪。这个对话框的源码是SystemUpdateInstallDialog.java。数据库


        在mNowButton按钮的监听事件里,会调用mService.rebootAndUpdate(new  File(mFile))。这个mService就是SystemUpdateService的实例。 这  个类所在的源码文件是SystemUpdateService.java。这个函数的参数是一个文件。它确定就是咱们的update.zip包了。咱们能够证明一下这个猜测。app

        mFile的值:在SystemUpdateInstallDialog.java中的ServiceConnection中咱们能够看到这个mFile的值有两个来源。ionic

                 来源一:函数

                  mFile的一个来源是这个是否当即更新提示框接受的上一个Activity以“file”标记传来的值。这个Activity就是SystemUpdate.java。它是一个PreferenceActivity类型的。在其onPreferenceChange函数中定义了向下一个Activity传送的值,这个值是根据咱们不一样的选择而定的。若是咱们在以前选择了从SD卡安装,则这个传下去的“file”值为“/sdcard/update.zip”。若是选择了从NAND安装,则对应的值为“/nand/update.zip”。测试


                 来源二:spa

                 另个一来源是从mService.getInstallFile()得到。咱们进一步跟踪就可发现上面这个函数得到的值就是“/cache”+ mUpdateFileURL.getFile();这就是OTA在线下载后对应的文件路径。不论参数mFile的来源如何,咱们能够发如今mNowButton按钮的监听事件里是将整个文件,也就是咱们的update.zip包做为参数往rebootAndUpdate()中传递的。线程

        rebootAndUpdate:在这个函数中Main System作了重启前的准备。继续跟踪下去会发现,在SystemUpdateService.java中的rebootAndUpdate函数中新建了一个线程,在这个线程中最后调用的就是RecoverySystem.installPackage(mContext,mFile),咱们的update.zip包也被传递进来了。

        RecoverySystem类:RecoverySystem类的源码所在文件路径为:gingerbread0919/frameworks/base/core/java/android/os/RecoverySystem.java。咱们关心的是installPackage(Context context,FilepackageFile)函数。这个函数首先根据咱们传过来的包文件,获取这个包文件的绝对路径filename。而后将其拼成arg=“--update_package=”+filename。它最终会被写入到BCB中。这个就是重启进入Recovery模式后,Recovery服务要进行的操做。它被传递到函数bootCommand(context,arg)。

        bootCommand():在这个函数中才是Main System在重启前真正作的准备。主要作了如下事情,首先建立/cache/recovery/目录,删除这个目录下的command和log(可能不存在)文件在sqlite数据库中的备份。而后将上面④步中的arg命令写入到/cache/recovery/command文件中。下一步就是真正重启了。接下来看一下在重启函数reboot中所作的事情。

         pm.reboot():重启以前先得到了PowerManager(电源管理)并进一步得到其系统服务。而后调用了pm.reboot(“recovery”)函数。他就是/gingerbread0919/bionic/libc/unistd/reboot.c中的reboot函数。这个函数其实是一个系统调用,即__reboot(LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,mode,NULL);从这个函数咱们能够看出前两个参数就表明了咱们的组合键,mode就是咱们传过来的“recovery”。再进一步跟踪就到了汇编代码了,咱们没法直接查看它的具体实现细节。但能够确定的是 这个函数只将“recovery”参数传递过去了,以后将“boot-recovery”写入到了MISC分区的BCB数据块的command域中。这样在重启以后Bootloader才知道要进入Recovery模式。


         在这里咱们没法确定Main System在重启以前对BCB的recovery域是否进行了操做。其实在重启前是否更新BCB的recovery域是不重要的,由于进入Recovery服务后,Recovery会自动去/cache/recovery/command中读取要进行的操做而后写入到BCB的recovery域中。

         至此,Main System就开始重启并进入Recovery模式。在这以前Main System作的最实质的就是两件事,一是将“boot-recovery”写入BCB的command域,二是将--update_package=/cache/update.zip”或则“--update_package=/sdcard/update.zip”写入/cache/recovery/command文件中。下面的部分就开始重启并进入Recovery服务了。


2、从reboot到Recovery服务

       

            这个过程咱们在上文(对照第一个图)已经讲过了。从Bootloader开始若是没有组合键按下,就从MISC分区读取BCB块的command域(在主系统时已经将“boot-recovery”写入)。而后就以Recovery模式开始启动。与正常启动不一样的是Recovery模式下加载的镜像是recovery.img。这个镜像同boot.img相似,也包含了标准的内核和根文件系统。其后就与正常的启动系统相似,也是启动内核,而后启动文件系统。在进入文件系统后会执行/init,init的配置文件就是/init.rc。这个配置文件来自bootable/recovery/etc/init.rc。查看这个文件咱们能够看到它作的事情很简单:

       ①设置环境变量。

       ②创建etc链接。

       ③新建目录,备用。

       ④挂载/tmp为内存文件系统tmpfs

       ⑤启动recovery(/sbin/recovery)服务。

       ⑥启动adbd服务(用于调试)。

       这里最重要的就是固然就recovery服务了。在Recovery服务中将要完成咱们的升级工做。

       咱们将在下一篇详细分析Recovery服务的流程细节。

相关文章
相关标签/搜索