今天我们直接来看下android中具体的升级过程是如何的。

升级流程概述

升级的流程图:

升级流程分析

第一步:升级包获取

升级获取可以通过远程下载,也可直接拷贝到指定目录即可。

第二步:准备升级

然后调用RecoverySystem.installPackage将目录通过传参方式传递下去。这是应用层代码如下:

public void updateSystem(String updateSavePath) {File packageFile = new File(updateSavePath);try {//调用升级接口RecoverySystem.installPackage(this, packageFile);} catch (IOException e) {LOG.e(TAG, "RecoverySystem ERROR!!!");e.printStackTrace();String errDesc =String.format("execute system update fail. reason-> %s", e.toString());reportUpdateError(errDesc);}LOG.d(TAG, "RecoverySystem OK!!!");copyUpdateFileIsSuccess = false;
}

在应用层下载升级包后,会调用RecoverySystem.installPackage(Context context, File packageFile)函数来发起安装过程,这个过程主要的原理,实际上只是往 /cache/recovery/command 写入升级包存放路径,然后重启到recovery模式,仅此而已。

public static void installPackage(Context context, File packageFile)throws IOException {String filename = packageFile.getCanonicalPath();Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");//升级包路径final String filenameArg = "--update_package=" + filename;final String localeArg = "--locale=" + Locale.getDefault().toString();bootCommand(context, filenameArg, localeArg);
}private static void bootCommand(Context context, String... args) throws IOException {RECOVERY_DIR.mkdirs();  // In case we need itCOMMAND_FILE.delete();  // In case it's not writableLOG_FILE.delete();FileWriter command = new FileWriter(COMMAND_FILE);try {for (String arg : args) {if (!TextUtils.isEmpty(arg)) {command.write(arg);command.write("\n");}}} finally {command.close();}// Having written the command file, go ahead and rebootPowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);//重启到recovery模式pm.reboot(PowerManager.REBOOT_RECOVERY);throw new IOException("Reboot failed (no permissions?)");
}

PowerManager.REBOOT_RECOVERY的值为字符串"recovery",pm.reboot()方法最后会将recovery写入到misc分区的BCB中去。BCB即Bootloader Control Block,启动控制信息块,位于misc分区,从代码上看,就是一个结构体。如下:

struct bootloader_message {  char command[32];  char status[32];  char recovery[1024];
}; 

bootloader_message 结构体包含三个字段,具体含义如下:

command 字段中存储的是命令,它有以下几个可能值: 
* boot-recovery:系统将启动进入Recovery模式 
* update-radia 或者 update-hboot:系统将启动进入更新firmware的模式,这个更新过程由bootloader完成 
* NULL:空值,系统将启动进入Main System主系统,正常启动。

status 字段存储的是更新的结果。更新结束后,由Recovery或者Bootloader将更新结果写入到这个字段中。

recovery 字段存放的是recovry模块的启动参数,一般包括升级包路径。其存储结构如下:第一行存放字符串“recovery”,第二行存放路径信息“–update_package=/mnt/sdcard/update.zip”等。 因此,参数之间是以“\n”分割的。

第三步:系统重启进入Recovery模式,进行升级操作

Android系统进行升级的时候,有两种途径:

一种是通过接口传递升级包路径自动升级(Android系统SD卡升级),升级完之后系统自动重启。

另一种是手动进入recovery模式下,选择升级包进行升级,升级完成之后停留在recovery界面,需要手动选择重启。

前者多用于手机厂商的客户端在线升级,后者多用于开发和测试人员。但不管哪种,原理都是一样的,都要在recovery模式下进行升级。

下面介绍的是升级包保存在cache目录下,且升级包路径保存在/cache/recovery/command中的方式(升级包的存放路径,从BCB或者/cache/recovery/command里面解析得到的)。

重启进入升级主要流程:

  1. 系统重启进入Recovery模式。读取BCB的command,读取到”boot-recovery”后,加载recovery.img,启动recovery。
  2. 在install.cpp进行升级操作
  3. try_update_binary执行升级脚本
  4. 调用finish_recovery方法,清除BCB信息,重启

1、系统重启进入Recovery模式

系统重启时会判断/cache/recovery目录下是否有command文件,如果存在就进入recovery模式,否则就正常启动。

进入到Recovery模式下,将执行recovery.cpp的main函数,下面贴出关键代码片段:

... ...
while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {  switch (arg) {  case 's': send_intent = optarg; break;  case 'u': update_package = optarg; break;  ... ...
}
... ...

2、在install.cpp进行升级操作

在main函数中最终会调用到install_package方法。

... ...
if (update_package != NULL) {  status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE, true);  ... ...
} ... ...

具体的升级过程都是在install.cpp中执行的,再来看看install_package方法。

int install_package(const char* path, int* wipe_cache, const char* install_file,  bool needs_mount)
{  ... ...if (setup_install_mounts() != 0) {  ... ...} else {  result = really_install_package(path, wipe_cache, needs_mount);  }... ...
}  

install_package方法中创建了log文件(记录升级报错的信息)。然后调用really_install_package方法。

static int really_install_package(const char *path, int* wipe_cache, bool needs_mount)
{  ... ...// 装入签名文件Certificate* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);... ...// 验证签名err = verify_file(map.addr, map.length, loadedKeys, numKeys);... ...// 打开升级包  err = mzOpenZipArchive(map.addr, map.length, &zip);... ... // 执行升级脚本文件,开始升级  int result = try_update_binary(path, &zip, wipe_cache);... ...
}  

really_install_package方法中,首先验证签名,再读取升级包,然后进行调用try_update_binary方法升级

3、try_update_binary执行升级脚本

static int try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {const ZipEntry* binary_entry = mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);... ...const char* binary = "/tmp/update_binary";unlink(binary);int fd = creat(binary, 0755); ... ...//将升级包里面的update_binary解压到/tmp/update_binarybool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);... ...const char** args = (const char**)malloc(sizeof(char*) * 5);args[0] = binary; //update_binary存放路径args[1] = EXPAND(RECOVERY_API_VERSION);  // Recovery版本号char* temp = (char*)malloc(10);sprintf(temp, "%d", pipefd[1]);args[2] = temp;args[3] = (char*)path; //升级包存放路径args[4] = NULL;pid_t pid = fork();//fork一个子进程if (pid == 0) {close(pipefd[0]);//子进程调用update-binary执行升级操作execv(binary, (char* const*)args);fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));_exit(-1);}//父进程负责接受子进程发送的命令去更新ui显示 ... ...int status;waitpid(pid, &status, 0);if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {//安装失败,返回INSTALL_ERRORreturn INSTALL_ERROR;}//安装成功,返回INSTALL_SUCCESSreturn INSTALL_SUCCESS;
}

4、调用finish_recovery方法,清除BCB信息,重启

OTA升级成功,清空misc分区(BCB置零),并将保存到内存系统的升级日志/tmp/recovery.log保存到/cache/recovery/last_log。重启设备进入Main System,升级完成。

结束语

以上就是对升级流程的分析,希望对大家有所帮助。后续我们还会带来系统升级流程相关的介绍,感兴趣的同学可以关注我们的微信公众号。

上一篇:目录

下一篇:【android系统】android系统升级流程分析(二)---update包分析

【android系统】android系统升级流程分析(一)---recovery模式中进行update包升级流程分析相关推荐

  1. Android系统解除USER版本无法进入Recovery模式限制

    需求描述 user版本默认是不支持recovery的,用户需要在user版本可以使用fastboot烧录镜像 解决方案 diff --git a/bootable/recovery/recovery. ...

  2. android流程点击开机键熄屏,一种基于android系统的灭屏状态下指纹解锁加速亮屏方法与流程...

    本发明涉及android系统解锁显示方法,尤其涉及一种基于android系统的灭屏状态下指纹解锁加速亮屏方法. 背景技术: 目前,随着指纹技术越来越普及,很多android系统设备都带有指纹外设,特别 ...

  3. Android系统(MT6797)CPU频率工作模式以及调整频率的方法

    声明: 最近在做一款MT6797架构的Android平板的系统优化工作,公司总觉得平板运行不是很流畅,考虑到的一点是是不是平板的CPU被降频影响的性能上的损失太大,CPU降频这种操作一般就是为了能够省 ...

  4. 如何提升android系统,Android系统智能手机如何提升上网速度

    怎样才能保证使用的Android系统智能手机保持良好的上网速度呢?是重启手机?其实简单的重启并不能拥有很好的效果,在重启之前,我们还需要采取一些其它措施才能让Android智能手机在重启后上网更快,下 ...

  5. 调用Android系统自带相机拍照,从相册中获取图片

    一,前言: 在日常的手机应用开发过程中,经常会遇到上传图片的需求,像上传头像之类的,这就需要调用系统的相机,相册获取照片.但是在Android 系统7.0之后认为这种操作是不安全的,这篇文章主要就是记 ...

  6. uefi装完系统后无法引导_Win10用UEFI模式安装无法引导启动的原因分析及解决方法...

    现在很多用户安装Win10系统都会采用UEFI+GPT的安装模式,这也是微软Win10原版的安装方式.可以让电脑启动速度更快,但是一些用户发现使用UEFI模式安装之后系统无法启动,那么这时该如何解决呢 ...

  7. r语言找不到cochrane函数_网状meta必备技能之6-利用R中的meta包实现meta分析

    我们仅仅是代码的编辑者.整合者.搬运工,仅免费传授方法,下文数据和代码取自于网络和免费软件"R语言说明书",如果您觉得我们侵犯了您的版权,请通知我们撤稿.请大家谅解,谢谢! 相信大 ...

  8. 最新 android系统 设备 分布情况,2019年第二季度国内操作系统及浏览器占比情况分析...

    国家互联网应急中心(以下简称CNCERT)对2019年第二季度国内网络访问情况进行了抽样分析,重点针对操作系统及浏览器占比情况进行统计,发现以下特点: 1.通过移动终端上网的用户数量多于通过PC终端上 ...

  9. 智能投影机android系统,Android对比Windows 谁带投影入智能化

    投影智能 现况分析 [中关村在线投影机频道原创]每当我们提起智能化,首先出现在脑海中的一定是电脑和手机.从传统观念看,智能似乎与投影不沾边,然而现实告诉我们,投影智能化意识大势所趋. 投影进入智能化 ...

最新文章

  1. 正则表达式grep、egrep--already
  2. 透视大数据,未来市场谁主沉浮?这个4月,3W企服大数据OpenForm等你报名!
  3. PAT (Basic Level) Practice (中文)1001 害死人不偿命的(3n+1)猜想 (15 分)
  4. Matplot的常见问题
  5. 字符输出流_Writer类FileWriter类介绍
  6. linux单个core的线程,正确使用Core Data多线程的3种方式
  7. 使用Matplotlib创建散点图
  8. 达摩院再获自动驾驶权威测评第一,车辆可识别“厘米级”障碍物
  9. Git基础知识与常用命令
  10. -字符串-搜索和替换--聚合
  11. 3、用一个div模拟textarea的实现
  12. 浅谈算法和数据结构: 九 平衡查找树之红黑树
  13. 线束对插件厂商网站汇总
  14. 上海电力大学本科毕业论文答辩PPT模板
  15. HTML页面浏览历史,浏览历史记录功能
  16. 多传感器融合算法,基于Lidar,Radar,Camera算法
  17. ABAP 去重 delete adjacent duplicates
  18. 读取HDF或者NetCDF格式的栅格数据
  19. 3D Max动画制作
  20. 用keras tuner 来优化tensorflw超参数

热门文章

  1. 计算机网络 安全协议,网络安全协议包括哪些
  2. FIRST集、FOLLOW集和SELECT集
  3. 计算机无法更新一直在撤销更改,您好!win10更新一直是“无法完成更新,正在撤销更改”,几个月了A - Microsoft Community...
  4. Prompt Engineering 面面观
  5. Centos6.7创建逻辑卷挂载1T机械硬盘
  6. sap学习手册III
  7. IDA7.7.220118 - The graph is too big
  8. Java编程思想---容器
  9. 三级分销最佳佣金比例
  10. 奶奶说标题不能起的太长要不然会有憨憨跟着读之动态路由(RIP)