Android系統Recovery工作原理之使用update.zip升級過程分析(五)---update.zip包怎樣從上層進入Recovery服務

 Android系統Recovery工作原理之使用update.zip升級過程分析(五)---update.zip包從上層進入Recovery服務

轉自:http://blog.csdn.net/mu0206mu/article/details/7465352

               文章開頭我們就提到update.zip包來源有兩種,一個是OTA在線下載(一般下載到/CACHE分區),一個是手動拷貝到SD卡中。不論是哪種方式獲得update.zip包,在進入Recovery模式前,都未對這個zip包做處理。只是在重啓之前將zip包的路徑告訴了Recovery服務(通過將--update_package=CACHE:some_filename.zip或--update_package=SDCARD:update.zip命令寫入到/cache/recovery/command中)。在這裏我們假設update.zip包已經製作好並拷貝到了SD卡中,並以Settings-->About Phone-->System Update-->Installed From SDCARD方式升級。

         我們的測試開發板是TCC8800,使用的Android源碼是gingerbread0919,在這種方式下升級的源碼位於gingerbread/device/telechips/common/apps/TelechipsSystemUpdater/src/com/telechips/android/systemupdater/下。         下面我們具體分析這種升級方式下,我們的update.zip是怎樣從上層一步步進入到Recovery模式的。


一、從System Update到Reboot


        當我們依次選擇Settings-->About Phone-->System Update-->Installed From SDCARD後會彈出一個對話框,提示已有update.zip包是否現在更新,我們從這個地方跟蹤。這個對話框的源碼是SystemUpdateInstallDialog.java。


        在mNowButton按鈕的監聽事件裏,會調用mService.rebootAndUpdate(new  File(mFile))。這個mService就是SystemUpdateService的實例。 這  個類所在的源碼文件是SystemUpdateService.java。這個函數的參數是一個文件。它肯定就是我們的update.zip包了。我們可以證實一下這個猜想。

        mFile的值:在SystemUpdateInstallDialog.java中的ServiceConnection中我們可以看到這個mFile的值有兩個來源。

                 來源一:

                  mFile的一個來源是這個是否立即更新提示框接受的上一個Activity以“file”標記傳來的值。這個Activity就是SystemUpdate.java。它是一個PreferenceActivity類型的。在其onPreferenceChange函數中定義了向下一個Activity傳送的值,這個值是根據我們不同的選擇而定的。如果我們在之前選擇了從SD卡安裝,則這個傳下去的“file”值爲“/sdcard/update.zip”。如果選擇了從NAND安裝,則對應的值爲“/nand/update.zip”。


                 來源二:

                 另個一來源是從mService.getInstallFile()獲得。我們進一步跟蹤就可發現上面這個函數獲得的值就是“/cache”+ mUpdateFileURL.getFile();這就是OTA在線下載後對應的文件路徑。不論參數mFile的來源如何,我們可以發現在mNowButton按鈕的監聽事件裏是將整個文件,也就是我們的update.zip包作爲參數往rebootAndUpdate()中傳遞的。

        rebootAndUpdate:在這個函數中Main System做了重啓前的準備。繼續跟蹤下去會發現,在SystemUpdateService.java中的rebootAndUpdate函數中新建了一個線程,在這個線程中最後調用的就是RecoverySystem.installPackage(mContext,mFile),我們的update.zip包也被傳遞進來了。

        RecoverySystem類:RecoverySystem類的源碼所在文件路徑爲:gingerbread0919/frameworks/base/core/java/android/os/RecoverySystem.java。我們關心的是installPackage(Context context,FilepackageFile)函數。這個函數首先根據我們傳過來的包文件,獲取這個包文件的絕對路徑filename。然後將其拼成arg=“--update_package=”+filename。它最終會被寫入到BCB中。這個就是重啓進入Recovery模式後,Recovery服務要進行的操作。它被傳遞到函數bootCommand(context,arg)。

        bootCommand():在這個函數中才是Main System在重啓前真正做的準備。主要做了以下事情,首先創建/cache/recovery/目錄,刪除這個目錄下的command和log(可能不存在)文件在sqlite數據庫中的備份。然後將上面④步中的arg命令寫入到/cache/recovery/command文件中。下一步就是真正重啓了。接下來看一下在重啓函數reboot中所做的事情。

         pm.reboot():重啓之前先獲得了PowerManager(電源管理)並進一步獲得其系統服務。然後調用了pm.reboot(“recovery”)函數。他就是/gingerbread0919/bionic/libc/unistd/reboot.c中的reboot函數。這個函數實際上是一個系統調用,即__reboot(LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,mode,NULL);從這個函數我們可以看出前兩個參數就代表了我們的組合鍵,mode就是我們傳過來的“recovery”。再進一步跟蹤就到了彙編代碼了,我們無法直接查看它的具體實現細節。但可以肯定的是 這個函數只將“recovery”參數傳遞過去了,之後將“boot-recovery”寫入到了MISC分區的BCB數據塊的command域中。這樣在重啓之後Bootloader才知道要進入Recovery模式。


         在這裏我們無法肯定Main System在重啓之前對BCB的recovery域是否進行了操作。其實在重啓前是否更新BCB的recovery域是不重要的,因爲進入Recovery服務後,Recovery會自動去/cache/recovery/command中讀取要進行的操作然後寫入到BCB的recovery域中。

         至此,Main System就開始重啓並進入Recovery模式。在這之前Main System做的最實質的就是兩件事,一是將“boot-recovery”寫入BCB的command域,二是將--update_package=/cache/update.zip”或則“--update_package=/sdcard/update.zip”寫入/cache/recovery/command文件中。下面的部分就開始重啓並進入Recovery服務了。


二、從reboot到Recovery服務

       

            這個過程我們在上文(對照第一個圖)已經講過了。從Bootloader開始如果沒有組合鍵按下,就從MISC分區讀取BCB塊的command域(在主系統時已經將“boot-recovery”寫入)。然後就以Recovery模式開始啓動。與正常啓動不同的是Recovery模式下加載的鏡像是recovery.img。這個鏡像同boot.img類似,也包含了標準的內核和根文件系統。其後就與正常的啓動系統類似,也是啓動內核,然後啓動文件系統。在進入文件系統後會執行/init,init的配置文件就是/init.rc。這個配置文件來自bootable/recovery/etc/init.rc。查看這個文件我們可以看到它做的事情很簡單:

       ①設置環境變量。

       ②建立etc連接。

       ③新建目錄,備用。

       ④掛載/tmp爲內存文件系統tmpfs

       ⑤啓動recovery(/sbin/recovery)服務。

       ⑥啓動adbd服務(用於調試)。

       這裏最重要的就是當然就recovery服務了。在Recovery服務中將要完成我們的升級工作。

       我們將在下一篇詳細分析Recovery服務的流程細節。

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