查看系统是怎么做到守护进程的


查看系统是怎么做到守护进程的

查看系统是怎么做到守护进程的

什么系统关键服务 系统的关键服务的ppid也就是父进程都是为1的
闹钟  LayoutInflater   WindowManager    不是    
网络服务,多媒体服务 ,音量服务,安装服务。 电话服务,adb服务  ,触摸事件服务  
netd  网络服务  封装了复杂的底层各种类型的网络
mediaservice   多媒体服务   手机开机需要声音,画面    
ueventd  屏幕响应事件的服务
ueventd  屏幕响应事件的服务
事件分发   activity ondispatchevent()
logd     日志服务
vold     外部存储设备服务  管理和控制Android平台外部存储设备,包括SD插拨、挂载、卸载、格式化等;
Rild     是电话系统的核心部分

进入adb shell 命令执行ps查看进程的消息
结果显示

源码分析,我们这里采用的6.0的源码

首先我们知道,系统在启动的时候,首先会去加载一个文件,为init文件,利用as,可以查看到,可以发现他的权限是有x的,代表是一个可以执行的文件
结果显示
init可以执行的文件是通过下面的源码路径来编译的 F:\AndroidSource\android-6.0.0_r1\android-6.0.0_r1\system\core ,core目录下面还有很多可以执行的文件比如adb
结果显示

既然是一个可以执行的文件,那么肯定有一个文件还有main函数的入口,这里main函数的入口即为init.cpp文件中
int main(int argc, char** argv) {
    if (!strcmp(basename(argv[0]), "ueventd")) {
        return ueventd_main(argc, argv);
    }
    ......
    init_parse_config_file("/init.rc");
    .....
}
查看这个函数的实现 init_parse_config_file("/init.rc");
这个文件里面有很多类似这样的,来声明配置一个服务,
我们能不能获取root权限后  通过修改init.rc配置文件 启动 自己的服务呢?

 即使有了root权限,可以修改该文件也没有。因为我们在根目录看到的文件只是内存文件的镜像。也就是说,android启动后,会将init.rc文件装载到内存。
 而修改init.rc文件的内容实际上只是修改内存中的init.rc文件的内容。一旦重启android,init.rc文件的内容又会恢复到最初的装载。
 想彻底修改init.rc文件内容的唯一方式是修改Android的ROM中的内核镜像(boot.img)。其实boot.img名为内核镜像,有一个镜像ramdisk.img就包含了init.rc文件和init命令。
 所以只有修改ramdisk.img文件中的init.rc文件,并且重新打包boot.img文件,并刷机,才能彻底修改init.rc文件。将Android源代码,编译后,
 就会看到out目录中的相关子目录会生成一个root目录,该目录实际上就是ramdisk.img解压后的内容。会看到有init命令和init.rc文件。通过简单的修改init.rc文件是达不到的
service netd /system/bin/netd
    class main
    socket netd stream 0660 root system
    socket dnsproxyd stream 0660 root inet
    socket mdns stream 0660 root system

此函数中有 parse_config(path, data);
static void parse_config(const char *fn, const std::string& data)
{
    struct listnode import_list;
    struct listnode *node;
    ......
    for (;;) {
        switch (next_token(&state)) {
        case T_EOF:
            state.parse_line(&state, 0, 0);
            goto parser_done;
        case T_NEWLINE:
            state.line++;
            if (nargs) {
                int kw = lookup_keyword(args[0]);
                if (kw_is(kw, SECTION)) {
                    state.parse_line(&state, 0, 0);
                    parse_new_section(&state, kw, nargs, args);
                } else {
                    state.parse_line(&state, nargs, args);
                }
                nargs = 0;
            }
            break;
        case T_TEXT:
            if (nargs < INIT_PARSER_MAXARGS) {
                args[nargs++] = state.text;
            }
            break;
        }
    }
    ....
}
int kw = lookup_keyword(args[0]); 是根据第一个的字符,得到对应的函数 
比如init.rc文件中的
on nonencrypted
    class_start late_start

service drm /system/bin/drmserver
    class main
    user drm
    group drm system inet drmrpc

static int lookup_keyword(const char *s) 其中的s就代表的是第二行的内容 比如这里是 class_start class main 注意这里的class main 跟class_start是一样的
{
    switch (*s++) {
    case 'b':
        if (!strcmp(s, "ootchart_init")) return K_bootchart_init;
        break;
    case 'c':
        if (!strcmp(s, "opy")) return K_copy;
        if (!strcmp(s, "lass")) return K_class;
        if (!strcmp(s, "lass_start")) return K_class_start;
        if (!strcmp(s, "lass_stop")) return K_class_stop;
        if (!strcmp(s, "lass_reset")) return K_class_reset;
        if (!strcmp(s, "onsole")) return K_console;
        if (!strcmp(s, "hown")) return K_chown;
        if (!strcmp(s, "hmod")) return K_chmod;
        if (!strcmp(s, "ritical")) return K_critical;
        break
        ....
}
所以上面会返回一个K_class_start,而k_class_start为  KEYWORD(class_start, COMMAND, 1, do_class_start) 也就为 do_class_start,是一个函数指针
int do_class_start(int nargs, char **args)
{
        /* Starting a class does not start services
         * which are explicitly disabled.  They must
         * be started individually.
         */
    service_for_each_class(args[1], service_start_if_not_disabled);
    return 0;
}

然后执行 parse_new_section(&state, kw, nargs, args);
static void parse_new_section(struct parse_state *state, int kw,
                       int nargs, char **args)
{
    printf("[ %s %s ]\n", args[0],
           nargs > 1 ? args[1] : "");
    switch(kw) {
    case K_service:  对应的init.rc文件中的service开头的 
        state->context = parse_service(state, nargs, args);
        if (state->context) {
            state->parse_line = parse_line_service;
            return;
        }
        break;
    case K_on:   对应的init.rc 文件中的 on 开头的
        state->context = parse_action(state, nargs, args);
        if (state->context) {
            state->parse_line = parse_line_action;
            return;
        }
        break;
    case K_import:  对应的init.rc 文件中的 import 开头的
        parse_import(state, nargs, args);
        break;
    }
    state->parse_line = parse_line_no_op;
}
parse_service(state,nargs,args);函数实现
static void *parse_service(struct parse_state *state, int nargs, char **args)
{
    ......
    从service集合里面查找如果查找到了直接返回
    service* svc = (service*) service_find_by_name(args[1]);
    if (svc) {
        parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
        return 0;
    }
    nargs -= 2;
    如果没有查找到就new 一个service 分配内存空间
    svc = (service*) calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
    if (!svc) {
        parse_error(state, "out of memory\n");
        return 0;
    }
    给service 赋值

    svc->name = strdup(args[1]);
    svc->classname = "default";
    memcpy(svc->args, args + 2, sizeof(char*) * nargs);
    trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
    svc->args[nargs] = 0;
    svc->nargs = nargs;
    list_init(&svc->onrestart.triggers);
    cur_trigger->name = "onrestart";
    list_add_tail(&svc->onrestart.triggers, &cur_trigger->nlist);
    执行下面的代码就会给 serivce 中的action 中的 command 里面的  int (*func)(int nargs, char **args); 这个成员变量赋值为通过lookup_keyword 返回的那个函数指针
    list_init(&svc->onrestart.commands);
    list_add_tail(&service_list, &svc->slist);
    return svc;
}

解析完init.rc文件之后
init.rc main函数中还有这样的,下面的是用来解析不是配置在init.rc文件中的服务的
queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done"); 第一个参数就为一个函数指针
void queue_builtin_action(int (*func)(int nargs, char **args), const char *name)
{
    action* act = (action*) calloc(1, sizeof(*act));
    trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
    cur_trigger->name = name;
    list_init(&act->triggers);
    list_add_tail(&act->triggers, &cur_trigger->nlist);
    list_init(&act->commands);
    list_init(&act->qlist);

    command* cmd = (command*) calloc(1, sizeof(*cmd));
    给入口函数赋值
    cmd->func = func;
    cmd->args[0] = const_cast<char*>(name);
    cmd->nargs = 1;
    list_add_tail(&act->commands, &cmd->clist);
    添加到servic列表里面
    list_add_tail(&action_list, &act->alist);
    action_add_queue_tail(act);
}
等上面的serive所有都解析完之后,init main 函数中还有
 while (true) {
     if (!waiting_for_exec) {
            启动服务
            execute_one_command();
            restart_processes();
}
execute_one_command()中含有下面的代码,获取第一个的service,然后从这个service里面获取到第一个command,赋值给cur_command
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;
        }

        build_triggers_string(name_str, sizeof(name_str), cur_action);

        INFO("processing action %p (%s)\n", cur_action, name_str);
        cur_command = get_first_command(cur_action);
    } else {
        cur_command = get_next_command(cur_action, cur_command);
    }
    然后执行这个函数,这个就会执行到解析到service里面的func 函数指针比如
    int result = cur_command->func(cur_command->nargs, cur_command->args);
比如上面的queue_builtin_action(keychord_init_action, "keychord_init"); 这里的func为,执行对应的函数的初始话操作
void keychord_init() {
    service_for_each(add_service_keycodes);

    // Nothing to do if no services require keychords.
    if (!keychords) {
        return;
    }

    keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC));
    if (keychord_fd == -1) {
        ERROR("could not open /dev/keychord: %s\n", strerror(errno));
        return;
    }

    int ret = write(keychord_fd, keychords, keychords_length);
    if (ret != keychords_length) {
        ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno));
        close(keychord_fd);
    }

    free(keychords);
    keychords = nullptr;
    register_epoll_handler(keychord_fd, handle_keychord);
}

执行 restart_processes();
static void restart_processes()
{
    process_needs_restart = 0;
    service_for_each_flags(SVC_RESTARTING,restart_service_if_needed);restart_service_if_needed 为函数指针
}
void service_for_each_flags(unsigned matchflags,
                            void (*func)(struct service *svc))
{
    struct listnode *node;
    struct service *svc;
    list_for_each(node, &service_list) {
        svc = node_to_item(node, struct service, slist);
        if (svc->flags & matchflags) {
            func(svc); 即会回调传递过来的函数指针,即restart_service_if_needed
        }
    }
}
函数指针的实现为
static void restart_service_if_needed(struct service *svc)
{
    time_t next_start_time = svc->time_started + 5;

    if (next_start_time <= gettime()) {
        svc->flags &= (~SVC_RESTARTING);
        service_start(svc, NULL); 开启服务
        return;
    }

    if ((next_start_time < process_needs_restart) ||
        (process_needs_restart == 0)) {
        process_needs_restart = next_start_time;
    }
}
  service_start(svc, NULL); 开启服务 函数实现
void service_start(struct service *svc, const char *dynamic_args)
{
 也是通过fork一个子进程,在子进程里面启动这个服务,至此服务被启动完成,这里没有看到守护进程的代码,这里需要了解的是
 fork一个进程 会让子进程跟父进程拥有同样的资源,所以可能父进程里面有处理
 pid_t pid = fork();
    if (pid == 0) {
        struct socketinfo *si;
        struct svcenvinfo *ei;
        char tmp[32];
        int fd, sz;


        char *arg_ptrs[INIT_PARSER_MAXARGS+1];
        int arg_idx = svc->nargs;
        char *tmp = strdup(dynamic_args);
        char *next = tmp;
        char *bword;

        /* Copy the static arguments */
        memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));

        while((bword = strsep(&next, " "))) {
                arg_ptrs[arg_idx++] = bword;
                if (arg_idx == INIT_PARSER_MAXARGS)
                    break;
         }
        rg_ptrs[arg_idx] = NULL;
        execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);  通过这个可执行的命令启动一个服务execve
     }
}
在init.cpp 文件中的main方法中有这样的代码

    signal_handler_init();
    property_load_boot_defaults();
    start_property_service();

signal_handler_init(); 函数的实现
void signal_handler_init() {
    // Create a signalling mechanism for SIGCHLD.
    int s[2];
    这里创建俩个socket套接字,是一对来的,一个用来做客户端,一个用来做服务端
    if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
        ERROR("socketpair failed: %s\n", strerror(errno));
        exit(1);
    }
    给全局的变量赋值
    signal_write_fd = s[0];
    signal_read_fd = s[1];

    // Write to signal_write_fd if we catch SIGCHLD.
    struct sigaction act;
    memset(&act, 0, sizeof(act));

    SIGCHLD_handlerw为一个函数指针,也即是当系统杀死调进程的时候,会回调执行的函数
    act.sa_handler = SIGCHLD_handler;
    act.sa_flags = SA_NOCLDSTOP;
    sigaction(SIGCHLD, &act, 0);

    reap_any_outstanding_children();

    注册监听
    register_epoll_handler(signal_read_fd, handle_signal);
}
handle_signal 为一个函数指针,函数的原型为
static void handle_signal() {
    // Clear outstanding requests.
    char buf[32];
    //从signal_read_fd读取内容,read 会阻塞
    read(signal_read_fd, buf, sizeof(buf));
    reap_any_outstanding_children();
}


register_epoll_handler函数的实现为
void register_epoll_handler(int fd, void (*fn)()) {
    epoll_event ev;
    ev.events = EPOLLIN;
    将fn 赋值给ev.data.ptr
    ev.data.ptr = reinterpret_cast<void*>(fn);
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
        ERROR("epoll_ctl failed: %s\n", strerror(errno));
    }
}

SIGCHLD_handler函数的原型为
static void SIGCHLD_handler(int) {
    这里利用 signal_write_fd 客户端的socket套接字直接的发消息,这样我们查看接受的地方
    if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {
        ERROR("write(signal_write_fd) failed: %s\n", strerror(errno));
    }
}

main函数中的while循环中
epoll_event ev;
        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
        if (nr == -1) {
            ERROR("epoll_wait failed: %s\n", strerror(errno));
        } else if (nr == 1) {
            ((void (*)()) ev.data.ptr)(); 执行回调函数,也就是执行到了handle_signal 这个函数里面,这样当客户端收到了要关闭的进程之后,就主动的发了一个消息,这样服务端就接受到了
}

static void handle_signal() {
    // Clear outstanding requests.
    char buf[32];
    //从signal_read_fd读取内容,read 会阻塞
    read(signal_read_fd, buf, sizeof(buf));
    reap_any_outstanding_children();
}
然后执行reap_any_outstanding_children
static void reap_any_outstanding_children() {
    while (wait_for_one_process()) {
    }
}
wait_for_one_process()函数里面有这样的关键代码
 // Execute all onrestart commands for this service.
    struct listnode* node;
    list_for_each(node, &svc->onrestart.commands) {
        command* cmd = node_to_item(node, struct command, clist);
         执行入口函数
         cmd->func(cmd->nargs, cmd->args);
    }
    服务又再次的被启动
    svc->NotifyStateChange("restarting");
    return true;
然后main 中的while循环里面就会把这个服务启动    

方式二 main函数中有这样的代码
start_property_service();
函数原型实现
void start_property_service() {
    创建socket套接字
    property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                    0666, 0, 0, NULL);
    if (property_set_fd == -1) {
        ERROR("start_property_service socket creation failed: %s\n", strerror(errno));
        exit(1);
    }
    监听,8为并发数
    listen(property_set_fd, 8);

    注册监听
    register_epoll_handler(property_set_fd, handle_property_set_fd);handle_property_set_fd为一个函数指针

}
handle_property_set_fd 函数原型的实现为:
static void handle_property_set_fd()
{
    监听
    if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
        return;
    }

    /* Check socket options here */
    if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
        close(s);
        ERROR("Unable to receive socket options\n");
        return;
    }

    ufds[0].fd = s;
    ufds[0].events = POLLIN;
    ufds[0].revents = 0;

    .......
     handle_control_message((char*) msg.name + 4, (char*) msg.value);
    .......
}
handle_control_message()函数原型实现
void handle_control_message(const char *msg, const char *arg)
{
    if (!strcmp(msg,"start")) {
        msg_start(arg); 启动服务
    } else if (!strcmp(msg,"stop")) {
        msg_stop(arg);
    } else if (!strcmp(msg,"restart")) {
        msg_restart(arg);
    } else {
        ERROR("unknown control msg '%s'\n", msg);
    }
}
启动服务
static void msg_start(const char *name)
{
    struct service *svc = NULL;
    char *tmp = NULL;
    char *args = NULL;

    if (!strchr(name, ':'))
        svc = service_find_by_name(name);
    else {
        tmp = strdup(name);
        if (tmp) {
            args = strchr(tmp, ':');
            *args = '\0';
            args++;

            svc = service_find_by_name(tmp);
        }
    }

    if (svc) {
        service_start(svc, args); 启动服务
    } else {
        ERROR("no such service '%s'\n", name);
    }
    if (tmp)
        free(tmp);
}

流程图:
结果显示


文章作者: AheadSnail
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 AheadSnail !
评论
  目录