在ROM定製中,通常需要修改 system.img
、userdata.img
、boot.img
、recovery.img
這四個鏡像文件。
一、修改系統鏡像(system.img)
一、 判斷文件類型
system.img
文件格式有yaffs2
格式和 ext
格式兩種。解壓前應當用在linux下用file
命令對文件格式進行判斷。
$ file system.img
yaffs
格式會輸出:system.img: VMS Alpha executable
ext
格式會輸出:system.img:data
二、解壓
對於system.img
文件,通常使用 unyaffs
命令進行解壓。unyaffs
源碼文件地址 : ,在烏班圖下輸入下面的命令進行編譯:
gcc -o unyaffs unyaffs.c
解壓 system.img
文件的命令如下:
$ unyaffs system.img
對於 ext
文件格式類型文件,使用<Android源碼根目錄>/out/host/linux-x86/bin
目錄中的simg2img
二進制文件將system.img轉換爲普通的linux鏡像文件(ext4)文件格式
$ simg2img system.img system.img.raw
用file system.img.raw
命令查看 system.img.raw
文件的格式,會發現輸出:
$ file system.img.raw
system.img.raw: Linux rev 1.0 ext4 filesystem data, UUID=57f8f4bc-abf4-655f-bf67-946fc0f9f25b (extents) (large files)
system.img.raw 文件類型爲 ext4
類型
然後在/mnt
目錄中創建一個system
子目錄,並執行下面的命令掛載系統鏡像`
$ sudo mount -t ext4 -o loop system.img.raw /mnt/system
三、重打包
對於ext4
文件系統,修改完系統鏡像後,需要使用make_ext4fs
命令將/mnt/system目錄重新生成system.img文件。該文件的目錄爲:
<Android 源代碼根目錄> /out/host/linux-x86/bin
在linux終端執行執行如下的命令生成system.img
文件
$ make_ext4fs -s -l 512M -a system newsystem.img /home/aosp444/unyaffs/system
-s 指 Sparse 文件格式的鏡像文件。掛載Sparse格式的鏡像文件,需要首先使用simg2img
命令進行掛載。
-l 是指鏡像文件刷入設備後所佔非分區大小。一般略大於 img
鏡像文件
-a 指的是掛載點 這裏指的是 system
對於yaff2
文件系統 ,修改完系統鏡像後,需要使用out/host/linux-x86/bin/mkyaffs2image
文件進行重打包,打包命令
$ mkyaffs2image -f system newsystem.img
二、用戶數據鏡像(userdata.img)
安卓設備的內部存儲器被劃分爲不同的分區。其中userdata.img
屬於userdata
分區,該分區指是內存,內部存儲器的剩餘部分被視爲外部存儲、屬於sdcard
分區。
使用simg2img
文件對鏡像進行轉換成’ext4’ 格式的文件
$ simg2img userdata.img userdata.img.raw
在當前目錄下創建userdata
文件夾,將userdata.img.raw
文件掛載到該目錄下。
$ sudo mount -t ext4 -o loop userdata.img.raw ./userdata
進入userdata
目錄後看到該目錄下只有lost+found
目錄,
查看該掛載點的大小
aosp444@aosp444-virtual-machine:~/unyaffs/userdata$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda6 14G 3.4G 9.6G 27% /
udev 2.0G 4.0K 2.0G 1% /dev
tmpfs 394M 776K 394M 1% /run
none 5.0M 0 5.0M 0% /run/lock
none 2.0G 152K 2.0G 1% /run/shm
/dev/sda1 180M 32M 136M 19% /boot
/dev/sda7 137G 125G 4.9G 97% /home
/dev/sr0 758M 758M 0 100% /media/Ubuntu 12.04.5 LTS amd64
/dev/loop0 992M 268M 709M 28% /mnt/system
/dev/loop1 992M 268M 709M 28% /home/aosp444/unyaffs/system
/dev/loop2 13G 33M 13G 1% /home/aosp444/unyaffs/userdata
aosp444@aosp444-virtual-machine:~/unyaffs/userdata$
掛載點的大小爲13左右
在userdata
目錄下新建一個app
目錄,將apk文件放入其中
重新打包該文件
$ make_ext4fs -s -l 13G -a data userdata.img.new ./userdata
然後使用下面的命令將userdata.img.new
文件刷入手機
$ adb reboot bootloader
$ fastboot flash userdata userdata.img.new
發現之前複製到app
目錄中的apk文件安裝到了手機中。
三、內存磁盤鏡像(ramdisk.img)
ramdisk.img
其實是對root目錄的打包和壓縮,ramdisk根文件系統中包含一些對於啓動android的很重要的文件,比如內核啓動完後加載的第一個進程init、一些重要的配置文件等,總之它控制着整個android的啓動。根據 init.rc,init.goldfish.rc來初始化並裝載系統庫、程序等直到開機完成。init.rc腳本包括了文件系統初始化、裝載的許多過程。ramdisk.img最後和kernel一起打包生成boot.img鏡像。
ramdisk.img是一個普通的zip
文件,可以用gunzip命令對其進行解壓
$ gunzip -c ramdisk.img > ramdisk.cpio
解壓後並不是原始文件和目錄,而是由cpio命令備份還原的文件,還需要繼續還原
$ cpio -i < ../ramdisk.cpio
drwxrwxr-x 9 aosp444 aosp444 4096 Jul 27 22:00 ./
drwxrwxr-x 3 aosp444 aosp444 4096 Jul 27 21:58 ../
-rwxr-x--- 1 aosp444 aosp444 272364 Jul 27 22:00 charger*
drwxrwx--x 2 aosp444 aosp444 4096 Jul 27 22:00 data/
-rw-r--r-- 1 aosp444 aosp444 286 Jul 27 22:00 default.prop
drwxr-xr-x 2 aosp444 aosp444 4096 Jul 27 22:00 dev/
-rw-r--r-- 1 aosp444 aosp444 8983 Jul 27 22:00 file_contexts
-rw-r----- 1 aosp444 aosp444 2653 Jul 27 22:00 fstab.hammerhead
-rwxr-x--- 1 aosp444 aosp444 179484 Jul 27 22:00 init*
-rwxr-x--- 1 aosp444 aosp444 919 Jul 27 22:00 init.environ.rc*
-rwxr-x--- 1 aosp444 aosp444 16671 Jul 27 22:00 init.hammerhead.rc*
-rwxr-x--- 1 aosp444 aosp444 5710 Jul 27 22:00 init.hammerhead.usb.rc*
-rwxr-x--- 1 aosp444 aosp444 20177 Jul 27 22:00 init.rc*
-rwxr-x--- 1 aosp444 aosp444 1795 Jul 27 22:00 init.trace.rc*
-rwxr-x--- 1 aosp444 aosp444 3915 Jul 27 22:00 init.usb.rc*
drwxr-xr-x 2 aosp444 aosp444 4096 Jul 27 22:00 proc/
-rw-r--r-- 1 aosp444 aosp444 2161 Jul 27 22:00 property_contexts
drwxr-xr-x 3 aosp444 aosp444 4096 Jul 27 22:00 res/
drwxr-x--- 2 aosp444 aosp444 4096 Jul 27 22:00 sbin/
-rw-r--r-- 1 aosp444 aosp444 656 Jul 27 22:00 seapp_contexts
-rw-r--r-- 1 aosp444 aosp444 74890 Jul 27 22:00 sepolicy
drwxr-xr-x 2 aosp444 aosp444 4096 Jul 27 22:00 sys/
drwxr-xr-x 2 aosp444 aosp444 4096 Jul 27 22:00 system/
-rw-r--r-- 1 aosp444 aosp444 2204 Jul 27 22:00 ueventd.hammerhead.rc
-rw-r--r-- 1 aosp444 aosp444 4024 Jul 27 22:00 ueventd.rc
上面的命令可以合成如下的一行:
$ gunzip -c ../ramdisk.img | cpio -i
將busybox
二進制文件放入ramdisk中的sbin目錄,
在解壓出的目錄中,執行下面的目錄進行壓縮
$ mkbootfs . | minigzip > ../ramdisk.img.new
四、Linux 內核鏡像(boot.img)
Android linux內核鏡像包含了內核二進制文件(zImage)和內存磁盤鏡像(ramdisk.img),一般對應的鏡像文件是boot.img
.由於ramdisk.img
中包含的init命令是與Linux內核第一個交互的程序,所以boot.img
鏡像包括zImage
和 ramdisk.img
。當linux內核調用init後。系統就會根據init.rc 及相關文件中的代碼對整個Android系統進行初始化。其中主要的初始化工作就是建立如/system
、data
等系統目錄,然後使用mount
命令將相應的鏡像掛載到這些目錄上。
用unpackbootimg
命令將boot.img解壓
drwxrwxr-x 2 aosp444 aosp444 4096 Jul 28 12:00 ./
drwxrwxr-x 3 aosp444 aosp444 4096 Jul 28 11:02 ../
-rw-rw-r-- 1 aosp444 aosp444 9 Jul 28 12:00 boot.img-base
-rw-rw-r-- 1 aosp444 aosp444 1 Jul 28 12:00 boot.img-board
-rw-rw-r-- 1 aosp444 aosp444 107 Jul 28 12:00 boot.img-cmdline
-rw-rw-r-- 1 aosp444 aosp444 9 Jul 28 12:00 boot.img-kerneloff
-rw-rw-r-- 1 aosp444 aosp444 5 Jul 28 12:00 boot.img-pagesize
-rw-rw-r-- 1 aosp444 aosp444 498994 Jul 28 12:00 boot.img-ramdisk.gz
-rw-rw-r-- 1 aosp444 aosp444 9 Jul 28 12:00 boot.img-ramdiskoff
-rw-rw-r-- 1 aosp444 aosp444 9 Jul 28 12:00 boot.img-tagsoff
-rw-rw-r-- 1 aosp444 aosp444 8405280 Jul 28 12:00 boot.img-zImage
除了zImage和random.gz兩個主要的文件外,其它幾個都是參數的配置文件 其中cmdline
、base
、pagesize
這三個參數需要自己制定。
然後使用mkbootimg
命令進行重打包, 將配置參數替換成解壓出的值進行重打包
$ mkbootimg --base 0 --pagesize 2048 --kernel_offset 0x00008000 --ramdisk_offset 0x02900000 --second_offset 0x00f00000 --tags_offset 0x02700000 --cmdline 'console=ttyHSL0,115200,n8 androidboot.hardware=hammerhead user_debug=31 maxcpus=2 msm_watchdog_v2.enable=1' --kernel boot.img-zImage --ramdisk boot.img-ramdisk.gz -o boot.img.new
bootimg相關的工具
mkbootimg_tools:https://github.com/xiaolu/mkbootimg_tools(不用設置參數)
bootimg-tools :https://github.com/pbatard/bootimg-tools
五、製作已經有ROOT權限的ROM
製作已有root
權限的ROM,需要將su
二進制文件放到解壓的system.img
文中 /system/xbin
目錄中,再重打包成system.img
。 但這樣從PC
進入Android系統的Shell
時,默認並不是ROOT權限,還要執行su
命令纔會切換到ROOT
權限,而且也不執行adb remount
對系統目錄(/system/app)寫入的權限。需要修改Linux 內核鏡像文件(boot.img)中ramdisk.img
文件中的default.prop
文件。
ro.secure=0
ro.allow.mock.location=1
ro.debuggable=1
persist.sys.usb.config=mtp,adb
ro.adb.secure=1
persist.service.adb.enable=1
六、Recovery鏡像(recovery.img)
Recovery鏡像只用於刷機,它與boot.img一樣都包含linux(zImage)文件和ramdisk.img
文件,只不過ramdisk.img
文件不一樣。.它們內核調用的init
命令和init.rc
文件內容不一樣。
它的解壓也使用unpackbootimg
命令
ramdisk.gz 解壓也使用gunzip
和cpio
打包使用mkbootimg
具體操作可以參考boot.img
七、緩存鏡像(cache.img)
cache.img鏡像存儲系統或用戶產生的臨時數據,它實際上是一個空的ext4格式的文件系統鏡像
$ mkdir -p /mnt/rom/cache
$ make_ext4fs -s -l 256M -a cache cache.img /mnt/rom/cahe
八、製作Bootloader ROM
Bootloader ROM 包中主要包含system.img
userdata.img
、 boot.img
和 recovery.img
四個鏡像文件,將這是個文件壓縮成一個zip文件(文件名可以隨意取)。爲了對壓縮包能刷的android設備進行限制, 可在壓縮包中包含一個android-info.txt
文件。下面是nexus5 android-info.txt
文件中 的內容,科長/proc/cpuinfo
中查看board
的信息。
require board=hammerhead
require version-bootloader=HHZ11k
require version-baseband=M8974A-2.0.50.1.16
刷機命令
fastboot -w update update.zip
九、製作Recovery ROM
Bootloader ROM 只能對整個分區進行更新,如果需要更新分區中的一部分,則需要recovery ROM。
recovery ROM 刷機時通常不會刷recovery分區,並且清楚用戶和Cache數據。主要對boot
分區和system
分區進行更新。
Recovery ROM 壓縮包的格式爲zip,通常由一個三部分組成:
- META-INF目錄:包含存儲簽名文件、更新腳本等內容
- system目錄:要複製到System分區的文件。目錄結構應當與system分區一樣。
- boot.img文件:內核鏡像文件。
META-INF目錄比較特別:除了簽名外,還包括如下兩個非常重要的文件:
META-INF/com/google/android/updater-script
META-INF/com/google/android/update-binary
update-binary
是一個腳本解釋器,解釋腳本文件updater-script
,updater-script
腳本語言爲Edify
語言,是Android
系統內嵌的微型語言之一。 製作Recovery ROM 過程中需要編寫updater-script
。
下面製作一個Recovery包,將 su
和busybox
複製到系統system
分區中
一、建立system目錄
建立一個system/xbin目錄,並將su和busy文件複製進去
二、建立META-INF目錄
建立META-INF目錄,並在目錄中建立META-INF/com/google/android
目錄,並將update-binary
複製進去,新建一個updater-script
文件,update-binary
可以找到相應設備的recovery更新包中獲取
三、編寫更新腳本
ui_print("*********************");
ui_print("My First Recovery Update");
ui_print("*********************");
ui_print("----Mounting /system ----");
run_program("/sbin/busybox", "mount","-o", "rw", "/system");
ui_print("----Delete /system/xbin/su ----");
delete("/system/xbin/su");
ui_print("----Delete /system/xbin/busybox ----");
delete("/system/xbin/busybox");
ui_print("----Extracting files");
package_extract_dir("system", "/system");
ui_print("----- Setting permissions");
set_perm(0, 0, 0777, "/system/xbin/su");
set_perm(0, 0, 0777, "/system/xbin/busybox");
unmount("/system");
ui_print("finished");
四、生成壓縮包
用zip壓縮文件將META-INF
和system
目錄壓縮成zip文件。
五、簽名
簽名是非必須的,Clockworkmod Recovery允許刷未簽名的ROM.
java -jar signapk.jar -w testkey.x509.pem testkey.pk8 update.zip signed-update.zip
注意事項:
- recovery刷機包中目錄不應該包含雙字節
- package_extract_dir
不會創建目錄,目錄應該跟system分區標準目錄一致
下面
製作
參考文章:
1. http://blog.163.com/zz_forward/blog/static/212898222201592810729837/
2. 《Android 深度探索 卷2》