文章出处:http://blog.csdn.net/shift_wwx


init进程是用户空间执行的第一个进程,直接进入code:/system/core/init/init.c

int main(int argc, char **argv){    int fd_count = 0;    struct pollfd ufds[4];    char *tmpdev;    char* debuggable;    char tmp[32];    int property_set_fd_init = 0;    int signal_fd_init = 0;    int keychord_fd_init = 0;    bool is_charger = false;    if (!strcmp(basename(argv[0]), "ueventd"))        return ueventd_main(argc, argv);    if (!strcmp(basename(argv[0]), "watchdogd"))        return watchdogd_main(argc, argv);    /* 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", MS_NOSUID, "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);        /* indicate that booting is in progress to background fw loaders, etc */    close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));        /* 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();    klog_init();    property_init();    get_hardware_name(hardware, &revision);    process_kernel_cmdline();    union selinux_callback cb;    cb.func_log = klog_write;    selinux_set_callback(SELINUX_CB_LOG, cb);    cb.func_audit = audit_callback;    selinux_set_callback(SELINUX_CB_AUDIT, cb);    selinux_initialize();    /* These directories were necessarily created before initial policy load     * and therefore need their security context restored to the proper value.     * This must happen before /dev is populated by ueventd.     */    restorecon("/dev");    restorecon("/dev/socket");    restorecon("/dev/__properties__");    restorecon_recursive("/sys");    is_charger = !strcmp(bootmode, "charger");    INFO("property init\n");    if (!is_charger)        property_load_boot_defaults();    if (!strcmp(bootmode,"factory"))       init_parse_config_file("/init.factorytest.rc");    else if (!strcmp(bootmode,"factory2"))       init_parse_config_file("/init.factorytest2.rc");    else       init_parse_config_file("/init.rc");    action_for_each_trigger("early-init", action_add_queue_tail);    queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");    queue_builtin_action(keychord_init_action, "keychord_init");    queue_builtin_action(console_init_action, "console_init");    /* execute all the boot actions to get us started */    action_for_each_trigger("init", action_add_queue_tail);    aml_firstbootinit();        /* skip mounting filesystems in charger mode */    if (!is_charger) {        action_for_each_trigger("early-fs", action_add_queue_tail);        action_for_each_trigger("fs", action_add_queue_tail);        action_for_each_trigger("post-fs", action_add_queue_tail);        action_for_each_trigger("post-fs-data", action_add_queue_tail);    }    /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random     * wasn't ready immediately after wait_for_coldboot_done     */    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");    queue_builtin_action(property_service_init_action, "property_service_init");    queue_builtin_action(signal_init_action, "signal_init");    queue_builtin_action(check_startup_action, "check_startup");    /* run all property triggers based on current state of the properties */    queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");    if (is_charger) {        action_for_each_trigger("charger", action_add_queue_tail);    } else {        action_for_each_trigger("early-boot", action_add_queue_tail);        queue_builtin_action(ubootenv_init_action, "ubootenv_init");        queue_builtin_action(set_firstboot_complete_flag, "firstboot_complete");        action_for_each_trigger("boot", action_add_queue_tail);    }#if BOOTCHART    queue_builtin_action(bootchart_init_action, "bootchart_init");#endif    for(;;) {        int nr, i, timeout = -1;        execute_one_command();        restart_processes();        if (!property_set_fd_init && get_property_set_fd() > 0) {            ufds[fd_count].fd = get_property_set_fd();            ufds[fd_count].events = POLLIN;            ufds[fd_count].revents = 0;            fd_count++;            property_set_fd_init = 1;        }        if (!signal_fd_init && get_signal_fd() > 0) {            ufds[fd_count].fd = get_signal_fd();            ufds[fd_count].events = POLLIN;            ufds[fd_count].revents = 0;            fd_count++;            signal_fd_init = 1;        }        if (!keychord_fd_init && get_keychord_fd() > 0) {            ufds[fd_count].fd = get_keychord_fd();            ufds[fd_count].events = POLLIN;            ufds[fd_count].revents = 0;            fd_count++;            keychord_fd_init = 1;        }        if (process_needs_restart) {            timeout = (process_needs_restart - gettime()) * 1000;            if (timeout < 0)                timeout = 0;        }        if (!action_queue_empty() || cur_action)            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;        for (i = 0; i < fd_count; i++) {            if (ufds[i].revents == POLLIN) {                if (ufds[i].fd == get_property_set_fd())                    handle_property_set_fd();                else if (ufds[i].fd == get_keychord_fd())                    handle_keychord();                else if (ufds[i].fd == get_signal_fd())                    handle_signal();            }        }    }    return 0;}

1、创建文件系统目录并挂载相关的文件系统

    mkdir("/dev", 0755);    mkdir("/proc", 0755);    mkdir("/sys", 0755);    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "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);
目前Linux有很多通讯机制可以在用户空间和内核空间之间交互,例如设备驱动文件(位于/dev目录中)、内存文件(/proc、/sys目录等)。了解Linux的同学都应该知道Linux的重要特征之一就是一切都是以文件的形式存在的,例如,一个设备通常与一个或多个设备文件对应。这些与内核空间交互的文件都在用户空间,所以在Linux内核装载完,需要首先建立这些文件所在的目录。

1.1 在init初始化过程中,Android分别挂载了tmpfs,devpts,proc,sysfs 4类文件系统

1.1.1 tmpfs文件系统

tmpfs是一种虚拟内存文件系统,因此它会将所有的文件存储在虚拟内存中,并且tmpfs下的所有内容均为临时性的内容,如果你将tmpfs文件系统卸载后,那么其下的所有的内容将不复存在。

tmpfs有些像虚拟磁盘(ramdisk),但不是一回事。说其像虚拟磁盘,是因为它可以使用你的RAM,但它也可以使用你的交换分区。传统的虚拟磁盘是一个块设备,而且需要一个mkfs之类的命令格式化它才能使用。tmpfs是一个独立的文件系统,不是块设备,只要挂接,立即就可以使用。

tmpfs的大下是不确定的,它最初只有很小的空间,但随着文件的复制和创建,它的大小就会不断变化,换句话说,它会根据你的实际需要而改变大小;tmpfs的速度非常惊人,毕竟它是驻留在RAM中的,即使用了交换分区,性能仍然非常卓越;由于tmpfs是驻留在RAM的,因此它的内容是不持久的,断电后,tmpfs的内容就消失了,这也是被称作tmpfs的根本原因。

1.1.2 devpts文件系统

devpts文件系统为伪终端提供了一个标准接口,它的标准挂接点是/dev/pts。只要pty的主复合设备/dev/ptmx被打开,就会在/dev/pts下动态的创建一个新的pty设备文件。

1.1.3 proc文件系统

proc文件系统是一个非常重要的虚拟文件系统,它可以看作是内核内部数据结构的接口,通过它我们可以获得系统的信息,同时也能够在运行时修改特定的内核参数。
在proc文件系统中,你可以修改内核的参数,是不是很强大?怎么修改呢?你只需要echo一个新的值到对应的文件中即可,但是如果在修改过程中发生错误的话,那么你将别无选择,只能重启设备。

1.1.4 sysfs文件系统

与proc文件系统类似,sysfs文件系统也是一个不占有任何磁盘空间的虚拟文件系统。它通常被挂接在/sys目录下。sysfs文件系统是Linux2.6内核引入的,它把连接在系统上的设备和总线组织成为一个分级的文件,使得它们可以在用户空间存取。

2、查看.booting是否有读写权限

        /* indicate that booting is in progress to background fw loaders, etc */        close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));

3、屏蔽标准的输入输出,即标准的输入输出定向到NULL设备。

open_devnull_stdio();
void open_devnull_stdio(void){    int fd;    static const char *name = "/dev/__null__";    //创建一个字符专用文件    if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {        fd = open(name, O_RDWR);        unlink(name);        //将与进程相关的标准输入(0)、标准输出(1)、标准出错(2)都定向到null        if (fd >= 0) {            dup2(fd, 0);            dup2(fd, 1);            dup2(fd, 2);            if (fd > 2) {                close(fd);            }            return;        }    }    exit(1);}
这里解释一下
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
过程:
首先说明以下dup2的作用,这个函数主要是复制一个函数的描述符,一般用于重定向进程的stdin,stdout,stderr。它的原型如下:
int dup2(int oldfd, int newfd);
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
这三次调用一次将依次代表stdin,stdout,stderr的描述符0,1,2,重定向到dev/null,通过这种方式达到屏蔽标准输入输出的作用。

4、初始化内核log系统

klog_init();
void klog_init(void){    static const char *name = "/dev/__kmsg__";    if (klog_fd >= 0) return; /* Already initialized */    if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {        klog_fd = open(name, O_WRONLY);        if (klog_fd < 0)                return;        fcntl(klog_fd, F_SETFD, FD_CLOEXEC);        unlink(name);    }}

有上述实现看出内核的log输出是通过文件描述符log_fd写入的,那到底写入到什么设备呢?/dev/kmsg,这个设备则会把它收到的任何写入都作为printk的输出。printk函数是内核中运行的向控制台输出显示的函数。

5、初始化属性空间

property_init();

为属性分配一些存储空间。

static int init_property_area(void){    if (property_area_inited)        return -1;    if(__system_property_area_init())        return -1;    if(init_workspace(&pa_workspace, 0))        return -1;    fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);    property_area_inited = 1;    return 0;}
第一个变量,就是为了防止重新init;

__system_property_area_init()函数来看一下source code:

@/bionic/libc/bionic/system_properties.c

int __system_property_area_init(){    return map_prop_area_rw();}
static int map_prop_area_rw(){    prop_area *pa;    int fd;    int ret;    /* dev is a tmpfs that we can use to carve a shared workspace     * out of, so let's do that...     */    fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC |            O_EXCL, 0444);//打开文件property_filename,头文件中有定义:/dev/__properties__    if (fd < 0) {        if (errno == EACCES) {            /* for consistency with the case where the process has already             * mapped the page in and segfaults when trying to write to it             */            abort();        }        return -1;    }    ret = fcntl(fd, F_SETFD, FD_CLOEXEC);//这里设置为FD_CLOEXEC表示当程序执行exec函数时本fd将被系统自动关闭,表示不传递给exec创建的新进程    if (ret < 0)        goto out;    if (ftruncate(fd, PA_SIZE) < 0)//更改fd指向文件的大小为PA_SIZE(128*1024)大小        goto out;    pa_size = PA_SIZE;    pa_data_size = pa_size - sizeof(prop_area);    compat_mode = false;    pa = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);//用的是共享内存    if(pa == MAP_FAILED)        goto out;    memset(pa, 0, pa_size);    pa->magic = PROP_AREA_MAGIC;    pa->version = PROP_AREA_VERSION;    /* reserve root node */    pa->bytes_used = sizeof(prop_bt);    /* plug into the lib property services */    __system_property_area__ = pa;    close(fd);    return 0;out:    close(fd);    return -1;}

6、获取hardware和revision值

get_hardware_name(hardware, &revision);
void get_hardware_name(char *hardware, unsigned int *revision){    char data[1024];    int fd, n;    char *x, *hw, *rev;    /* Hardware string was provided on kernel command line */    if (hardware[0])        return;    fd = open("/proc/cpuinfo", O_RDONLY);    if (fd < 0) return;    n = read(fd, data, 1023);    close(fd);    if (n < 0) return;    data[n] = 0;    hw = strstr(data, "\nHardware");    rev = strstr(data, "\nRevision");    if (hw) {        x = strstr(hw, ": ");        if (x) {            x += 2;            n = 0;            while (*x && *x != '\n' && !isspace(*x)) {                hardware[n++] = tolower(*x);                x++;                if (n == 31) break;            }            hardware[n] = 0;        }    }    if (rev) {        x = strstr(rev, ": ");        if (x) {            *revision = strtoul(x + 2, 0, 16);        }    }}
从/proc/cpuinfo中读取1023个字节存入data中,并查找第一次出现Hardware和Revision的地方。然后进行一系列的解析,最终获得hardware和revision。

这个hardware和revision是干嘛的呢?

code中给出了答案:

    /* if this was given on kernel command line, override what we read     * before (e.g. from /proc/cpuinfo), if anything */    ret = property_get("ro.boot.hardware", tmp);    if (ret)        strlcpy(hardware, tmp, sizeof(hardware));    property_set("ro.hardware", hardware);    snprintf(tmp, PROP_VALUE_MAX, "%d", revision);    property_set("ro.revision", tmp);
如果ro.boot.hardware有值,hardware会被重置,如果没有,从之前获取的hardware值会将ro.hardware置上。

ro.revision则是通过之前获取的revision值置上的。

ro.hardware这个属性,会在后面解析init.rc的时候用到:

import /init.${ro.hardware}.rc
7、process_kernel_cmdline();

static void process_kernel_cmdline(void){    /* don't expose the raw commandline to nonpriv processes */    chmod("/proc/cmdline", 0440);    /* first pass does the common stuff, and finds if we are in qemu.     * second pass is only necessary for qemu to export all kernel params     * as props.     */    import_kernel_cmdline(0, import_kernel_nv);    if (qemu[0])        import_kernel_cmdline(1, import_kernel_nv);    /* now propogate the info given on command line to internal variables     * used by init as well as the current required properties     */    export_kernel_boot_props();}
7.1 import_kernel_cmdline主要是导入一些内核变量。

cat /proc/cmdline:

init=/init console=ttyS0,115200n8 mem=1024m logo=osd0,loaded,panel mac=00:15:18:01:81:31
具体怎么实现的主要是函数import_kernel_nv:

static void import_kernel_nv(char *name, int for_emulator){    char *value = strchr(name, '=');    int name_len = strlen(name);    if (value == 0) return;    *value++ = 0;    if (name_len == 0) return;    if (for_emulator) {        /* in the emulator, export any kernel option with the         * ro.kernel. prefix */        char buff[PROP_NAME_MAX];        int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );        if (len < (int)sizeof(buff))            property_set( buff, value );        return;    }    if (!strcmp(name,"qemu")) {        strlcpy(qemu, value, sizeof(qemu));    } else if (!strncmp(name, "androidboot.", 12) && name_len > 12) {        const char *boot_prop_name = name + 12;        char prop[PROP_NAME_MAX];        int cnt;        if (!strcmp(name,"androidboot.resolution")) {            strlcpy(resolution, value, sizeof(resolution));        }if (!strcmp(name,"androidboot.realoutput")) {strlcpy(realoutput, value, sizeof(realoutput));ERROR("androidboot.realoutput:%s\n",realoutput);}        cnt = snprintf(prop, sizeof(prop), "ro.boot.%s", boot_prop_name);        if (cnt < PROP_NAME_MAX)            property_set(prop, value);    } else if (!strcmp(name,"hdmimode")) {        strlcpy(hdmimode, value, sizeof(hdmimode));    } else if (!strcmp(name,"cvbsmode")) {        strlcpy(cvbsmode, value, sizeof(cvbsmode));    } }
从code中可以看出来,主要找一个resolution、hdmimode、cvbsmode等。

其中ro.boot.%s需要注意了,这里boot相关的prop就是之前读到的/prop/cmdline中console、hardware、mac、mem等。后面就会看到了

7.2 export_kernel_boot_props();

static void export_kernel_boot_props(void){    char tmp[PROP_VALUE_MAX] = {0};    int ret;    unsigned i;    #ifdef CUSTOMER_SERIALNO_MAC    struct {        const char *src_prop;        const char *dest_prop;        const char *def_val;    } prop_map[] = {        { "ro.boot.serialno", "ro.serialno", "00AA000102090300015F881036202785", },        { "ro.boot.mode", "ro.bootmode", "unknown", },        { "ro.boot.baseband", "ro.baseband", "unknown", },        { "ro.boot.bootloader", "ro.bootloader", "unknown", },        { "ro.boot.firstboot", "ro.firstboot", "0"},    };    #else    struct {        const char *src_prop;        const char *dest_prop;        const char *def_val;    } prop_map[] = {        { "ro.boot.serialno", "ro.serialno", "12345678900", },        { "ro.boot.mode", "ro.bootmode", "unknown", },        { "ro.boot.baseband", "ro.baseband", "unknown", },        { "ro.boot.bootloader", "ro.bootloader", "unknown", },        { "ro.boot.firstboot", "ro.firstboot", "0"},    };    #endif    for (i = 0; i < ARRAY_SIZE(prop_map); i++) {        ret = property_get(prop_map[i].src_prop, tmp);        if (ret > 0)            property_set(prop_map[i].dest_prop, tmp);        else            property_set(prop_map[i].dest_prop, prop_map[i].def_val);    }    ret = property_get("ro.boot.console", tmp);    if (ret)        strlcpy(console, tmp, sizeof(console));    /* save a copy for init's usage during boot */    property_get("ro.bootmode", tmp);    strlcpy(bootmode, tmp, sizeof(bootmode));    /* if this was given on kernel command line, override what we read     * before (e.g. from /proc/cpuinfo), if anything */    ret = property_get("ro.boot.hardware", tmp);    if (ret)        strlcpy(hardware, tmp, sizeof(hardware));    property_set("ro.hardware", hardware);    snprintf(tmp, PROP_VALUE_MAX, "%d", revision);    property_set("ro.revision", tmp);    /* TODO: these are obsolete. We should delete them */    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");        #ifdef CUSTOMER_SERIALNO_MAC    property_set("ro.mac", "00:22:7E:0B:53:26");    #endif}
可以看出这里主要ro.boot.console等属性就是之前通过import_kernel_nv解析出来的prop,而之前提到过的ro.boot.hardware也是需要import_kernel_nv解析,如果没有设置的话hardware的值就是通过/proc/cpuinfo来的。

8、解析init.rc

    if (!strcmp(bootmode,"factory"))       init_parse_config_file("/init.factorytest.rc");    else if (!strcmp(bootmode,"factory2"))       init_parse_config_file("/init.factorytest2.rc");    else       init_parse_config_file("/init.rc");
根据启动模式,加载init.rc

    action_for_each_trigger("early-init", action_add_queue_tail);
 /* execute all the boot actions to get us started */ action_for_each_trigger("init", action_add_queue_tail); aml_firstbootinit();  /* skip mounting filesystems in charger mode */ if (!is_charger) { action_for_each_trigger("early-fs", action_add_queue_tail); action_for_each_trigger("fs", action_add_queue_tail); action_for_each_trigger("post-fs", action_add_queue_tail); action_for_each_trigger("post-fs-data", action_add_queue_tail); }
    if (is_charger) {        action_for_each_trigger("charger", action_add_queue_tail);    } else {        action_for_each_trigger("early-boot", action_add_queue_tail);        queue_builtin_action(ubootenv_init_action, "ubootenv_init");        queue_builtin_action(set_firstboot_complete_flag, "firstboot_complete");        action_for_each_trigger("boot", action_add_queue_tail);    }
根据流程,确定了trigger的顺序。从on early-init 、on init、on early-fs、on fs。。。,将这些action去不放到action链表中。
至于init.rc的详细解释,可以看一下《 Android init.rc详解》。

9、action queue

    /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random     * wasn't ready immediately after wait_for_coldboot_done     */    queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");    queue_builtin_action(property_service_init_action, "property_service_init");    queue_builtin_action(signal_init_action, "signal_init");    queue_builtin_action(check_startup_action, "check_startup");    /* run all property triggers based on current state of the properties */    queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
还有一些配置也会存储在action链表中,参数前面是command的函数,后面的action name。

其中解释一下:

queue_builtin_action(property_service_init_action, "property_service_init");
static int property_service_init_action(int nargs, char **args){    /* 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.     */    start_property_service();    return 0;}
void start_property_service(void){    int fd;    load_properties_from_file(PROP_PATH_SYSTEM_BUILD);    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);    load_override_properties();    /* Read persistent properties after all default values have been loaded. */    load_persistent_properties();    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);    if(fd < 0) return;    fcntl(fd, F_SETFD, FD_CLOEXEC);    fcntl(fd, F_SETFL, O_NONBLOCK);    listen(fd, 8);    property_set_fd = fd;}

就是加载一些prop,其中的过程还是比较复杂的。可以看一下我之前小结的一篇博文《Android系统中prop的使用

其中的宏是定义在bionic/libc/include/sys/_system_properties.h

#define PROP_PATH_RAMDISK_DEFAULT  "/default.prop"#define PROP_PATH_SYSTEM_BUILD     "/system/build.prop"#define PROP_PATH_SYSTEM_DEFAULT   "/system/default.prop"#define PROP_PATH_LOCAL_OVERRIDE   "/data/local.prop"#define PROP_PATH_FACTORY          "/factory/factory.prop"
还有个persistent

#define PERSISTENT_PROPERTY_DIR  "/data/property"
10、死循环

    for(;;) {        int nr, i, timeout = -1;        execute_one_command();        restart_processes();        if (!property_set_fd_init && get_property_set_fd() > 0) {            ufds[fd_count].fd = get_property_set_fd();            ufds[fd_count].events = POLLIN;            ufds[fd_count].revents = 0;            fd_count++;            property_set_fd_init = 1;        }        if (!signal_fd_init && get_signal_fd() > 0) {            ufds[fd_count].fd = get_signal_fd();            ufds[fd_count].events = POLLIN;            ufds[fd_count].revents = 0;            fd_count++;            signal_fd_init = 1;        }        if (!keychord_fd_init && get_keychord_fd() > 0) {            ufds[fd_count].fd = get_keychord_fd();            ufds[fd_count].events = POLLIN;            ufds[fd_count].revents = 0;            fd_count++;            keychord_fd_init = 1;        }        if (process_needs_restart) {            timeout = (process_needs_restart - gettime()) * 1000;            if (timeout < 0)                timeout = 0;        }        if (!action_queue_empty() || cur_action)            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;        for (i = 0; i < fd_count; i++) {            if (ufds[i].revents == POLLIN) {                if (ufds[i].fd == get_property_set_fd())                    handle_property_set_fd();                else if (ufds[i].fd == get_keychord_fd())                    handle_keychord();                else if (ufds[i].fd == get_signal_fd())                    handle_signal();            }        }    }
10.1 依次执行action序列

execute_one_command();
void execute_one_command(void){    int ret;    if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {        cur_action = action_remove_queue_head();        cur_command = NULL;        if (!cur_action)            return;        INFO("processing action %p (%s)\n", cur_action, cur_action->name);        cur_command = get_first_command(cur_action);    } else {        cur_command = get_next_command(cur_action, cur_command);    }    if (!cur_command)        return;    ret = cur_command->func(cur_command->nargs, cur_command->args);    INFO("command '%s' r=%d\n", cur_command->args[0], ret);}
依次执行,一直到最后一个action command。

10.2 重启所有需要重启的services

restart_processes();
static void restart_processes(){    process_needs_restart = 0;    service_for_each_flags(SVC_RESTARTING,                           restart_service_if_needed);}
也就是说对SVC_RESTARTING相关的service做restart_service_if_needed操作。

10.3 对3个文件描述符进行轮询

分别是property_set_fd、keychord_fd、signal_fd。

        for (i = 0; i < fd_count; i++) {            if (ufds[i].revents == POLLIN) {                if (ufds[i].fd == get_property_set_fd())                    handle_property_set_fd();//处理prop                else if (ufds[i].fd == get_keychord_fd())                    handle_keychord();                else if (ufds[i].fd == get_signal_fd())                    handle_signal();//处理SIGCHLD信号            }        }

这三个fd可以说android系统启动后最关键的监听器了,需要好好分析一下。

1)property_set_fd

Android系统中prop详解中讲了prop set的过程,会创建一个property_service的socket,并对其listen。

......

具体的稍后补充说明。


参考文献:

http://www.cnblogs.com/nokiaguy/archive/2013/04/14/3020774.html

http://blog.csdn.net/windskier/article/details/6416547





更多相关文章

  1. 一款常用的 Squid 日志分析工具
  2. GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
  3. RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
  4. Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
  5. BuildGradle自定义打包
  6. android studio 安装时sdk更新指南
  7. Android小程序实现个人信息管理系统
  8. Android(安卓)Studio gradle配置实践
  9. Android进行全屏设置

随机推荐

  1. Android第三方经典项目,框架,效果等的大集
  2. 异步访问----Android(安卓)AsyncTask 源
  3. Android(安卓)特别好用的框架 二,Spinner(
  4. Android获取短信session
  5. Android中获取图片尺寸大小两种方法
  6. Android支付宝-2016最新版支付宝,实现支付
  7. 学习android的都来看一下,新手或是进阶
  8. Android数字签名的学习
  9. ApiDemos导入eclipse
  10. Qt on Android(安卓)之设置应用名为中文