寫(xiě)這篇文章時(shí)想起我的第一部Android手機(jī)HTC Hero。買(mǎi)回來(lái)后,同事告訴我可以去刷機(jī)玩玩。刷機(jī),怎么刷?同事說(shuō),你個(gè)土人,刷機(jī)都不知道,很多刷機(jī)論壇的,你去逛逛,挺簡(jiǎn)單的。我去逛了逛機(jī)鋒論壇(那時(shí)還不知道MIUI),打開(kāi)一看,什么recovery, radio, root各種詞匯撲面而來(lái),oh my lady gaga,這么復(fù)雜。但是為了不被鄙視,而且閑著也是閑著,還是刷著玩玩吧。后來(lái)就結(jié)識(shí)MIUI來(lái)到了小米。這是題外話,咱們言歸正傳。
在這紛紛擾擾的Android世界里,如何找到那條刷機(jī)大道呢,或許它只是個(gè)傳說(shuō),我們只是一直在探索。讓我們從零開(kāi)始來(lái)看一看,看能發(fā)現(xiàn)點(diǎn)什么。
1. bootloader
當(dāng)我們拿到一款手機(jī),第一件事應(yīng)該就是按下電源鍵開(kāi)機(jī),那么從開(kāi)機(jī)到進(jìn)入到桌面程序這中間發(fā)生了些什么呢,我們從下面這張簡(jiǎn)化了的手機(jī)結(jié)構(gòu)圖開(kāi)始:
注意:該結(jié)構(gòu)圖并不反映手機(jī)的實(shí)際分區(qū)順序和位置,只是一個(gè)邏輯結(jié)構(gòu)圖。
大家可以簡(jiǎn)單的把手機(jī)的ROM存儲(chǔ)類比為我們電腦上的硬盤(pán),這個(gè)硬盤(pán)被分成了幾個(gè)分區(qū):bootloader分區(qū),boot分區(qū),system分區(qū)等等。后面我們會(huì)逐漸介紹各個(gè)分區(qū)的用途。所謂的刷機(jī)我們可以簡(jiǎn)單的理解成把軟件安裝在手機(jī)的某些分區(qū)中,類似于我們?cè)陔娔X上安裝Windows系統(tǒng)。
當(dāng)按下電源鍵手機(jī)上電啟動(dòng)后,首先從bootloader分區(qū)中一個(gè)固定的地址開(kāi)始執(zhí)行指令,如圖所示,bootloader分區(qū)分成兩個(gè)部分,分別叫做primary bootloader和secondary stage bootloader。Primary bootloader主要執(zhí)行硬件檢測(cè),確保硬件能正常工作后將secondary stage bootloader拷貝到內(nèi)存(RAM)開(kāi)始執(zhí)行。Secondary stage bootloader會(huì)進(jìn)行一些硬件初始化工作,獲取內(nèi)存大小信息等,然后根據(jù)用戶的按鍵進(jìn)入到某種啟動(dòng)模式。比如說(shuō)大家所熟知的通過(guò)電源鍵和其它一些按鍵的組合,可以進(jìn)入到recovery,fastboot或者選擇啟動(dòng)模式的啟動(dòng)界面等。我們?cè)谡搲峡吹降腷ootloader通常指的就是secondary stage bootloader。不過(guò)我們不需要關(guān)心太多的細(xì)節(jié),可以簡(jiǎn)單的理解為bootloader就是一段啟動(dòng)代碼,根據(jù)用戶按鍵有選擇的進(jìn)入某種啟動(dòng)模式。
fastboot模式:fastboot是android定義的一種簡(jiǎn)單的刷機(jī)協(xié)議,用戶可以通過(guò)fastboot命令行工具來(lái)進(jìn)行刷機(jī)。比如說(shuō)fastboot flash boot boot.img這個(gè)命令就是把boot.img的內(nèi)容刷寫(xiě)到boot分區(qū)中。一般的手機(jī)廠商不直接提供fastboot模式刷機(jī),而是為了顯示他們的牛B之處,總是會(huì)提供自己專有的刷機(jī)工具和刷機(jī)方法。比如說(shuō)三星的Odin,摩托的RSD,華為的粉屏等等。但是其本質(zhì)實(shí)際上是相同的,都是將軟件直接flash到各個(gè)分區(qū)中。
recovery模式:recovery是android定義的一個(gè)標(biāo)準(zhǔn)刷機(jī)協(xié)議。當(dāng)進(jìn)入recovery模式時(shí),secondary stage bootloader從recovery分區(qū)開(kāi)始啟動(dòng),recovery分區(qū)實(shí)際上是一個(gè)簡(jiǎn)單的Linux系統(tǒng),當(dāng)內(nèi)核啟動(dòng)完畢后,開(kāi)始執(zhí)行第一個(gè)程序init(init程序是Linux系統(tǒng)所有程序的老祖宗)。init會(huì)啟動(dòng)一個(gè)叫做recovery的程序(recovery模式的名稱也由此而來(lái))。通過(guò)recovery程序,用戶可以執(zhí)行清除數(shù)據(jù),安裝刷機(jī)包等操作。一般的手機(jī)廠商都提供一個(gè)簡(jiǎn)單的recovery刷機(jī),而大名鼎鼎的CWM Recovery就是一個(gè)加入了很多增強(qiáng)功能的recovery,要想用上CWM Recovery前提是recovery分區(qū)可以被刷寫(xiě)。大家在論壇上看到的解鎖bootloader,通常指的就是解鎖recovery或fastboot,允許刷寫(xiě)recovery分區(qū),這樣大家就可以用上喜愛(ài)的CWM Recovery了。
手機(jī)除了普通的CPU芯片以外,還有MODEM處理器芯片。該芯片的功能就是實(shí)現(xiàn)手機(jī)必需的通信功能,大家通常所的刷RADIO就是刷寫(xiě)modem分區(qū)。
2. 正常啟動(dòng)
當(dāng)我們只是按下電源鍵開(kāi)機(jī)時(shí),會(huì)進(jìn)入正常啟動(dòng)模式。Secondary stage bootloader會(huì)從boot分區(qū)開(kāi)始啟動(dòng)。Boot分區(qū)的格式是固定的,首先是一個(gè)頭部,然后是Linux內(nèi)核,最后是用作根文件系統(tǒng)的ramdisk。
一般針對(duì)每個(gè)機(jī)型的完整刷機(jī)包中會(huì)有一個(gè)boot.img文件,這就是boot分區(qū)鏡像文件。如何編輯該鏡像文件可以參照這篇文章
http://android-dls.com/wiki/inde ... Re-Pack_Boot_Images。
當(dāng)Linux內(nèi)核啟動(dòng)完畢后,就開(kāi)始執(zhí)行根文件系統(tǒng)中的init程序,init程序會(huì)讀取啟動(dòng)腳本文件(init.rc和init.xxxx.rc)。啟動(dòng)腳本文件的格式大家可以在網(wǎng)上找到很多參考資料,這里就不寫(xiě)了,而且我們?cè)谠瓘SROM上移植MIUI的原則是不修改boot分區(qū),因?yàn)橛幸恍C(jī)型無(wú)法修改boot分區(qū)。
根文件系統(tǒng)中有一個(gè)重要的配置文件,叫default.prop,該文件的內(nèi)容一般為:
#
# ADDITIONAL_DEFAULT_PROPERTIES
#
ro.secure=1
ro.allow.mock.location=1
ro.debuggable=0
persist.service.adb.enable=1。
文件中的每一行對(duì)某個(gè)屬性賦值,在后續(xù)的文章中我們還會(huì)談到屬性。這里面大家需要注意的兩個(gè)屬性:ro.secure和ro.debuggable。如果ro.secure=0允許我們運(yùn)行adb root命令。在下一篇我們會(huì)詳細(xì)介紹adb,這是我們做ROM移植的利器。通常大家說(shuō)得內(nèi)核ROOT指的就是ro.secure=0。ROOT權(quán)限只是的手機(jī)上有一個(gè)名為授權(quán)管理的程序(Superuser.apk)可以授予程序root用戶的權(quán)限。ro.deguggable=1允許調(diào)試系統(tǒng)APP。
init程序讀取啟動(dòng)腳本,執(zhí)行腳本中指定的動(dòng)作和命令,腳本中的一部分是運(yùn)行system分區(qū)的程序,下一節(jié)我們就來(lái)看看system分區(qū)的結(jié)構(gòu)。
3. system分區(qū)
在講system分區(qū)之前,我們先來(lái)看下面這張Android的軟件系統(tǒng)架構(gòu)圖。
從上到下依次為:
核心應(yīng)用層:這一層就是大家平常所接觸的各種各樣的系統(tǒng)自帶應(yīng)用,比如聯(lián)系人,電話,音樂(lè)等。應(yīng)用層往下就是開(kāi)發(fā)人員所接觸的。
框架層:這一層是Android系統(tǒng)的核心,它提供了整個(gè)Android系統(tǒng)運(yùn)作的機(jī)制,像窗口管理,程序安裝包管理,開(kāi)發(fā)人員所接觸的Activity, Service, broadcast等等。
JNI層:JNI層是Java程序和底層操作系統(tǒng)通信的一個(gè)機(jī)制,它使得Java代碼可以調(diào)用C/C++代碼來(lái)訪問(wèn)底層操作系統(tǒng)的API。
Dalvik虛擬機(jī):Android開(kāi)發(fā)使用Java語(yǔ)言,應(yīng)用程序的Java代碼會(huì)被編譯成dalvik虛擬機(jī)字節(jié)碼,這些字節(jié)碼由dalvik虛擬機(jī)解釋執(zhí)行。
本地庫(kù):本地庫(kù)一般是由C/C++語(yǔ)言所開(kāi)發(fā),直接編譯成相應(yīng)CPU的機(jī)器碼,這其中包含標(biāo)準(zhǔn)C庫(kù),用以繪制圖形的skia庫(kù),瀏覽器核心引擎webkit等。
HAL:硬件抽象層,為了和各個(gè)廠家的不同硬件工作,Android定義了一套硬件接口,比如說(shuō)為了使用相機(jī),廠家的相機(jī)驅(qū)動(dòng)必須提供的接口方法。這樣使得上層的代碼可以獨(dú)立于不同的硬件運(yùn)行。
廠家適配層:本來(lái)Android定義的HAL層是直接和廠家提供的設(shè)備驅(qū)動(dòng)打交道的,但是目前廠家不想開(kāi)源HAL部分的代碼,因此很多廠家都提供了一個(gè)我稱之為廠家適配層的代碼,這樣在HAL層接口的實(shí)現(xiàn)只是一個(gè)簡(jiǎn)單的對(duì)廠家適配層接口函數(shù)的調(diào)用。
內(nèi)核:這一層就是大家熟悉的Linux內(nèi)核,內(nèi)核中包含有各種硬件驅(qū)動(dòng),這些驅(qū)動(dòng)不同的手機(jī)廠商不同的手機(jī)是不一樣的。Linux內(nèi)核是支持驅(qū)動(dòng)模塊化機(jī)制的,簡(jiǎn)單的說(shuō)就是允許用戶動(dòng)態(tài)的加載或者卸載某個(gè)硬件驅(qū)動(dòng),但是目前來(lái)看,手機(jī)廠商除了提供WIFI驅(qū)動(dòng)單獨(dú)加載外,其它驅(qū)動(dòng)都是和內(nèi)核綁定在一起的。
從這張軟件結(jié)構(gòu)圖來(lái)看,除了內(nèi)核是放在boot分區(qū)外,其它層的代碼都是在system分區(qū)中。
下面結(jié)合這張圖來(lái)介紹system分區(qū)的主要目錄內(nèi)容:
system/app: app目錄下存放的是核心應(yīng)用,也就是大家熟知的系統(tǒng)APP,這些系統(tǒng)自帶的程序是不能簡(jiǎn)單的卸載的,要通過(guò)一些特殊的方式才能刪除(大家熟悉的一種方法是用RE文件管理器)。
system/lib: lib目錄下存放的是組成JNI層,Dalvik虛擬機(jī),本地庫(kù),HAL層和廠家適配層的所有動(dòng)態(tài)鏈接庫(kù)(.so文件)。
system/framework: 該目錄下存放的是框架層的JAR包,其中對(duì)MIUI移植來(lái)說(shuō)有3個(gè)最重要的JAR包(framework.jar, android.policy.jar, services.jar)。后續(xù)的文章會(huì)重點(diǎn)介紹這3個(gè)包。
system/fonts: 該目錄下存放的是系統(tǒng)缺省的字體文件。
system/media:該目錄下存放的是系統(tǒng)所使用的各種媒體文件,比如說(shuō)開(kāi)機(jī)音樂(lè),動(dòng)畫(huà),壁紙文件等。不同的手機(jī)該目錄的組織方式可能不一樣。如何修改這些文件請(qǐng)參考網(wǎng)上對(duì)應(yīng)機(jī)型形形色色的教程,這里不再贅敘。
system/bin: 該目錄下存放的是一些可執(zhí)行文件,基本上是由C/C++編寫(xiě)的。其中有一個(gè)重要的命令叫app_process下一節(jié)單獨(dú)介紹。
system/xbin: 該目錄下存放的是一些擴(kuò)展的可執(zhí)行文件,既該目錄可以為空。大家常用的busybox就放在該目錄下。Busybox所建立的各種符號(hào)鏈接命令都是放在該目錄。
system/build.prop: build.prop和上節(jié)說(shuō)得根文件系統(tǒng)中的default.prop文件格式一樣,都稱為屬性配置文件。它們都定義了一些屬性值,代碼可以讀取或者修改這些屬性值。屬性值有一些命名規(guī)范:
ro開(kāi)頭的表示只讀屬性,即這些屬性的值代碼是無(wú)法修改的。
persist開(kāi)頭的表示這些屬性值會(huì)保存在文件中,這樣重新啟動(dòng)之后這些值還保留。
其它的屬性一般以所屬的類別開(kāi)頭,這些屬性是可讀可寫(xiě)的,但是對(duì)它們的修改重啟之后不會(huì)保留。
很多ROM制作者都會(huì)修改一下build.prop信息,里面的一些以ro.build開(kāi)頭的屬性就是你在手機(jī)設(shè)置中的關(guān)于手機(jī)里看到的??梢酝ㄟ^(guò)修改build.prop文件來(lái)將這個(gè)ROM打上自己的印記(XXX所修改)。我見(jiàn)過(guò)一個(gè)只是刪了system/app的一些程序,然后修改build.prop中的ro.build.display.id和ro.build.version.incremental中的兩個(gè)屬性值打上自己的大名的ROM。
system/etc: 該目錄存放一些配置文件,和屬性配置文件不一樣,這下面的配置文件可能稍微沒(méi)那么的有規(guī)律。一般來(lái)說(shuō),一些腳本程序,還有大家所熟悉GPS配置文件(gps.conf)和APN配置文件(apns-conf.xml)放在這個(gè)目錄。像HTC將相機(jī)特效所使用的一些文件也放在這個(gè)目錄下。
4. Zygote(app_process)
上一節(jié)提到init會(huì)執(zhí)行一個(gè)重要的命令程序叫app_process,一般大家稱之為Zygote。(Zygote是卵的意思,所有的Android進(jìn)程都是由它生出來(lái)的)。Zygote首先會(huì)加載dalvik虛擬機(jī),然后產(chǎn)生一個(gè)叫做system_server的進(jìn)程。system_server顧名思義被稱作Android的系統(tǒng)服務(wù)程序,它主要管理整個(gè)android系統(tǒng)。system_server啟動(dòng)完成后開(kāi)始尋找一個(gè)叫做啟動(dòng)器的程序,找到之后由zygote開(kāi)始啟動(dòng)執(zhí)行啟動(dòng)器,這就是我們常見(jiàn)到的桌面程序。
上面描述的是一個(gè)相當(dāng)簡(jiǎn)化的啟動(dòng)過(guò)程,了解這些對(duì)于適配MIUI基本上就夠了,如果大家對(duì)這些想進(jìn)一步了解的話,請(qǐng)關(guān)注市面上各種Android內(nèi)幕書(shū)籍。
5. data和cache分區(qū)
這一節(jié)簡(jiǎn)單的介紹一下data和cache分區(qū)。當(dāng)我們開(kāi)機(jī)進(jìn)入桌面程序后,一般來(lái)說(shuō)我們都會(huì)下載安裝一些APP,這些APP都安裝在data/app目錄下。所有的Android程序生成的數(shù)據(jù)基本上都保存在data/data目錄下。wipe data實(shí)質(zhì)上就是格式化data分區(qū),這樣我們安裝的所有APP和程序數(shù)據(jù)就都丟失了。
cache分區(qū)從名字上來(lái)看是用來(lái)緩存一些文件的,比如說(shuō)一些音樂(lè)下載的臨時(shí)文件,或者下載管理下載的內(nèi)容基本上放在這個(gè)分區(qū)。
6. 小結(jié)
本章主要是介紹了一下Android手機(jī)的硬軟件結(jié)構(gòu)以及主要分區(qū)的內(nèi)容,并簡(jiǎn)要的介紹了一些開(kāi)機(jī)啟動(dòng)過(guò)程。了解這些內(nèi)容有助于我們從整體上理解ROM移植。