Android5.0开关机模块——init进程(init.rc、property_service)

本文深入探讨Android 5.0的init进程,包括init.rc文件的语法、service管理以及property_service的工作原理。分析了init如何通过SIGCHLD信号处理子进程死亡,以及如何响应系统属性变化。同时,讨论了不同类型的service在死亡后的处理方式,特别是对关键进程的处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇最后提到init进程的轮询机制,init进程主要轮询property、signal、组合键等,这里探究一下这几个内容是如何实现的。

要说明这一部分内容,必须先来分析一下init.rc的语法问题

import /init.trace.rc  前文说过,就是在解析完init.rc后把其他XX.rc的内容也解析出来

on early-init
    # Set init and its forked children's oom_adj.
    write /proc/1/oom_adj -16

    # Set the security context for the init process.
    # This should occur before anything else (e.g. ueventd) is started.
    setcon u:r:init:s0

    start ueventd

on关键字对应的就是一个action,一个action里会对应一些command,这个action会被放到action_queue中,里面的command最终会由execute_one_command()执行


service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd
    onrestart setprop ro.yulong.ylcrash syscrash
    onrestart start crash_and_reset

      service会被放进service_list队列中,每个service下面都对应很多的option,class main表示这个service属于main这一组,当执行命令class_start main时,所有main组里的       service都会被执行;onrestart是指当这个service死掉后,执行onrestart后面的命令

     service的执行是调用init.c中的service_start来执行的,在service_start中,用fork() + execve()来创建子进程并执行service指定的可执行文件来终于启动了service

     没启动一个service就会创建一个子进程。


on property:vold.decrypt=trigger_reset_main
    class_reset main

       当系统属性的判断成立时,执行下面的命令


      上面是init.rc的一些简单语法,下面结合init.rc这些语法特点来分析前面的轮询问题

      在init进程里面,init进程会通过捕获SIGCHLD得知其子进程的死亡,并据情况决定是否重启之。记住,在Linux的世界里,在子进程死亡的时候,父进程会收到一个SIGCHLD信号,而后父进程通过wait()系统调用,清理子进程僵尸。大家都知道,一个进程死亡的时候,如果它还有子进程,典型地,子进程会被托孤给init进程,这种情况非常普遍,所以任何一个Linux系统,它的init程序,少不了要做一件事情,就是反复通过wait()清理僵尸,否则Linux系统就会尸横遍野,整个一部生化危机啊有木有?Linux是个怎样残酷的世界啊,我艰于呼吸视听啊,哪里还能有什么言语?永远都是白发人送黑发人,父进程清理子进程。——网络牛人

      get_signal_fd是前面提到的一种轮询,它的主要作用就是接收死亡进程的消息。比如,当zygote死亡后,会给init发信号,会触发init进程执行handle_signal()

void handle_signal(void)
{<pre name="code" class="cpp">static int wait_for_one_process(int block)
{
    …

    while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR ); // 干掉僵尸

    svc = service_find_by_pid(pid);
    if (!svc) {  // 无主僵尸
        ERROR("untracked pid %d exited\n", pid);
        return 0;
    }

    NOTICE("process '%s', pid %d exited\n", svc->name, pid);

    …

        /* oneshot processes go into the disabled state on exit */
    if (svc->flags & SVC_ONESHOT) {  //不投胎的僵尸
        svc->flags |= SVC_DISABLED;
    }

        /* disabled processes do not get restarted automatically */
    if (svc->flags & SVC_DISABLED) {
        notify_service_state(svc->name, "stopped");
        return 0;
    }

    now = gettime();
    if (svc->flags & SVC_CRITICAL) { //重要僵尸
        //短时间内反复挂,重启
        if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
            if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
                …
                sync();
                __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
                         LINUX_REBOOT_CMD_RESTART2, "recovery");
                return 0;
            }
        } else {
            svc->time_crashed = now;
            svc->nr_crashed = 1;
        }
    }

    svc->flags |= SVC_RESTARTING; //标记重启中

    /* Execute all onrestart commands for this service. */
    list_for_each(node, &svc->onrestart.commands) { //执行onrestart里面的命令
        cmd = node_to_item(node, struct command, clist);
        cmd->func(cmd->nargs, cmd->args);
    }
    notify_service_state(svc->name, "restarting");
    return 0;
}

char tmp[32]; /* we got a SIGCHLD - reap and restart as needed */ read(signal_recv_fd, tmp, sizeof(tmp)); while (!wait_for_one_process(0)) ;}

 1、无主僵尸 

       挂的时候有“untracked pid %d exited”打印的进程属于init的子进程,但是并没有在 init.rc里面注册service。典型地,那些先父仙游后被托孤给init的进程!

2、不投胎的僵尸

       有oneshot标志的服务,死亡以后,只能手动重启

servicebootsound /system/bin/playmp3
    user media
    group audio
    oneshot
3、可以重启的僵尸

      这类进程就爽了,因为被“svc->flags |= SVC_RESTARTING”盖章了,死了会重新投胎, 下次init执行到restart_processes()的时候就可以重启之

4、重要进程
      如果一个service是critical的,而它又在短时间内反复挂,restart后又总是夭折,我们很可能不能再让它这么痛苦下去了,唯一的方法就是让它解脱,于是整个系统重启。这样的service包括:

service ueventd /sbin/ueventd
    critical

service servicemanager /system/bin/servicemanager
    user system
    critical
    onrestart restart zygote
    onrestart restart media


下面说下系统属性修改的过程

设置property,有C/S架构组成。客户端的程序位于properties.c,服务端的程序位于property_service.c。

前文提到过,

queue_builtin_action(property_service_init_action, "property_service_init");  和 queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");

这两个函数只能算是初始化服务器端的作用

建了一个socket,其名为ANDROID_SOCKET_DIR"/PROP_SERVICE_NAME",也即 "/dev/socket/property_service“

然后调用listen监听这个socket,并将创建的socket描述符赋值给全局变量property_set_fd

当用户执行setprop时,调用的其实是properties.c中的property_set函数,该函数会发送socket消息,最终调用到property_service.c中的handle_property_set_fd(),然后调用是property_set,然后是property_changed,在property_changed中会调用queue_property_triggers()来把对应的action放入queue中,这样,就可以执行到这个action中的命令了


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值