Android Virtual A/B 系统简称 VAB,我在这一系列里面又将其称为虚拟分区。
我有个 Android OTA 讨论群,群里的大部分朋友都知道一个梗,就是我五一前立下 flag 说要在那个假期完成虚拟分区分析的,但放飞自我远比写东西容易得多,所以这事就搁置了。
从 Android R 开始(2020),各家厂商推出的最新系统就陆续支持 VAB (VAB 或 Virtual A/B),眨眼间两年过去了,Android 陆续又发布了 S 和 T,VAB 也进一步演化成 VABC (Virtual A/B with Compression),增加了压缩功能。
两年过去,好多朋友基于 VAB 已经工作了相当长一段时间,对 VAB 有了深入的理解,坦白说比我深入得多,远离 OTA 的工作让我在这方面比较业余;另外网上陆续有不少分析 VAB 的文章,所以我一度很犹豫,觉得时间过了这么久,没啥必要再写 VAB 了。
不过群里有时候也有朋友抱怨说 VAB 的资料很少,VAB 学习起来有些困难;再加上大环境的因素,太过于关注于外界的消息会让人沉沦,让人看不到希望。面对这一切,自己又做不了什么,为了让自己更聚焦一些,不至于太闲,所以我最终还是决定继续写一写 Android 的虚拟分区系统。
这一篇主要梳理一下我学习 Android 虚拟分区所用到的资料,也顺便推荐给你。
主要有 3 类,Android 官方 VAB 文档,Device Mapper 文档以及 Android 代码。
第 1, 2, 3 部分分别详细介绍了我为什么要推荐这些文档,以及相关文档链接;
如果只对资料汇总列表感兴趣,请跳转到第 4 节,参考资料汇总;
如果对本系列后续计划感兴趣,请跳转到第 5 节,后续计划;
官方文档永远是最重要的参考资料,值得一遍又一遍的阅读
这里我要说的不仅仅是 Android 官方的 VAB 文档,而是你想学习的任何东西的官方文档。因为那是官方开发者的表述,第一手的资料。任何第三方的分析和解释都掺杂了主观解读的成分,通俗来说都算是二手货了,都可能是不准确的,包括我即将写的本系列文章。我建议你把本系列当做官方文档之外的补充,阅读官方文档有不了解的,到我这一系列文章来,看看我是如何分析理解的。
回到官方文档,如果是英文,最明显的一点,不同人的背景不同,英语水平不同,翻译成中文以后意思可能大相径庭。最糟糕的情况就是,翻译出来的东西词不达意,不知所云,类似甚至还不如机翻。
我自己的习惯是,如果一份文档或者标准原来是英文版,那除了阅读中文的参考资料便于快速理解之外,还应该找到原文仔细阅读一下。有时候翻译过来的那些不知所云的词汇,在原文表述中可能相当的浅显易懂。
官方文档的每一段描述都有其用意,你可以试着在阅读后自己向自己解释这段话的作用,如果你解释起来模棱两可,含含糊糊,那就说明还没有真正理解。具体做法参考小黄鸭调试法。
再强调一次:
官方文档永远是最重要的参考资料,值得一遍又一遍的阅读,直到完全弄懂每一段话、每一张图的真正含义。
一开始这一步会很难,因为官方文档通常比较晦涩,或者比较笼统,让人没有去阅读的欲望,但这是成长的必由之路。
说完了废话,该入正题了。
Android 官方 VAB 文档主要包括:
Virtual A/B Overview
从比较宏观的层面综述 Virtual A/B 的功能。
无梯子版本:https://source.android.google.cn/docs/core/ota/virtual_ab?hl=zh_cn
Implementing Virtual A/B
着重讲了 Virtual A/B 的编译开关,在各个组件(包括 BootCtl,fstab,Bootloader,kernel)中涉及的修改。
无梯子版本:https://source.android.google.cn/docs/core/ota/virtual_ab/implement?hl=zh_cn
Implementing Virtual A/B - Patches
讲了针对 Virtual A/B 推出以后发现问题提供的一些修复补丁(fix patch)。
无梯子版本:https://source.android.google.cn/docs/core/ota/virtual_ab/implement-patches?hl=zh_cn
总体来说,这三个页面先从宏观层面综述,再下到模块开关和特性,再到具体问题和补丁,依次从高到低介绍 Virtual A/B,虽然有些简单,但仍然值得反复阅读。因为刚开始阅读,总容易漏掉一些东西。
举个例子,前段时间对 merge 的状态不是很肯定,在群里求证:
但这个问题的答案就在官方文档中,只不过没留意,被我遗漏了,直到多次阅读后才发现:
另外,在 Android S(12) 推出以后,又添加了 VABC 的内容,所以如果你只想学 VAB,所有 VABC 相关的内容都可以忽略。不过还是建议进行略读,以免遗漏像上面这样重要的内容。
官方网站始终保持着最新内容,无法查看历史版本。如果你有保存刚推出 VAB 时的页面,欢迎分享。因为那时候的页面更便于集中学习 VAB。
这里所说的半公开文档是指:Android_VirtualAB_Design_Performance_Caveats.pdf
所谓半公开,是因为它属于 partner 文档。只有当你的公司成为 Google 的 partner,Google 才会给你开放 partner 账号,通过 partner 账号才能访问的内容。
这是我目前见过最详细的介绍 Android VAB 的文档,除了没有展示代码细节外,几乎涉及了 VAB 的方方面面。
以下是几个官文这个文档的截图:
上面这张示例截图只包含了升级过程描述的部分。
OTA 讨论群里也分享很多讲述 VAB 的文章或文档,包括一些原厂的资料,基本上都离不开这篇文档,其中用于描述的图片和更新流程的介绍,也都出自这篇文档。
所以,如果你手上有这份文档,目前网络上所有介绍的 VAB 操作的资料都不需要再看了,你所需要做的,就是反复阅读这份文档。
另外,特别备注感谢当初分享这份文档的朋友,老朋友们应该知道我说的谁~
安卓虚拟分区 VAB 最难的地方在于加入了 snapshot, COW 和 merge 等一系列 Device Mapper 的行为和特性,让系统分区不再拥有静态的布局。升级过程中分区动态的变化让初次接触的人觉得错综复杂,难以理解数据到底流向了哪里,不明白某个时刻系统中的镜像到底是什么状态。虽然从 Android Q 开始的动态分区就已经不再是完全静态了,但相比于后面 Android R 的 VAB 来说,还是简单很多。
所以,如果能清晰的理解 Device Mapper 的行为,学习起 VAB 来就更容易。
Device Mapper 支持的设备种类很多,VAB 中涉及的主要是 dm-verity, dm-linear 和 dm-snapshot,尤其 dm-snapshot。
我在《Android 动态分区详解(一) 5 张图让你搞懂动态分区原理》有提到一篇从比较高层次介绍 device mapper 机制的文章:
作为 linux 的驱动模块,自然建议参考 linux 的官方文档,位于 Documentation/device-mapper
目录下。
这个文档也有在线版本,推荐必看 dm-snapshot 文档:
说到 Device Mapper,就不得不提到调试工具 dmsetup,如果单纯看文档不好理解 device mapper 如何工作,则可以通过 dmsetup 工具来进行实践,加深理解。只有动手做了,才会有更深刻的印象。
我在 《Android 动态分区详解(二) 核心模块和相关工具介绍》 一文中有介绍过如何使用 dmsetup 来映射动态分区。实际上主要参考了下面这个网页,它详细演示如何使用 dmsetup 来进行各种 dm 设备的操作:
类似的参考文档还有 RedHat 官方的 Logical Volume Manager Administration 的附录A
这篇可以和前面介绍 dmsetup 操作的交叉阅读,如果只推荐一篇的话,推荐参考前一篇。
当然,如果有兴趣的话,也可以读一读 dmsetup 工具的命令行帮助文档,这里就不再详细说明了。
为了能比较好理解 snapshot 是如何工作的,也建议了解下 snapshot 的基本原理,推荐阅读下面这篇文章:
还有这一篇,主要介绍了 IBM 存储设备系统上使用的 Redirect-on-Write (ROW):
需要特别说明的是,IBM 的知识库文章经常更新,所以上面这个链接可能过一段时间就不能访问了。
这里有一篇简单介绍存储设备 NetApp 厂家的 snapshot 实现的,知识量小,比较浅显:
为了避免你关于 snapshot 的原理看多了走火入魔,导致 COW(Copy-On-Write) 和 ROW(Redirect-On-Write) 傻傻分不清,以下特别做一个简单总结,后面会单独开一篇介绍 Android 中我对 COW 的理解。
从快照( snapshot) 原理的角度来讲,一共分 3 种:
实际使用中,跟上面提到的快照原理有些不同:
而且实际使用中,基于 linux 的系统,快照基本上都是使用 ROW 的方式,即新数据写入到快照设备中,旧数据在原始设备中维持不变,然后再通过一个叫做 merge 的操作,将快照设备中的新数据写入覆盖原始设备中的数据。
所以,Android 文档中提到的 COW 设备,对应于快照原理的 ROW 操作(创建快照写入新数据时,原来设备中的数据不变,新数据写入到快照设备中,再通过 merge 操作改写原始设备中的数据)。如果这一点没搞清楚,估计就会非常迷糊。
可能是做了太久技术支持的缘故,为了找到 bug 的原因,已经习惯了基于最小化差异的方式进行工作。凡事都尽可能隔离其他因素的影响,使用单一变量进行跟踪。
例如,研究虚拟分区,我推荐这样学习源码:
Android Q(10) 支持动态分区,Android R(11) 在动态分区的基础上引入虚拟分区 VAB,我会选取动态分区 Android 的最后一个版本(android-10.0.0_r41),和支持虚拟分区 VAB 的第一个版本(android-11.0.0_r1),然后对比这两个版本的代码来研究虚拟分区到底引入了哪些代码上的改变。
我学习动态分区时也是使用这种方式。
关于如何查看 Android 个版本支持的设备,请参考:
无梯子版本:
参考资料(点击链接直达):
Android 官方网站关于 Virtual A/B 相关的网页
以上网页需要梯子,以下是无障碍版本:
Android Partner 文档 (强烈推荐,反复学习)
Device Mapper 文档
snapshot 原理和 COW 介绍
Android 源码,推荐对照以下两个版本学习
这些资料部分来自群友分享和推荐,部分是我学习查找的资料,希望对你有用。
如果你有更好的资料也欢迎推荐,一起学习。
既然 Android_VirtualAB_Design_Performance_Caveats.pdf 是最详细的文档,后续文章将围绕这个文档的分析展开。主要包括以下内容:
虚拟分区布局
虚拟分区原理和状态变化
OTA 更新流程介绍
OTA 更新流程主要步骤的代码分析
以上只是初步设想的文章内容,具体可能会有些变化。
除了上面列举的话题外,也可能会增加一些其他感兴趣的话题。
洛奇工作中常常会遇到自己不熟悉的问题,这些问题可能并不难,但因为不了解,找不到人帮忙而瞎折腾,往往导致浪费几天甚至更久的时间。
所以我组建了几个微信讨论群(记得微信我说加哪个群,如何加微信见后面),欢迎一起讨论:
在工作之余,洛奇尽量写一些对大家有用的东西,如果洛奇的这篇文章让您有所收获,解决了您一直以来未能解决的问题,不妨赞赏一下洛奇,这也是对洛奇付出的最大鼓励。扫下面的二维码赞赏洛奇,金额随意:
洛奇自己维护了一个公众号“洛奇看世界”,一个很佛系的公众号,不定期瞎逼逼。公号也提供个人联系方式,一些资源,说不定会有意外的收获,详细内容见公号提示。扫下方二维码关注公众号: