OTA和Recovery系統升級流程介紹

本文介紹了Android原生OTA和Recovery升級過程步驟.

進入升級

- 1.1 正常啓動和進入Recovery的區別

下面給出了升級流程的簡單示意圖。
這裏寫圖片描述
上圖中的上下兩個部分,上面一部分是正常的啓動模式,下面一部分爲Recovery模式。正常的啓動模式是從boot.img啓動系統(Main System),而recovery模式則是從reovery.img啓動系統;(reovery.img只包含內核、簡單的文件管理系統和圖形系統)

Boot分區包括linux內核和Ramdisk,Recovery分區也包括Linux內核和Ramdisk,一般來說內核是一樣的,但Ramdisk區別則非常大,recovery中的ramdisk會有更多的recovery需要使用的程序和數據。

- 1.2 分區介紹

這裏說到的boot.img和recovery.img,其實就對應了一個Android設備中的分區,一般來說,android設備會包含以下幾個分區

Boot:包含Linux內核和一個最小的root文件系統(裝載到RAM disk中),用於掛載系統和其他的分區,並開始Runtime
System:包括了系統應用和庫文件(AOSP中可以獲取到源代碼),在運行的過程中,這個分區是read-only的,只有在OTA升級的時候纔會發生變化
Vendor:包括了系統應用和庫文件(AOSP中不能獲取到源代碼),和System分區一樣,只有在OTA升級的時候纔會發生變化
Userdata:用戶安裝的應用程序會把數據保存在這裏,正常情況下OTA是不會清除這裏的數據的,指定要刪除出具的除外
Cache:臨時的保存應用數據(要把數據保存在這裏,需要特地的app permission),OTA的升級包也可以保存在這裏。OTA升級過程可能會清楚這個分區的數據。
Recovery:包括了一個完整Linux內核和一些特殊的recovery binary,可以讀取升級文件用這些文件來更新其他的分區
Misc:一個非常小的分區,recovery用這個分區來保存一些關於升級的信息,應對升級過程中的設備掉電重啓的狀況

這些分區是Google官方的標準,實際的情況可能不太一樣,就Find 7而言,刷機包裏面的分區只有以下幾個 :芯片廠商和手機廠商會根據自己的需要加一些其他的分區,如下面的persist.img是高通的,reserve4是我們自己加的保留分區,MTK還有preloader、lk,高通的還有NON-HLOS.bin、sbl、emms_aboot等。

Bootloader

- 2.1 什麼是Bootloader?
在嵌入式操作系統中,Bootloader在操作系統內核運行之前運行,可以初始化硬件設備、建立內存空間映射圖,爲調用操作系統內核準備好正確的環境。Bootloader和硬件是強相關的,且廠商一般都會對bootloader加鎖,這樣就不能隨便刷機了。
當然bootloader也是可以解鎖的,這裏不得不提一下root和bootloader解鎖分別是怎麼一回事:root是通過內核漏洞獲取最高的權限,也就是所謂的超級用戶(su,superuser),屬於系統層面,root之後就可以修改system分區的數據;bootloader解鎖則屬於硬件層面的解鎖boot和recovery分區,解鎖bootloader不會root手機。更多見參考文獻[1].

- 2.2 Fastboot和recovery的區別?
Bootloader過程中,先做一些初始化,然後根據組合鍵做不同的事情,這個過程內核沒有加載,機器知識在按順序執行指令。
Fastboot:在這種模式下,可以修改手機的硬件,並且允許我們發送一些命令給Bootloader。如使用電腦刷機,則需要進入fastboot模式,通過電腦執行命令將系統鏡像刷到通過USB刷到手機中。
Recovery:Recovery是一個小型的操作系統,並且會加載部分文件系統,這樣才能從sdcard中讀取升級包。
Bootloader.cpp
Bootloader(bootable/recovery/bootloader.cpp)會讀取位於MISC分區的啓動控制信息塊BCB(Bootloader Control Block),通過函數

int get_bootloader_message(struct bootloader_message *out);
int set_bootloader_message(const struct bootloader_message *in);

如果command的值爲“boot-recovery”時,就進入recovery模式。Recovery升級過程中掉電,下次按power鍵開機也會進入recovery模式就是因爲misc分區依然存在recovery信息(掉電保護)。

Recovery模式

- 3.1 Recovery、Bootloader以及Main System通信方法
圖1中給出模式比較簡單,實際上三個實體的交互過程並不是圖1那種單向的順序流程,而是一個雙向的流程,於是就涉及到個三個部分的通信方法的實現。
Recovery和Main System交互
這一部分源代碼(bootable/recovery/recovery.cpp)註釋中有詳細的介紹,這裏大致總結一下:這兩個部分交互是通過/cache文件來實現的,涉及到的文件如下表。
這裏寫圖片描述
Recovery、Main System和Bootloader交互
這個交互過程是通過BCB來完成的,BCB其實就是一個struct(在misc分區),在(bootable/recovery/bootloader.h)中定義。

struct bootloader_message {
    char command[32];//command存儲在這個field裏面
    char status[32];
    char recovery[768];
    char stage[32];
    char reserved[224];
};

Command:重啓進入recovery或者是更新radio或Bootloader硬件時,會更新這個域;
Status:在bootloader完成“update-radio”和”update-hboot”命令之後更新;
Recovery:用於system和recovery之間的通信;
Stage:需要重啓多次的packages會寫入這個值,表示所處的狀態。
上面的過程可以總結爲如下的示意圖:
這裏寫圖片描述

cache/recovery/command中command有哪些?
下表給出一些常用的命令和其含義。
這裏寫圖片描述

- 3.3 Factory Reset—恢復出廠設置
恢復出廠設置也在recovery.cpp中完成,具體的流程如下:
1) 用戶選擇恢復出廠設置
2) Main System會在cache/recovery/command中寫入—wipe-data的命令,然後重啓進入recovery
3) 通過get_args在BCB中寫入boot-recovery和wipe-data命令
4) 然後重啓進行erase_volume
5) 擦除數據之後調用finish_recovery將BCB中的數據清除
6) main()函數調用reboot()進入Main System;
這裏寫圖片描述

OTA安裝

  • 4.1 OTA簡介

OTA,即Over the air,它可以實現完整的版本升級,也可以是增量升級。用戶可以選擇在SD卡中作本地升級,也可以直接採用網絡在線升級。不管是哪種方式,都有幾個過程:生成升級包、獲取升級包、執行升級包,生成升級包不做介紹,。
實際上,所謂OTA的整個過程可以用如下示意圖表示。
這裏寫圖片描述
首先,用戶用手機的OTA檢查更新(或者是自動更新),發送查詢數據給服務器,然後服務器查詢到相應的包,並返回下載地址給OTA.apk,然後OTA.apk進行下載,把下載的數據存儲在手機的某個分區。完成之後用於選擇是否升級,升級的時候OTA會發送命令給Main System,進入recovery,recovery根據利用下載下來的升級包完成升級過程。
從圖中,我們可以看出OTA.apk實際上只是完成了從服務下下載安裝包,以及發送升級命令,功能似乎很容易描述,但是實際上要做的事情卻是非常多的,特別是OTA 2.0將Applypatch功能移植到OTA.apk之後,複雜度進一步增加了。

  • 4.2 OTA安裝流程

    下面對Recovery的升級步驟做一個梳理:
    1) Main System下載OTA升級包,官方推薦下載到/cache分區下,但是實際上可以自己選擇存儲地方;
    2) Main System在/cache/recovery/command中寫入“—update_package=安裝包路徑”
    3) 系統重啓進入recovery,這一步是通過PowerManager的reboot(“recovery”)實現的
    4) Get_args()在BCB中寫入“boot-recovery”和”—update_package“,這樣就保證了即便是設備出故障重啓了,只有這兩個命令還在,就會嘗試重新安裝OTA升級包
    5) Install_package嘗試開始安裝OTA升級包
    6) Finish_package擦除BCB
    7) 如果升級失敗
    Prompt_and_wait顯示錯誤,並等待用戶響應
    用戶重啓
    8) 設備重啓進入MainSystem
    此外,還有個maybe_install_firmware_upadate,具體過程不做介紹了。

下面是Recovery的代碼的區別,實際上2.3/3.0/4.4和5.0的代碼差別還是非常大的,原因是5.0的recovery用C++改寫了一遍,官方文檔兩者改寫的函數進行了對比
這裏寫圖片描述
這裏寫圖片描述

這裏寫圖片描述

  • 4.3 Install_package過程

    安裝過程在/bootable/recovery/install.cpp中,
    install_package(const char* path, int* wipe_cache, const char* install_file, bool needs_mount)
    在recovery的main函數中傳入的參數如下:
    install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE, true);
    參數列表:
    -Path:傳入的安裝包地址
    -wipe_cache:是否擦除cache分區
    -install_file:實際上是安裝過程的臨時安裝文件的地址(/tmp/last_install),包括install_log
    -needs_mount:是否需要Mount,安裝過程傳入的是true
    在install_package函數中,其實真正調用的是really_install_package函數:
    result = really_install_package(path, wipe_cache, needs_mount);
    這裏對幾個重要的流程做一些介紹:
    -Set_install_mounts:檢查安裝包所在路徑的分區是否掛載,否則返回安裝失敗
    -Set_backgroud:升級過程的UI界面顯示
    -Load_keys,加載公鑰,我們系統的簽名文件放在/build/target/product/security/目錄下。這樣做的目的是爲了防止用戶使用不同的項目的升級包進行混刷,導致刷機變磚的情況;
    -verify_file():對升級包update.zip包進行簽名驗證;
    -mzOpenZipArchive():打開升級包,並將相關的信息拷貝到一個臨時的ZipArchinve變量中。這一步並未對我們的update.zip包解壓。
    -try_update_binary():在這個函數中才是對我們的update.zip升級的地方。這個函數一開始先根據我們上一步獲得的zip包信息,以及升級包的絕對路徑將update_binary文件拷貝到內存文件系統的/tmp/update_binary中
    -execv(binary,args)的作用就是去執行binary程序,這個程序的實質就是去解析update.zip包中的updater-script腳本中的命令並執行
    這裏寫圖片描述

  • 4.4 Update-binary和Updater-script

上面,我們講到execv執行二進制文件和Updater-script腳本中的命令,這兩個文件在下面的目錄。Apply_patch過程其實是會預先在APK端提取出來這兩個文件的。
try_update_binary運行時,會首先從安裝包中讀取出update-binary這個可執行文件。創建一個管道(作用稍後會講到),並在一個新線程中運行這個update-binary(即updater,主函數見bootable/recovery/updater/updater.c),update-binary運行的時候,先會從升級包中讀取update-script。
bootable/recovery/updater/updater.c中會註冊函數,而這些被註冊的函數在updater-script中有使用到。

    // Configure edify's functions.
    RegisterBuiltins();
    RegisterInstallFunctions();
    RegisterBlockImageFunctions();
    RegisterDeviceExtensions();
    FinishRegistration();

常用的Updater-script命令
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章