Android系统启动-Init篇

本文深入解析Android系统的启动过程,从init进程的角色与功能入手,详细阐述了init进程如何解析init.rc文件,启动核心服务,处理子进程信号,以及提供属性服务。文章还探讨了关键服务如Zygote的启动机制及其重启逻辑。

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

转载:http://gityuan.com/2016/02/05/android-init/

基于Android 6.0的源码剖析, 分析Android启动过程进程号为1的init进程的工作内容

<span style="color:#333333"><code>/<span style="color:#cc7832">system</span>/core/init/
  - init.cpp
  - init_parser.cpp
  - signal_handler.cpp
</code></span>

一、概述

init是Linux系统中用户空间的第一个进程,进程号为1。Kernel启动后,在用户空间,启动init进程,并调用init中的main()方法执行init进程的职责。对于init进程的功能分为4部分:

  • 分析和运行所有的init.rc文件;
  • 生成设备驱动节点; (通过rc文件创建)
  • 处理子进程的终止(signal方式);
  • 提供属性服务。

接下来从main()方法说起。

1.1 main

[-> init.cpp]

<span style="color:#333333"><code><span style="color:#cc7832">int</span> main(<span style="color:#cc7832">int</span> argc, <span style="color:#cc7832">char</span>** argv) {
    ...
    umask(<span style="color:#6897bb">0</span>); <span style="color:#808080">//设置文件属性0777</span>
    
    klog_init();  <span style="color:#808080">//初始化kernel log,位于设备节点/dev/kmsg【见小节1.2】</span>
    klog_set_level(KLOG_NOTICE_LEVEL); <span style="color:#808080">//设置输出的log级别</span>
    <span style="color:#808080">// 输出init启动阶段的log</span>
    NOTICE(<span style="color:#6a8759">"init%s started!\n"</span>, is_first_stage ? <span style="color:#6a8759">""</span> : <span style="color:#6a8759">" second stage"</span>);
    
    property_init(); <span style="color:#808080">//创建一块共享的内存空间,用于属性服务</span>
    signal_handler_init();  <span style="color:#808080">//初始化子进程退出的信号处理过程【见小节2.1】</span>

    property_load_boot_defaults(); <span style="color:#808080">//加载default.prop文件</span>
    start_property_service();   <span style="color:#808080">//启动属性服务器(通过socket通信)【5.1】</span>
    init_parse_config_file(<span style="color:#6a8759">"/init.rc"</span>); <span style="color:#808080">//解析init.rc文件</span>

    <span style="color:#808080">//执行rc文件中触发器为 on early-init的语句</span>
    action_for_each_trigger(<span style="color:#6a8759">"early-init"</span>, action_add_queue_tail);
    <span style="color:#808080">//等冷插拔设备初始化完成</span>
    queue_builtin_action(wait_for_coldboot_done_action, <span style="color:#6a8759">"wait_for_coldboot_done"</span>);
    queue_builtin_action(mix_hwrng_into_linux_rng_action, <span style="color:#6a8759">"mix_hwrng_into_linux_rng"</span>);
    <span style="color:#808080">//设备组合键的初始化操作</span>
    queue_builtin_action(keychord_init_action, <span style="color:#6a8759">"keychord_init"</span>);
    <span style="color:#808080">// 屏幕上显示Android静态Logo 【见小节1.3】</span>
    queue_builtin_action(console_init_action, <span style="color:#6a8759">"console_init"</span>);
    
    <span style="color:#808080">//执行rc文件中触发器为 on init的语句</span>
    action_for_each_trigger(<span style="color:#6a8759">"init"</span>, action_add_queue_tail);
    queue_builtin_action(mix_hwrng_into_linux_rng_action, <span style="color:#6a8759">"mix_hwrng_into_linux_rng"</span>);
    
    <span style="color:#cc7832">char</span> bootmode[PROP_VALUE_MAX];
    <span style="color:#808080">//当处于充电模式,则charger加入执行队列;否则late-init加入队列。</span>
    <span style="color:#cc7832">if</span> (property_get(<span style="color:#6a8759">"ro.bootmode"</span>, bootmode) > <span style="color:#6897bb">0</span> && strcmp(bootmode, <span style="color:#6a8759">"charger"</span>) == <span style="color:#6897bb">0</span>) {
       action_for_each_trigger(<span style="color:#6a8759">"charger"</span>, action_add_queue_tail);
    } <span style="color:#cc7832">else</span> {
       action_for_each_trigger(<span style="color:#6a8759">"late-init"</span>, action_add_queue_tail);
    }
    <span style="color:#808080">//触发器为属性是否设置</span>
    queue_builtin_action(queue_property_triggers_action, <span style="color:#6a8759">"queue_property_triggers"</span>);
     
    <span style="color:#cc7832">while</span> (<span style="color:#6897bb">true</span>) {
        <span style="color:#cc7832">if</span> (!waiting_for_exec) {
            execute_one_command();
            restart_processes(); <span style="color:#808080">//【见小节1.4】</span>
        }
        <span style="color:#cc7832">int</span> timeout = <span style="color:#6897bb">-1</span>;
        <span style="color:#cc7832">if</span> (process_needs_restart) {
            timeout = (process_needs_restart - gettime()) * <span style="color:#6897bb">1000</span>;
            <span style="color:#cc7832">if</span> (timeout < <span style="color:#6897bb">0</span>)
                timeout = <span style="color:#6897bb">0</span>;
        }
        <span style="color:#cc7832">if</span> (!action_queue_empty() || cur_action) {
            timeout = <span style="color:#6897bb">0</span>;
        }

        epoll_event ev;
        <span style="color:#808080">//循环 等待事件发生</span>
        <span style="color:#cc7832">int</span> nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, <span style="color:#6897bb">1</span>, timeout));
        <span style="color:#cc7832">if</span> (nr == <span style="color:#6897bb">-1</span>) {
            ERROR(<span style="color:#6a8759">"epoll_wait failed: %s\n"</span>, strerror(errno));
        } <span style="color:#cc7832">else</span> <span style="color:#cc7832">if</span> (nr == <span style="color:#6897bb">1</span>) {
            ((<span style="color:#cc7832">void</span> (*)()) ev.data.ptr)();
        }
    }
    <span style="color:#cc7832">return</span> <span style="color:#6897bb">0</span>;
}
</code></span>

1.2 log系统

此时android的log系统还没有启动,采用kernel的log系统,打开的设备节点/dev/kmsg, 那么可通过cat /dev/kmsg来获取内核log。

接下来,设置log的输出级别为KLOG_NOTICE_LEVEL(5),当log级别小于5时则会输出到kernel log, 默认值为3.

<span style="color:#333333"><code><span style="color:#bbb529">#define KLOG_ERROR_LEVEL 3</span>
<span style="color:#bbb529">#define KLOG_WARNING_LEVEL 4</span>
<span style="color:#bbb529">#define KLOG_NOTICE_LEVEL 5</span>
<span style="color:#bbb529">#define KLOG_INFO_LEVEL 6</span>
<span style="color:#bbb529">#define KLOG_DEBUG_LEVEL 7</span>
<span style="color:#bbb529">#define KLOG_DEFAULT_LEVEL 3 <span style="color:#808080">//默认为3</span></span>
</code></span>

1.3 console_init_action

[-> init.cpp]

<span style="color:#333333"><code><span style="color:#cc7832">static</span> <span style="color:#cc7832">int</span> <span style="color:#ffc66d">console_init_action</span>(<span style="color:#cc7832">int</span> nargs, <span style="color:#cc7832">char</span> **args) {
    <span style="color:#cc7832">char</span> console[PROP_VALUE_MAX];
    <span style="color:#cc7832">if</span> (property_get(<span style="color:#6a8759">"ro.boot.console"</span>, console) > <span style="color:#6897bb">0</span>) {
        snprintf(console_name, <span style="color:#cc7832">sizeof</span>(console_name), <span style="color:#6a8759">"/dev/%s"</span>, console);
    }

    <span style="color:#cc7832">int</span> fd = open(console_name, O_RDWR | O_CLOEXEC);
    <span style="color:#cc7832">if</span> (fd >= <span style="color:#6897bb">0</span>)
        have_console = <span style="color:#6897bb">1</span>;
    close(fd);

    fd = open(<span style="color:#6a8759">"/dev/tty0"</span>, O_WRONLY | O_CLOEXEC);
    <span style="color:#cc7832">if</span> (fd >= <span style="color:#6897bb">0</span>) {
        <span style="color:#cc7832">const</span> <span style="color:#cc7832">char</span> *msg;
            msg = <span style="color:#6a8759">"\n"</span>
        <span style="color:#6a8759">"\n"</span>
        <span style="color:#6a8759">"\n"</span>
        <span style="color:#6a8759">"\n"</span>
        <span style="color:#6a8759">"\n"</span>
        <span style="color:#6a8759">"\n"</span>
        <span style="color:#6a8759">"\n"</span>  <span style="color:#808080">// console is 40 cols x 30 lines</span>
        <span style="color:#6a8759">"\n"</span>
        <span style="color:#6a8759">"\n"</span>
        <span style="color:#6a8759">"\n"</span>
        <span style="color:#6a8759">"\n"</span>
        <span style="color:#6a8759">"\n"</span>
        <span style="color:#6a8759">"\n"</span>
        <span style="color:#6a8759">"\n"</span>
        <span style="color:#6a8759">" A N D R O I D "</span>;
        write(fd, msg, strlen(msg));
        close(fd);
    }

    return <span style="color:#6897bb">0</span>;
}
</code></span>

这便是开机显示的底部带ANDROID字样的画面。

1.4 restart_processes

[-> init.cpp]

<span style="color:#333333"><code><span style="color:#cc7832">static</span> <span style="color:#cc7832">void</span> <span style="color:#ffc66d">restart_processes</span>() {
    process_needs_restart = <span style="color:#6897bb">0</span>;
    service_for_each_flags(SVC_RESTARTING,
                           restart_service_if_needed);
}
</code></span>

检查service_list中的所有服务,对于带有SVC_RESTARTING标志的服务,则都会调用其相应的restart_service_if_needed。

<span style="color:#333333"><code><span style="color:#cc7832">static</span> <span style="color:#cc7832">void</span> <span style="color:#ffc66d">restart_service_if_needed</span>(<span style="color:#cc7832">struct</span> service *svc) {
    <span style="color:#cc7832">time_t</span> next_start_time = svc->time_started + <span style="color:#6897bb">5</span>;

    <span style="color:#cc7832">if</span> (next_start_time <= gettime()) {
        svc->flags &= (~SVC_RESTARTING);
        service_start(svc, <span style="color:#6897bb">NULL</span>); 
        return;
    }

    <span style="color:#cc7832">if</span> ((next_start_time < process_needs_restart) ||
        (process_needs_restart == <span style="color:#6897bb">0</span>)) {
        process_needs_restart = next_start_time;
    }
}
</code></span>

之后再调用service_start来启动服务。

二、信号处理

在init.cpp的main()方法中,通过signal_handler_init()来初始化信号处理过程。

主要工作:

  • 初始化signal句柄;
  • 循环处理子进程;
  • 注册epoll句柄;
  • 处理子进程的终止;

2.1 signal_handler_init

[-> signal_handler.cpp]

<span style="color:#333333"><code><span style="color:#cc7832">void</span> <span style="color:#ffc66d">signal_handler_init</span>() {
    <span style="color:#cc7832">int</span> s[<span style="color:#6897bb">2</span>];
    <span style="color:#808080">// 创建socket pair</span>
    <span style="color:#cc7832">if</span> (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, <span style="color:#6897bb">0</span>, s) == <span style="color:#6897bb">-1</span>) {
        exit(<span style="color:#6897bb">1</span>);
    }
    signal_write_fd = s[<span style="color:#6897bb">0</span>];
    signal_read_fd = s[<span style="color:#6897bb">1</span>];
    <span style="color:#808080">//当捕获信号SIGCHLD,则写入signal_write_fd</span>
    <span style="color:#cc7832">struct</span> sigaction act;
    memset(&act, <span style="color:#6897bb">0</span>, <span style="color:#cc7832">sizeof</span>(act));
    act.sa_handler = SIGCHLD_handler;
    <span style="color:#808080">//SA_NOCLDSTOP使init进程只有在其子进程终止时才会受到SIGCHLD信号</span>
    act.sa_flags = SA_NOCLDSTOP;
    sigaction(SIGCHLD, &act, <span style="color:#6897bb">0</span>);
    reap_any_outstanding_children(); 【见小节<span style="color:#6897bb">2.2</span>】
    register_epoll_handler(signal_read_fd, handle_signal);  <span style="color:#808080">//【见小节2.3】</span>
}
</code></span>

每个进程在处理其他进程发送的signal信号时都需要先注册,当进程的运行状态改变或终止时会产生某种signal信号,init进程是所有用户空间进程的父进程,当其子进程终止时产生SIGCHLD信号,init进程调用信号安装函数sigaction(),传递参数给sigaction结构体,便完成信号处理的过程。

这里有两个重要的函数:SIGCHLD_handler和handle_signal,如下:

<span style="color:#333333"><code><span style="color:#808080">//写入数据</span>
<span style="color:#cc7832">static</span> <span style="color:#cc7832">void</span> <span style="color:#ffc66d">SIGCHLD_handler</span>(<span style="color:#cc7832">int</span>) {
    <span style="color:#808080">//向signal_write_fd写入1,直到成功为止</span>
    <span style="color:#cc7832">if</span> (TEMP_FAILURE_RETRY(write(signal_write_fd, <span style="color:#6a8759">"1"</span>, <span style="color:#6897bb">1</span>)) == <span style="color:#6897bb">-1</span>) {
        ERROR(<span style="color:#6a8759">"write(signal_write_fd) failed: %s\n"</span>, strerror(errno));
    }
}

<span style="color:#808080">//读取数据</span>
<span style="color:#cc7832">static</span> <span style="color:#cc7832">void</span> <span style="color:#ffc66d">handle_signal</span>() {
    <span style="color:#cc7832">char</span> buf[<span style="color:#6897bb">32</span>];
    <span style="color:#808080">//读取signal_read_fd数据,放入buf</span>
    read(signal_read_fd, buf, <span style="color:#cc7832">sizeof</span>(buf));
    reap_any_outstanding_children(); 【见流程<span style="color:#6897bb">3</span><span style="color:#6897bb">-1</span>】
}
</code></span>

2.2 reap_any_outstanding_children

[-> signal_handler.cpp]

<span style="color:#333333"><code><span style="color:#cc7832">static</span> void reap_any_outstanding_children() {
    <span style="color:#cc7832">while</span> (wait_for_one_process()) { }
}

<span style="color:#cc7832">static</span> bool wait_for_one_process() {
    int status;
    <span style="color:#808080">//等待任意子进程,如果子进程没有退出则返回0,否则则返回该子进程pid。</span>
    pid_t pid = TEMP_FAILURE_RETRY(waitpid(<span style="color:#6897bb">-1</span>, &status, WNOHANG));
    <span style="color:#cc7832">if</span> (pid == <span style="color:#6897bb">0</span>) {
        <span style="color:#cc7832">return</span> <span style="color:#cc7832">false</span>;
    } <span style="color:#cc7832">else</span> <span style="color:#cc7832">if</span> (pid == <span style="color:#6897bb">-1</span>) {
        ERROR(<span style="color:#6a8759">"waitpid failed: %s\n"</span>, strerror(errno));
        <span style="color:#cc7832">return</span> <span style="color:#cc7832">false</span>;
    }
    service* svc = service_find_by_pid(pid); <span style="color:#808080">//根据pid查找到相应的service</span>
    std::string name;

    <span style="color:#cc7832">if</span> (!svc) {
        <span style="color:#cc7832">return</span> <span style="color:#cc7832">true</span>;
    }

    <span style="color:#808080">//当flags为RESTART,且不是ONESHOT时,先kill进程组内所有的子进程或子线程</span>
    <span style="color:#cc7832">if</span> (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
        kill(-pid, SIGKILL);
    }

    <span style="color:#808080">//移除当前服务svc中的所有创建过的socket</span>
    <span style="color:#cc7832">for</span> (socketinfo* si = svc->sockets; si; si = si->next) {
        char tmp[<span style="color:#6897bb">128</span>];
        snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR<span style="color:#6a8759">"/%s"</span>, si->name);
        unlink(tmp);
    }

    <span style="color:#808080">//当flags为EXEC时,释放相应的服务</span>
    <span style="color:#cc7832">if</span> (svc->flags & SVC_EXEC) {
        waiting_for_exec = <span style="color:#cc7832">false</span>;
        list_remove(&svc->slist);
        free(svc->name);
        free(svc);
        <span style="color:#cc7832">return</span> <span style="color:#cc7832">true</span>;
    }
    svc->pid = <span style="color:#6897bb">0</span>;
    svc->flags &= (~SVC_RUNNING);

    <span style="color:#808080">//对于ONESHOT服务,使其进入disabled状态</span>
    <span style="color:#cc7832">if</span> ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
        svc->flags |= SVC_DISABLED;
    }
    <span style="color:#808080">//禁用和重置的服务,都不再自动重启</span>
    <span style="color:#cc7832">if</span> (svc->flags & (SVC_DISABLED | SVC_RESET))  {
        svc->NotifyStateChange(<span style="color:#6a8759">"stopped"</span>); <span style="color:#808080">//设置相应的service状态为stopped</span>
        <span style="color:#cc7832">return</span> <span style="color:#cc7832">true</span>;
    }

    <span style="color:#808080">//服务在4分钟内重启次数超过4次,则重启手机进入recovery模式</span>
    time_t now = gettime();
    <span style="color:#cc7832">if</span> ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {
        <span style="color:#cc7832">if</span> (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
            <span style="color:#cc7832">if</span> (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
                android_reboot(ANDROID_RB_RESTART2, <span style="color:#6897bb">0</span>, <span style="color:#6a8759">"recovery"</span>);
                <span style="color:#cc7832">return</span> <span style="color:#cc7832">true</span>;
            }
        } <span style="color:#cc7832">else</span> {
            svc->time_crashed = now;
            svc->nr_crashed = <span style="color:#6897bb">1</span>;
        }
    }
    svc->flags &= (~SVC_RESTART);
    svc->flags |= SVC_RESTARTING;

    <span style="color:#808080">//执行当前service中所有onrestart命令</span>
    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);
    }
    <span style="color:#808080">//设置相应的service状态为restarting</span>
    svc->NotifyStateChange(<span style="color:#6a8759">"restarting"</span>);
    <span style="color:#cc7832">return</span> <span style="color:#cc7832">true</span>;
}
</code></span>

另外:通过getprop | grep init.svc 可查看所有的service运行状态。状态总共分为:running, stopped, restarting

2.3 register_epoll_handler

[-> signal_handler.cpp]

<span style="color:#333333"><code><span style="color:#cc7832">void</span> <span style="color:#ffc66d">register_epoll_handler</span>(<span style="color:#cc7832">int</span> fd, <span style="color:#cc7832">void</span> (*fn)()) {
    epoll_event ev;
    ev.events = EPOLLIN; <span style="color:#808080">//可读</span>
    ev.data.ptr = reinterpret_cast<<span style="color:#cc7832">void</span>*>(fn);
    <span style="color:#808080">//将fd的可读事件加入到epoll_fd的监听队列中</span>
    <span style="color:#cc7832">if</span> (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -<span style="color:#6897bb">1</span>) {
        ERROR(<span style="color:#6a8759">"epoll_ctl failed: %s\n"</span>, strerror(errno));
    }
}
</code></span>

三、rc文件语法

rc文件语法是以行尾单位,以空格间隔的语法,以#开始代表注释行。rc文件主要包含Action、Service、Command、Options,其中对于Action和Service的名称都是唯一的,对于重复的命名视为无效。

3.1 Action

Action: 通过trigger,即以 on开头的语句,决定何时执行相应的service。

  • on early-init; 在初始化早期阶段触发;
  • on init; 在初始化阶段触发;
  • on late-init; 在初始化晚期阶段触发;
  • on boot/charger: 当系统启动/充电时触发,还包含其他情况,此处不一一列举;
  • on property:<key>=<value>: 当属性值满足条件时触发;

3.2 Service

服务Service,以 service开头,由init进程启动,一般运行于另外一个init的子进程,所以启动service前需要判断对应的可执行文件是否存在。init生成的子进程,定义在rc文件,其中每一个service,在启动时会通过fork方式生成子进程。

例如: service servicemanager /system/bin/servicemanager代表的是服务名为servicemanager,服务的路径,也就是服务执行操作时运行/system/bin/servicemanager。

3.3 Command

下面列举常用的命令

  • class_start <service_class_name>: 启动属于同一个class的所有服务;
  • start <service_name>: 启动指定的服务,若已启动则跳过;
  • stop <service_name>: 停止正在运行的服务
  • setprop <name> <value>:设置属性值
  • mkdir <path>:创建指定目录
  • symlink <target> <sym_link>: 创建连接到<target>的<sym_link>符号链接;
  • write <path> <string>: 向文件path中写入字符串;
  • exec: fork并执行,会阻塞init进程直到程序完毕;
  • exprot <name> <name>:设定环境变量;
  • loglevel <level>:设置log级别

3.4 Options

Options是Services的可选项,与service配合使用

  • disabled: 不随class自动启动,只有根据service名才启动;
  • oneshot: service退出后不再重启;
  • user/group: 设置执行服务的用户/用户组,默认都是root;
  • class:设置所属的类名,当所属类启动/退出时,服务也启动/停止,默认为default;
  • onrestart:当服务重启时执行相应命令;
  • socket: 创建名为/dev/socket/<name>的socket
  • critical: 在规定时间内该service不断重启,则系统会重启并进入恢复模式

default: 意味着disabled=false,oneshot=false,critical=false。

四、启动服务

4.1 启动顺序

<span style="color:#333333"><code>on early-init
on init
on late-init //挂载文件系统,启动核心服务
    trigger post-fs
    trigger load_system_props_action 
    trigger post-fs-data //挂载data
    trigger load_persist_props_action
    trigger firmware_mounts_complete
    trigger boot
    
on post-fs
    <span style="color:#cc7832">start</span> logd
    <span style="color:#cc7832">mount</span> rootfs rootfs / ro remount
    <span style="color:#cc7832">mount</span> rootfs rootfs / <span style="color:#cc7832">shared</span> rec 
    <span style="color:#cc7832">mount</span> <span style="color:#cc7832">none</span> /mnt/runtime/<span style="color:#cc7832">default</span> /<span style="color:#cc7832">storage</span> <span style="color:#cc7832">slave</span> bind rec
    ...
     
<span style="color:#cc7832">on</span> post-fs-<span style="color:#cc7832">data</span>
    <span style="color:#cc7832">start</span> logd
    <span style="color:#cc7832">start</span> vold //启动vold
    ...
    
<span style="color:#cc7832">on</span> boot
    ...
    class_start core //启动core <span style="color:#cc7832">class</span>
</code></span>

由on early-init -> init -> late-init -> boot。

先启动core class, 至于main class的启动是由vold.decrypt的以下4个值的设置所决定的, 该过程位于system/vold/cryptfs.c文件。

<span style="color:#333333"><code><span style="color:#6a8759">on</span> nonencrypted
    class_start main
    class_start late_start
    
<span style="color:#6897bb">on</span> property:vold.decrypt=trigger_restart_min_framework
    class_start main

<span style="color:#6897bb">on</span> property:vold.decrypt=trigger_restart_framework
    class_start main
    class_start late_start

<span style="color:#6897bb">on</span> property:vold.decrypt=trigger_reset_main
    class_reset main
        
<span style="color:#6897bb">on</span> property:vold.decrypt=trigger_shutdown_framework
    class_reset late_start
    class_reset main
</code></span>

4.2 服务启动(Zygote)

在init.zygote.rc文件中,zygote服务定义如下:

<span style="color:#333333"><code>service zygote /<span style="color:#cc7832">system</span>/bin/app_process -Xzygote /<span style="color:#cc7832">system</span>/bin --zygote --start-<span style="color:#cc7832">system</span>-server
    class main
    <span style="color:#cc7832">socket</span> zygote stream <span style="color:#6897bb">660</span> root <span style="color:#cc7832">system</span>
    onrestart <span style="color:#cc7832">write</span> /sys/android_power/request_state wake
    onrestart <span style="color:#cc7832">write</span> /sys/power/<span style="color:#cc7832">state</span> on
    onrestart restart media
    onrestart restart netd
</code></span>

通过init_parser.cpp完成整个service解析工作,此处就不详细展开讲解析过程,该过程主要是创建一个名”zygote”的service结构体,一个socketinfo结构体(用于socket通信),以及一个包含4个onrestart的action结构体。

Zygote服务会随着main class的启动而启动,退出后会由init重启zygote,即使多次重启也不会进入recovery模式。zygote所对应的可执行文件是/system/bin/app_process,通过调用pid =fork()创建子进程,通过execve(svc->args[0], (char**)svc->args, (char**) ENV),进入App_main.cpp的main()函数。故zygote是通过fork和execv共同创建的。

流程如下:

zygote_init

而关于Zygote重启在前面的信号处理过程中讲过,是处理SIGCHLD信号,init进程重启zygote进程,更多关于Zygote内容见Zygote篇

4.3 服务重启

init_oneshot

当init子进程退出时,会产生SIGCHLD信号,并发送给init进程,通过socket套接字传递数据,调用到wait_for_one_process()方法,根据是否是oneshot,来决定是重启子进程,还是放弃启动。

所有的Service里面只有servicemanager ,zygote ,surfaceflinger这3个服务有onrestart关键字来触发其他service启动过程。

<span style="color:#333333"><code>//zygote可触发media、netd重启
service zygote /<span style="color:#cc7832">system</span>/bin/app_process -Xzygote /<span style="color:#cc7832">system</span>/bin --zygote --start-<span style="color:#cc7832">system</span>-server
    class main
    <span style="color:#cc7832">socket</span> zygote stream <span style="color:#6897bb">660</span> root <span style="color:#cc7832">system</span>
    onrestart <span style="color:#cc7832">write</span> /sys/android_power/request_state wake
    onrestart <span style="color:#cc7832">write</span> /sys/power/<span style="color:#cc7832">state</span> on
    onrestart restart media
    onrestart restart netd

//servicemanager可触发healthd、zygote、media、surfaceflinger、drm重启
service servicemanager /<span style="color:#cc7832">system</span>/bin/servicemanager
    class core
    user <span style="color:#cc7832">system</span>
    group <span style="color:#cc7832">system</span>
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart drm

//surfaceflinger可触发zygote重启
service surfaceflinger /<span style="color:#cc7832">system</span>/bin/surfaceflinger
    class core
    user <span style="color:#cc7832">system</span>
    group graphics drmrpc
    onrestart restart zygote
</code></span>

由上可知:

  • zygote:触发media、netd以及子进程(包括system_server进程)重启;
  • system_server: 触发zygote重启;
  • surfaceflinger:触发zygote重启;
  • servicemanager: 触发zygote、healthd、media、surfaceflinger、drm重启

所以,surfaceflinger,servicemanager,zygote自身以及system_server进程被杀都会触发Zygote重启。

五、属性服务

当某个进程A,通过property_set()修改属性值后,init进程会检查访问权限,当权限满足要求后,则更改相应的属性值,属性值一旦改变则会触发相应的触发器(即rc文件中的on开头的语句),在Android Shared Memmory(共享内存区域)中有一个_system_property_area_区域,里面记录着所有的属性值。对于进程A通过property_get()方法,获取的也是该共享内存区域的属性值。

5.1 初始化

[-> property_service.cpp]

<span style="color:#333333"><code><span style="color:#cc7832">void</span> <span style="color:#ffc66d">property_init</span>() {
    <span style="color:#808080">//用于保证只初始化_system_property_area_区域一次</span>
    <span style="color:#cc7832">if</span> (property_area_initialized) {
        <span style="color:#cc7832">return</span>;
    }
    property_area_initialized = <span style="color:#cc7832">true</span>;
    <span style="color:#cc7832">if</span> (__system_property_area_init()) {
        <span style="color:#cc7832">return</span>;
    }
    pa_workspace.size = <span style="color:#6897bb">0</span>;
    pa_workspace.fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
    <span style="color:#cc7832">if</span> (pa_workspace.fd == -<span style="color:#6897bb">1</span>) {
        ERROR(<span style="color:#6a8759">"Failed to open %s: %s\n"</span>, PROP_FILENAME, strerror(errno));
        <span style="color:#cc7832">return</span>;
    }
}
</code></span>

在properyty_init函数中,先调用init_property_area函数,创建一块用于存储属性的共享内存,而共享内存是可以跨进程的。

关于加载的prop文件

通过load_all_load_all_propsprops()方法,加载以下:

  1. /system/build.prop;
  2. /vendor/build.prop;
  3. /factory/factory.prop;
  4. /data/local.prop;
  5. /data/property路径下的persist属性

5.2 属性类别

  1. 属性名以ctl.开头,则表示是控制消息,控制消息用来执行一些命令。例如:
    • setprop ctl.start bootanim 查看开机动画;
    • setprop ctl.stop bootanim 关闭开机动画;
    • setprop ctl.start pre-recovery 进入recovery模式。
  2. 属性名以ro.开头,则表示是只读的,不能设置,所以直接返回。
  3. 属性名以persist.开头,则需要把这些值写到对应文件中去。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值