嵌入式 Linux 开发 10:软件升级

简介软件升级

无论是修复软件缺陷,还是提高系统性能或添加新功能,软件升级都是不可避免的。
升级一台嵌入式 Linux 设备要考虑的因素有:存储设备类型,文件系统和软件独立性。

以下 3 种方法都可以实现软件升级。

  • 本地更新:技术人员使用 U 盘或 TF 卡逐个更新每台 Linux 设备。
  • 远程更新:用户或技术人员从远程服务器下载更新。
  • 无线更新:完全远程推送和管理更新,无须本地操作。

嵌入式 Linux 设备的设计和实现非常多样化。但是,它们都具有以下基本组件。

  • 引导加载程序:一般不需要更新,它仅在开机时运行很短的时间,通常不是错误的重要来源。
  • 内核:添加新功能和驱动时需要更新内核文件,这包括 kernel DTB(Device Tree Binary)和内核模块。
  • 根文件系统:修复系统缺陷,提高性能或增加功能需要更新根文件系统,这包括基本系统库,实用程序和脚本。
  • 系统应用程序:这是设备的主要有效载荷,负责设备的主要功能,它们可能会经常更新以修复错误并添加功能。
  • 与特定设备相关的数据:一般需要在更新期间被保留,包括配置设置,日志,用户提供的数据等。

软件升级需要实现 3 个原则。

稳定可靠:不会因更新而导致设备无法使用。关键在于原子性(atomicity)包括:

  • 对称(A/B)镜像更新(Symmetric Image Update)
  • 非对称镜像更新(Asymmetric Image Update)
  • 原子文件更新(Atomic File Update)

故障安全:在所有其他方法都失败时还有一个备用模式。下面以 U-Boot 为例:

  • bootcount:每次引导时,该计数都会递增。
  • bootlimit:如果 bootcount 超过 bootlimit,则运行 altbootcmd 中的命令(取代 bootcmd 中的命令)。
  • altbootcmd:包含备用引导命令,例如,回滚到先前版本的软件或启动恢复模式操作系统。
  • fw_setenv:允许用户空间程序重置引导计数。
  • upgrade_available:在安装更新后被设置为1(开启bootcount递增),新系统成功运行后设置为0(禁止bootcount递增)。

安全机制:防止设备被人劫持,安装未经授权的更新。

  • 在开始下载之前对更新服务器进行身份验证,使用安全的传输通道,如 HTTPS 以防止篡改下载流。
  • 工厂对内核镜像使用数字密钥签名,引导加载程序可以在加载内核之前检查密钥,如果密钥不匹配,则拒绝加载它。
  • U-Boot 实现了检查内核密钥的机制,详细描述在 doc/uImage.FIT/verified-boot.txt 中。

更新机制的类型

方法 原理 缺点 开源项目
对称镜像更新 下载新镜像到"非工作区"->修改引导标志->加载新系统 更新包大下载慢,存储空间要求多 Mender SWUpdate RAUC fwup
非对称镜像更新 恢复系统下载新镜像到"主系统区"->清除引导标志->加载新系统 运行恢复系统时设备无法正常运转 SWUpdate RAUC
原子文件更新 更新"非工作"目录树->下次引导时使用 chroot 挂载为根目录 实现复杂,使用较困难 OSTree(libOSTree)

OTA 更新

无线(over-the-air, OTA)更新意味着能够通过网络将软件推送到设备或设备组,通常无须最终用户与设备进行任何交互。
这需要一个中央服务器来控制更新过程,设备需要安装更新客户端,还需要一个让这二者通信的协议。

  • 客户端不时地轮询更新服务器以检查是否有任何更新,通常是几十分钟到几个小时的间隔。
  • 来自设备的轮询消息包含某种唯一标识符(如序列号或 MAC 地址)以及当前软件版本,更新服务器可以查看是否需要更新。
  • 更新服务器将新版本的软件分发给设备,追踪设备的当前状态,并突出显示问题。
  • 客户端和服务器通过交换证书来相互验证,客户端可以验证已下载的升级软件包是否由预期的密钥签名。
  • 可以用于 OTA 更新的 3 个开源项目: Mender, Balena, Eclipse hawkBit(with SWUpdate or RAUC)

“失效安全性”(fail-safe)的升级方案

一个 fail-safe 的软件升级是原子性的,就像一笔数据库交易,最终只有 2 种状态

  • 升级成功后,启动有效的新版软件
  • 升级失败后,启动有效的旧版软件

因为 Linux 软件包含各种不同的文件,包括可执行文件,共享程序库,设备文件,内核镜像--它们都可能存在依赖关系。
逐文件(file by file)进行升级是不现实的,必须对整个文件系统进行处理。

如下图所示,进行 fail-safe 更新的流程如下

  • 将 image_new 下载到 MTD 存储设备分区
  • 检查 image_new 正确性(如检查 CRC 或加密签章)以确认传输无误
  • 以“原子”方式变更 boot_flag,通知 U-Boot 开机期间使用 image_new
  • 让系统重新开机

+-----------+
| u-boot  |
+-----------+
| boot_flag |
+-----------+
| image_old |
+-----------+
| image_new |
+-----------+

posted @ 2022-09-22 13:33  KevinAshton  阅读(1054)  评论(0)    收藏  举报