各位看官好,上一篇文章我們聊了一下關(guān)于
OTA 升級(jí)過(guò)程中,新的
軟件包是如何
從開(kāi)發(fā)者的電腦上,安全的下載到
嵌入式設(shè)備中的。
這個(gè)流程似乎很簡(jiǎn)單,不就是下載一個(gè)文件而已嘛,怎么還值得寫(xiě)成一篇文章呢?
其實(shí)這
不僅僅是下載文件這么簡(jiǎn)單,這其中涉及到如何對(duì)眾多的終端設(shè)備進(jìn)行
批量升級(jí)的策略問(wèn)題。
如果你親自在AWS的平臺(tái)上操刀一次,就知道這其中有很多
細(xì)節(jié)問(wèn)題是需要考慮的。
一失足成千古恨哪!一旦設(shè)備升級(jí)策略忽略了一個(gè)小細(xì)節(jié),也許某一天就是我們的深淵!

包括產(chǎn)品的
生產(chǎn)過(guò)程也是如此,那些踩過(guò)的坑,真是一把鼻涕一把淚,這個(gè)問(wèn)題后面有時(shí)間專(zhuān)門(mén)寫(xiě)一篇。
今天,我們繼續(xù)OTA升級(jí)過(guò)程中后續(xù)的階段。
還記得我們之前的假設(shè)嗎?
設(shè)備中正在執(zhí)行的V1版本的程序,包括這3個(gè)文件,它們位于文件系統(tǒng)中的/root/app目錄下:
main: 主程序;
config.ini: 配置文件(包括一個(gè)配置項(xiàng):version=V1_0);
mylib.so: 實(shí)現(xiàn)了某個(gè)算法的動(dòng)態(tài)庫(kù),被 main 程序調(diào)用;
現(xiàn)在,新的版本V2優(yōu)化了算法,壓縮包名稱(chēng)是app_V2.0.tgz,其中包括文件:
main: 沒(méi)有變化;
config.ini: 配置項(xiàng)修改了:version=V2_0;
mylib.so: 優(yōu)化了算法,主要就是想升級(jí)這個(gè)動(dòng)態(tài)庫(kù);
upgrade.sh: 一個(gè)腳本程序,新增的文件;
升級(jí)包app_V2.0.tgz已經(jīng)被下載到設(shè)備本地的文件系統(tǒng)中了,假設(shè)解壓到目錄/root/upgrade中。
現(xiàn)在需要做的事情就是:新版本程序,去替代/root/app目錄中的舊版本程序。
upgrade.sh 升級(jí)腳本
我們首先要明白一個(gè)問(wèn)題:執(zhí)行升級(jí)指令、下載壓縮包,都是此刻
正在執(zhí)行的main程序來(lái)執(zhí)行的。
如果把
復(fù)制替換的操作也讓main程序來(lái)執(zhí)行的話(huà),肯定是會(huì)出問(wèn)題的:它不可能去復(fù)制一個(gè)新的main文件,來(lái)
把自己替換掉!

寫(xiě)過(guò)
單片機(jī)程序的小伙伴肯定都知道:當(dāng)新的固件下載到flash之后,一般都是重新啟動(dòng)設(shè)備,然后由bootloader來(lái)執(zhí)行具體的文件復(fù)制操作。
那么對(duì)于帶有
文件系統(tǒng)的設(shè)備來(lái)說(shuō),也可以模仿類(lèi)似的操作方式。
比如:當(dāng)設(shè)備重新啟動(dòng)后,當(dāng)執(zhí)行/etc/rc.local時(shí),此時(shí)main應(yīng)用程序還沒(méi)有啟動(dòng)。
此時(shí)就可以在rc.local這個(gè)文件中去做升級(jí)操作。
但是這樣的方式,相當(dāng)于是輕微的
侵入了操作系統(tǒng),總感覺(jué)這樣做不太好。
此刻,upgrade.sh升級(jí)腳本開(kāi)始登場(chǎng)了!

這個(gè)腳本文件的主要作用就是用來(lái)
控制升級(jí)過(guò)程。
這里隱藏這一個(gè)很重要的思想:upgrade.sh
是放在升級(jí)包中的,它并沒(méi)有固化在終端設(shè)備中。
這樣的話(huà),
每次執(zhí)行升級(jí)任務(wù)時(shí),都可以根據(jù)
本次的升級(jí)需要,來(lái)
靈活的編寫(xiě)升級(jí)腳本。
換句話(huà)說(shuō):只要能保證升級(jí)的
通道沒(méi)有問(wèn)題,那么升級(jí)的過(guò)程就
完全由這個(gè)腳本文件來(lái)控制,你想怎么搞,就怎么搞!
完全升級(jí)
所謂的
完全升級(jí),就是把舊版本的程序全部丟棄,把升級(jí)包中的新程序全部復(fù)制過(guò)去。
此時(shí),升級(jí)腳本文件upgrade.sh就完成下面這幾個(gè)主要工作:
-
停止(kill)當(dāng)前正在執(zhí)行的 V1.0 版本的程序;
-
刪除 /root/app 目錄下的所有舊文件;
-
把升級(jí)包中所有的新版本文件 /root/upgrade/* 復(fù)制到 /root/app 目錄下;
這樣的完全升級(jí)方式是最無(wú)腦、最粗魯?shù)摹?
當(dāng)然,還有一些
細(xì)節(jié)問(wèn)題是需要考慮的。比如:如果復(fù)制文件過(guò)程中出現(xiàn)錯(cuò)誤怎么辦?
還有一點(diǎn),既然剛才提到了配置文件config.ini,不知您是否會(huì)有這樣一個(gè)疑問(wèn):
如果
配置信息被用戶(hù)修改了,那么升級(jí)之后,所有的配置信息又被
恢復(fù)為默認(rèn)值了,用戶(hù)的私人配置信息全丟了怎么辦?

關(guān)于這個(gè)問(wèn)題,我們就繼續(xù)來(lái)聊一下增量升級(jí)!
增量升級(jí)
所謂的
增量升級(jí):就是升級(jí)時(shí)并
不會(huì)把
所有的文件全部進(jìn)行替換,而只是替換那些需要更新的文件。
對(duì)于我們假設(shè)的升級(jí)場(chǎng)景,只需要做2件事情:
-
替換 mylib.so 庫(kù)文件;
-
把配置文件 config.ini 中的版本字段修改為:version=V2_0;
同樣的,所有的升級(jí)過(guò)程仍然是寫(xiě)在upgrade.sh這個(gè)升級(jí)腳本中:
-
停止(kill)當(dāng)前正在執(zhí)行的 V1.0 版本的程序;
-
把 /root/upgrade/mylib.so 文件復(fù)制到 /root/app 目錄下;
-
使用 sed 命令來(lái)修改 config.ini 文件中的 version 字段;
PS:此時(shí)升級(jí)包中,只需要包含必要的文件就可以了,不需要把其他用不到的文件也放進(jìn)去了。

從我描述的文字來(lái)看,似乎
完全升級(jí)和
增量升級(jí)差別不大。
這是因?yàn)檫@里的示例太簡(jiǎn)單,如果是一個(gè)比較復(fù)雜的、有多個(gè)模塊相互配合的應(yīng)用程序,
增量升級(jí)的優(yōu)勢(shì)就明顯了。
關(guān)于OTA升級(jí)過(guò)程,就先說(shuō)這么多了,主要是以思想為主,畢竟每一個(gè)項(xiàng)目的需求場(chǎng)景是不一樣的,從大方向上明白
OTA的升級(jí)過(guò)程就可以了。
One more thing
為了表示我
不是在胡說(shuō)八道,這里提供一個(gè)很多年前的項(xiàng)目中,
升級(jí)腳本文件的模板。
在公眾號(hào)
后臺(tái)留言:601,即可收到。

另外,不知道是否有小伙伴對(duì)于ESP32中的升級(jí)流程感興趣,下次再專(zhuān)門(mén)寫(xiě)一篇ESP32模組,如何與AWS后臺(tái)通過(guò)MQTT指令進(jìn)行交互,以及固件的
下載、
升級(jí)流程。
------ End ------