【android系统】android系统升级流程分析(一)---recovery模式中进行update包升级流程分析
今天我们直接来看下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里面解析得到的)。
重启进入升级主要流程:
- 系统重启进入Recovery模式。读取BCB的command,读取到”boot-recovery”后,加载recovery.img,启动recovery。
- 在install.cpp进行升级操作
- try_update_binary执行升级脚本
- 调用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包升级流程分析相关推荐
- Android系统解除USER版本无法进入Recovery模式限制
需求描述 user版本默认是不支持recovery的,用户需要在user版本可以使用fastboot烧录镜像 解决方案 diff --git a/bootable/recovery/recovery. ...
- android流程点击开机键熄屏,一种基于android系统的灭屏状态下指纹解锁加速亮屏方法与流程...
本发明涉及android系统解锁显示方法,尤其涉及一种基于android系统的灭屏状态下指纹解锁加速亮屏方法. 背景技术: 目前,随着指纹技术越来越普及,很多android系统设备都带有指纹外设,特别 ...
- Android系统(MT6797)CPU频率工作模式以及调整频率的方法
声明: 最近在做一款MT6797架构的Android平板的系统优化工作,公司总觉得平板运行不是很流畅,考虑到的一点是是不是平板的CPU被降频影响的性能上的损失太大,CPU降频这种操作一般就是为了能够省 ...
- 如何提升android系统,Android系统智能手机如何提升上网速度
怎样才能保证使用的Android系统智能手机保持良好的上网速度呢?是重启手机?其实简单的重启并不能拥有很好的效果,在重启之前,我们还需要采取一些其它措施才能让Android智能手机在重启后上网更快,下 ...
- 调用Android系统自带相机拍照,从相册中获取图片
一,前言: 在日常的手机应用开发过程中,经常会遇到上传图片的需求,像上传头像之类的,这就需要调用系统的相机,相册获取照片.但是在Android 系统7.0之后认为这种操作是不安全的,这篇文章主要就是记 ...
- uefi装完系统后无法引导_Win10用UEFI模式安装无法引导启动的原因分析及解决方法...
现在很多用户安装Win10系统都会采用UEFI+GPT的安装模式,这也是微软Win10原版的安装方式.可以让电脑启动速度更快,但是一些用户发现使用UEFI模式安装之后系统无法启动,那么这时该如何解决呢 ...
- r语言找不到cochrane函数_网状meta必备技能之6-利用R中的meta包实现meta分析
我们仅仅是代码的编辑者.整合者.搬运工,仅免费传授方法,下文数据和代码取自于网络和免费软件"R语言说明书",如果您觉得我们侵犯了您的版权,请通知我们撤稿.请大家谅解,谢谢! 相信大 ...
- 最新 android系统 设备 分布情况,2019年第二季度国内操作系统及浏览器占比情况分析...
国家互联网应急中心(以下简称CNCERT)对2019年第二季度国内网络访问情况进行了抽样分析,重点针对操作系统及浏览器占比情况进行统计,发现以下特点: 1.通过移动终端上网的用户数量多于通过PC终端上 ...
- 智能投影机android系统,Android对比Windows 谁带投影入智能化
投影智能 现况分析 [中关村在线投影机频道原创]每当我们提起智能化,首先出现在脑海中的一定是电脑和手机.从传统观念看,智能似乎与投影不沾边,然而现实告诉我们,投影智能化意识大势所趋. 投影进入智能化 ...
最新文章
- 正则表达式grep、egrep--already
- 透视大数据,未来市场谁主沉浮?这个4月,3W企服大数据OpenForm等你报名!
- PAT (Basic Level) Practice (中文)1001 害死人不偿命的(3n+1)猜想 (15 分)
- Matplot的常见问题
- 字符输出流_Writer类FileWriter类介绍
- linux单个core的线程,正确使用Core Data多线程的3种方式
- 使用Matplotlib创建散点图
- 达摩院再获自动驾驶权威测评第一,车辆可识别“厘米级”障碍物
- Git基础知识与常用命令
- -字符串-搜索和替换--聚合
- 3、用一个div模拟textarea的实现
- 浅谈算法和数据结构: 九 平衡查找树之红黑树
- 线束对插件厂商网站汇总
- 上海电力大学本科毕业论文答辩PPT模板
- HTML页面浏览历史,浏览历史记录功能
- 多传感器融合算法,基于Lidar,Radar,Camera算法
- ABAP 去重 delete adjacent duplicates
- 读取HDF或者NetCDF格式的栅格数据
- 3D Max动画制作
- 用keras tuner 来优化tensorflw超参数
热门文章
- 计算机网络 安全协议,网络安全协议包括哪些
- FIRST集、FOLLOW集和SELECT集
- 计算机无法更新一直在撤销更改,您好!win10更新一直是“无法完成更新,正在撤销更改”,几个月了A - Microsoft Community...
- Prompt Engineering 面面观
- Centos6.7创建逻辑卷挂载1T机械硬盘
- sap学习手册III
- IDA7.7.220118 - The graph is too big
- Java编程思想---容器
- 三级分销最佳佣金比例
- 奶奶说标题不能起的太长要不然会有憨憨跟着读之动态路由(RIP)