- 0. 导读
- 1. Android 传统 A/B 分区和动态分区布局
- 2. Android 虚拟分区布局
- 3. 虚拟分区的思考
- 2.1 分区只有一套,如何实现 A/B 系统特性?
- 2.2 部分分区还有 A/B 两套,只要一套不行吗?
- 2.3 为什么不把所有分区都放到动态分区里?
- 4. 其它
0. 导读Android 从 R 开始引入 Virtual A/B 系统,简称 VAB,这里称为虚拟分区。
Android 虚拟分区详解系列:
- 《Android 虚拟分区详解(一) 参考资料推荐》
本系列文章基于 Android R(11) 进行分析,如果没有特别说明,均基于代码版本 android-11.0.0_r46
上一篇《Android 虚拟分区详解(一) 参考资料推荐》提到了学习虚拟分区的一些参考资料,本篇简单说下虚拟分区的布局。
说到 Android 虚拟分区布局,基本上都是直接上一张布局图就完事了,一张图就能搞定的事所以其实也没什么好说的。那为什么又要单独开篇来说呢,因为本文想在分区布局图之外说点别的,如果你很清楚各分区的布局,又能回答以下问题,那就不需要再看本文了。
- 虚拟分区中的各种系统分区(system, vendor, product, oem)只有一套,如何实现所说的 A/B 系统特性?
- 分区布局有还有部分分区有 A/B 两套,只要一套不行吗?
- 对于这些还存在 A/B 两套的分区,为什么不和其他分区一样,都放到 super 对应的动态分区里?
如果只对虚拟分区的布局感兴趣,请跳转到第 2 节;
如果只对上面的问题感兴趣,请跳转到第 3 节;
1. Android 传统 A/B 分区和动态分区布局有部分新接触升级系统的朋友可能不了解以前的 Android 分区布局,我这里再贴一下以前传统 A/B 分区以及动态分区的布局,清楚以前分区布局的请自行略过本节。
- 传统 A/B 分区
Android 从 N(7.1) 开始引入 A/B 升级系统,所有分区都有 A/B 两套,且分区大小固定,这里将其称为传统 A/B 分区,至于 A/B 之前的系统,这里不再提及。
更多传统分区布局,请参考: 《Android A/B System OTA分析(一)概览》
- 动态分区
Android 从 Q(10) 开始引入动态分区,本质还是 A/B 系统,所有分区也都有 A/B 两套,只是将 system/vendor/product/oem 等分区放到 super 分区这个容器中,大小不再固定,升级时可以变化。
这里贴一张 《Android 动态分区详解(一) 5 张图让你搞懂动态分区原理》 中的配图:
从图中可以看到,对于 system, vendor, product 等这一类分区统一存放到 super 分区中,但还是存在 A/B 两套分区,在 super 分区的头部存放 metadata 数据(相当于分区表),通过解析 metadata 得到分区内的具体构造,从而加载相应的分区。
更多动态分区布局细节,请参考: 《Android 动态分区详解(一) 5 张图让你搞懂动态分区原理》
2. Android 虚拟分区布局对于 Android 虚拟分区布局,我记得以前 Android 官方网站的页面 Virtual A/B Overview (或无障碍版本: 虚拟 A/B 概览) 是有这个图的,但最新的网页上已经没有这个图了。
以下内容来自官方文档: Android_VirtualAB_Design_Performance_Caveats.pdf
在文档中是这么说的:
把上面这张分区布局图要点总结如下:
分区有两类,橙色分区和包含在 super 内部的绿色分区;
橙色分区是启动的关键,直接由 bootloader 加载;
绿色分区(橙色分区之外的其它分区)都是动态的,因此包含在 super 分区中;
橙色分区有 A/B 两套,并且分区都比较小,保留 A/B 分区后缀 (
_a
和_b
);- 例如: vbmeta 为 64 KB,boot 为 64MB,dtbo 为 8MB
- 由于橙色部分对应的分区都比较小,因此使用 A/B 两套带来的开销相对较小;
绿色分区不使用后缀(只有一套包含在 super 内部的动态分区)
重点:启动中需要的关键分区(橙色)还保留 A/B 两套及相应后缀,其它分区(绿色)都放到动态分区中。即使橙色分区保留了 A/B 两套,但由于绿色分区只有一套,因此也能有效减少升级时对空间的需求。
这里展开说下上图中 A/B 两套分区带来的开销。
手机系统有很强烈的 App 安装需求,目前基本上都是 64G 存储起步,128G,256G 算是标配,往上 512G, 1T 甚至更多。
手机之外的设备,例如电视和机顶盒,没有强烈的 App 安装需求,大部分设备出厂时内置的 App 就贯穿了整个生命周期,所以这类设备的存储大小一般为 16G 或 32G,有部分设备甚至只有 8G(不过随着 Android 本身系统的增大,8G 已经不太够用了),主流 16G 左右。
对一个有 16G 存储的设备来说,分区中多一套(vbmeta + boot + dtbo 等)带来的开销大概率少于 200M。以 200M 为例,相较于总体的 16G 存储,比例 1.25%,几乎可以忽略不计。
3. 虚拟分区的思考 2.1 分区只有一套,如何实现 A/B 系统特性?相比于动态分区,虚拟分区中的 system, vendor 等分区只有一套,那是如何实现 A/B 系统两套分区升级特性的呢?
答案就在虚拟二字。
以下从宏观的角度大致阐述虚拟分区系统的升级流程:
- update engine 接收到升级数据以后,根据升级数据 payload 头部的 metadata 更新设备动态分区 super 头部的分区表。
从第一节的图可以看到,动态分区头部实际上存放的是一个 metadata 结构,但为了不和 payload 头部的 metadata 混淆,这里将动态分区头部的 metadata 称为分区表。
通过解析动态分区头部的分区表就可以加载 Android 需要的各 system, vendor 等分区。
- 系统平时基于 super 内的实际分区运行,这里称为真实分区 A。升级时,系统根据分区表的内容,使用 super 内空闲的空间,以及 data 分区内的空间,映射出一套虚拟分区 B;
系统优先使用 super 分区内的空闲空间,不够的时候再从 data 内分配空间。映射的虚拟分区信息也会写入分区表中。
- update engine 往虚拟分区 B 里写入升级数据,和以前 A/B 系统两套分区时的方式一样进行升级;
- 升级完成后第一次重启,通过 super 头部的分区表加载虚拟分区 B;如果失败,则回退回真实分区 A (升级开始前的状态);
- 系统从虚拟分区 B 启动成功以后,需要把虚拟分区 B 的内容同步回真实分区 A,从而确保真实分区 A 和虚拟分区 B 的内容一样;
把分区 B 的内容同步回分区 A 的操作实际上叫做 merge,为了简单起见,这里理解为一种同步操作即可。
在同步没有完成以前,分区 A 是不可用的,但虚拟分区 B 一直可用,所以如果同步被中断了,重新开机以后还会进入虚拟分区 B 继续同步。但此时如果虚拟分区 B 损坏了,那此时整个系统就无法启动了。
- 同步完成后,系统重启并从真实分区 A 启动,删除虚拟出来的分区 B,成功完成一次升级;
为了方便理解,以上步骤屏蔽了复杂的虚拟分区底层映射和操作细节。至于虚拟分区的工作原理(如何创建,使用和销毁),请参考后续博客。
2.2 部分分区还有 A/B 两套,只要一套不行吗?答案是不行。
在官方页面 Virtual A/B Overview (或无障碍版本: 虚拟 A/B 概览) 的一开始就介绍了虚拟分区的特性:
无缝和回滚两个特性都要求在某个时刻必须同时存在两套分区:
- 基于无缝的增量升级,要求在更新的时候,从一个分区复制内容到另外一个分区。对于 Virtual A/B 系统,就是一套正在运行的实际分区,和一套基于实际分区虚拟出来的目标分区
- 回滚要求如果升级失败,需要回退到升级前的分区。对于 Virtual A/B 系统,升级是总是往虚拟出来的分区写内容,如果升级失败,需要回退回世纪分区。
所以如果只有一套分区,满足不了需求。
2.3 为什么不把所有分区都放到动态分区里?现在系统的 system, vendor 等分区放在动态分区(super)中,正常启动时通过解析 super 分区头部的分区表映射出实际分区;升级时通过虚拟化得到两套分区,即实际分区 A 和基于分区 A 虚拟出来的分区 B。
那为什么不把所有分区都这样进行处理?
了解动态分区加载和虚拟的原理以后,理论上肯定是可以把所有分区都放到动态分区里面的。
一般来说是这样做:
第一级 bootloader 启动后,读取 super 头部的分区表,解析找到所需要的分区数据,例如 boot, vbmeta, dtbo 等,加载使用相关数据启动 kernel,在 kernel 启动后进一步解析 super 的数据加载 system, vendor 等分区。
但 bootloader 本身作为一个加载器,内容比较简单,执行时间很短,目的就是准备并加载 linux kernel。
所以,如果需要把所有分区都放到动态分区的话,一级的 bootloader 就需要添加解析和使用动态分区数据的功能,从而可以操作 super 内的分区。解析线性映射的分区映射还好,解析虚拟分区映射的数据则更加复杂。
相比于承担 1% 左右的空间开销(在动态分区之外单独实现 A/B 两套分区),给简单的 bootloader 添加复杂的动态分区和虚拟分区操作功能代码显得极不划算。
另外,也要考虑从旧设备升级的可能,这里不再展开描述。
因此,把所有分区都放到动态分区中,理论可行,但实际没什么必要。
4. 其它洛奇工作中常常会遇到自己不熟悉的问题,这些问题可能并不难,但因为不了解,找不到人帮忙而瞎折腾,往往导致浪费几天甚至更久的时间。
所以我组建了几个微信讨论群(记得微信我说加哪个群,如何加微信见后面),欢迎一起讨论:
- 一个密码编码学讨论组,主要讨论各种加解密,签名校验等算法,请说明加密码学讨论群。
- 一个Android OTA的讨论组,请说明加Android OTA群。
- 一个git和repo的讨论组,请说明加git和repo群。
在工作之余,洛奇尽量写一些对大家有用的东西,如果洛奇的这篇文章让您有所收获,解决了您一直以来未能解决的问题,不妨赞赏一下洛奇,这也是对洛奇付出的大鼓励。扫下面的二维码赞赏洛奇,金额随意:
洛奇自己维护了一个公众号“洛奇看世界”,一个很佛系的公众号,不定期瞎逼逼。公号也提供个人联系方式,一些资源,说不定会有意外的收获,详细内容见公号提示。扫下方二维码关注公众号:
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
文章名称:Android虚拟分区详解(二)虚拟分区布局-创新互联
分享链接:http://lswzjz.com/article/deeiji.html