对远程升级OTA和相关控制的思考
远程控制OTA说明
远程升级 OTA(Over The Air,空中下载)是一种通过移动通信网络进行软件更新的技术,它可以在不使用任何物理连接的情况下,直接对设备进行软件更新。与传统的软件更新方式相比,OTA 更加方便快捷,可以大大减少用户更新软件的时间和成本。
相关控制是指对 OTA 更新过程的控制,包括更新的时间、更新的内容、更新的顺序等方面的控制。相关控制对于 OTA 更新至关重要,因为它可以确保更新的安全性和稳定性,防止更新过程中出现意外情况。
总体来说,OTA 和相关控制是一种非常方便和高效的软件更新技术,可以帮助用户更好地使用设备,并提高设备的可靠性和安全性。
一个通用的 OTA 服务管理平台需包含以下功能:
- 更新包的管理:需要对更新包进行管理和验证,确保其完整性和真实性。同时,还需要对更新包进行加密和压缩,以保障更新的安全性和效率。
- 更新过程的控制:需要设计相关控制功能,包括更新的顺序、更新的时间、更新的内容等。这些控制功能可以确保更新的安全性和稳定性,防止更新过程中出现意外情况。
- 更新状态的管理:需要对更新状态进行管理,包括更新包的下载、安装、验证等状态。同时,还需要提供相应的接口和功能,以方便用户和管理员查询更新状态。
- 用户界面设计:需要提供友好的用户界面,以方便用户进行软件更新。用户界面应该包括更新包的下载、安装、验证等过程的管理,同时还需要提供相应的提示和帮助信息,以方便用户进行操作。
- 系统兼容性:需要考虑系统的兼容性问题,以确保OTA更新可以兼容不同的设备和操作系统。
- 网络安全性:需要考虑网络安全性问题,以防止更新包在传输过程中被窃取或篡改。可以采用加密和数字签名等技术,保障更新的安全性和真实性。
总体来说,远程升级 OTA 和相关控制功能的设计需要综合考虑安全性、稳定性、效率、易用性等方面的问题,以确保 OTA 更新的可靠性和可用性。
业务现状分析
随着业务不断发展,公司平台运营的飞机数量将在可预见的未来逐渐增加,业务的发展也对运维提出了更高的要求。
当前平台运营飞机共14架,受各方管理限制,每日对飞机进行升级或维护等操作的时间有限。
近期,随着新功能不断完成研发,对飞机相关系统的升级也相应频繁。该过程可简化为对远程设备的软件升级,使用 OTA 技术已成为必然选择。
当前,系统已支持多种 OTA 命令,可通过多种命令组合实现对远程设备的相应控制,但该过程仍存在缺陷和可优化处。 为进一步加强对 OTA 技术的应用以减少运营压力,有必要对比进行较深入的研究。
系统设计优化
当前远端系统由多个版本,此处将其简化为一个通用模块 ASL 进行以下探讨。 为保证系统稳定,需遵守如下基本设计原则:
- OTA 模块需独立于 ASL
- OTA 模块需有备份
- OTA 模块需访问网络和访问系统目录的权限
- OTA 模块需尽可能延长存活时间
基于以上 OTA 设计原则,远端服务的最简结构需包含一个 ASL 和两个 OTA 模块。 物理机结合 docker 可创建如下合理部署方案:
- 全物理机部署:ASL、OTA-P1、OTA-P2
- 物理机+Docker方案一:Docker ASL、物理机 OTA-P1 和 OTA-P2
- 物理机+Docker方案二:Docker1 ASL、Docker2 OTA-P1、物理机 OTA-P2
- 物理机+Docker方案三:Docker ASL 和 OTA-P1、物理机 OTA-P2
- 全Docker方案一:Docker1 ASL 和 OTA-P1、Docker2 OTA-P2
- 全Docker方案二:Docker ASL、OTA-P1、OTA-P2
为保证 OTA 正常运行,当其运行在 Docker 内且与 ASL 间隔部署时,需确保 OTA 可通过 SSH 访问宿主机命令。
另,OTA 作为有限功能的远端组件,适合使用 C/C++、Golang 等语言开发。
OTA 生命周期
地面系统升级模板
OTA 可根据具体需求设计成一键自动执行或步进式执行。 地面系统可创建升级模板,多个升级任务可配置先后顺序。该功能可扩展,暂不讨论。
key | 名称 | 说明 |
---|---|---|
name | 任务名 | |
type | 任务类型 | plan 计划任务<br>now 立即执行 |
startTime | 任务开始时间 | |
pid | 前置任务 id | |
status | 任务状态 | new 新建任务<br>enabled 任务开启<br>pause 任务暂停<br>cancel 任务取消 |
netPermit | 任务执行时的网络状态 | 4g 仅4G下执行<br>sat 仅卫星下执行<br>all 任意网络类型即可 |
tailNo | 机尾号 | |
serviceName | 升级目标服务名称 | |
auto | 是否自动执行 | |
fileUrl4g | 4G环境下的文件下载地址 | 配合netPermit |
fileUrlSat | 卫星环境下的文件下载地址 | 配合netPermit |
fileMd5 | 更新文件的MD5 | |
downloadPermit | 是否允许下载更新文件 | |
downloadResult | 下载更新文件后与MD5的对比结果 | |
upgradePermit | 是否允许执行更新操作 | |
upgradeCommand | 更新操作 shell 命令 | |
upgradeRetryCount | 更新失败后的重试次数 | |
upgradeResult | 更新结果 | |
upgradeSuccessFallback | 更新成功后执行的 shell 命令 | |
upgradeFailFallback | 更新失败后执行的 shell 命令 | 在 upgradeRetryCount 重试后执行 |
backup | 是否执行备份操作 |
该升级模板为简易示例,其主要目的为规定一次OTA升级过程中每个步骤的前因后果与相互间的执行顺序。这种明确的执行模板在远程命令执行过程中及其重要,它将避免远端系统在网络连接断开时无法获取下一步指令而陷入宕机状态,是系统正确执行和自我恢复的重要保证。
远端功能开发
在地面系统创建升级模板后,远端若想正确执行该模板仍面临以下问题。
- 远端接口固定,仅能解析固定格式数据。
- 远端接口有限,无法对每一步都进行单独处理。
基于以上问题,可假设远端系统需支持在任意时刻接收到任意状态的升级命令都能正确执行的功能。又由于升级命令需按指定顺序和状态执行,故开发中应使用”责任链模式“,”状态模式“无法保证任务执行顺序。
简易功能设计如下(以通关游戏为例):
/*
* 抽象升级处理类
*/
public abstract class AbstractUpgradeHandler {
protected AbstractHandler next;
public void setNext(AbstractHandler next) {
this.next = next;
}
public abstract int handler();
}
public class FirstPassHandler extends AbstractUpgradeHandler{
private int play(){
return 80;
}
@Override
public int handler(){
System.out.println("第一关-->FirstPassHandler");
int score = play();
if(score >= 80){
//分数>=80 并且存在下一关才进入下一关
if(this.next != null){
return this.next.handler();
}
}
return score;
}
}
public class SecondPassHandler extends AbstractUpgradeHandler{
private int play(){
return 90;
}
public int handler(){
System.out.println("第二关-->SecondPassHandler");
int score = play();
if(score >= 90){
//分数>=90 并且存在下一关才进入下一关
if(this.next != null){
return this.next.handler();
}
}
return score;
}
}
public class ThirdPassHandler extends AbstractUpgradeHandler{
private int play(){
return 95;
}
public int handler(){
System.out.println("第三关-->ThirdPassHandler");
int score = play();
if(score >= 95){
//分数>=95 并且存在下一关才进入下一关
if(this.next != null){
return this.next.handler();
}
}
return score;
}
}
/**
* 组装处理
*/
public class HandlerClient {
public static void main(String[] args) {
FirstPassHandler firstPassHandler = new FirstPassHandler();//第一关
SecondPassHandler secondPassHandler = new SecondPassHandler();//第二关
ThirdPassHandler thirdPassHandler = new ThirdPassHandler();//第三关
// 和上面没有更改的客户端代码相比,只有这里的set方法发生变化,其他都是一样的
firstPassHandler.setNext(secondPassHandler);//第一关的下一关是第二关
secondPassHandler.setNext(thirdPassHandler);//第二关的下一关是第三关
//说明:因为第三关是最后一关,因此没有下一关
//从第一个关卡开始
firstPassHandler.handler();
}
}
注意
由于远端系统存在诸多不确定性,最稳妥的方式为每一步都向地面系统进行确认,得到明确答复后再执行后续步骤,且需支持临时修改命令的功能。
后续
该设计仅为当前工作环境下的场景抽象,具体实现方法需根据实际环境进行调整。