OTA--卡刷全包、差分升級包制作、分析(代碼摘自Google)---2


OTA官網介紹:
https://source.android.com/devices/tech/ota/
OTA–卡刷全包、差分升級包制作、分析

1 .OTA升級流程框架

標准的OTA升級流程包括一下幾個步驟:
1).Android設備首先會與OTA服務器進行交互,如果有更新會推送給客戶。推送的信息常常會包含OTA更新包的下載地址和一些版本信息。
2).Update程序會將更新包下載到cache分區下,並提醒用戶安裝更新。
3).設備會重啟進入recovery模式,同時啟動recovery分區下運行環境,不再啟動boot分區下的運行環境。
4).recovery運行環境初始化時會啟動recovery二進制程序並根據/cache/recovery/command中的命令對更新包進行下一步操作。
5).Recovery運行環境對更新包中/res/key的簽名進行校驗,如果校驗失敗會中斷升級。
6).Recovery二進制程序會對更新包中的數據進行解壓同時根據解壓出的數據對boot、system、和vender分區進行相應的更新。對system分區的更新也同時包含了新的recovery分區的更新。
7).重啟設備
a.載入新的boot分區,並執行升級后的system分區中的二進制文件。
b.系統啟動時會同時校驗recovery分區,如果recovery與升級時保存在system分區下的信息不一致會對recovery進行更新。
8).系統更新完成。

2、OTA全包、差分包制作步驟

在源碼目錄下新建文件夾OTA

1、source build/envsetup.sh。

2、 lunch 然后選擇需要的配置。

3、make 編譯

4、 make otapackage。

5、拷貝out/target/product/(項目名)/ (項目名)-ota-eng.(用戶名).zip到OTA並 且重命名A1.zip

6、拷貝out/target/product/(項目名)/obj/PACKAGING/target_files_intermediates/(項目名)-target_files-eng.(用戶名).zip到OTA並重命名A2.zip

7、修改源碼添加一個log信息,然后刪除out/target/product/(項目名)/system/build.prop

8、source build/envsetup.sh

9、 lunch 然后選擇配置。

10、make 編譯

11、make otapackage。

12、拷貝out/target/product/(項目名)/ (項目名)-ota-eng.xukang.zip到OTA並且重命名B1.zip

13、拷貝out/target/product/(項目名)/obj/PACKAGING/target_files_intermediates/(項目名)-target_files-eng.(用戶名).zip到OTA並重命名B2.zip

14、制作差分包:

./build/tools/releasetools/ota_from_target_files.py -k build/target/product/security/testkey -i ./OTA/A2.zip ./OTA/B2.zip ./OTA/update.zip (A1.zip B1.zip 不能制作差分包)

15、現在OTA下有五個文件:A1.zip A2.zip B1.zip B2.zip update.zip

    其中A1.zip    B1.zip 是可以卡刷的全包,但是不能制作差分包

A2.zip B2.zip是不能卡刷的全包,但是能制作差分包。

16、拷貝到SD卡

17、平板鏈接:adb devices,adb reboot fastboot (recovery) 音量上下鍵選擇和power鍵確認,調整進入recover 模式

18、差分包的升級一定要以A1.zip燒制的那個系統版本為基礎
(按一下“音量下”鍵,選擇“apply update from ADB”,然后按下電源鍵確認.

在命令行中輸入”adb sideload update.zip”(ota.zip為自己命名的手機系統升級包)
adb sideload線刷 OTA 升級的方法)
19、System reboot

3、OTA制包過程理論分析,代碼追蹤

3.1、OTA本質
先以PC機進行類比。假設計算機操作系統裝在C盤,當加電啟動時,引導程序會將C盤的系統程序裝入內存並運行,而系統升級或重裝系統,則是將C盤中原來的系統文件部分或全部重寫。對於手機及其上的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分區的?

3.2、OTA制作代碼流程圖
這里寫圖片描述

3.3、整包的制作過程代碼追蹤
包有整包與差分包之分。顧名思義,所謂整包即包含整個system分區中的數據文件;而差分包則僅包含兩個版本之間改動的部分。利用整包升級好比對電腦進行重作系統,格式分系統分區,並將新系統數據寫入分區;而利用差分包升級不會格式化system分區,只是對其中部分存儲段的內容進行重寫。除升級包之外,制作過程中還會涉及到另一種zip包,代碼中稱之為target-files zipfile(out/target/product/(項目名)/obj/PACKAGING/target_files_intermediates/ (項目名)-target_files-eng. (用戶名).zip),我稱之為差分資源包。首先闡述下整包的制作過程。
系統經過整編后,執行make otapackage命令,即可完成整包的制作,而此命令可分為兩個階段進行。首先執行./build/core/Makefile中的代碼:

1.  # ----------------------------------------------------------------- 
2. # OTA update package
3.
4. name := $(TARGET_PRODUCT)
5. ifeq ($(TARGET_BUILD_TYPE),debug)
6. name := $(name)_debug
7. endif
8. name := $(name)-ota-$(FILE_NAME_TAG)
9.
10. INTERNAL_OTA_PACKAGE_TARGET := $(PRODUCT_OUT)/$(name).zip
11.
12. $(INTERNAL_OTA_PACKAGE_TARGET): KEY_CERT_PAIR := $(DEFAULT_KEY_CERT_PAIR)
13.
14. $(INTERNAL_OTA_PACKAGE_TARGET): $(BUILT_TARGET_FILES_PACKAGE) $(OTATOOLS)
15. @echo "Package OTA: $@"
16. $(hide) ./build/tools/releasetools/ota_from_target_files -v \
17. -n \
18. -p $(HOST_OUT) \
19. -k $(KEY_CERT_PAIR) \
20. $(ota_extra_flag) \
21. $(BUILT_TARGET_FILES_PACKAGE) $@
22. .PHONY: otapackage
23. otapackage: $(INTERNAL_OTA_PACKAGE_TARGET)
24. # -----------------------------------------------------------------
        代碼段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。摘取部分代碼片段如下:

1.  script.FormatPartition("/system")  
2. script. FormatPartition ("/system")
3. script.UnpackPackageDir("recovery", "/system")
4. script.UnpackPackageDir("system", "/system")
5.
6. (symlinks, retouch_files) = CopySystemFiles(input_zip, output_zip)
7. script.MakeSymlinks(symlinks)
8. if OPTIONS.aslr_mode:
9. script.RetouchBinaries(retouch_files)
10. else:
11. script.UndoRetouchBinaries(retouch_files)
代碼2 WriteFullOTAPackage代碼片段生成全包

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

1.  def AddToZip(self, input_zip, output_zip, input_path=None):  
2. """Write the accumulated script to the output_zip file. input_zip
3. is used as the source for the 'updater' binary needed to run
4. script. If input_path is not None, it will be used as a local
5. path for the binary instead of input_zip."""

6.
7. self.UnmountAll()
8.
9. common.ZipWriteStr(output_zip, "META-INF/com/google/android/updater-script",
10. "\n".join(self.script) + "\n")
11.
12. if input_path is None:
13. data = input_zip.read("OTA/bin/updater")
14. else:
15. data = open(os.path.join(input_path, "updater")).read()
16. common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary",
17. data, perms=0755)
     代碼段3  edify_generator中的AddToZip方法

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

3.4、差分包的制作

生成差分包調用的是文件./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。見如下代碼:

1. const char** args = (const char**)malloc(sizeof(char*) * 5);  
2. args[0] = binary;
3. args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk
4. char* temp = (char*)malloc(10);
5. sprintf(temp, "%d", pipefd[1]);
6. args[2] = temp;
7. args[3] = (char*)path;
8. args[4] = NULL;
9.
10. pid_t pid = fork();
11. if (pid == 0) {
12. close(pipefd[0]);
13. execv(binary, (char* const*)args);
14. _exit(-1);
15. }
16. 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//obj/EXECUTABLES/
updater_intermediates/中;而在生成差分資源包(target-files zipfile)時,會將此文件添加到壓縮包中。

1.  built_ota_tools := \  
2. $(call intermediates-dir-for,EXECUTABLES,applypatch)/applypatch \
3. $(call intermediates-dir-for,EXECUTABLES,applypatch_static)/applypatch_static \
4. $(call intermediates-dir-for,EXECUTABLES,check_prereq)/check_prereq \
5. $(call intermediates-dir-for,EXECUTABLES,sqlite3)/sqlite3 \
6. $(call intermediates-dir-for,EXECUTABLES,updater)/updater
     代碼段5 Makefile中定義的變量built_ota_tools
1.  $(hide) mkdir -p $(zip_root)/OTA/bin  
2. $(hide) $(ACP) $(INSTALLED_ANDROID_INFO_TXT_TARGET) $(zip_root)/OTA/
3. $(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函數)。

參考文檔:

1、OTA制作及升級過程筆記
http://blog.csdn.net/teliduxing1029/article/details/51536560#comments

2、OTA本質與實現流程分析
http://blog.csdn.net/bi511304183/article/details/9340175


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com