最近在做rk3288 linux的OTA A/B升级方案,因此研究了一下rk3288自带的OTA升级流程,将其记录下来。

1.概述

1.1 什么是OTA升级?

OTA是Over-the-Air的简称,OTA升级可以理解为用户正常使用过程中进行升级,OTA 升级旨在升级基础操作系统、系统分区上安装的只读应用和/或时区规则。

1.2 什么是OTA A/B升级?

A/B 系统升级(也称为无缝更新)的目标是确保在OTA升级期间在磁盘上保留一个可正常启动和使用的系统。

1.3 rk3288分区信息

参考:https://github.com/rockchip-linux/docs/blob/master/Tools/Rockchip-Parameter-File-Format-Version1.4.pdf

Rockchip android系统平台使用parameter文件来配置一些系统参数,比如固件版本,存储器分区信息等。

以下是一个典型的parameter.txt文件内容:

FIRMWARE_VER: 8.1
MACHINE_MODEL:rk3288
MACHINE_ID:007
MANUFACTURER:RK3288
MAGIC: 0x5041524B
ATAG: 0x00200800
MACHINE: 3288
CHECK_MASK: 0x80
PWR_HLD: 0,0,A,0,1
TYPE: GPT
CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(trust),0x00002000@0x00008000(misc),0x00010000@0x0000a000(boot),0x00010000@0x0001a000(recovery),0x00010000@0x0002a000(backup),0x00020000@0x0003a000(oem),0x00700000@0x0005a000(rootfs),-@0x0075a000(userdata:grow)
uuid:rootfs=614e0000-0000-4b53-8000-1d28000054a9

这里重点关注其中的CMDLINE中的MTD分区定义:

例如:0x00700000@0x0005a000(rootfs),@符号之前的数值是分区大小,@符号之后的数值是分区的起始位置,括号里面的字符是分区的名字。所有数值的单位是sector,1个sector为512Bytes。此处定义了一个名为rootfs的分区,其大小为0x00700000个sector(3GB),起始位置为0x0005a000个sector(180MB)。

1.4 rk3288 linux SDK获取

参考https://github.com/rockchip-linux/docs/blob/master/Rockchip_Developer_Guide_Linux_Software_CN.pdf

以下代码路径均以SDK为根

2.rk3288 OTA升级

2.1 升级流程

  1. 运行update程序,命令为update ota /path/to/update.img
  2. update程序解析update.img文件,升级recovery分区
  3. update程序将升级指令写入misc分区,重启
  4. 重启后进入uboot,uboot解析misc分区中的命令,如果是升级指令,则从recovery分区引导
  5. 进入recovery模式,执行rkupdate程序,该程序将update.img中包含的各分区包写入到对应位置,然后清除misc分区中的命令,完成升级
  6. 重启,进入正常使用

rk3288 OTA升级流程涉及到update程序,misc分区,uboot,recovery分区,rkupdate程序。

2.2 update程序

update程序的源码位于buildroot/package/rockchip/update/路径下,进行OTA升级时其代码调用路径如下:

main()->WriteFwData()->GetFwSize()   # get update.img's size->GetFwOffset() # get firmware offset in update.img->if recovery partition exist both in flash and update.img, read it from update.img and write to flash->CheckFwData() # binary check recovery partition's data->rebootUpdate()->installPackage()->bootCommand() # write struct android_bootloader_message to misc partition offset 16 *1024, then rebootstruct android_bootloader_message {char command[32];char status[32];char recovery[768];/* The 'recovery' field used to be 1024 bytes.  It has only ever* been used to store the recovery command line, so 768 bytes* should be plenty.  We carve off the last 256 bytes to store the* stage string (for multistage packages) and possible future* expansion. */char stage[32];/* The 'reserved' field used to be 224 bytes when it was initially* carved off from the 1024-byte recovery field. Bump it up to* 1184-byte so that the entire bootloader_message struct rounds up* to 2048-byte. */char reserved[1184];
};

可见,update程序主要功能是:

  1. 如果update.img文件中包括recovery分区内容,则升级recovery分区
  2. 将android_bootloader_message写入misc分区16KB偏移处,android_bootloader_message中包含了下次启动时供uboot读取的升级指令

2.3 uboot启动流程

uboot源码位于u-boot/目录下,rk3288开机默认执行的是boot_android指令,该指令对应的入口为do_boot_android(),位于u-boot/cmd/boot_android.c

do_boot_android()->android_bootloader_boot_flow()->part_get_info_by_name("misc", ...)->android_bootloader_load_and_clear_mode()->if ANDROID_BOOT_MODE_NORMAL->boot part is ANDROID_PARTITION_BOOT->if ANDROID_BOOT_MODE_RECOVERY->boot part is ANDROID_PARTITION_RECOVERY->if ANDROID_BOOT_MODE_BOOTLOADER->android_bootloader_boot_bootloader()->android_image_load(boot_part_info, ...)->android_assemble_cmdline()->android_bootloader_boot_kernel()->do_bootm()->...

可见,uboot启动时从misc分区中获取command用以决定从哪个分区读取内核。OTA升级时会从recovery分区引导。

2.4 recovery分区

recovery分区启动后会启动recovery程序,recovery程序的源码位于external/recovery/目录下,recovery程序是AOSP(Android Open Source Project)提供的,rockchip在其基础上改动,增加了对rkupdate程序的调用。具体的recovery分区和recovery程序的代码由于没有走读,故此略过。

2.5 rkupdate程序

rkupdate程序位于external/rkupdate/目录下,OTA升级时,其调用流程如下:

main()->do_rk_firmware_upgrade()->CRKAndroidDevice::GetFlashInfo()->CRKAndroidDevice::DownloadImage()->get struct STRUCT_RKIMAGE_HDR from update.img->for item in update.img do CRKAndroidDevice::RKA_File_Download()->for item in update.img do CRKAndroidDevice::RKA_File_Check()

3.OTA A/B升级方案

通过前面的分析,参考AOSP的A/B升级方案(https://source.android.google.cn/devices/tech/ota/ab)rk3288 OTA A/B升级可以基于现有的OTA升级流程进行修改实现。

3.1 分区信息修改

修改parameter.txt,支持slot A和slot B,slot A包括boot_a分区和system_a分区,slot B包括boot_b分区和system_b分区。

典型的A/B parameter.txt如下:

FIRMWARE_VER: 8.1
MACHINE_MODEL:rk3288
MACHINE_ID:007
MANUFACTURER:RK3288
MAGIC: 0x5041524B
ATAG: 0x00200800
MACHINE: 3288
CHECK_MASK: 0x80
PWR_HLD: 0,0,A,0,1
TYPE: GPT
CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(trust),0x00002000@0x00008000(misc),0x00010000@0x0000a000(boot_a),0x00010000@0x0001a000(boot_b),0x00010000@0x0002a000(recovery),0x00010000@0x0003a000(backup),0x00400000@0x0004a000(system_a),0x00400000@0x0044a000(system_b),0x00020000@0x0084a000(oem),-@0x0086a000(userdata:grow)
uuid:rootfs=614e0000-0000-4b53-8000-1d28000054a9

上面的分区信息中保留了recovery分区,在实施时可以去掉。

3.2 uboot修改

uboot中原本包含了A/B启动的代码,主要需要将u-boot/configs/rk3288_defconfig修改;由于现在不再进入recovery模式,还需要修改u-boot/common/android_bootloader.c中android_bootloader_boot_flow()中对启动模式的判断部分。其中u-boot/configs/rk3288_defconfig需要增加以下内容:

+CONFIG_SHA256=y
+CONFIG_AVB_LIBAVB=y
+CONFIG_AVB_LIBAVB_AB=y
+CONFIG_AVB_LIBAVB_ATX=y
+CONFIG_AVB_LIBAVB_USER=y
+CONFIG_RK_AVB_LIBAVB_USER=y
+CONFIG_ANDROID_AB=y

打开CONFIG_ANDROID_AB后,android_bootloader_boot_flow()中会增加对A/B分区的选择,其调用流程如下:

android_bootloader_boot_flow()->rk_avb_get_current_slot()->rk_avb_ab_slot_select()->avb_ab_data_read()->read_from_partition()->avb_ab_data_verify_and_byteswap()->avb_crc32()/* Struct used for recording per-slot metadata.** When serialized, data is stored in network byte-order.*/
typedef struct AvbABSlotData {/* Slot priority. Valid values range from 0 to AVB_AB_MAX_PRIORITY,* both inclusive with 1 being the lowest and AVB_AB_MAX_PRIORITY* being the highest. The special value 0 is used to indicate the* slot is unbootable.*/uint8_t priority;/* Number of times left attempting to boot this slot ranging from 0* to AVB_AB_MAX_TRIES_REMAINING.*/uint8_t tries_remaining;/* Non-zero if this slot has booted successfully, 0 otherwise. */uint8_t successful_boot;/* Reserved for future use. */uint8_t reserved[1];
} AVB_ATTR_PACKED AvbABSlotData;/* Struct used for recording A/B metadata.** When serialized, data is stored in network byte-order.*/
typedef struct AvbABData {/* Magic number used for identification - see AVB_AB_MAGIC. */uint8_t magic[AVB_AB_MAGIC_LEN];/* Version of on-disk struct - see AVB_AB_{MAJOR,MINOR}_VERSION. */uint8_t version_major;uint8_t version_minor;/* Padding to ensure |slots| field start eight bytes in. */uint8_t reserved1[2];/* Per-slot metadata. */AvbABSlotData slots[2];/* Reserved for future use. */uint8_t reserved2[12];/* CRC32 of all 28 bytes preceding this field. */uint32_t crc32;
} AVB_ATTR_PACKED AvbABData;

android_bootloader_boot_flow()流程中从misc分区的2048字节处读取struct AvbABData结构,然后根据SLOT的priority,tries_remaining,和successful_boot判断从SLOT A还是SLOT B启动,具体的判断逻辑代码如下:

static bool slot_is_bootable(AvbABSlotData* slot) {return (slot->priority > 0) && (slot->successful_boot || (slot->tries_remaining > 0));
}if (slot_is_bootable(&ab_data.slots[0]) && slot_is_bootable(&ab_data.slots[1])) {if (ab_data.slots[1].priority > ab_data.slots[0].priority) {slot_index_to_boot = 1;} else {slot_index_to_boot = 0;}} else if(slot_is_bootable(&ab_data.slots[0])) {slot_index_to_boot = 0;} else if(slot_is_bootable(&ab_data.slots[1])) {slot_index_to_boot = 1;} else {avb_error("No bootable slots found.\n");ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS;goto out;}if (slot_index_to_boot == 0) {strcpy(select_slot, "_a");} else if(slot_index_to_boot == 1) {strcpy(select_slot, "_b");}

3.3 rkupdate修改

rkupdate程序的修改涉及以下:

  1. 获取当前系统是SLOT A还是SLOT B,可以从/proc/cmdline中读取,如:androidboot.slot_suffix=_a,该参数是uboot启动内核时设置的参数,可以参见uboot代码
  2. 由于现在有两个SLOT,因此修改更新flash的流程,如果当前系统是SLOT A,则更新SLOT B对应的数据
  3. 更新misc中struct AvbABData,位于misc分区2048字节位置。

rk3288 linux OTA A/B升级分析相关推荐

  1. linux ab双分区升级,AB 系统OTA升级

    A/B System 概述 Android从7.0开始,引入了新的OTA升级方式 A/B System Updates A/B系统是指设备上有A和B两套可以工作的系统(用户数据只有一份,为两套系统共用 ...

  2. android 系统(154)----OTA制作及升级过程

    OTA制作及升级过程 1.概述 1.1   文档概要 前段时间学习了AndroidRecovery模式及OTA升级过程,为加深理解和防止以后遗忘,所以写这篇文档进行一个总结和梳理,以便日后查阅回顾.文 ...

  3. OTA制作及升级过程笔记

    1.概述 1.1   文档概要 前段时间学习了AndroidRecovery模式及OTA升级过程,为加深理解和防止以后遗忘,所以写这篇文档进行一个总结和梳理,以便日后查阅回顾.文档主要包括两部分,第一 ...

  4. OTA制作及升级过程

    OTA制作及升级过程 1.概述 1.1 文档概要 前段时间学习了AndroidRecovery模式及OTA升级过程,为加深理解和防止以后遗忘,所以写这篇文档进行一个总结和梳理,以便日后查阅回顾.文档主 ...

  5. OTA制作及升级过程笔记【转】

    本文转载自:http://www.it610.com/article/5752570.htm 1.概述 1.1   文档概要 前段时间学习了AndroidRecovery模式及OTA升级过程,为加深理 ...

  6. android ota服务器搭建,Android OTA 差分包升级

    稍作修改,因为直接用会有些错误 另外附上超详细的recovery模式update.zip升级分析说明的地址: 根目录下两个命令: 1.make --会生成系统的img文件,system.img,boo ...

  7. “linux性能”工具集助力分析优化Linux

    序 这段时间的工作全都扔在了Linux性能分析优化上. 看"一点"的优化,测试程序能轻松完成数据统计,并且自定义程度高:但"全局"的优化,或是在"侦查 ...

  8. Android原生OTA和Recovery升级过程步骤

    本文介绍了Android原生OTA和Recovery升级过程步骤. 进入升级 - 1.1 正常启动和进入Recovery的区别 下面给出了升级流程的简单示意图. 上图中的上下两个部分,上面一部分是正常 ...

  9. linux病毒木马分析,Linux平台“盖茨木马”分析

    最近对Linux.BackDoor.Gates.6的一个病毒样本进行了分析,通过调查发现Linux盖茨木马是一类有着丰富历史,隐藏手法巧妙,网络攻击行为显著的DDoS木马.这篇文章主要介绍了Linux ...

最新文章

  1. ASP.net MVC自定义错误处理页面的方法
  2. PAT1127 如何根据后序遍历中序遍历建树?
  3. Jquery判断元素是否隐藏:display属性状态值
  4. bootstrap 解决弹出窗口(modal) 常见问题
  5. POJ3414 Pots —— BFS + 模拟
  6. 跨域请求Ajax(POST)处理方法
  7. iis mysql端口修改_如何处理IIS和Apache之间经常端口冲突
  8. 导入html文件到onenote,onenote怎么导入文件 onenote添加文件附件的图文步骤
  9. Ubuntu14下安装使用SVN RabbitVCS客户端
  10. PDF文件如何转JPG图片?简单三步轻松转换
  11. 苹果电脑系统重装 —— U盘操作
  12. QS排名前70-100的英国大学怎么选?
  13. 网格简化 二 、QEM算法
  14. 浅谈JAVA设计模式之——责任链模式(COR)
  15. ABB机器人动作监控和无动作执行的使用
  16. 数学建模国赛2022C解题分享
  17. php artisan nohup,artisan命令生成和redis消息订阅和任务调度
  18. 信号量——P、V操作、临界资源、临界区、进程同步
  19. 设计模式学习(十一):Builder建造者模式
  20. 坚强的人:可以承受压力的品质是包容

热门文章

  1. 漫谈IT项目团队管理心得
  2. 虚幻商城模型转MetaHuman
  3. python爬取全国高校在某省的录取分数线
  4. QWebEngineView-官翻
  5. Unity UGUI如何计算drawcall
  6. 天翼物联助力杭州电信打造全国首个5G LAN全连接工厂
  7. java识别植物病虫害,水稻茎基部病害图像智能采集与病斑检测系统的设计与实现...
  8. 线程创建_同步_通信
  9. 当哪种公司做什么性质的销售才能够拿到高工资的探讨
  10. [数据库]三级模式-两级映像详解