Android系統Recovery模式的工作原理
在使用update.zip包升級時怎樣從主系統(main system)重啟進入Recovery模式,進入Recovery模式後怎樣判斷做何種操作,以及怎樣獲得主系統發送給Recovery服務的命令,這一系列問題的解決是通過整個軟體平台的不同部分之間的密切通訊配合來完成的。為此,我們必須要瞭解Recovery模式的工作原理,這樣才能知道我們的update.zip包是怎樣一步步進入Recovery中升級並最後到達主系統的。
一、Recovery模式中的三個部分
Recovery的工作需要整個軟體平台的配合,從通訊架構上來看,主要有三個部分。
①MainSystem:即上面提到的正常啟動模式(BCB中無命令),是用boot.img啟動的系統,Android的正常工作模式。更新時,在這種模式中我們的上層操作就是使用OTA或則從SD卡中升級update.zip包。在重啟進入Recovery模式之前,會向BCB中寫入命令,以便在重啟後告訴bootloader進入Recovery模式。
②Recovery:系統進入Recovery模式後會裝載Recovery分區,該分區包含recovery.img(同boot.img相同,包含了標準的核心和根檔案系統)。進入該模式後主要是運行Recovery服務(/sbin/recovery)來做相應的操作(重啟、升級update.zip、擦除cache分區等)。
③Bootloader:除了正常的載入啟動系統之外,還會通過讀取MISC分區(BCB)獲得來至Main system和Recovery的訊息。
二、Recovery模式中的兩個通訊介面
在Recovery服務中上述的三個實體之間的通訊是必不可少的,他們相互之間又有以下兩個通訊介面。
(一)通過CACHE分區中的三個檔案:
Recovery通過/cache/recovery/目錄下的三個檔案與mian system通訊。具體如下
①/cache/recovery/command:這個檔案儲存著Main system傳給Recovery的命令列,每一行就是一條命令,支援一下幾種的組合。
--send_intent=anystring //write the text out to recovery/intent 在Recovery結束時在finish_recovery函數中將定義的intent字串作為參數傳進來,並寫入到/cache/recovery/intent中
--update_package=root:path //verify install an OTA package file Main system將這條命令寫入時,代表系統需要升級,在進入Recovery模式後,將該檔案中的命令讀取並寫入BCB中,然後進行相應的更新update.zip包的操作。
--wipe_data //erase user data(and cache),then reboot。擦除使用者資料。擦除data分區時必須要擦除cache分區。
--wipe_cache //wipe cache(but not user data),then reboot。擦除cache分區。
②/cache/recovery/log:Recovery模式在工作中的log列印。在recovery服務運行過程中,stdout以及stderr會重定位到/tmp/recovery.log在recovery退出之前會將其轉存到/cache/recovery/log中,供查看。
③/cache/recovery/intent:Recovery傳遞給Main system的資訊。作用不詳。
(二)通過BCB(Bootloader Control Block):
BCB是bootloader與Recovery的通訊介面,也是Bootloader與Main system之間的通訊介面。儲存在flash中的MISC分區,佔用三個page,其本身就是一個結構體,具體成員以及各成員含義如下:
struct bootloader_message{
char command[32];
char status[32];
char recovery[1024];
};
①command成員:其可能的取值我們在上文已經分析過了,即當我們想要在重啟進入Recovery模式時,會更新這個成員的值。另外在成功更新後結束Recovery時,會清除這個成員的值,防止重啟時再次進入Recovery模式。
②status:在完成相應的更新後,Bootloader會將執行結果寫入到這個欄位。
③recovery:可被Main System寫入,也可被Recovery服務程式寫入。該檔案的內容格式為:
“recovery\n
<recovery command>\n
<recovery command>”
該檔案儲存體的就是一個字串,必須以recovery\n開頭,否則這個欄位的所有內容域會被忽略。“recovery\n”之後的部分,是/cache/recovery/command支援的命令。可以將其理解為Recovery操作過程中對命令操作的備份。Recovery對其操作的過程為:先讀取BCB然後讀取/cache/recovery/command,然後將二者重新寫回BCB,這樣在進入Main system之前,確保操作被執行。在操作之後進入Main
system之前,Recovery又會清空BCB的command域和recovery域,這樣確保重啟後不再進入Recovery模式。
三、如何從Main System重啟並進入Recovery模式
我們先看一下以上三個部分是怎樣進行通訊的,先看:
我們只看從Main System如何進入Recovery模式,其他的通訊在後文中詳述。先從Main System開始看,當我們在Main System使用update.zip包進行升級時,系統會重啟並進入Recovery模式。在系統重啟之前,我們可以看到,Main System定會向BCB中的command域寫入boot-recovery(粉紅色線),用來告知Bootloader重啟後進入recovery模式。這一步是必須的。至於Main
System是否向recovery域寫入值我們在源碼中不能肯定這一點。即便如此,重啟進入Recovery模式後Bootloader會從/cache/recovery/command中讀取值並放入到BCB的recovery域。而Main System在重啟之前肯定會向/cache/recovery/command中寫入Recovery將要進行的操作命令。
至此,我們就大概知道了,在上層使用update.zip升級時,主系統是怎樣告知重啟後的系統進入Recovery模式的,以及在Recovery模式中完成什麼樣的操作。
下一篇開始分析第一個階段,即我們在上層使用update.zip包升級時,Main System怎樣重啟並進入Recovery服務的細節流程。