和一般的Linux系统开发流程一样,Android平台开发的一个很重要的基础工作就是对其内核的编译和移植。本文的目的就在于构建出可以在Android自带的ARM QEMU模拟器上运行的内核映像,希望对于大家做内核的移植和系统构建有帮助。
请先参考我的另一篇文章如何取得Android源代码,确保正确地拿到了Android kernel/common项目的Goldfish分支(该分支用于构建运行在emulator上的系统内核,而主线则是用于构建运行在实际设备上的内核代码)上的内核代码。另外,需要提醒一下大家的是Android的sourcecode目前只能在Linux或者Mac OS下做交叉编译编译,Windows并没有被支持,以下将以Ubuntu 8.04为Host OS来说明。
Android对Linux Kernel做了不少的改进,比如添加对yaffs2文件系统的支持,改进蓝牙的支持,改进电源管理机制,以及为模拟器版本添加的Goldfish平台等等,不过内核的编译方式和标准的kernel并没有区别。
这里唯一需要注意的是,Android 1.0_r2以后,整个项目的sourcecode就全部转移到git了,Google Code上不会再有更新,请确保从Git上拿到了android-goldfish-2.6.27分支上的内核代码。
1、在Host OS上准备编译环境
尽管很多人安装完Ubuntu后第一件事情就是装上build-essential,不过我在这里还是要提醒一下大家,另外做menuconfig的时候ncurses-devel库也是必须的。运行以下命令,一次搞定:
sudo apt-get install build-essential ncurses-dev
2、准备交叉编译工具链
Android代码树中有一个prebuilt项目,包含了我们编译内核所需的交叉编译工具,如果你拿了完整的Android 1.5代码树,它就会在prebuilt目录下。如果没有拿完整的代码树也没有关系,只要用Git clone一个或者到从GitWeb下载一个prebuilt项目,如果是从GitWeb下载的话记得解压缩就行。
3、设定环境变量
把刚才下载的prebuilt中的arm-eabi编译器加入$PATH
$export PATH=$PATH:/home/william/android-source/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin
设定目标arch为arm
$export ARCH=arm
4、设定交叉编译参数
打开kernel目录下的Makefile文件,把CROSS_COMPILE指向刚才下载的prebuilt中的arm-eabi编译器
CROSS_COMPILE ?= arm-eabi-
把
LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,/
$(call ld-option, -Wl$(comma)–build-id,))
这一行注释掉,并且添加一个空的LDFLAGS_BUILD_ID定义,如下:
LDFLAGS_BUILD_ID =
下面的这段解释来自陈罡的blog
把它注释掉的原因是目前android的内核还不支持这个选项。–build-id选项,主要是用于在生成的elf可执行文件中加入一个内置的id,这样在core dump,或者debuginfo的时候就可以很快定位这个模块是哪次build的时候弄出来的。这样就可以避免,每次都把整个文件做一遍效验,然后才能得到该文件的是由哪次build产生的。对于内核开发者来说,这是很不错的想法,可以节约定位模块版本和其影响的时间。目前,该功能还出于early stage的状态,未来的android或许会支持,但至少目前的版本是不支持的。
对这个–build-id选项感兴趣的朋友,可以访问下面的网址,它的作者已经解释得非常明白了:
http://fedoraproject.org/wiki/Releases/FeatureBuildId
5、从1.5_r1捆绑的SDK中获得内核配置文件
大家都知道,内核编译中有一步make menuconfig,用于配置kernel,这里我们可以先获取官方的配置,如果必要的话再作改动。先启动模拟器,然后通过adb pull命令(该命令用于从设备上复制文件到本地)即可完成。
$adb pull /proc/config.gz ~/
现在我们用gunzip把config.gz解开,把得到的config文件移动到kernel source所在的目录,然后重命名为.config即可。
$ gunzip config.gz
$ mv config ~/sources/goldfish-kernel/.config
6、开始编译
因为我们之前已经吧1.5_r1中的.config复制到了kernel目录下,如果需要修改配置,可以使用
make menuconfig
修改并保存配置,如果没有特殊需要的话就可以直接用
make
命令来编译内核了
7、测试生成的zImage
编译内核的过程应该很顺利,因为默认的配置对内核作了大幅的精简,大约5~6分钟就可以编译完成了,会在最终会在arch/arm/boot目录下面生成一个zImage,这个就是我们所要的运行在模拟器上的内核映像了。
下面我们就在模拟器中测试一下我们所生成的zImage。
emulator @1.5_L2 -kernel ./zImage
其中1.5_L2是我之前创建的AVD,如果想输出kernel log,请加上-show-kernel参数。
一切顺利的话,我们应该可以看到Android顺利启动了。
通过adb shell,我们可以查看version信息,如下图:
关于为实际设备编译kernel
如果要为一个实际的设备比如说G1重新编译内核映像,步骤和上述为一个运行在模拟器上的内核映像步骤基本一致,只是所需要的源代码应当来自主线而不是goldfish分支。另外,编译完成以后载入映像的方式也不同,需要通过USB将映像烧入nand flash。