OTA本质与实现流程分析
接觸OTA也有段時(shí)間了,是時(shí)候總結(jié)下了。所謂OTA(Over-the-AirTechnology)是指手機(jī)終端通過(guò)無(wú)線網(wǎng)下載遠(yuǎn)程服務(wù)器上的升級(jí)包,對(duì)系統(tǒng)或應(yīng)用進(jìn)行升級(jí)的技術(shù)。有關(guān)網(wǎng)絡(luò)部分不做過(guò)多討論,本文重點(diǎn)放在系統(tǒng)升級(jí)這一概念上。
一 OTA本質(zhì)
先以PC機(jī)進(jìn)行類(lèi)比。假設(shè)計(jì)算機(jī)操作系統(tǒng)裝在C盤(pán),當(dāng)加電啟動(dòng)時(shí),引導(dǎo)程序會(huì)將C盤(pán)的系統(tǒng)程序裝入內(nèi)存并運(yùn)行,而系統(tǒng)升級(jí)或重裝系統(tǒng),則是將C盤(pán)中原來(lái)的系統(tǒng)文件部分或全部重寫(xiě)。對(duì)于手機(jī)及其上的ANDROID系統(tǒng)而言,同樣如此,需要一個(gè)存儲(chǔ)系統(tǒng)文件的“硬盤(pán)”。
圖1 某android手機(jī)存儲(chǔ)設(shè)備結(jié)構(gòu)圖
?
圖1 是某款手機(jī)的存儲(chǔ)設(shè)備結(jié)構(gòu)圖,其存儲(chǔ)區(qū)(紅色框圖部分)分為四部分:SRAM、Nand Flash、SDRAM及外設(shè)地址空間。其中Nand Flash中存儲(chǔ)著全部系統(tǒng)數(shù)據(jù)(通過(guò)專(zhuān)門(mén)的燒寫(xiě)工具將編譯后的映象文件download到Nand Flash中,工具由IC廠商提供),包括boot.img、system.img、recovery.img等,因此Nand Flash即是上文所說(shuō)的手機(jī)上的“硬盤(pán)”。圖1最右部分(圖中綠色框圖部分)是Nand Flash存儲(chǔ)區(qū)更詳細(xì)的劃分,我們將主要關(guān)注system分區(qū)(藍(lán)色框圖),因?yàn)镺TA升級(jí)主要是對(duì)這部分系統(tǒng)數(shù)據(jù)的重寫(xiě)(當(dāng)然boot分區(qū)也可升級(jí))。除此之外,藍(lán)黑色區(qū)域標(biāo)示的misc分區(qū)也應(yīng)值得注意,它在OTA升級(jí)中發(fā)揮著重要的作用。
OK,一言以蔽之,所謂OTA就是將升級(jí)包(zip壓縮包)寫(xiě)入到系統(tǒng)存儲(chǔ)區(qū),因此我們需要考慮兩個(gè)問(wèn)題,1.升級(jí)包是如何生成的?2.升級(jí)包是如何寫(xiě)入到system分區(qū)的?
二 問(wèn)題一:升級(jí)包的制作
1.整包的制作
升級(jí)包有整包與差分包之分。顧名思義,所謂整包即包含整個(gè)system分區(qū)中的數(shù)據(jù)文件;而差分包則僅包含兩個(gè)版本之間改動(dòng)的部分。利用整包升級(jí)好比對(duì)電腦進(jìn)行重作系統(tǒng),格式分系統(tǒng)分區(qū),并將新系統(tǒng)數(shù)據(jù)寫(xiě)入分區(qū);而利用差分包升級(jí)不會(huì)格式化system分區(qū),只是對(duì)其中部分存儲(chǔ)段的內(nèi)容進(jìn)行重寫(xiě)。除升級(jí)包之外,制作過(guò)程中還會(huì)涉及到另一種zip包,代碼中稱(chēng)之為target-files zipfile,我稱(chēng)之為差分資源包。首先闡述下整包的制作過(guò)程。
系統(tǒng)經(jīng)過(guò)整編后,執(zhí)行make otapackage命令,即可完成整包的制作,而此命令可分為兩個(gè)階段進(jìn)行。首先執(zhí)行./build/core/Makefile中的代碼:
# ----------------------------------------------------------------- # OTA update packagename := $(TARGET_PRODUCT) ifeq ($(TARGET_BUILD_TYPE),debug)name := $(name)_debug endif name := $(name)-ota-$(FILE_NAME_TAG)INTERNAL_OTA_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip$(INTERNAL_OTA_PACKAGE_TARGET): KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR)$(INTERNAL_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(OTATOOLS)@echo "Package OTA: $@"$(hide) ./build/tools/releasetools/ota_from_target_files -v \-n \-p $(HOST_OUT) \-k $(KEY_CERT_PAIR) \$(ota_extra_flag) \$(BUILT_TARGET_FILES_PACKAGE) $@ .PHONY: otapackage otapackage: $(INTERNAL_OTA_PACKAGE_TARGET) # -----------------------------------------------------------------代碼段1 make otapackage目標(biāo)代碼
圖2 target-files zipfile目錄結(jié)構(gòu)
其中,OTA目錄值得關(guān)注,因?yàn)樵诖四夸浵麓嬖谥粋€(gè)至關(guān)重要的文件:OTA/bin/updater(后文會(huì)有詳述)。生成的差分資源包被傳遞給./build/tools/releasetools/
ota_from_target_files執(zhí)行第二階段的操作:制作升級(jí)包。
圖3 ./build/tools/releasetools目錄下的文件
圖3是./build/tools/releasetools目錄下所包含的文件,這組文件是Google提供的用來(lái)制作升級(jí)包的代碼工具,核心文件為:ota_from_target_files和img_from_target_files。其中,前者用來(lái)制作recovery模式下的升級(jí)包;后者則用來(lái)制作fastboot下的升級(jí)包(fastboot貌似是一種更底層的刷機(jī)操作,未過(guò)多研究,不再詳述)。其他文件則是為此二者提供服務(wù)的,比如,common.py中包含有制作升級(jí)包所需操作的代碼;edify_generator.py則用于生成recovery模式下升級(jí)的腳本文件:<升級(jí)包>.zip/ META-INF/com/google/android/updater-script。
文件ota_from_target_files是本文所關(guān)注的重點(diǎn),其中定義了兩個(gè)主要的方法:WriteFullOTAPackage和WriteIncrementalOTAPackage。前者用于生成整包,后者用來(lái)生成差分包。接著上文,當(dāng)Makefile調(diào)用ota_from_target_files,并將差分資源包傳遞進(jìn)來(lái)時(shí),會(huì)執(zhí)行WriteFullOTAPackage。此方法完成的工作包括:(1)將system目錄,boot.img等文件添加到整包中;(2)生成升級(jí)包中的腳本文件:<升級(jí)包>.zip/META-INF/com/google/android/updater-script;(3)將上文提到的可執(zhí)行文件:OTA/bin/
updater添加到升級(jí)包中:META-INF/com/google/android/updater-script。摘取部分代碼片段如下:
代碼2 WriteFullOTAPackage代碼片段
其中的script為edify_generator對(duì)象,其FormatPartition、UnpackPackageDir等方法分別是向腳本文件update-script中寫(xiě)入格式化分區(qū)、解壓包等指令。
代碼段3 ?edify_generator中的AddToZip方法
WriteFullOTAPackage執(zhí)行的最后會(huì)調(diào)用此方法。將資源差分包中OTA/bin/updater文件copy到升級(jí)包中META-INF/com/google/android/update-binary。此文件是OTA升級(jí)的關(guān)鍵,其將在recovery模式下被執(zhí)行,用來(lái)將代碼段2中生成的指令轉(zhuǎn)換為相應(yīng)的函數(shù)去執(zhí)行,從而完成對(duì)系統(tǒng)數(shù)據(jù)的重寫(xiě)。
2.差分包的制作
生成差分包調(diào)用的是文件./build/tools/releasetools/ota_from_target_files中的WriteIncrementalOTA方法,調(diào)用時(shí)需要將兩個(gè)版本的差分資源包作為參數(shù)傳進(jìn)來(lái),形如:
./build/tools/releasetools/ota_from_target_files –n –i ota_v1.zip ota_v2.zip update.zip
其中,參數(shù)n表示忽略時(shí)間戳;i表示生成增量包(即差分包);ota_v1.zip與ota_v2.zip分別代表前后兩個(gè)版本的差分資源包;而update.zip則表示最終生成的差分包。
WriteIncrementalOTA函數(shù)會(huì)計(jì)算輸入的兩個(gè)差分資源包中版本的差異,并將其寫(xiě)入到差分包中;同時(shí),將updater及生成腳本文件udpate-script添加到升級(jí)包中。
三 問(wèn)題二:將升級(jí)包寫(xiě)入系統(tǒng)存儲(chǔ)區(qū)
制作完升級(jí)包后,之后便是將其寫(xiě)入到相應(yīng)存儲(chǔ)區(qū)中,這部分工作是在recovery模式下完成的。之前的幾篇筆記亦有描述,recovery模式下通過(guò)創(chuàng)建一個(gè)新的進(jìn)程讀取并執(zhí)行腳本文件META-INF/com/google/android/updater-script。見(jiàn)如下代碼:
const char** args = (const char**)malloc(sizeof(char*) * 5);args[0] = binary;args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mkchar* temp = (char*)malloc(10);sprintf(temp, "%d", pipefd[1]);args[2] = temp;args[3] = (char*)path;args[4] = NULL;pid_t pid = fork();if (pid == 0) {close(pipefd[0]);execv(binary, (char* const*)args);_exit(-1);}close(pipefd[1]);代碼段4 創(chuàng)建新進(jìn)程安裝升級(jí)包
分析代碼之前,首先介紹linux中函數(shù)fork與execv的用法。
pid_t fork( void)
??????? 創(chuàng)建新的進(jìn)程,fork調(diào)用的一個(gè)奇妙之處就是它僅僅被調(diào)用一次,卻能夠返回兩次,它可能有三種不同的返回值:
1)在父進(jìn)程中,fork返回新創(chuàng)建子進(jìn)程的進(jìn)程ID;
2)在子進(jìn)程中,fork返回0;
3)如果出現(xiàn)錯(cuò)誤,fork返回一個(gè)負(fù)值;
??????? 在fork函數(shù)執(zhí)行完畢后,如果創(chuàng)建新進(jìn)程成功,則出現(xiàn)兩個(gè)進(jìn)程,一個(gè)是子進(jìn)程,一個(gè)是父進(jìn)程。在子進(jìn)程中,fork函數(shù)返回0,在父進(jìn)程中,fork返回新創(chuàng)建子進(jìn)程的進(jìn)程ID。我們可以通過(guò)fork返回的值來(lái)判斷當(dāng)前進(jìn)程是子進(jìn)程還是父進(jìn)程(http://os.chinaunix.net/a2012/0203/1306/000001306508.shtml)。
int execv(const char *progname, char *const argv[])
??????? execv會(huì)停止執(zhí)行當(dāng)前的進(jìn)程,并且以progname應(yīng)用進(jìn)程替換被停止執(zhí)行的進(jìn)程,進(jìn)程ID沒(méi)有改變。
??????? progname: 被執(zhí)行的應(yīng)用程序。
??????? argv: 傳遞給應(yīng)用程序的參數(shù)列表, 注意,這個(gè)數(shù)組的第一個(gè)參數(shù)應(yīng)該是應(yīng)用程序名字本身,并且最后一個(gè)參數(shù)應(yīng)該為NULL,不參將多個(gè)參數(shù)合并為一個(gè)參數(shù)放入數(shù)組。
?代碼4見(jiàn)于bootable/recovery/install.c的try_update_binary函數(shù)中,是OTA升級(jí)的核心代碼之一。通過(guò)對(duì)fork及execv函數(shù)的介紹可知,代碼4創(chuàng)建了一個(gè)新的進(jìn)程并在新進(jìn)程中運(yùn)行升級(jí)包中的META-INF/com/google/android/updater-binary文件(參數(shù)binary已在此前賦值),此文件將按照META-INF/com/google/android/updater-script中的指令將升級(jí)包里的數(shù)據(jù)寫(xiě)入到存儲(chǔ)區(qū)中。OK,我們來(lái)看下META-INF/com/google/android/updater-binary文件的來(lái)歷。
在源代碼的./bootable/recovery/updater目錄下,存在著如下幾個(gè)文件:
圖4 ./bootable/recovery/updater目錄
?
通過(guò)查看Android.mk代碼可知,文件install.c、updater.c將會(huì)被編譯為可執(zhí)行文件updater存放到目錄out/target/product/<product-name>/obj/EXECUTABLES/
updater_intermediates/中;而在生成差分資源包(target-files zipfile)時(shí),會(huì)將此文件添加到壓縮包中。
built_ota_tools := \$(call intermediates-dir-for,EXECUTABLES,applypatch)/applypatch \$(call intermediates-dir-for,EXECUTABLES,applypatch_static)/applypatch_static \$(call intermediates-dir-for,EXECUTABLES,check_prereq)/check_prereq \$(call intermediates-dir-for,EXECUTABLES,sqlite3)/sqlite3 \$(call intermediates-dir-for,EXECUTABLES,updater)/updater代碼段5 Makefile中定義的變量built_ota_tools
代碼段6 復(fù)制built_ota_tools工具到差分資源包
如代碼段5,Makefile中定義了執(zhí)行OTA所需要的一組工具(built_ota_tools),其中便包括由圖4中文件編譯而成的文件updater;而在生成差分資源包時(shí),會(huì)將這組工具拷貝到差分資源包的OTA/bin目錄中(見(jiàn)代碼段6);在生成升級(jí)包時(shí)(無(wú)論是執(zhí)行WriteFullOTAPackage還是WriteIncrementalOTAPackage),最后都會(huì)調(diào)用edify_generator的AddToZip方法,將updater添加到升級(jí)包中(更名為"META-INF/com/google/android/update-binary");最終在recovery模式下被執(zhí)行,這便是其來(lái)龍去脈。而關(guān)于updater的執(zhí)行,也大致的描述下吧。
由前文可知,updater主要由bootable/recovery/updater目錄下的install.c和updater.c編譯而成,主函數(shù)位于updater.c。其中,在install.c中定義了讀寫(xiě)系統(tǒng)存儲(chǔ)區(qū)的操作函數(shù)(這才是重寫(xiě)系統(tǒng)數(shù)據(jù)的真正代碼)并將這些函數(shù)與updater-script中的指令映射起來(lái)。而在updater.c會(huì)首先裝載install.c定義的函數(shù),之后便解析升級(jí)腳本updater-script,執(zhí)行其對(duì)應(yīng)的操作命令。與此同時(shí),執(zhí)行updater的進(jìn)程還會(huì)與父進(jìn)程通信,通知父進(jìn)程進(jìn)行UI的相關(guān)操作(代碼見(jiàn)bootable/recovery/install.c中的try_update_binary函數(shù))。
貌似差不多了,就此打住。
PS:唉,發(fā)現(xiàn)現(xiàn)在的表達(dá)能力真TMD差,寫(xiě)個(gè)總結(jié)都TM憋屈得要死。。。
總結(jié)
以上是生活随笔為你收集整理的OTA本质与实现流程分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【华为云技术分享】一文看懂什么是汽车OT
- 下一篇: OTA全称为Over-The-Air t