方案简要框图:
1 | @startuml |
根据目标镜像动态自适应调整物理分区的技术,在升级过程中不会丢失用户数据。可供项目人员灵活配置哪些分区需要特殊处理,用户在升级时可以察觉到分区是否发生了变动。Ota升级时调整分区的场景完善的断电保护方案。小存储设备上可以留给用户更多的使用存储空间
首先对于基于安卓的通用升级方案来说,是不能在ota升级的时候,根据目标版本动态修改物理分区的,这种方案存在以下弊端:
1.目前的升级方案中,不会调整物理分区,假设目标版本的某分区因新加功能或者解决bug,调整架构等需要的空间增大了。如果项目初始阶段,分区的空间分配的比较小,量产发布给用户后,因为某分区的空间不足,往往会因不能动态的调整物理分区大小而使升级时会受限。
2.由于项目需要,在发布版本给用户以后,可能需要新增分区或者删减分区,这种需求也会因为升级程序无法动态的调整物理分区而受限。
3.对于ROM 磁盘比较小的设备,由于不能动态调整分区。厂家一般采用的方案是,项目初始阶段就分配好了各分区的大小。系统分区(如system分区或modem分区等)通常留有比较大的余量为后面的升级作准备。用户是看不到也不能使用这些系统分区的。这些系统分区留有的余量只能用作升级使用,不能达到很好的利用率。对于本来就很珍贵的ROM空间,造成了浪费。
针对以上缺点,本发明的方案可以在升级时自动的识别分区的改动,并进行针对性的调整。不会丢失数据,用户可以感知到调整了物理分区。用户可以毫无顾虑的进行系统升级。对于厂家而言,减小了分区配置的难度。同时也不需要协调各分区相应模块的研发人员必须按照一定的分区大小的标准进行开发。系统升级的难度变小,厂家可以更从容的推送升级包给用户,减小了用户强升某系统版本因分区不足导致的设备变砖风险。较小了维护成本以及退修返修的概率。对于ROM比较小的设备,合理利用了ROM空间。增大了用户的可使用空间。
1. 编译系统修改
ota升级包含两个大步骤,本地对当前版本打包的过程
将升级包推送到手机中,手机进recovery子系统执行系统升级的流程。
Ota的target-files中保存了完整的用于升级的各镜像的原始信息。
通过该原始包来制作ota的整包和差分包。
在展讯平台上通过xml文件管理手机设备中的物理分区。
在存储容量比较小的设备上,为了留给用户尽量多的内部存储空间,需要将system分区的空间尽量减小。在编译时将xml中关于system分区大小的部分修正为自适应分区后的大小。(推送给用户的版本一般是只读的,debug版本需要留给system分区一定的余量方便研发人员调试)
编译target-files文件时,需要将xml拷贝到target-files压缩文件中。拷贝时检索xml中是否含有Product、ProductList、 Partitions等关键字(预定的关键tag信息,分区的信息是里面的元素),同时包含这些关键字才进行拷贝。
2. 解析xml分区表生成配置文件
在进行整包升级,差分升级的过程中加入分区表的解析过程.
解析文件,将分区的名称,大小,分区备份以及其他一些标志位写到配置文件, 将配置文件写入到ota升级包中.
调整分区工具的参数有备份文件存放的目录,配置文件,磁盘节点名,是否为check模式等
- 整包升级时, 不需要备份system
- 差分升级, 需要备份system
3. Recovery子系统中加入检测分区变化的功能
从升级包中解压出分区表配置文件、repart二进制文件解压到设备的临时目录,调用repart进程,传入参数备份文件存放的目标目录、配置文件、磁盘节点名, check模式。
解压时,先将升级包映射到共享内存中,将压缩包中的分区配置文件转移到ramdisk中的文件里。
检测到分区变化时,根据返回码,如果有分区发生变化,弹出
“分区已经变化,是否继续?”
用户点击继续后,执行具体的升级流程。用户点击否,不再执行后面的流程,升级中止。
4. 调整物理分区工具处理分区主要流程
初始化GPT分区相关的一些通用数据结构,初始化gpt分区的加密表单。
解析传入参数(磁盘节点名称、备份路径、是否为check模式、配置文件路径)
解析配置文件,将分区信息置于一个partition的结构体中,保存各分区的名称、大小、以及有配置文件中传来的一些关于该分区的标志位。
LoadPartitions 加载主分区信息头、备份分区信息头、具体分区数据:
加载分区头及分区数据时,首先会从磁盘中load主分区头及备份分区头,通过header中的headerCRC值与整个header校验得出的CRC值进行比较,相等则该分区头是正确的数据。
该过程中会初始化设置一些GPTData数据结构中的关键信息(如numParts 、blockSize、diskSize等)
Load详细分区数据时,有两个来源(LBA2-LBA33和LBA-2 – LBA-33)。只有当数据块的CRC值与mainHeader或secondHeader的partitionEntriesCRC值匹配时,才说明是正确的数据。
如果header或详细分区数据无法匹配对应的crc,程序终止,并报错分区数据损坏
4.1. 检查分区是否有变化
遍历分区表,通过比对磁盘中的分区和配置文件中的分区表,根据以下规则确定分区是否发生了变化.
1 | @startuml |
通过如下方式判断分区有没有改变:
1.检测分区名字是否变化
2.检测分区大小是否有变化
system分区特殊处理、data分区特殊处理。(System分区特殊处理?如果system分区前面,有分区变动,认为分区变动;如果system是第一个变动的分区,
则与磁盘中的system分区大小进行比较,如果差值在经验值内,则认为此时分区没有变化,否则认为分区已经变化;如果system后面的分区变动,认为分区已经变动)。
Data分区不检测,直接忽略过去
System分区特殊处理的依据:
由于system分区是根据最终打包的system目录下的所有文件所占用的空间总量加上一定的余量做成的。每次更新版本时,system分区的大小都会变化,
而留有的余量通常也是比较小的如果每次更新版本都要因system分区的变动去调整分区,这样的设计会给用户带来非常差的体验,每次执行整包升级或差分升级都需要消耗
比较长的时间。我们给定一个经验值,判断如果这次版本与手机中已经存在的版本的system物理分区的大小小于该经验值,则认为system分区没有变动,
不需要只因为system分区的变动而调整物理分区
3.检测分区总数是否有变化
4.2. check 模式
一旦检测到分区变化,将给变化的分区位置传出来。
如果是check模式进程终止,返回结果(分区是否变化)
4.3. 非check模式
遍历partition结构体数组,变化分区的位置前面的所有分区设置备份标志为0。
根据分区变动的位置,再次判断那些分区需要备份。备份需要备份的分区到文件中。
备份时Data分区需要特殊处理,新的安卓版本中的selinux权限比较严格,升级程序不允许对data分区里的文件具有写权限。因此不能按文件拷贝data分区的内容。如果按字节直接拷贝data分区,因data分区物理分区空间较大,直接拷贝花费的时间较长。我们通过压缩文件系统,使得记录data分区文件系统的有效字节全被压缩到物理分区的前部,只需要拷贝有效的字节即可。
遍历需要备份的分区(备份标志位为1的分区),检查对应的备份文件是否已经存在,如果已经存在,将已有的文件删除。
检查外部存储剩余空间是否可以存放下备份文件。遍历需要备份的分区,根据备份标志位查看哪些分区需要备份,如果需备份的分区为data分区,需要mount 查看其已用空间,根据已用空间确定需要拷贝的大小。如果没有文件系统,则直接计算其分区大小。同时计算emmc中剩给data分区的可分配空间大小,与已用空间进行比较,如果前者比后者小,则退出程序。
计算总的备份文件需要的空间,将该大小与外部存储卡的剩余空间大小比较,如果大于外部存储卡的剩余空间,返回返回码给脚本,脚本中加逻辑表明这时的情况是外部存储卡没有空间,终止脚本执行,并在屏幕上打印此时外部存储卡的剩余空间不足。
5. 更新分区
根据分区变更的原则,更新分区数据结构中各分区的起始偏移量和终止偏移量(firstLBA和lastLBA)。
将新的分区数据结构按gpt分区的格式写入对应的四个关键地方(GPT物理分区结构图中的绿条和蓝条部分LBA1 LBA2-33 LBA-1 LBA-2–LBA-33):
写入的过程是顺序执行的,这样总能保证有一组header和entry的内容是完好的。
开机引导程序需要支持从gpt 备份header和entry中读取分区数据,同时该调整物理分区的工具也支持,这样杜绝了系统变转的风险。
6. 恢复分区
按字节或文件系统恢复相应分区的数据,system分区特殊处理,system分区的数据是只读的,不能修改,也不能挂载,只能按字节拷贝。
将Data分区有效的数据恢复回来后,需要将其文件系统扩满物理分区。每恢复完一个分区,需要将对应的备份文件删除。
6.1. 升级过程中断电保护:
需要充分考虑断电对整个升级流程的影响:
断电会打断当前的升级流程, 尤其对于备份恢复流程以及识别分区是否发生了变动,在断电后,这些判断逻辑都发生了变化。
断电后,手机会重新进入recovery模式重新从头开始进行升级过程。
需要一个标志位,标记手机重启前是否正在升级,且未完成升级过程,中间发生了意外断电。
进recovery子系统后,一旦检测到该标志位有效,忽略检测过程,不需要用户参与,即使分区没有变化,也直接进入repart程序进行分区的管理。
- 此时分区没有变动,说明 上次执行时 是在更新完分区后断电退出的,一般是恢复分区的流程进行了一部分。
需要找备份目录中存在哪些备份文件,并校验备份文件,如果校验通过,则需要将备份文件写入到对应的分区中。 - 分区发生了变动,说明上次执行时还没有更新分区就发生了断电,一般是备份分区过程中发生了断电。
对于检测到的需要备份的分区,校验已经存在的备份文件的正确性,如果校验通过,则不需要对该分区再进行从分区备份的工作。