Android1.6 启动init.c分析

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值