参考文章:
http://dingpwen.spaces.live.com/blog/cns!4CADD02D22459860!208.entry?fl=cat
http://www.eepw.com.cn/article/89567.htm
http://blog.csdn.net/guiterb/archive/2009/04/03/4047369.aspx
先来看看Android系统在手机内存中的是怎么放置的
地址最低的地方放Bootloader,
然后放Linux Kernel,
接下来的三个区域分别放置编译源码生成的三个img文件(ramdisk.img, system.img和data.image),用户在使用过程中产生的文件等都是放在最后一个Data Image区域里面(即/data/data/<package>),这部分区域大小不固定,根据手机实际内存来确定.
手机启动的时候从最低的地址开始执行(具体的可以参看转载的另一篇博文--Linux的启动过程),首先执行Bootloader,Bootloader会去加载Linux Kernel,初始化硬件,然后挂载Ram Disk(Init process放在这里面的,另:init process的PID=1),并启动一个初始化的进程,对应的初始化的源码为:system/core/init/Init.c,简单的来看看这里面到底做了些什么
int main(int argc, char **argv) { int device_fd = -1; int property_set_fd = -1; int signal_recv_fd = -1; int keychord_fd = -1; int fd_count; int s[2]; int fd; struct sigaction act; char tmp[PROP_VALUE_MAX]; struct pollfd ufds[4]; char *tmpdev; char* debuggable; act.sa_handler = sigchld_handler; act.sa_flags = SA_NOCLDSTOP; act.sa_mask = 0; act.sa_restorer = NULL; sigaction(SIGCHLD, &act, 0); /* clear the umask */ umask(0); /* Get the basic filesystem setup we need put * together in the initramdisk on / and then we'll * let the rc file figure out the rest. */ mkdir("/dev", 0755); mkdir("/proc", 0755); mkdir("/sys", 0755); mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755"); mkdir("/dev/pts", 0755); mkdir("/dev/socket", 0755); mount("devpts", "/dev/pts", "devpts", 0, NULL); mount("proc", "/proc", "proc", 0, NULL); mount("sysfs", "/sys", "sysfs", 0, NULL); /* We must have some place other than / to create the * device nodes for kmsg and null, otherwise we won't * be able to remount / read-only later on. * Now that tmpfs is mounted on /dev, we can actually * talk to the outside world. */ open_devnull_stdio(); log_init(); INFO("reading config file/n"); parse_config_file("/init.rc"); /* pull the kernel commandline and ramdisk properties file in */ qemu_init(); import_kernel_cmdline(0); get_hardware_name(); snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware); parse_config_file(tmp); action_for_each_trigger("early-init", action_add_queue_tail); drain_action_queue(); INFO("device init/n"); device_fd = device_init(); property_init(); // only listen for keychords if ro.debuggable is true debuggable = property_get("ro.debuggable"); if (debuggable && !strcmp(debuggable, "1")) { keychord_fd = open_keychord(); } if (console[0]) { snprintf(tmp, sizeof(tmp), "/dev/%s", console); console_name = strdup(tmp); } fd = open(console_name, O_RDWR); if (fd >= 0) have_console = 1; close(fd); if( load_565rle_image(INIT_IMAGE_FILE) ) { fd = open("/dev/tty0", O_WRONLY); if (fd >= 0) { const char *msg; msg = "/n" "/n" "/n" "/n" "/n" "/n" "/n" // console is 40 cols x 30 lines "/n" "/n" "/n" "/n" "/n" "/n" "/n" " A N D R O I D "; write(fd, msg, strlen(msg)); close(fd); } } if (qemu[0]) import_kernel_cmdline(1); if (!strcmp(bootmode,"factory")) property_set("ro.factorytest", "1"); else if (!strcmp(bootmode,"factory2")) property_set("ro.factorytest", "2"); else property_set("ro.factorytest", "0"); property_set("ro.serialno", serialno[0] ? serialno : ""); property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown"); property_set("ro.baseband", baseband[0] ? baseband : "unknown"); property_set("ro.carrier", carrier[0] ? carrier : "unknown"); property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown"); property_set("ro.hardware", hardware); snprintf(tmp, PROP_VALUE_MAX, "%d", revision); property_set("ro.revision", tmp); /* execute all the boot actions to get us started */ action_for_each_trigger("init", action_add_queue_tail); drain_action_queue(); /* read any property files on system or data and * fire up the property service. This must happen * after the ro.foo properties are set above so * that /data/local.prop cannot interfere with them. */ property_set_fd = start_property_service(); /* create a signalling mechanism for the sigchld handler */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) { signal_fd = s[0]; signal_recv_fd = s[1]; fcntl(s[0], F_SETFD, FD_CLOEXEC); fcntl(s[0], F_SETFL, O_NONBLOCK); fcntl(s[1], F_SETFD, FD_CLOEXEC); fcntl(s[1], F_SETFL, O_NONBLOCK); } /* make sure we actually have all the pieces we need */ if ((device_fd < 0) || (property_set_fd < 0) || (signal_recv_fd < 0)) { ERROR("init startup failure/n"); return 1; } /* execute all the boot actions to get us started */ action_for_each_trigger("early-boot", action_add_queue_tail); action_for_each_trigger("boot", action_add_queue_tail); drain_action_queue(); /* run all property triggers based on current state of the properties */ queue_all_property_triggers(); drain_action_queue(); /* enable property triggers */ property_triggers_enabled = 1; ufds[0].fd = device_fd; ufds[0].events = POLLIN; ufds[1].fd = property_set_fd; ufds[1].events = POLLIN; ufds[2].fd = signal_recv_fd; ufds[2].events = POLLIN; fd_count = 3; if (keychord_fd > 0) { ufds[3].fd = keychord_fd; ufds[3].events = POLLIN; fd_count++; } else { ufds[3].events = 0; ufds[3].revents = 0; } #if BOOTCHART bootchart_count = bootchart_init(); if (bootchart_count < 0) { ERROR("bootcharting init failure/n"); } else if (bootchart_count > 0) { NOTICE("bootcharting started (period=%d ms)/n", bootchart_count*BOOTCHART_POLLING_MS); } else { NOTICE("bootcharting ignored/n"); } #endif for(;;) { int nr, i, timeout = -1; for (i = 0; i < fd_count; i++) ufds[i].revents = 0; drain_action_queue(); restart_processes(); if (process_needs_restart) { timeout = (process_needs_restart - gettime()) * 1000; if (timeout < 0) timeout = 0; } #if BOOTCHART if (bootchart_count > 0) { if (timeout < 0 || timeout > BOOTCHART_POLLING_MS) timeout = BOOTCHART_POLLING_MS; if (bootchart_step() < 0 || --bootchart_count == 0) { bootchart_finish(); bootchart_count = 0; } } #endif nr = poll(ufds, fd_count, timeout); if (nr <= 0) continue; if (ufds[2].revents == POLLIN) { /* we got a SIGCHLD - reap and restart as needed */ read(signal_recv_fd, tmp, sizeof(tmp)); while (!wait_for_one_process(0)) ; continue; } if (ufds[0].revents == POLLIN) handle_device_fd(device_fd); if (ufds[1].revents == POLLIN) handle_property_set_fd(property_set_fd); if (ufds[3].revents == POLLIN) handle_keychord(keychord_fd); } return 0; }
对应着代码依次看下来,它主要做了以下的事情:
1. 在根目录下面创建一些文件夹,比如/sys,/dev,也会把基本的文件系统mount上去
2. 显示Android的logo,注意这个不是开机动画,开机动画在后面才会做.
3. 解析/init.rc这个脚本
4. 初始化/init.<hardware>.rc里面的硬件设备,如果是模拟器的话,这个脚本就是init.goldfish.rc
5. 读取.prop文件,并创建SystemProperties服务
6. 解析kernel命令行,并设置相应属性
7. Trigger在init.rc中定义的action
下面来看一下第三步中init.rc文件里面的内容,以及第七步是如何来trigger里面的action的.
*.rc文件是google定义的脚本文件,关于这部分内容具体可以参照文章开头给的链接,先简单说明以下
rc文件里面主要包含了action, service, option和commands,其中action和service是具体的某个动作,option和commands是他们的一些选项
Action
action其实就是一堆命令的集合,action会有一个tigger,表示如果发生了某件事的时候就执行action里面的命令
所以action的格式是
Actions take the form of:
on <trigger>
<command>
<command>
<command>
表示当trigger发生的时候就会执行下面三个操作.
例如:
on init
export PATH /sbin:/system/sbin:/system/bin
export ANDROID_ROOT /system
export ANDROID_DATA /data
symlink /system/etc /etc
mkdir /data
mkdir /cache
mount /tmp /tmp tmpfs
就表示,当在init的时候,就会执行下面这些linux commands(设置环境变量,link两个目录,创建一些目录等)
其中的triggers主要包括下面几种:
Service
service表示在init的时候需要启动的一些服务,格式如下
service <name> <pathname> [ <argument> ]*
<option>
<option>
例如:
service media /system/bin/mediaserver
user media
group system audio camera graphics inet net_bt net_bt_admin
表示启动AudioFlinger, MediaPlayerService and CameraService这些服务.
从init.rc文件我们可以看到在init过程中我们依次启动了以下的服务
console: star a shell. The source is in device/system/bin/ash.
adbd: start adb daemon. The source is in device/tools/adbd. By default is disabled.
servicemanager: start binder system. The source is in device/commands/binder.
mountd: mount all fs defined in /system/etc/mountd.conf if started, receive commands through local socket to mount any fs. The source is in device/system/bin/mountd.
debuggerd: start debug system. The source is in device/system/bin/debuggerd.
rild: start radio interface layer daemon. The source is in device/commands/rind.
zygote: start Android Java Runtime and start system server. It’s the most important service. The source is in device/servers/app.
media: start AudioFlinger, MediaPlayerService and CameraService. The source is in device/commands/mediaserver.
bootsound: play the default boot sound /system/media/audio/ui/boot.mp3. The source is in device/commands/playmp3.
dbus: start dbus daemon, it’s only used by BlueZ. The source is in device/system/Bluetooth/dbus-daemon.
hcid: redirect hcid’s stdout and stderr to the Android logging system. The source is in device/system/bin/logwrapper. By default is disabled.
hfag: start Bluetooth handsfree audio gateway, it’s only used by BlueZ. The source is in device/system/Bluetooth/bluez-utils. By default is disabled.
hsag: start Bluetooth headset audio gateway, it’s only used by BlueZ. The source is in device/system/Bluetooth/bluez-utils. By default is disabled.
installd: start install package daemon. The source is in device/servers/installd.
flash_recovery: load /system/recovery.img. The source is in device/commands/recovery/mtdutils.
其中zygote启动了java runtime是这里面最重要的一个服务.
Zygote service does the following tasks step by step:
1. Create JAVA VM.
2. Register android native function for JAVA VM.
3. Call the main function in the JAVA class named com.android.internal.os.ZygoteInit whose source is device/java/android/com/android/internal/os/ZygoteInit.java.
a) Load ZygoteInit class
b) Register zygote socket
c) Load preload classes(the default file is device/java/android/preloaded-classes)
d) Load preload resources
e) Call Zygote::forkSystemServer (implemented in device/dalvik/vm/InternalNative.c) to fork a new process. In the new process, call the main function in the JAVA class named com.android.server.SystemServer, whose source is in device/java/services/com/android/server.
i. Load libandroid_servers.so
ii. Call JNI native init1 function implemented in device/libs/android_servers/com_android_server_SystemServers. It only calls system_init implemented in device/servers/system/library/system_init.cpp.
l If running on simulator, instantiate AudioFlinger, MediaPlayerService and CameraService here.
l Call init2 function in JAVA class named com.android.server.SystemServer, whose source is in device/java/services/com/android/server. This function is very critical for Android because it start all of Android JAVA services.
l If not running on simulator, call IPCThreadState::self()->joinThreadPool() to enter into service dispatcher.
Commands
commands包括一下几种: