这几天可能要接个Android的项目,基于x86平台。所以先了解一下android的安装过程。在其官方网站上下载了Android的img,先面就解压出来看看吧,需要说明的是以下的操作都是在root用户下进行的。
mkdir android mount android-x86-4.3-20130725.iso android
通过以上的命令可以把我们下载的android镜像挂载到android目录下,下面我们可以看一下他的目录结构:
├── initrd.img ├── install.img ├── isolinux │ ├── android-x86.png │ ├── boot.cat │ ├── isolinux.bin │ ├── isolinux.cfg │ ├── TRANS.TBL │ └── vesamenu.c32 ├── kernel ├── ramdisk.img ├── system.sfs └── TRANS.TBL
对以上文件详细的了解可以参考csdn的这篇博文
http://blog.csdn.net/liujixin8/article/details/4029887
接下来看一下install.img这个文件,我们用file命令看一下这个文件属性
android# file install.img install.img: gzip compressed data, from Unix, last modified: Fri Jul 26 02:05:58 2013, max compression
可以看到这个文件是一个gzip的文件,所以我们可以解压出来看看,命令如下:
mkdir install cp /tmp/android/install.img /tmp/install mv install.img install.img.gz gunzip install.img.gz cpio -i -F install.img
这个时候我们看下install这个目录的结构:
install# ls bin grub install.img lib sbin scripts
可以看出通过这个文件的解压多出了以下目录:
bin grub lib sbin scripts
不过通过以上的目录可以看出,基于x86结构的android是用grub引导的。接下来看一下他的启动流程,在看启动流程之前我们先看一下isolinux.cfg这个文件,这个文件的具体作用在上面的内容中已经说过,在此不在赘述,文件内容如下:
default vesamenu.c32 timeout 600 menu background android-x86.png menu title Android-x86 Live & Installation CD 4.3-test menu color border 0 #ffffffff #00000000 menu color sel 7 #ffffff00 #ff000000 menu color title 0 #ffffffff #00000000 menu color tabmsg 0 #ffffffff #00000000 menu color unsel 0 #ffffffff #00000000 menu color hotsel 0 #ffffff00 #ff000000 menu color hotkey 7 #ffffff00 #00000000 label livem menu label Live CD - ^Run Android-x86 without installation kernel /kernel append initrd=/initrd.img root=/dev/ram0 androidboot.hardware=android_x86 video=-16 quiet SRC= DATA= label vesa menu label Live CD - ^VESA mode kernel /kernel append initrd=/initrd.img root=/dev/ram0 androidboot.hardware=android_x86 video=-16 quiet nomodeset vga=788 SRC= DATA= label debug menu label Live CD - ^Debug mode kernel /kernel append initrd=/initrd.img root=/dev/ram0 androidboot.hardware=android_x86 video=-16 vga=788 DEBUG=2 SRC= DATA= label install menu label Installation - ^Install Android-x86 to harddisk kernel /kernel append initrd=/initrd.img root=/dev/ram0 androidboot.hardware=android_x86 video=-16 INSTALL=1 DEBUG=
我们主要看下面的label这几个选项。一共有四个label选项,前面的两个不太熟悉,不过在这里不影响我们。第三个为debug模式,第四个为install模式,也就是android的安装,从加在这里的内核参数可以看出,系统启动的是initrd.img里的内容,那接下来我们就分析一下initrd.img 这个文件。我们用file命令看一下这个文件的属性就可以知道他和上文说的install.img的文件属性是一样的,我们用同样的方法把他解压出来,内容如下:
initrd# ls
android bin hd init lib mnt proc sbin scripts sfs sys tmp
以上就是把initrd.img文件解压出来的内容,系统的启动就是从这个地方开始,熟悉linux的朋友看到这个就知道是从那个文件开始执行了。接下来我们看一下init这个文件,这个文件是一个文本文件,可以看一下它的文件属性
initrd# file init init: a /bin/busybox sh script, ASCII text executable
下面可以看一下这个脚本的内容:
echo -n Detecting Android-x86... mount -t tmpfs tmpfs /android cd /android while :; do for device in ${ROOT:-/dev/sr* /dev/[hs]d[a-z]*}; do check_root $device && break 2 mountpoint -q /mnt && umount /mnt done sleep 1 echo -n . done
这个是脚本的初始函数,相当于c语言的mian函数,首先看到的地一个mount命令挂载了tmpfs文件系统,对这个不是很熟悉,等有时间了学习了一下这个在把这个补上。看看接下来while循环,在这一段内容里重点看一下 check_root,这个是定义的一个函数,这个函数定义如下:
try_mount() { RW=$1; shift if [ "${ROOT#*:/}" != "$ROOT" ]; then # for NFS roots, use nolock to avoid dependency to portmapper RW="nolock,$RW" fi # FIXME: any way to mount ntfs gracefully? mount -o $RW $@ || mount.ntfs-3g -o rw,force $@ } check_root() { try_mount ro $1 /mnt && [ -e /mnt/$SRC/ramdisk.img ] [ $? -ne 0 ] && return 1 zcat /mnt/$SRC/ramdisk.img | cpio -id > /dev/null if [ -e /mnt/$SRC/system.sfs ]; then mount -o loop /mnt/$SRC/system.sfs /sfs mount -o loop /sfs/system.img system elif [ -e /mnt/$SRC/system.img ]; then mount -o loop /mnt/$SRC/system.img system elif [ -d /mnt/$SRC/system ]; then remount_rw mount --bind /mnt/$SRC/system system else rm -rf * return 1 fi mkdir cache mnt mnt/sdcard mount -t tmpfs tmpfs cache echo " found at $1" }
这个函数的作用主要是挂载ramdisk.img和system.sfs,这两个文件可以看看我们最初始解压的文件。这里需要说明的是system.sfs这个文件解压出来是system.img。system.img里包含的就是具体的系统文件了。这个到后面会讲到。
ln -s mnt/$SRC /src
ln -s android/system /
ln -s ../system/lib/modules /lib
ln -s ../system/lib/firmware /lib
if [ -n "$INSTALL" ]; then
cd /
zcat /src/install.img | cpio -iud > /dev/null
fi
if [ -x system/bin/ln -a ( -n "$DEBUG" -o -n "$BUSYBOX" ) ]; then
mv /bin /lib .
system/bin/ln -s android/lib /lib
system/bin/ln -s android/bin /bin
sed -i 's|(PATH *)(/sbin)|1/bin:2|' init.rc
mv /sbin/* sbin
rmdir /sbin
ln -s android/sbin /
fi
# ensure keyboard driver is loaded
[ -n "$INSTALL" -o -n "$DEBUG" ] && modprobe atkbd
if [ 0$DEBUG -gt 0 ]; then
echo -e "
Type 'exit' to continue booting...
"
debug_shell debug-found
fi
# load scripts
for s in `ls /scripts/* /src/scripts/*`; do
test -e "$s" && source $s
done
以上做的就是一些初始化的工作,并且根据不同启动参数,所做的操作也略有不同。可以看看上面标出的红色部分,此处的主要作用是如果判断出系统启动时所带的参数为install,则进入安装模式。接着往下看
[ "$AUTO" != "1" ] && detect_hardware && FOUND=1 [ -n "$INSTALL" ] && do_install load_modules mount_data mount_sdcard setup_tslib setup_dpi post_detect find_network_dev_name if [ 0$DEBUG -gt 1 ]; then echo -e " Use Alt-F1/F2/F3 to switch between virtual consoles" echo -e "Type 'exit' to enter Android... " debug_shell debug-late fi [ -n "$DEBUG" ] && SWITCH=${SWITCH:-chroot} # We must disable mdev before switching to Android # since it conflicts with Android's init echo > /proc/sys/kernel/hotplug exec ${SWITCH:-switch_root} /android /init # avoid kernel panic while :; do echo echo ' Android-x86 console shell. Use only in emergencies.' echo debug_shell fatal-err done
可以看出上面的代码用红色标注了两处,其中第一处是用来判断是否是install模式,在这个地方需要注意下,如果是正常的启动此处是不会执行到的,如果是安装模式则会调用安装脚本,这个安装脚本是放在install.img 这个文件里。这个文件的目录在上文我已经列过了。具体的看看do_install这个函数,这个函数是定义在install.img 解压出文件的scripts/1-install这个文件当中,在这个脚本中为什么能调用这个函数呢,注意这一句:
# load scripts
for s in `ls /scripts/* /src/scripts/*`; do
test -e "$s" && source $s
done
这一段代码遍历了/scripts/和 /src/scripts/这两个目录下的脚本文件。注意后面的source $s,正是有了这一句,我们才可以在在init脚本里调用1-install这个脚本的函数。这个install.sh就是实现了我们的安装功能。我们将在下一篇中分析do_install 这个函数