现在的位置: 首页 > 综合 > 正文

Android系统init分析

2017年11月10日 ⁄ 综合 ⁄ 共 13276字 ⁄ 字号 评论关闭

       init是一个守护进程,是linux系统中用户空间的第一个进程,即1号进程。由于android是基于linux内核的,所以也是android系统中用户空间的第一个进程。Init进程需要完成极其重要的任务。下面分析init进程。

它的位置在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;

    if (!strcmp(basename(argv[0]), "ueventd"))

        return ueventd_main(argc, argv);

    /* clear the umask */

    umask(0);

  /*创建文件夹,并挂载这些设备。这些文件系统放在uramdisk里,通过解析rc文件使之生效               

*/

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

        /* 重定向标准输入/输出到/dev/_null_

         */

    open_devnull_stdio();

    //初始化日志信息设备

    log_init();

    INFO("reading config file\n");

    //解析init.rc配置文件

    init_parse_config_file("/init.rc");

    //导入内核命令行

    import_kernel_cmdline(0);

    //通过读取/proc/cpuinfo得到机器名

    get_hardware_name(hardware, &revision);

    snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);

    //解析与机器相关的配置文件

    init_parse_config_file(tmp);

    //得到一系列的action,注意这是early-init阶段的action,加入action队列尾部

    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(property_init_action, "property_init");

//加入keychord(与键盘设置有关)初始化动作

    queue_builtin_action(keychord_init_action, "keychord_init");

    //加入控制台初始化动作

    queue_builtin_action(console_init_action, "console_init");

    //加入设置属性初始化动作

    queue_builtin_action(set_init_properties_action, "set_init_properties");

    //加入init阶段的action

    action_for_each_trigger("init", action_add_queue_tail);

    //加入early-fs(文件系统相关)阶段的action

    action_for_each_trigger("early-fs", action_add_queue_tail);

    //加入fs阶段的action

    action_for_each_trigger("fs", action_add_queue_tail);

    //加入post-fs阶段的action

    action_for_each_trigger("post-fs", action_add_queue_tail);

    //加入属性服务初始化动作

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

    //加入early-boot阶段的action

    action_for_each_trigger("early-boot", action_add_queue_tail);

    //加入boot阶段的action

    action_for_each_trigger("boot", action_add_queue_tail);

        /* 加入当前状态的属性action */

    queue_builtin_action(queue_property_triggers_action, "queue_propety_triggers");

#if BOOTCHART

     //与boot char相关的操作,它是一个工具,对系统性能进行分析

    queue_builtin_action(bootchart_init_action, "bootchart_init");

#endif

    for(;;) {

        //init无限循环

        int nr, i, timeout = -1;

         //执行动作

        execute_one_command();

        //重启死去的进程

        restart_processes();

        //init关注3个方面的事件

        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;//置1

        }

        if (!signal_fd_init && get_signal_fd() > 0) {

            /*关于get_signal_fd(signal_recv_fd) ,可以去sigchld_handler.c跟踪它的来由,它由socketpair 创建,事件来自另外的socket(signal_fd)*/

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

            /* keychord初始化成功,也会监听来自keychord(与键盘设置相关)设备的事件 */

            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

        //poll等待事件的发生

        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();//处理keychord事件

                else if (ufds[i].fd == get_signal_fd())

                    handle_signal();//处理socket事件

            }

        }

    }

    return 0;

}

由于keychord不常用,下面来讨论signal和property。

关于signal

在sigchld_handler.c中:

int get_signal_fd()

{

    return signal_recv_fd;

}

接下来,

void signal_init(void)

{

    int s[2];

 

    struct sigaction act;

    act.sa_handler = sigchld_handler;

    act.sa_flags = SA_NOCLDSTOP;

    act.sa_mask = 0;

    act.sa_restorer = NULL;

    sigaction(SIGCHLD, &act, 0);

    /* create a signalling mechanism for the sigchld handler */

    //与socketpair有关

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

    }

    handle_signal();

}

在socket.c中:

//供系统调用

SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,

                   int __user *, usockvec)

{

         struct socket *sock1, *sock2;

         int fd1, fd2, err;

         struct file *newfile1, *newfile2;

         int flags;

          ….

         err = sock1->ops->socketpair(sock1, sock2);//这里是一个回调函数

         if (err < 0)

                   goto out_release_both;

 

         fd1 = sock_alloc_file(sock1, &newfile1, flags);

         if (unlikely(fd1 < 0)) {

                   err = fd1;

                   goto out_release_both;

         }

         fd2 = sock_alloc_file(sock2, &newfile2, flags);

         if (unlikely(fd2 < 0)) {

                   err = fd2;

                   fput(newfile1);

                   put_unused_fd(fd1);

                   sock_release(sock2);

                   goto out;

         }

         …

out_release_both:

         sock_release(sock2);

out_release_1:

         sock_release(sock1);

out:

         return err;

}

继续跟踪:

在socketpair.S中有如下定义:

    .text

    .type socketpair, #function

    .globl socketpair

    .align 4

    .fnstart

socketpair:

    .save   {r4, r7}

    stmfd   sp!, {r4, r7}

    ldr     r7, =__NR_socketpair

    swi     #0

    ldmfd   sp!, {r4, r7}

    movs    r0, r0

    bxpl    lr

    b       __set_syscall_errno

    .fnend

         signal及socketpair分析到此,来看看property吧,在init.rc里我们经常会设置一些属性,在系统层根据这些属性值来执行相关操作。比如双显(LVDS屏和HDMI),如果设置了,假设属性值为1,那么系统层获取该属性值为1,就执行双显功能。否则,跳过执行。

   1.先看property_init(),在property_service.c:

   void property_init(void)

{

    init_property_area();//初始化property存储区

    load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);/* #define PROP_PATH_RAMDISK_DEFAULT  "/default.prop",即加载default.prop 文件*/

}

2.启动属性服务

  void start_property_service(void)

{

    int 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"

*/

    load_properties_from_file(PROP_PATH_SYSTEM_BUILD);

    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);

    load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);

    //加载属性文件,这些文件保存到永久介质上

    load_persistent_properties();

    //创建socket,用于进程间通信

    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;

}

   3.用handle_property_set_fd()处理事件

     void handle_property_set_fd()

{

    prop_msg msg;

    int s;

    int r;

    int res;

    struct ucred cr;

    struct sockaddr_un addr;

    socklen_t addr_size = sizeof(addr);

    socklen_t cr_size = sizeof(cr);

    //socket接收网络连接

    if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {

        return;

    }

    /* 获取用户端进程的属性 */

    if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {

        close(s);

        ERROR("Unable to recieve socket options\n");

        return;

    }

    //接受数据请求

    r = recv(s, &msg, sizeof(msg), 0);

    close(s);

    if(r != sizeof(prop_msg)) {

        ERROR("sys_prop: mis-match msg size recieved: %d expected: %d\n",

              r, sizeof(prop_msg));

        return;

    }

    //客户端消息命令码为PROP_MSG_SETPROP?

    switch(msg.cmd) {

    case PROP_MSG_SETPROP:

        msg.name[PROP_NAME_MAX-1] = 0;

        msg.value[PROP_VALUE_MAX-1] = 0;

        //接受ctl.开头的控制消息,用一些命令来执行

        if(memcmp(msg.name,"ctl.",4) == 0) {

            if (check_control_perms(msg.value, cr.uid, cr.gid)) {

                handle_control_message((char*) msg.name + 4, (char*) msg.value);

            } else {

                ERROR("sys_prop: Unable to %s service ctl [%s] uid: %d pid:%d\n",

                        msg.name + 4, msg.value, cr.uid, cr.pid);

            }

        } else {

            //检查客户端的权限

            if (check_perms(msg.name, cr.uid, cr.gid)) {

                property_set((char*) msg.name, (char*) msg.value);//调用property_set

            } else {

                ERROR("sys_prop: permission denied uid:%d  name:%s\n",

                      cr.uid, msg.name);

            }

        }

        break;

    default:

        break;

    }

}

下面分析在property_service.c文件中的property_set和property_get

nt property_set(const char *name, const char *value)

{

    prop_area *pa;

    prop_info *pi;

    int namelen = strlen(name);

    int valuelen = strlen(value);

    if(namelen >= PROP_NAME_MAX) return -1;

    if(valuelen >= PROP_VALUE_MAX) return -1;

    if(namelen < 1) return -1;

    //查找该属性是否存在

    pi = (prop_info*) __system_property_find(name);

    if(pi != 0) {

        /* ro. 开头的属性表示只读*/

        if(!strncmp(name, "ro.", 3)) return -1;

        pa = __system_property_area__;

        //更新值

        update_prop_info(pi, value, valuelen);

        pa->serial++;

        __futex_wake(&pa->serial, INT32_MAX);

    } else {

        // PA_COUNT_MAX=247,如果没有找到属性,这里要增加属性,创建新的属性//并分配空间,如果属性总数超过247,直接返回

        pa = __system_property_area__;

        if(pa->count == PA_COUNT_MAX) return -1;

        pi = pa_info_array + pa->count;

        pi->serial = (valuelen << 24);

        memcpy(pi->name, name, namelen + 1);

        memcpy(pi->value, value, valuelen + 1);

        pa->toc[pa->count] =

            (namelen << 24) | (((unsigned) pi) - ((unsigned) pa));

        pa->count++;

        pa->serial++;

        __futex_wake(&pa->serial, INT32_MAX);

    }

    /* 如果是以net.开头的属性,当做DNS这类属性*/

    if (strncmp("net.", name, strlen("net.")) == 0)  {

        if (strcmp("net.change", name) == 0) {

            return 0;

        }

       /*

         如果有更新,重新设置

        */

        property_set("net.change", name);

    } else if (persistent_properties_loaded &&

            strncmp("persist.", name, strlen("persist.")) == 0) {

        /*

        如果是以persist.开头的属性,写到/data/property /.temp文件里

         */

        write_persistent_property(name, value);

    }

    //属性设置后,执行操作生效

    property_changed(name, value);

    return 0;

}

下面:

const char* property_get(const char *name)

{

    prop_info *pi;

 

    if(strlen(name) >= PROP_NAME_MAX) return 0;

    //查找属性存在与否

    pi = (prop_info*) __system_property_find(name);

    if(pi != 0) {

        return pi->value;//得到值

    } else {

        return 0;

    }

}

之前提到socket,用于进程间通信,上述是属性服务端,那么要看看客户端的情况。

在properties.c中:

Step1:

int property_set(const char *key, const char *value)

{

    prop_msg msg;

    unsigned resp;

    if(key == 0) return -1;

    if(value == 0) value = "";

    if(strlen(key) >= PROP_NAME_MAX) return -1;

    if(strlen(value) >= PROP_VALUE_MAX) return -1;

    msg.cmd = PROP_MSG_SETPROP;//设置消息码

    strcpy((char*) msg.name, key);

    strcpy((char*) msg.value, value);

    return send_prop_msg(&msg);//发送请求

}

Step2:

   static int send_prop_msg(prop_msg *msg)

{

    int s;

    int r;

    //和服务端的socket连接

    s = socket_local_client(PROP_SERVICE_NAME,

                            ANDROID_SOCKET_NAMESPACE_RESERVED,

                            SOCK_STREAM);

    if(s < 0) return -1;

    //通过socket发送消息

    while((r = send(s, msg, sizeof(prop_msg), 0)) < 0) {

        if((errno == EINTR) || (errno == EAGAIN)) continue;

        break;

    }

    if(r == sizeof(prop_msg)) {

        r = 0;

    } else {

        r = -1;

    }

    close(s);

    return r;

}

Step3:

int  property_get(const char *key, char *value, const char *default_value)

{

    int len;

 

    len = __system_property_get(key, value);//调用system_properties.c里的

    //__system_property_get()函数

    //如果读到值,返回长度

    if(len > 0) {

        return len;

    }

    //如果没读到,将默认值赋给value,并返回长度

    if(default_value) {

        len = strlen(default_value);

        memcpy(value, default_value, len + 1);

    }

    return len;

}

说明:如果定义HAVE_SYSTEM_PROPERTY_SERVER这个宏,客户端与服务端socket连接如下:

Step1:

  static void init(void)

{

    assert(gPropFd == -1);

    // #define SYSTEM_PROPERTY_PIPE_NAME       "/tmp/android-sysprop"

    gPropFd = connectToServer(SYSTEM_PROPERTY_PIPE_NAME);//连接服务端

    if (gPropFd < 0) {

        //LOGW("not connected to system property server\n");

    } else {

        //LOGV("Connected to system property server\n");

    }

}

Step2:

static int connectToServer(const char* fileName)

{

    int sock = -1;

    int cc;

    struct sockaddr_un addr;

    //创建客户端的socket

    sock = socket(AF_UNIX, SOCK_STREAM, 0);

    if (sock < 0) {

        LOGW("UNIX domain socket create failed (errno=%d)\n", errno);

        return -1;

    }

   /*连接操作 */

    strcpy(addr.sun_path, fileName);    // max 108 bytes

    addr.sun_family = AF_UNIX;

    cc = connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));

    if (cc < 0) {

        // ENOENT means socket file doesn't exist

        // ECONNREFUSED means socket exists but nobody is listening

        //LOGW("AF_UNIX connect failed for '%s': %s\n",

        //    fileName, strerror(errno));

        close(sock);

        return -1;

    }

    return sock;

}

         init这个超级守护进程分析到这里。

抱歉!评论已关闭.