rk3288 linux OTA A/B升级分析
最近在做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 升级流程
- 运行update程序,命令为update ota /path/to/update.img
- update程序解析update.img文件,升级recovery分区
- update程序将升级指令写入misc分区,重启
- 重启后进入uboot,uboot解析misc分区中的命令,如果是升级指令,则从recovery分区引导
- 进入recovery模式,执行rkupdate程序,该程序将update.img中包含的各分区包写入到对应位置,然后清除misc分区中的命令,完成升级
- 重启,进入正常使用
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程序主要功能是:
- 如果update.img文件中包括recovery分区内容,则升级recovery分区
- 将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程序的修改涉及以下:
- 获取当前系统是SLOT A还是SLOT B,可以从/proc/cmdline中读取,如:androidboot.slot_suffix=_a,该参数是uboot启动内核时设置的参数,可以参见uboot代码
- 由于现在有两个SLOT,因此修改更新flash的流程,如果当前系统是SLOT A,则更新SLOT B对应的数据
- 更新misc中struct AvbABData,位于misc分区2048字节位置。
rk3288 linux OTA A/B升级分析相关推荐
- linux ab双分区升级,AB 系统OTA升级
A/B System 概述 Android从7.0开始,引入了新的OTA升级方式 A/B System Updates A/B系统是指设备上有A和B两套可以工作的系统(用户数据只有一份,为两套系统共用 ...
- android 系统(154)----OTA制作及升级过程
OTA制作及升级过程 1.概述 1.1 文档概要 前段时间学习了AndroidRecovery模式及OTA升级过程,为加深理解和防止以后遗忘,所以写这篇文档进行一个总结和梳理,以便日后查阅回顾.文 ...
- OTA制作及升级过程笔记
1.概述 1.1 文档概要 前段时间学习了AndroidRecovery模式及OTA升级过程,为加深理解和防止以后遗忘,所以写这篇文档进行一个总结和梳理,以便日后查阅回顾.文档主要包括两部分,第一 ...
- OTA制作及升级过程
OTA制作及升级过程 1.概述 1.1 文档概要 前段时间学习了AndroidRecovery模式及OTA升级过程,为加深理解和防止以后遗忘,所以写这篇文档进行一个总结和梳理,以便日后查阅回顾.文档主 ...
- OTA制作及升级过程笔记【转】
本文转载自:http://www.it610.com/article/5752570.htm 1.概述 1.1 文档概要 前段时间学习了AndroidRecovery模式及OTA升级过程,为加深理 ...
- android ota服务器搭建,Android OTA 差分包升级
稍作修改,因为直接用会有些错误 另外附上超详细的recovery模式update.zip升级分析说明的地址: 根目录下两个命令: 1.make --会生成系统的img文件,system.img,boo ...
- “linux性能”工具集助力分析优化Linux
序 这段时间的工作全都扔在了Linux性能分析优化上. 看"一点"的优化,测试程序能轻松完成数据统计,并且自定义程度高:但"全局"的优化,或是在"侦查 ...
- Android原生OTA和Recovery升级过程步骤
本文介绍了Android原生OTA和Recovery升级过程步骤. 进入升级 - 1.1 正常启动和进入Recovery的区别 下面给出了升级流程的简单示意图. 上图中的上下两个部分,上面一部分是正常 ...
- linux病毒木马分析,Linux平台“盖茨木马”分析
最近对Linux.BackDoor.Gates.6的一个病毒样本进行了分析,通过调查发现Linux盖茨木马是一类有着丰富历史,隐藏手法巧妙,网络攻击行为显著的DDoS木马.这篇文章主要介绍了Linux ...
最新文章
- ASP.net MVC自定义错误处理页面的方法
- PAT1127 如何根据后序遍历中序遍历建树?
- Jquery判断元素是否隐藏:display属性状态值
- bootstrap 解决弹出窗口(modal) 常见问题
- POJ3414 Pots —— BFS + 模拟
- 跨域请求Ajax(POST)处理方法
- iis mysql端口修改_如何处理IIS和Apache之间经常端口冲突
- 导入html文件到onenote,onenote怎么导入文件 onenote添加文件附件的图文步骤
- Ubuntu14下安装使用SVN RabbitVCS客户端
- PDF文件如何转JPG图片?简单三步轻松转换
- 苹果电脑系统重装 —— U盘操作
- QS排名前70-100的英国大学怎么选?
- 网格简化 二 、QEM算法
- 浅谈JAVA设计模式之——责任链模式(COR)
- ABB机器人动作监控和无动作执行的使用
- 数学建模国赛2022C解题分享
- php artisan nohup,artisan命令生成和redis消息订阅和任务调度
- 信号量——P、V操作、临界资源、临界区、进程同步
- 设计模式学习(十一):Builder建造者模式
- 坚强的人:可以承受压力的品质是包容