1. Android启动过程

参考文章:

 

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主要包括下面几种:

early-init – this is triggered by init process right after parsing of init. *. rc file but before the devices initialized
init –  action is triggered during init boot right afterearly-init
early-boot – action is triggered when init process completed initialization of itself and ready to execute all commands
boot – action is triggered during init boot right after early-boot
property:<name>=<value> - action is triggered when the property with name is set to specific value
device-added-<path> - triggered when device with specified path has been added to the system
device-removed-<path> - triggered when device  with specified path has been removed from the system
service-exited-<name> - triggered when the service with particular name has completed its execution and exited.

 

 

 

 

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包括一下几种:

exec <path> <argument> - executes the command under the speicified path. This command will block until execution completes
export <name> <value> - Set the environment variable <name> equal to <value> in the global environment (which will be inherited by all processes started after this command is executed)
import <filename> - parse init config file extending current configuration.
insmod <path>   - loads Linux Module into the system
mount <type> <device> <dir> [ < mountoption > ]* - Attempt to mount the named device at the directory <dir>. Syntax similar to standard mount command in Linux.
trigger <event> - Trigger an event.  Used to queue an action from another action.
Option:
Full set of options is described in /system/core/init.readme.txt file
Most important are listed bellow:
critical - This is a device-critical service. If it exits more than four times in four minutes, the device will reboot into recovery mode.
disabled – This service will not be started automatically with its class.
class <name> - specify the class of the service. If not specified then service class is set to “default”.
onrestart <command> - executes the command when service restarts.
setenv <name> <value> - sets an enviroment variable of <name> to the <value> inside the process of the service.
user <username> - runs a service with the specified username .

你可能感兴趣的:(android,service,command,action,Signal,triggers)