在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》