Android源碼編譯後,在out/target/product/generic下產生的三個鏡像檔案:ramdisk.img,system.img,userdata.img以及它們對應的分類樹root,system,data。ramdisk.img是根檔案系統,system.img包括了主要的包、庫等檔案,userdata.img包括了一些使用者資料,android載入這3個映像檔案後,會把 system和 userdata分別載入到 ramdisk檔案系統中的system和 data目錄下。
三個鏡像檔案及其三個分類樹之間的產生關係是我們進行ROM製作的基礎,下面將做詳細介紹。
Ramdisk.img
Ramdisk鏡像是採用cpio打包,gzip壓縮的。用file驗證:
# file ramdisk.img
輸出:
# ramdisk.img: gzip compressed data, from Unix
為了便於說明問題,我們將ramdisk.img拷貝到其它一個目錄,然後按以下步驟將ramdisk.img還原為分類樹:
# mv ramdisk.img ramdisk.img.gz
# gunzip ramdisk.img.gz
# mkdir ramdisk
#cd ramdisk
# cpio –i –F ../ramdisk.img
這樣,就得到一個完整的ramdisk目錄,與out/target/product/generic/root對比後,我們發現它們是一樣的內容。
通過執行以下的操作,我們可由分類樹再產生ramdisk鏡像
# cd ramdisk
# find . | cpio -o -H newc | gzip > ../ramdisk-new.img
system.img & userdata.img
這兩個鏡像都屬於yaffs2檔案格式,產生方式是一樣的。我們就以system.img為例來說明。
System.img >> system分類樹
所需工具unyaffs, http://code.google.com/p/unyaffs/downloads/list
# mkdir system
# cd system
# unyaffs ../system.img
system分類樹 >> system.img
所需工具 mkyaffs2image,Android源碼編譯後會產生該工具,在 out/host/linux-x86/bin 目錄下。
命令格式:
進入mkyaffs2image所在目錄,設定執行許可權chmod a+x ./mkyaffs2image
# ~/Code/cbin/mkyaffs2image ~/Code/system ~/Code/system_new.img
瞭解以上方法的意義在於,我們可以對鏡像檔案鏡像修改,定製,以符合自己的需求。
Android ROM的製作方法
網上有很多製作Android ROM的教程,這裡羅列一些連結:
北理工的陳罡寫的兩篇文章,是我目前發現的最好的教程,寫的非常詳細
http://blog.chinaunix.net/u/26691/showart_2193396.html
http://blog.chinaunix.net/u/26691/showart_2194274.html
這兩篇文章參考了國外論壇的幾個經典教程:
http://forum.xda-developers.com/showthread.php?t=566235
http://android-dls.com/wiki/index.php?title=HOWTO:_Unpack%2C_Edit%2C_and_Re-Pack_Boot_Images
國內還有一篇文章寫的也不錯,這篇文章更側重於製作類似Patch的ROM包
http://www.cnmsdn.com/html/201002/1267213800ID1030.html
這裡基於自己的理解和測試,總結了一些方法步驟。
1.從可用的ROM起步
Android 的ROM包通常稱為update.zip包,你可以到www.hiapk.com上下載現成的.zip包。要學習ROM包的製作,我們可以從這樣一個zip包開始。解開zip包後,通常有這樣一些內容:
boot.img
檔案
這是編譯核心原始碼產生的核心映像,然後與android源碼編譯出來的ramdisk.img一起通過mkbootimg工具建立出來的,圖省事的朋友也可以從網上其他的刷機包裡面拷貝一個能用的出來即可,基本上都差不多。
META-INF
目錄
這個目錄是手工建立的,主要用來存放一個升級指令碼update-script(這個指令碼的內容與system目錄中包含的檔案有很大關聯)以及簽名。
system
目錄
這個目錄就是編譯android的平台原始碼產生的
要建立自己的ROM,我們通常會涉及到以下的一些工作:
1. 編譯核心產生核心映像。但一般情況下,我們沒有必要自己去編,直接從刷機包裡面取出一個就可以。譬如,你要做一個2.2版本的升級包。可以到網上找一個與自己機型相匹配的刷機包,從裡面取出相應的kernel.img。
2. ramdisk.img的修改。ramdisk.img 是根檔案系統,裡麵包含了啟動配置指令碼。
3. update-script的修改。
4. System的修改。
我們先做個簡單的測試工作,來為後面更複雜的工作做好鋪墊。測試內容為:先對zip進行解包,然後分別在ramdisk和system的根目錄下添加一個小檔案,接著,產生新的ROM,並驗證ROM是否可用。
詳細的步驟可以參考http://blog.chinaunix.net/u/26691/showart_2194274.html。這裡要指出的是,這篇文章以及網上許多類似網站提到的方法都是針對HTC G1或 Nexus one的。而我在測試的時候,用的是HTC G3 Hero。以上的方法導致的一個後果是,重新打包後再燒錄,機器無法正常啟動,adb shell也無法登陸。後來在國外的一篇部落格上看到了對此問題的說明,問題的根源很簡單,從G3開始,打包的時候需要指定 “--base”參數。對於Hero,參數為”--base 0x19200000”,但對於其它型號的機器,”--base"要設定為多少,需要參考核心代碼的實現。
解包打包可用兩個指令碼完成unpack-bootimg.pl, repack-bootimg.pl。其中打包指令碼用到的mkbootimg工具,在out/host/linux-x86/bin目錄下。unpack-bootimg.pl可直接將boot.img產生核心鏡像boot.img-kernel和ramdisk分類樹boot.img-ramdisk。repack-bootimg.pl可將boot.img-kernel和boot.img-ramdisk重建boot.img。
在解包後,我們在ramdisk和system目錄下,各添加一個測試小檔案(譬如叫mytest)。做完這些開始組包,重建update.zip。到這裡我們的工作並沒有完全結束,還有最後的一步——簽名。簽名需要用到簽名工具testsign.jar,這是一個基於java 1.6版本的工具。在編譯Android源碼的時候,我們強調要用java 1.5。在這裡,我們必須切換到1.6版本。切換辦法見這裡。
2.利用自己編譯的鏡像產生ROM
1)重建boot.img
將前面解包得到的boot.img-ramdisk 和 編譯源碼後out/target/product/generic/下的root分類樹放在一個目錄下,然後用repack-bootimg.pl重建boot.img
2) 建立一個目錄 myupdate,將上面產生的boot.img放到這個目錄下
3)將編譯Android後,out/target/product/generic/產生的system分類樹拷貝到myupdate目錄
4)在myupdate目錄下建立update-script指令碼目錄
# mkdir -p META-INF/com/google/android
5)刪除system/bin目錄下的“符號連結”,建立update-script指令碼
update-script指令碼的文法可以參考 這裡 。研究原有的update-script指令碼,我們可以大致看出update-script負責檔案刪除拷貝,使用權限設定,符號連結建立等工作。我們可以在原有update-script的基礎上進行修改以得到我們自己的update-script。這裡,我們要注意的是,要保證update-script的link建立成功,必須把/system/bin下的link刪除。我們可以用一個指令碼來做這個工作 delsymlink。我修改後與自己編譯的Android2.2 system分類樹相匹配的指令碼。
6)重新打包並簽名
7)自製ROM下載時報錯
在實驗過程中,我經常遇到如下的報錯
Can't open/sdcard/download/update.hiapk
問題原因:當 update-script 中有命令操作錯誤,指令碼就會停止,並報這個錯誤,解決的辦法就是修正指令碼。你可以從這個錯誤前面的提示,知道指令碼哪一行出錯了。
3. 建立一個Patch功能的ROM
很多時候,你並不需要建立一個完整的ROM包。你需要的只是,添加刪除或修改一些功能(譬如你僅想添加一個應用,或者你想添加busybox工具)。我們可以參考這裡,來實現這個目的。
我用一個簡單的例子來說明這個過程。該例子是在system目錄下添加一個mytest檔案,同時建立一個指向這個檔案的符合連結mylink。以下是過程:
1) 建立patch_update目錄,並在該目錄下執行
# mkdir system
# mkdir –p META-INF/com/google/android
2) 在system目錄下產生mytest檔案
3) 在 META-INF/com/google/android 建立如下的update-script
show_progress 0.1 0
copy_dir PACKAGE:system SYSTEM:
symlink mytest SYSTEM:mylink
set_perm 0 0 0755 SYSTEM:mytest
4) 打包簽名
如果前面的3步曲,你已經很好的掌握了,應付你的日常工作應該沒有太大的問題。但要成為真正的ROM高手,你還有很多東西要修鍊。你要瞭解整個啟動過程,核心編譯,Android源碼的編譯及配置,檔案系統及啟動配置。。。
燒錄 Android 機器
HTC的官網上有一篇文章 這裡 詳細介紹了鏡像包及燒機方法。通常用兩種燒錄方式:recovery模式,fastboot模式。通過一些按鍵組合,可以進入燒錄模式。以HTC G3 Hero為例,“Home + Power”同時按,可以進入Recovery模式,“Back + Power”可以進入fastboot模式。
Recovery模式比較常用,它相當菜單介面的下載模式。直接把前面所述的update.zip檔案放到SD卡上,然後通過在機器上操作控制功能表,就可完成燒錄。Fastboot是基於命令列的較低級的下載模式,它可直接燒錄.img檔案。Fastboot工具也在out/host/linux-x86/bin目錄下。
在我測試過程中,發現fastboot模式無法燒錄,當我試圖燒錄system.img的時候,出現下面的出錯資訊:
# fastboot flash system system.img
# writing 'system'... INFOsignature checking...
FAILED (remote: signature verify fail)
在網上查了之後,發現這和簽名有關係,SPL要重新刷一下才可,預設是SPL-on,即檢測簽名,改成SPL-off,就不會出現這個問題,目前沒有什麼好辦法來處理這個問題。好在recovery模式已經能很好地滿足需求了,可以先放棄fastboot。
如果你通過recovery模式燒錄後,發現系統無法正常啟動,沒有關係,recovery還是可以進去的。在recovery模式下,你可以通過adb shell登陸機器。可能你進去後,發現SD卡並沒有掛接上來(執行mount就可以查看掛載情況)。但recovry模式要求update.zip必須放在SD卡根目錄下,怎麼辦?很簡單,執行“mount –a”就可把SD卡地區掛接上來。如果這招也不行,還有一招,就是把userdata分區手動掛接到sdcard目錄,這樣就騙過了recovery。
# mount /dev/mtdblock5 /sdcard
然後,你再用adb push把新的update.zip拷貝到sdcard目錄,重新進行燒錄。一般來說,在執行“Flash zip from sdcard”之前,都要先進行Wipe操作,以清除舊的使用者資料。
如何更新recovery?
可以參考http://bbs.gfan.com/viewthread.php?tid=66973,按照這個攻略,把自己的G3 Hero更新成了recovery-RA-hero-v1.6.2-blue.img。不過,一般無特別的需求,最好不要更新recovery。畢竟有一定風險,一不小心就成了板磚。
其它參考資訊:
知名的Android論壇:
國內:www.hiapk.com
國外:http://android-dls.com 很多國內論壇的文章都是參考或翻譯http://android-dls.com 的
國內一個很好的部落格:http://xy0811.spaces.live.com/ ,有很多對Android的研究專題
國外一個很好的部落格:http://blog.coralic.nl/category/android/ ,這個部落格幫我解決了在燒錄 HTC G3 HERO的時候,自己打的ROM包燒錄後無法啟動的問題
Android 檔案系統
http://www.ibm.com/developerworks/cn/linux/l-k26initrd/
http://developer.51cto.com/art/201001/180468.htm
http://git.source.android.com/?p=kernel/common.git;a=blob;f=Documentation/filesystems/ramfs-rootfs-initramfs.txt
http://dev.firnow.com/course/6_system/linux/Linuxjs/20090901/173312.html
Android init指令碼的文法
http://blog.chinaunix.net/u3/103613/showart.php?id=2237012
http://www.kandroid.org/android_pdk/bring_up.html