Android1.6 启动init.c分析

来源:互联网 发布:mac系统优化工具 编辑:程序博客网 时间:2024/06/06 01:06

android的启动大致分为6步
第一步:上电后boot启动
第二步:boot启动内核
第三部:内核运行根目录下的init,加载init.rc
第四部:init 启动启动各个service 包括servicemanager,vold,mount等,然后启动papp_process -Xzygote 启动java虚拟机。
第五步:zygote启动SystemServer,然后由SystemServer启动各个管理器。
第六步:启动完成,进入桌面。
第一步和第二步不再分析。
我们主要从第三步init开始分析。
init主要完成6件事。
第一.创建文件系统,挂载各个系统目录。
第二.加载init.rc,解析,运行。
第三.创建一个socket 用于僵死的子进程回收。
第四.创建系统属性读取写入的socket。
第五.创建uevent socket,用于监视uevent。
第六.无限循环处理僵死进程回收,属性处理,uevent监控等。
我们逐个分析:
第一.创建文件系统如下:

    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);

这部分最简单,相信大家都很熟悉。
第二.init.rc

引用块内容

第三.创建僵死进程回收处理

1.设置子进程僵死时的处理

act.sa_handler = sigchld_handler;    act.sa_flags = SA_NOCLDSTOP;    act.sa_mask = 0;    act.sa_restorer = NULL;    sigaction(SIGCHLD, &act, 0);

第一句是子进程僵死时的处理函数

static int signal_fd = -1;static void sigchld_handler(int s){    write(signal_fd, &s, 1);}

没头没脑的一个傻逼函数,刚看到时只能说一句,谁知道你在干嘛?
但当你到到2 和3的时候我想我们大家都懂得了。
第二句话的意思就是
SA_NOCLDSTOP
这个flag只对SIGCHLD信号有效,当这个flag设置的时候,系统会给终止的子进程发送一个信号,但是不会给已经停止的子进程发送信号。默认情况下,系统会向终止的子进程和停止的子进程都发送SIGCHLD信号。
其实也就是说当子进程僵死时sigchld_handler函数会被调用。
2.创建一个匿名通信管道,从signal_fd写入的数据可以在signal_recv_fd读取出来。

/* 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);    }

上面这些与第三点结合起来,我想你讲完全看懂。因为signal_recv_fd会在第3里面出现。也就是init的死循环里面。
3.监视signal_recv_fd,当进程僵死时在这里处理。

ufds[2].fd = signal_recv_fd;ufds[2].events = POLLIN;for(;;) {     .....      nr = poll(ufds, fd_count, timeout);      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;        }        ..... }

第四,属性处理

....property_init();//属性初始化....property_set_fd = start_property_service();//创建用于设置属性的socket进程间通讯....ufds[0].events = POLLIN;ufds[1].fd = property_set_fd;....for(;;) {    int nr, i, timeout = -1;    nr = poll(ufds, fd_count, timeout);    if (ufds[1].revents == POLLIN)        handle_property_set_fd(property_set_fd);//属性处理    ....}

property_init();属性处理我们暂不分析,我们主要分析start_property_service()和handle_property_set_fd(property_set_fd)函数。

#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"int start_property_service(void){    int fd;    load_properties_from_file(PROP_PATH_SYSTEM_BUILD);//加载属性文件    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);    load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);    /* Read persistent properties after all default values have been loaded. */    load_persistent_properties();    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);//创建socket    if(fd < 0) return -1;    fcntl(fd, F_SETFD, FD_CLOEXEC);//这个大家都懂得了    fcntl(fd, F_SETFL, O_NONBLOCK);    listen(fd, 8);//监听,最多8个线程同时读取    return fd;}

其实大多的处理都在create_socket函数里面,下面我们来看看

int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid){    struct sockaddr_un addr;    int fd, ret;    fd = socket(PF_UNIX, type, 0);//PF_UNIX 协议主要用于进程间通讯    if (fd < 0) {        ERROR("Failed to open socket '%s': %s\n", name, strerror(errno));        return -1;    }    memset(&addr, 0 , sizeof(addr));    addr.sun_family = AF_UNIX;    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",             name);//路径:/dev/socket/name    ret = unlink(addr.sun_path);    if (ret != 0 && errno != ENOENT) {        ERROR("Failed to unlink old socket '%s': %s\n", name, strerror(errno));        goto out_close;    }    ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));    if (ret) {        ERROR("Failed to bind socket '%s': %s\n", name, strerror(errno));        goto out_unlink;    }    chown(addr.sun_path, uid, gid);    chmod(addr.sun_path, perm);    INFO("Created socket '%s' with mode '%o', user '%d', group '%d'\n",         addr.sun_path, perm, uid, gid);    return fd;out_unlink:    unlink(addr.sun_path);out_close:    close(fd);    return -1;}

create_socket函数建立了一个进程间IPC通讯的socket service,并且启动监听,非阻塞方式。
然后到了for循环的时候,一直在循环处理poll,如果有客户,那么handle_property_set_fd函数会被调用。

0 0
原创粉丝点击