Android中ROM的制作

Android的ROM

    首先介绍一下ROM的基本知识,其实按照比较科学的方法来说,Android的“ROM”这种叫法本身就是错误的,只不过是历史遗留的称呼罢了。看看定义吧,所谓的“ROM是只读内存(Read-Only Memory)的简称。ROM所存数据,一般是装入整机前事先写好的,整机工作过程中只能读出,而不像随机存储器那样能快速地、方便地加以改写。ROM所存数据稳定 ,断电后所存数据也不会改变;其结构较简单,读出较方便,因而常用于存储各种固定程序和数据”。在Android之前的手机,包括智能机(Nokia、WM等)和非智能机(索爱,Moto P2K平台,MTK等)都有一个单独的ROM芯片保存系统文件,所谓的“刷ROM”(或是刷包)就是将官方或是第三方的ROM镜像文件通过工具烧写到ROM中的过程,而所谓的“做ROM”就是将个人定制的系统文件做成可烧写的ROM镜像的过程。不过在Android手机中,系统必要的文件不再保存在ROM中了,而是保存在原本就可擦写的文件分区之中了。虽然传统的ROM芯片已不存在,不过既然现在国内外还是把Android上的这玩意叫ROM,那我们也还是按照国际惯例继续称之为ROM吧。罗嗦了那么多,那么到底什么是Android ROM(以下简称ROM)呢?这个是没有官方定义的,按照我的个人见解,所谓ROM就是可以替换手机内必要文件的按照特定规则封装的一个或多个文件。从替换方式上可以分为文件镜像型和文件替换型,从替换程度上可以分为完整ROM和非完整ROM。
其中的名称解释:
封装:就是你所刷的ROM包中系统文件的包装格式,如HTC早期的G1的NBH,MOTO的sbf,三星的tar,以及最常见的zip等。封装只是为了让刷ROM的工具可以正确读取罢了,它只是一个外壳,不是ROM的实质;
文件镜像型:指ROM包中系统文件是通过烧写分区实现刷机的类型,如常见的img镜像,三星的rfs镜像等。文件镜像型的 ROM的原理是将一个镜像恢复到相应分区。如果要修改,需要将其解包,操作完成后重新生成一个镜像包;
文件替换型:指ROM包中系统文件是通过重建系统分区内文件实现刷机的类型,如常见的zip刷机包,openrecovery的刷机文件夹等。文件替换型ROM的原理是是根据相应脚本替换系统文件。如果要修改,需要增减相应文件,然后确保相应脚本无误;
完整ROM:指ROM包中包含了手机启动的全部必要程序的ROM包,包含bootloader,radio,kernel,system等。官方的ROM多数都是完整ROM;
非完整ROM:指ROM包中仅包含完整ROM中部分组件的ROM,一般来说仅包含system和kernel。第三方ROM多数都是非完整ROM。

怕大家听的有点晕,所以下面就用两个刷ROM的实例来讲解一下
1、现在各个机型最常用的刷机方法就是通过recovery刷机,过程是:进recovery,选择zip,刷入。其实这个刷这个ROM的过程可以分解为:启动recovery,选择要刷的zip包,校验zip包的签名以确保完整性(有些recovery可以跳过此步骤),读取zip包中的升级脚本然后开始升级。关键就在这个升级脚本中,它定义了recovery要执行的操作,一般来说脚本都包含这4个步骤:清空系统分区,复制zip包中的文件到手机中,创建文件链接,设置文件和目录的权限。多数的zip会包含一个boot.img,就是kernel,很少会有zip包含bootloader和radio。所以这个ROM就是封装成zip的文件替换型非完整ROM。
2、MOTO的手机通过RSD刷SBF的官方ROM,过程是:连接手机,载入sbf文件,开始刷机,好了,RSD刷写这个ROM的过程可以分解为:解包sbf为多个镜像文件,将镜像烧写到手机中对应的分区,校验分区签名,完成刷机。一般的官方sbf中都会包含bootloader等全部的文件。所以这个ROM就是封装成sbf的文件镜像型完整ROM。

到此,你应该也大致了解了什么是ROM以及ROM分类了。认清这些以后,我们就可以游刃有余的根据不同的手机灵活的修改和制作相应ROM了,例如制作HTC的zip格式的ROM,只需要将相应文件做成zip包然后添加相应脚本就好了;制作i9000的tar格式的ROM,只需要用文件替换的方法在一个手机里做好系统,然后用cat命令将system分区保存为rfs镜像,然后再打包成tar就好了;

 

Android编译生成的三个镜像文件
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 system/ 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

你可能感兴趣的:(Android中ROM的制作)