在嵌入式系统(尤其是Rockchip平台Android设备)中,A/B(Seamless Update)无缝更新是保障系统更新不丢数据、更新失败可回滚的核心机制。而SPL(Secondary Program Loader,二级程序加载器)作为系统启动的早期阶段,负责初始化硬件、选择启动分区,spl_ab.c正是SPL层处理A/B分区启动的核心代码。本文将从函数解析、核心流程、开发意义三个维度,彻底拆解这段代码。
一、A/B分区与SPL的核心作用
A/B分区将系统分为两个独立的槽位(Slot A/Slot B),更新时先更新非当前启动的槽位,更新完成后切换槽位启动;若启动失败,自动回退到原槽位。
SPL是BootLoader的早期阶段,执行优先级最高,spl_ab.c的核心目标是:读取A/B元数据、判断槽位可启动性、选择最优启动槽位、处理启动失败后的尝试次数递减与系统重置。
二、核心函数分类解析
代码中的函数可分为7大类,覆盖“基础工具→元数据处理→槽位管理→启动流程”全链路,以下是关键函数的作用拆解:
1.基础工具函数:解决通用问题
|
函数名
|
核心作用
|
|
safe_memcmp
|
安全的内存比较,无数据依赖分支(避免侧信道攻击),返回两内存区域是否不相等(0=相等,非0=不等)
|
|
htobe32
|
主机字节序→大端字节序转换(A/B元数据存储为大端)
|
|
be32toh
|
大端字节序→主机字节序转换(读取元数据后适配本地CPU)
|
2. A/B元数据处理:校验/更新/初始化
A/B元数据(AvbABData)存储在misc分区,包含槽位优先级、剩余尝试次数、启动成功标记等关键信息,这组函数是元数据操作的核心:
|
函数名
|
核心作用
|
|
spl_ab_data_verify_and_byteswap
|
校验元数据合法性:
|
|
spl_ab_data_update_crc_and_byteswap
|
更新元数据的CRC32:先拷贝数据,再计算CRC32并转换为大端序(用于写入存储)
|
|
spl_ab_data_init
|
初始化默认元数据:
|
3.元数据读写:对接存储层
|
函数名
|
核心作用
|
|
spl_read_ab_metadata
|
从misc分区指定偏移读取元数据到内存(单次读512字节,适配块设备读写粒度)
|
|
spl_write_ab_metadata
|
将内存中的元数据写入misc分区指定偏移
|
|
spl_ab_data_read
|
封装“读取+校验”:读取失败/校验失败时,初始化新元数据并写入misc分区
|
|
spl_ab_data_write
|
封装“更新CRC+写入”:先更新CRC32,再写入存储
|
4.槽位选择:核心决策逻辑
|
函数名
|
核心作用
|
|
spl_slot_is_bootable
|
判断槽位是否可启动:优先级>0且(已成功启动 或 剩余尝试次数>0)
|
|
spl_get_lastboot
|
获取上次启动的槽位索引(0=A,1=B)
|
|
spl_get_current_slot
|
选择当前要启动的槽位(核心函数):
|
5.分区名处理:适配槽位后缀
|
函数名
|
核心作用
|
|
spl_ab_append_part_slot
|
给分区名追加槽位后缀(如boot→boot_a);misc分区例外(无后缀);获取槽位失败时直接返回原分区名
|
6.槽位状态管理:处理启动失败
|
函数名
|
核心作用
|
|
spl_slot_set_unbootable
|
标记槽位为不可启动:优先级、剩余尝试次数、启动成功标记全置0
|
|
spl_slot_normalize
|
规范化槽位状态(处理非法场景):
|
|
spl_ab_decrease_tries
|
启动失败时减少当前槽位尝试次数:
|
|
spl_ab_decrease_reset
|
启动失败后重置系统:
|
7.启动参数传递:对接内核
|
函数名
|
核心作用
|
|
spl_ab_bootargs_append_slot
|
给设备树(FDT)的启动参数(bootargs)追加槽位后缀(如android.slot_suffix=_a),让内核感知当前启动槽位
|
三、SPL阶段A/B启动核心流程图

四、开发者关注这段代码的核心意义
对于嵌入式开发者(尤其是Rockchip/Android BootLoader开发者),理解spl_ab.c是保障A/B启动稳定的关键,核心价值体现在5个方面:
1.快速定位启动故障
当设备出现“A/B启动失败、卡在SPL阶段、槽位切换异常”时,可通过代码日志(如“CRC32 does not match”“No bootable slots found”)定位根因:
•元数据CRC不匹配:misc分区损坏,spl_ab_data_read会自动初始化元数据;
•无可用槽位:两槽位尝试次数耗尽,需手动重置元数据;
•槽位被标记为不可启动:检查spl_slot_normalize是否触发了非法状态处理。
2.定制A/B更新策略
默认逻辑可根据产品需求调整:
•调整默认优先级/尝试次数:修改spl_ab_data_init中的AVB_AB_MAX_PRIORITY/AVB_AB_MAX_TRIES_REMAINING;
•自定义槽位选择规则:修改spl_get_current_slot(如优先级相同时选上次启动的槽位,而非默认的Slot A);
•调整启动失败后的行为:修改spl_ab_decrease_reset(如增加重试次数阈值,或取消自动重置)。
3.适配不同硬件平台
不同存储设备(eMMC/NAND/SD卡)的块设备读写(blk_dread/blk_dwrite)逻辑有差异,需确保spl_read/write_ab_metadata适配硬件;不同CPU架构的字节序可能不同,需验证htobe32/be32toh的正确性。
4.提升系统稳定性
•safe_memcmp避免侧信道攻击,提升元数据比较的安全性;
•spl_save_metadata_if_changed仅在元数据变化时写入存储,减少misc分区的写操作,延长存储寿命;
•spl_slot_normalize处理非法状态,避免因元数据异常导致的启动逻辑崩溃。
5.适配Android无缝更新标准
Android A/B无缝更新的核心是槽位管理,这段代码是SPL层对接Android A/B规范的关键,确保更新后能正确切换槽位启动,失败时自动回滚,符合Google的A/B更新标准。
五、总结
spl_ab.c是SPL阶段A/B分区启动的“大脑”,从元数据读写、槽位决策到启动失败处理,覆盖了A/B启动的全核心流程。对于嵌入式开发者而言,理解这段代码不仅能快速定位启动故障,还能根据产品需求定制更新策略,保障设备在无缝更新场景下的稳定性与兼容性。
无论是调试A/B启动问题,还是适配新硬件平台,spl_ab.c都是必须深入掌握的核心模块——它是连接硬件初始化与系统启动的关键桥梁,也是保障Android无缝更新落地的基础。
-
Android
+关注
关注
12文章
4021浏览量
133744 -
嵌入式系统
+关注
关注
41文章
3739浏览量
133518 -
代码
+关注
关注
30文章
4965浏览量
73758 -
spl
+关注
关注
0文章
22浏览量
16732 -
Rockchip
+关注
关注
0文章
90浏览量
19546
发布评论请先 登录
Microchip 93XX66A/B/C系列4Kbit低电压串行EEPROM深度解析
PCA9545A/45B/45C:4通道I2C总线开关的深度解析
U-Boot SPL核心文件spl.c深度解析:从启动流程到调试优化
深入解析U-Boot TPL代码:嵌入式启动的“第一棒”背后的秘密
全新VisionFive 2无法启动怎么解决?
深入解析rk平台Android Bootloader核心代码:从启动流程到AVB验证
德州仪器LM5100A/B/C和LM5101A/B/C系列高压栅极驱动器的深度解析
Texas Instruments LM5100A/B/C和LM5101A/B/C高压栅极驱动器深度解析
d1哪吒开发板的启动流程分析
国产!全志T113-i 双核Cortex-A7@1.2GHz 工业开发板—eMMC配置核心板使用说明(二)
深度解析SPL阶段A/B分区启动:spl_ab.c代码全拆解
评论