日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OTA本质与实现流程分析

發布時間:2023/12/3 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OTA本质与实现流程分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

接觸OTA也有段時間了,是時候總結下了。所謂OTA(Over-the-AirTechnology)是指手機終端通過無線網下載遠程服務器上的升級包,對系統或應用進行升級的技術。有關網絡部分不做過多討論,本文重點放在系統升級這一概念上。
一 OTA本質

先以PC機進行類比。假設計算機操作系統裝在C盤,當加電啟動時,引導程序會將C盤的系統程序裝入內存并運行,而系統升級或重裝系統,則是將C盤中原來的系統文件部分或全部重寫。對于手機及其上的ANDROID系統而言,同樣如此,需要一個存儲系統文件的“硬盤”。

圖1 某android手機存儲設備結構圖

?

圖1 是某款手機的存儲設備結構圖,其存儲區(紅色框圖部分)分為四部分:SRAM、Nand Flash、SDRAM及外設地址空間。其中Nand Flash中存儲著全部系統數據(通過專門的燒寫工具將編譯后的映象文件download到Nand Flash中,工具由IC廠商提供),包括boot.img、system.img、recovery.img等,因此Nand Flash即是上文所說的手機上的“硬盤”。圖1最右部分(圖中綠色框圖部分)是Nand Flash存儲區更詳細的劃分,我們將主要關注system分區(藍色框圖),因為OTA升級主要是對這部分系統數據的重寫(當然boot分區也可升級)。除此之外,藍黑色區域標示的misc分區也應值得注意,它在OTA升級中發揮著重要的作用。

OK,一言以蔽之,所謂OTA就是將升級包(zip壓縮包)寫入到系統存儲區,因此我們需要考慮兩個問題,1.升級包是如何生成的?2.升級包是如何寫入到system分區的?

二 問題一:升級包的制作

1.整包的制作

升級包有整包與差分包之分。顧名思義,所謂整包即包含整個system分區中的數據文件;而差分包則僅包含兩個版本之間改動的部分。利用整包升級好比對電腦進行重作系統,格式分系統分區,并將新系統數據寫入分區;而利用差分包升級不會格式化system分區,只是對其中部分存儲段的內容進行重寫。除升級包之外,制作過程中還會涉及到另一種zip包,代碼中稱之為target-files zipfile,我稱之為差分資源包。首先闡述下整包的制作過程。

系統經過整編后,執行make otapackage命令,即可完成整包的制作,而此命令可分為兩個階段進行。首先執行./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目標代碼

這段代碼作用在于將系統資源(包括system、recovery、boot等目錄)重新打包,生成差分資源包(即target-files zipfile,下文將統一使用“差分資源包”這一概念)。我們可以看下差分資源包中的文件結構,如下:

圖2 target-files zipfile目錄結構

其中,OTA目錄值得關注,因為在此目錄下存在著一個至關重要的文件:OTA/bin/updater(后文會有詳述)。生成的差分資源包被傳遞給./build/tools/releasetools/

ota_from_target_files執行第二階段的操作:制作升級包。

圖3 ./build/tools/releasetools目錄下的文件

圖3是./build/tools/releasetools目錄下所包含的文件,這組文件是Google提供的用來制作升級包的代碼工具,核心文件為:ota_from_target_files和img_from_target_files。其中,前者用來制作recovery模式下的升級包;后者則用來制作fastboot下的升級包(fastboot貌似是一種更底層的刷機操作,未過多研究,不再詳述)。其他文件則是為此二者提供服務的,比如,common.py中包含有制作升級包所需操作的代碼;edify_generator.py則用于生成recovery模式下升級的腳本文件:<升級包>.zip/ META-INF/com/google/android/updater-script。

文件ota_from_target_files是本文所關注的重點,其中定義了兩個主要的方法:WriteFullOTAPackage和WriteIncrementalOTAPackage。前者用于生成整包,后者用來生成差分包。接著上文,當Makefile調用ota_from_target_files,并將差分資源包傳遞進來時,會執行WriteFullOTAPackage。此方法完成的工作包括:(1)將system目錄,boot.img等文件添加到整包中;(2)生成升級包中的腳本文件:<升級包>.zip/META-INF/com/google/android/updater-script;(3)將上文提到的可執行文件:OTA/bin/

updater添加到升級包中:META-INF/com/google/android/updater-script。摘取部分代碼片段如下:

script.FormatPartition("/system")script. FormatPartition ("/system")script.UnpackPackageDir("recovery", "/system")script.UnpackPackageDir("system", "/system")(symlinks, retouch_files) = CopySystemFiles(input_zip, output_zip)script.MakeSymlinks(symlinks)if OPTIONS.aslr_mode:script.RetouchBinaries(retouch_files)else:script.UndoRetouchBinaries(retouch_files)

代碼2 WriteFullOTAPackage代碼片段


其中的script為edify_generator對象,其FormatPartition、UnpackPackageDir等方法分別是向腳本文件update-script中寫入格式化分區、解壓包等指令。

def AddToZip(self, input_zip, output_zip, input_path=None):"""Write the accumulated script to the output_zip file. input_zipis used as the source for the 'updater' binary needed to runscript. If input_path is not None, it will be used as a localpath for the binary instead of input_zip."""self.UnmountAll()common.ZipWriteStr(output_zip, "META-INF/com/google/android/updater-script","\n".join(self.script) + "\n")if input_path is None:data = input_zip.read("OTA/bin/updater")else:data = open(os.path.join(input_path, "updater")).read()common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary",data, perms=0755)

代碼段3 ?edify_generator中的AddToZip方法

WriteFullOTAPackage執行的最后會調用此方法。將資源差分包中OTA/bin/updater文件copy到升級包中META-INF/com/google/android/update-binary。此文件是OTA升級的關鍵,其將在recovery模式下被執行,用來將代碼段2中生成的指令轉換為相應的函數去執行,從而完成對系統數據的重寫。

2.差分包的制作

生成差分包調用的是文件./build/tools/releasetools/ota_from_target_files中的WriteIncrementalOTA方法,調用時需要將兩個版本的差分資源包作為參數傳進來,形如:

./build/tools/releasetools/ota_from_target_files –n –i ota_v1.zip ota_v2.zip update.zip

其中,參數n表示忽略時間戳;i表示生成增量包(即差分包);ota_v1.zip與ota_v2.zip分別代表前后兩個版本的差分資源包;而update.zip則表示最終生成的差分包。

WriteIncrementalOTA函數會計算輸入的兩個差分資源包中版本的差異,并將其寫入到差分包中;同時,將updater及生成腳本文件udpate-script添加到升級包中。

三 問題二:將升級包寫入系統存儲區

制作完升級包后,之后便是將其寫入到相應存儲區中,這部分工作是在recovery模式下完成的。之前的幾篇筆記亦有描述,recovery模式下通過創建一個新的進程讀取并執行腳本文件META-INF/com/google/android/updater-script。見如下代碼:

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 創建新進程安裝升級包

分析代碼之前,首先介紹linux中函數fork與execv的用法。
pid_t fork( void)

??????? 創建新的進程,fork調用的一個奇妙之處就是它僅僅被調用一次,卻能夠返回兩次,它可能有三種不同的返回值:
  1)在父進程中,fork返回新創建子進程的進程ID;
  2)在子進程中,fork返回0;
  3)如果出現錯誤,fork返回一個負值;
??????? 在fork函數執行完畢后,如果創建新進程成功,則出現兩個進程,一個是子進程,一個是父進程。在子進程中,fork函數返回0,在父進程中,fork返回新創建子進程的進程ID。我們可以通過fork返回的值來判斷當前進程是子進程還是父進程(http://os.chinaunix.net/a2012/0203/1306/000001306508.shtml)。

int execv(const char *progname, char *const argv[])
??????? execv會停止執行當前的進程,并且以progname應用進程替換被停止執行的進程,進程ID沒有改變。
??????? progname: 被執行的應用程序。
??????? argv: 傳遞給應用程序的參數列表, 注意,這個數組的第一個參數應該是應用程序名字本身,并且最后一個參數應該為NULL,不參將多個參數合并為一個參數放入數組。

?代碼4見于bootable/recovery/install.c的try_update_binary函數中,是OTA升級的核心代碼之一。通過對fork及execv函數的介紹可知,代碼4創建了一個新的進程并在新進程中運行升級包中的META-INF/com/google/android/updater-binary文件(參數binary已在此前賦值),此文件將按照META-INF/com/google/android/updater-script中的指令將升級包里的數據寫入到存儲區中。OK,我們來看下META-INF/com/google/android/updater-binary文件的來歷。

在源代碼的./bootable/recovery/updater目錄下,存在著如下幾個文件:

圖4 ./bootable/recovery/updater目錄

?

通過查看Android.mk代碼可知,文件install.c、updater.c將會被編譯為可執行文件updater存放到目錄out/target/product/<product-name>/obj/EXECUTABLES/

updater_intermediates/中;而在生成差分資源包(target-files zipfile)時,會將此文件添加到壓縮包中。

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

$(hide) mkdir -p $(zip_root)/OTA/bin$(hide) $(ACP) $(INSTALLED_ANDROID_INFO_TXT_TARGET) $(zip_root)/OTA/$(hide) $(ACP) $(PRIVATE_OTA_TOOLS) $(zip_root)/OTA/bin/

代碼段6 復制built_ota_tools工具到差分資源包

如代碼段5,Makefile中定義了執行OTA所需要的一組工具(built_ota_tools),其中便包括由圖4中文件編譯而成的文件updater;而在生成差分資源包時,會將這組工具拷貝到差分資源包的OTA/bin目錄中(見代碼段6);在生成升級包時(無論是執行WriteFullOTAPackage還是WriteIncrementalOTAPackage),最后都會調用edify_generator的AddToZip方法,將updater添加到升級包中(更名為"META-INF/com/google/android/update-binary");最終在recovery模式下被執行,這便是其來龍去脈。而關于updater的執行,也大致的描述下吧。

由前文可知,updater主要由bootable/recovery/updater目錄下的install.c和updater.c編譯而成,主函數位于updater.c。其中,在install.c中定義了讀寫系統存儲區的操作函數(這才是重寫系統數據的真正代碼)并將這些函數與updater-script中的指令映射起來。而在updater.c會首先裝載install.c定義的函數,之后便解析升級腳本updater-script,執行其對應的操作命令。與此同時,執行updater的進程還會與父進程通信,通知父進程進行UI的相關操作(代碼見bootable/recovery/install.c中的try_update_binary函數)。

貌似差不多了,就此打住。

PS:唉,發現現在的表達能力真TMD差,寫個總結都TM憋屈得要死。。。

總結

以上是生活随笔為你收集整理的OTA本质与实现流程分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。