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

本文主要是介绍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方式升级。

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


一、从System Update到Reboot


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


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

        mFile的值:在SystemUpdateInstallDialog.java中的ServiceConnection中我们可以看到这个mFile的值有两个来源。

                 来源一:

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


                 来源二:

                 另个一来源是从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服务了。


二、从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服务的流程细节。

这篇关于Android系统Recovery工作原理之使用update.zip升级过程分析(五)---update.zip包从上层进入Recovery服务的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1100207

相关文章

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

Pandas使用SQLite3实战

《Pandas使用SQLite3实战》本文主要介绍了Pandas使用SQLite3实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1 环境准备2 从 SQLite3VlfrWQzgt 读取数据到 DataFrame基础用法:读

JSON Web Token在登陆中的使用过程

《JSONWebToken在登陆中的使用过程》:本文主要介绍JSONWebToken在登陆中的使用过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录JWT 介绍微服务架构中的 JWT 使用结合微服务网关的 JWT 验证1. 用户登录,生成 JWT2. 自定义过滤

Java中StopWatch的使用示例详解

《Java中StopWatch的使用示例详解》stopWatch是org.springframework.util包下的一个工具类,使用它可直观的输出代码执行耗时,以及执行时间百分比,这篇文章主要介绍... 目录stopWatch 是org.springframework.util 包下的一个工具类,使用它

Java使用Curator进行ZooKeeper操作的详细教程

《Java使用Curator进行ZooKeeper操作的详细教程》ApacheCurator是一个基于ZooKeeper的Java客户端库,它极大地简化了使用ZooKeeper的开发工作,在分布式系统... 目录1、简述2、核心功能2.1 CuratorFramework2.2 Recipes3、示例实践3

springboot security使用jwt认证方式

《springbootsecurity使用jwt认证方式》:本文主要介绍springbootsecurity使用jwt认证方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录前言代码示例依赖定义mapper定义用户信息的实体beansecurity相关的类提供登录接口测试提供一

go中空接口的具体使用

《go中空接口的具体使用》空接口是一种特殊的接口类型,它不包含任何方法,本文主要介绍了go中空接口的具体使用,具有一定的参考价值,感兴趣的可以了解一下... 目录接口-空接口1. 什么是空接口?2. 如何使用空接口?第一,第二,第三,3. 空接口几个要注意的坑坑1:坑2:坑3:接口-空接口1. 什么是空接

springboot security快速使用示例详解

《springbootsecurity快速使用示例详解》:本文主要介绍springbootsecurity快速使用示例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录创www.chinasem.cn建spring boot项目生成脚手架配置依赖接口示例代码项目结构启用s

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.