澳门新葡萄京娱乐场 1

澳门新葡萄京娱乐场Android系统启动:init进程与init语言

面向新的一年,我们可能启动了许多有意义的计划,在这个有着特殊意义的日子里,让我们来一起学习一下Android系统是如何启动的。

========================================================
       
 ========================================================

init进程与init.rc

init进程是一切的开始,在Android系统中,所有进程的进程号都是不确定的,唯独init进程的进程号一定是1。因为这个进程是系统起来的第一个进程。并且,init进程掌控了整个系统的启动流程。

我们知道,Android可能运行在各种不同的平台,不同的设备上。因此,启动的逻辑是不尽相同的。
为了适应各种平台和设备的需求,init进程的初始化工作通过init.rc配置文件来管理。init.rc以Android
Init Language作为语法,下文我们简称Android Init
Language为init语言。配置文件的主入口文件是/init.rc,这个文件会通过import关键字引入其他的配置文件。在这里,我们统称这些文件为init.rc

澳门新葡萄京娱乐场,/init.rc可能import以下路径中的.rc文件:

  • /init.${ro.hardware}.rc 硬件厂商提供的主配置文件
  • /system/etc/init/ 核心系统模块的配置文件
  • /vendor/etc/init/ SoC厂商提供的配置文件
  • /odm/etc/init/ 设备制造商提供的配置文件

=            
 【原创文章】:参考部分博客内容,学习之余进行了大量的筛减细化分析      
                 =          =                        
 【特殊申明】:避讳抄袭侵权之嫌疑,特此说明,欢迎转载!                
          =   

========================================================
       
 ========================================================

init语法说明

init语言,以换行为语句分隔,以空格来为符号分隔,以“#“为注释开始。配置文件中支持五种类型的表达式:

  • Action: 包含了一系列的Command
  • Command: init语言中的命令
  • Service: init进程启动的服务
  • Option: 对于服务的配置选项
  • Import: 引入其他配置文件

这其中,Action和Service需要保证名称唯一。

【前言】

Action与Command

Action表达式的语法如下:

on <trigger> [&& <trigger>]*
   <command>
   <command>
   <command>

这里的Trigger是Action执行的触发器,当触发器条件满足时,command会被执行。触发器有两类:

  1. 事件触发器:
    事件可以由”trigger”命令发出,也可以是init进程通过QueueEventTrigger()函数发出
  2. 属性触发器: 当指定的属性满足时触发

一个Action可以有多个属性触发器,但是只能包含一个事件触发器。下面是一些例子:

  • on boot && property:a=b 在”boot”事件发生时,并且属性a的值是b时触发
  • on property:a=b && property:c=d 在属性a的值是b并且属性c的值是d时触发

Action中的Command是init语言定义的命令,所有支持的命令如下表所示:

Command 参数格式 说明
bootchart_init 启动bootchart
chmod octal-mode path 改变文件的访问权限
chown owner group path 改变文件的拥有者和组
class_start serviceclass 启动指定类别的服务
class_stop serviceclass 停止并disable指定类别的服务
class_reset serviceclass 停止指定类别的服务,但是不disable它们
copy src dst 拷贝文件
domainname name 设置域名
enable servicename enable一个被disable的服务
exec [seclabel[user[group]]] – command [argument]* fork一个子进程来执行指定的命令
export name value 导出环境变量
hostname name 设置host名称
ifup iterface 使网卡在线
insmod path 安装指定路径的模块
load_all_props 从/system, /vendor等路径载入属性
load_persist_props 载入持久化的属性
loglevel level 设置内核的日志级别
mkdir path [mode] [owner] [group] 创建目录
mount_all fstab [ path ]* [–option] 挂载文件系统并且导入指定的.rc文件
mount type device dir [ flag ]* [options] 挂载一个文件系统
powerctl 内部实现使用
restart service 重启服务
restorecon path [ path ]* 设定文件的安全上下文
restorecon_recursive path [ path ]* restorecon的递归版本
rm path 对于指定路径调用unlink(2)
rmdir path 删除文件夹
setprop name value 设置属性值
setrlimit resource cur max 指定资源的rlimit
start service 启动服务
stop service 停止服务
swapon_all fstab 在指定文件上调用fs_mgr_swapon_all
symlink target path 创建符号链接
sysclktz mins_west_of_gmt 指定系统时钟基准
trigger event 触发一个事件
umount path unmount指定的文件系统
verity_load_state 内部实现使用
verity_update_state mount_point 内部实现使用
wait path [ timeout ] 等待某个文件存在直到超时,若存在则直接返回
write path content 写入内容到指定文件

  Android启动篇 —
init原理(一)
中讲解分init进程分析init创建系统目录并挂在相应系统文件、初始化属性域、设置系统属性、启动配置属性服务端等一系列复杂工作,很多工作和知识点跟Linux关系很大,所以没有作过多介绍,而本此对于init.rc的解析则是重中之重,所以单独拿出来进行详细分析。

Service与Option

Service是init进程启动的可执行程序。服务可以选择在自己退出之后,由init将其重启。

Service表达式的语法如下:

service <name> <pathname> [ <argument> ]*
   <option>
   <option>

Option是对服务的修饰,它们影响着init进程如何以及何时启动服务。所有支持的option如下表所示:

option 参数格式 说明
critical 标识为系统关键服务,该服务若退出多次将导致系统重启到recovery模式
disabled 不会随着类别自动启动,必须明确start
setenv name value 为启动的进程设置环境变量
socket name type perm [user [group [seclabel]]] 创建Unix Domain Socket
user username 在执行服务之前切换用户
group groupname [ groupname]* 在执行执行之前切换组
seclabel seclabel 在执行服务之前切换seclabel
oneshot 一次性服务,死亡之后不用重启
class name 指定服务的类别
onrestart 当服务重启时执行指定命令
writepid file… 写入子进程的pid到指定文件
int main(int argc, char** argv) {
    /* 01. 创建文件系统目录并挂载相关的文件系统 */
    /* 02. 屏蔽标准的输入输出/初始化内核log系统 */
    /* 03. 初始化属性域 */
    /* 04. 完成SELinux相关工作 */•
    /* 05. 重新设置属性 */
    /* 06. 创建epoll句柄 */
    /* 07. 装载子进程信号处理器 */
    /* 08. 设置默认系统属性 */
    /* 09. 启动配置属性的服务端 */
    /* 10. 匹配命令和函数之间的对应关系 */
-------------------------------------------------------------------------------------------   // Android启动篇 — init原理(一)中讲解
    /* 11. 解析init.rc */
    Parser& parser = Parser::GetInstance();       // 构造解析文件用的parser对象
    // 增加ServiceParser为一个section,对应name为service
    parser.AddSectionParser("service",std::make_unique<ServiceParser>());
    // 增加ActionParser为一个section,对应name为action
    parser.AddSectionParser("on", std::make_unique<ActionParser>());
    // 增加ImportParser为一个section,对应name为service
    parser.AddSectionParser("import", std::make_unique<ImportParser>());
    parser.ParseConfig("/init.rc");      // 开始实际的解析过程

Import

import是一个关键字,并不是一个命令。可以在.rc文件中通过这个关键字来加载其他的.rc文件。它的语法很简单:

import path

path可以是另外一个.rc文件,也可以是一个文件夹。如果是文件夹,那么这个文件夹下面的所有文件都会被导入,但是它不会循环加载子目录中的文件。

【正文】

init.rc代码实例

AOSP中包含了Android系统需要的最基本的.rc文件,它们位于这个路径:/system/core/rootdir/

我们选取其中了一两个代码片段来了解一下:

# /system/core/rootdir/init.rc

import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc

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

    # Disable sysrq from keyboard
    write /proc/sys/kernel/sysrq 0

    # Set the security context of /adb_keys if present.
    restorecon /adb_keys

    # Shouldn't be necessary, but sdcard won't start without it. http://b/22568628.
    mkdir /mnt 0775 root system

    # Set the security context of /postinstall if present.
    restorecon /postinstall

    start ueventd

on init
    sysclktz 0

    # Mix device-specific information into the entropy pool
    copy /proc/cmdline /dev/urandom
    copy /default.prop /dev/urandom

    # Backward compatibility.
    symlink /system/etc /etc
    symlink /sys/kernel/debug /d

    # Link /vendor to /system/vendor for devices without a vendor partition.
    symlink /system/vendor /vendor
...

这是根目录/init.rc文件中一开始的代码片段。有了前面的讲解之后,这段代码应当还是比较好理解的。在这段代码中:

  • 通过import关键字引入了其他几个.rc文件
  • 设定了一个事件为early-init的Action
  • 设定了一个事件init的Action

“eraly-init”和”init”这两个事件都是由init进程发出的。

下面,我们再来看另外一个代码片段:

这段代码定义了一个名称为zygote的Service,这个服务是通过可执行命令/system/bin/app_process启动的,启动的时候传递了参数:-Xzygote /system/bin --zygote --start-system-server

Zygote是Android系统中一个非常重要的服务,zygote的中文意思是“受精卵“。这是一个很有寓意的名称:所有的应用进程都是由zygote fork出来的子进程,因此zygote进程是所有应用进程的父进程。

关于Zygote,我们已经在另外一篇文章中讲解过了,参见这里Zygote进程,有兴趣的读者可以再次回顾一下。

  init.rc是一个配置文件,内部由Android初始化语言编写(Android Init
Language)编写的脚本,主要包含五种类型语句:Action、Command、Service、Option和Import,在分析代码的过程中我们会详细介绍。

结束语

Android系统是一个跨越了多种设备的操作系统,从最初的系统的研发到最终终端用户的使用,这其中经历了许多道的开发流程。而每一道流程的开发者都有可能对系统做不同程度的定制。

Android系统的设计者从一开始就考虑到了这种复杂性,这一点从很多系统模块的设计中很能看得出来。系统启动的机制便是一个很好的范例:这里在保证系统核心服务启动顺序的前提下,还为不同阶段的开发者预留好了便于调整和扩展的机制,并且不用修改任何的源代码。

这种对于“开闭原则”的遵守,是非常值得我们学习的。

  init.rc的配置代码在:system/core/rootdir/init.rc 中

  init.rc文件是在init进程启动后执行的启动脚本,文件中记录着init进程需执行的操作。

  init.rc文件大致分为两大部分,一部分是以“on”关键字开头的动作列表(action
list):

on early-init      // Action类型语句
    # Set init and its forked children's oom_adj.     // #:注释符号
    write /proc/1/oom_score_adj -1000
    ... ...
    start ueventd

  Action类型语句格式:

on <trigger> [&& <trigger>]*     // 设置触发器  
   <command>  
   <command>      // 动作触发之后要执行的命令

  另一部分是以“service”关键字开头的服务列表(service
list):  如 Zygote

service ueventd /sbin/ueventd
    class core
    critical
    seclabel u:r:ueventd:s0

  Service类型语句格式:

service <name> <pathname> [ <argument> ]*   // <service的名字><执行程序路径><传递参数>  
   <option>       // option是service的修饰词,影响什么时候、如何启动services  
   <option>  
   ...

  借助系统环境变量或Linux命令,动作列表用于创建所需目录,以及为某些特定文件指定权限,而服务列表用来记录init进程需要启动的一些子进程。如上面代码所示,service关键字后的第一个字符串表示服务(子进程)的名称,第二个字符串表示服务的执行路径。

  值得一提的是在Android
7.0中对init.rc文件进行了拆分,每个服务一个rc文件。我们要分析的zygote服务的启动脚本则在init.zygoteXX.rc中定义。

  在init.rc的import段我们看到如下代码:

import /init.${ro.zygote}.rc     // 可以看出init.rc不再直接引入一个固定的文件,而是根据属性ro.zygote的内容来引入不同的文件

  说明:

  从android5.0开始,android开始支持64位的编译,zygote本身也就有了32位和64位的区别,所以在这里用ro.zygote属性来控制启动不同版本的zygote进程。

  init.rc位于/system/core/rootdir下。在这个路径下还包括四个关于zygote的rc文件。分别是Init.zygote32.rc,Init.zygote32_64.rc,Init.zygote64.rc,Init.zygote64_32.rc,由硬件决定调用哪个文件。

  这里拿32位处理器为例,init.zygote32.rc的代码如下所示:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main         # class是一个option,指定zygote服务的类型为main
    socket zygote stream 660 root system          # socket关键字表示一个option,创建一个名为dev/socket/zygote,类型为stream,权限为660的socket
    onrestart write /sys/android_power/request_state wake          # onrestart是一个option,说明在zygote重启时需要执行的command
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    writepid /dev/cpuset/foreground/tasks

  “service zygote /system/bin/app_process -Xzygote /system/bin
–zygote –start-system-server”

  在Init.zygote32.rc中,定义了一个zygote服务:zygote,由关键字service告诉init进程创建一个名为zygote的进程,这个进程要执行的程序是:/system/bin/app_process,给这个进程四个参数:

    · -Xzygote:该参数将作为虚拟机启动时所需的参数

    · /system/bin:代表虚拟机程序所在目录

    ·
–zygote:指明以ZygoteInit.java类中的main函数作为虚拟机执行入口

    · –start-system-server:告诉Zygote进程启动SystemServer进程

   接下来,我们回到源码当中,继续分析main函数:

    /* 11. 解析init.rc */
    Parser& parser = Parser::GetInstance();       // 构造解析文件用的parser对象
    // 增加ServiceParser为一个section,对应name为service
    parser.AddSectionParser("service",std::make_unique<ServiceParser>());
    // 增加ActionParser为一个section,对应name为action
    parser.AddSectionParser("on", std::make_unique<ActionParser>());
    // 增加ImportParser为一个section,对应name为service
    parser.AddSectionParser("import", std::make_unique<ImportParser>());
    parser.ParseConfig("/init.rc");      // 开始实际的解析过程

  说明:

  上面在解析init.rc文件时使用了Parser类(在init目录下的init_parser.h中定义),
初始化ServiceParser用来解析
“service”块,ActionParser用来解析”on”块,ImportParser用来解析“import”块,“import”是用来引入一个init配置文件,来扩展当前配置的。

  /system/core/init/readme.txt
中对init文件中的所有关键字做了介绍,主要包含了Actions, Commands,
Services, Options, and Imports等,可自行学习解读。

  分析init.rc的解析过程:函数定义于system/core/init/
init_parser.cpp中

bool Parser::ParseConfig(const std::string& path) {
    if (is_dir(path.c_str())) {           // 判断传入参数是否为目录地址
        return ParseConfigDir(path);      // 递归目录,最终还是靠ParseConfigFile来解析实际的文件
    }
    return ParseConfigFile(path);         // 传入传输为文件地址
}

  继续分析ParseConfigFile():

bool Parser::ParseConfigFile(const std::string& path) {
    ... ...
    Timer t;
    std::string data;
    if (!read_file(path.c_str(), &data)) {       // 读取路径指定文件中的内容,保存为字符串形式
        return false;
}
... ...
    ParseData(path, data);        // 解析获取的字符串
    ... ...
}

  跟踪ParseData():

void Parser::ParseData(const std::string& filename, const std::string& data) {
    ... ...
    parse_state state;
    ... ...
    std::vector<std::string> args;

    for (;;) {
        switch (next_token(&state)) {    // next_token以行为单位分割参数传递过来的字符串,最先走到T_TEXT分支
        case T_EOF:
            if (section_parser) {
                section_parser->EndSection();    // 解析结束
            }
            return;
        case T_NEWLINE:
            state.line++;
            if (args.empty()) {
                break;
            }
            // 在前文创建parser时,我们为service,on,import定义了对应的parser 
            // 这里就是根据第一个参数,判断是否有对应的parser
            if (section_parsers_.count(args[0])) {
                if (section_parser) {
                    // 结束上一个parser的工作,将构造出的对象加入到对应的service_list与action_list中
                    section_parser->EndSection();
                }
                // 获取参数对应的parser
                section_parser = section_parsers_[args[0]].get();
                std::string ret_err;
                // 调用实际parser的ParseSection函数
                if (!section_parser->ParseSection(args, &ret_err)) {
                    parse_error(&state, "%sn", ret_err.c_str());
                    section_parser = nullptr;
                }
            } else if (section_parser) {
                std::string ret_err;
                // 如果第一个参数不是service,on,import
                // 则调用前一个parser的ParseLineSection函数
                // 这里相当于解析一个参数块的子项
                if (!section_parser->ParseLineSection(args, state.filename, 
                                                             state.line, &ret_err)) {
                    parse_error(&state, "%sn", ret_err.c_str());
                }
            }
            args.clear();       // 清空本次解析的数据
            break;
        case T_TEXT:
            args.emplace_back(state.text);     //将本次解析的内容写入到args中
            break;
        }
    }
}

  至此,init.rc解析完,接下来init会执行几个重要的阶段:

int main(int argc, char** argv) {

    /* 01. 创建文件系统目录并挂载相关的文件系统 */
    /* 02. 屏蔽标准的输入输出/初始化内核log系统 */
    /* 03. 初始化属性域 */
    /* 04. 完成SELinux相关工作 */•
    /* 05. 重新设置属性 */
    /* 06. 创建epoll句柄 */
    /* 07. 装载子进程信号处理器 */
    /* 08. 设置默认系统属性 */
    /* 09. 启动配置属性的服务端 */
    /* 10. 匹配命令和函数之间的对应关系 */
    /* 11. 解析init.rc*/
----------------------------------------------------------------------------
  /* 12.  向执行队列中添加其他action */

    // 获取ActionManager对象,需要通过am对命令执行顺序进行控制
    ActionManager& am = ActionManager::GetInstance();
    // init执行命令触发器主要分为early-init,init,late-init,boot等
    am.QueueEventTrigger("early-init");    // 添加触发器early-init,执行on early-init内容

    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
    // ... so that we can start queuing up actions that require stuff from /dev.
    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
    am.QueueBuiltinAction(keychord_init_action, "keychord_init");
    am.QueueBuiltinAction(console_init_action, "console_init");

    // Trigger all the boot actions to get us started.
    am.QueueEventTrigger("init");        // 添加触发器init,执行on init内容,主要包括创建/挂在一些目录,以及symlink等

    // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
    // wasn't ready immediately after wait_for_coldboot_done
    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");

    // Don't mount filesystems or start core system services in charger mode.
    if (bootmode == "charger") {
    am.QueueEventTrigger("charger");     // on charger阶段
    } else if (strncmp(bootmode.c_str(), "ffbm", 4) == 0) {
    NOTICE("Booting into ffbm moden");
    am.QueueEventTrigger("ffbm");
    } else {
    am.QueueEventTrigger("late-init");          // 非充电模式添加触发器last-init
    }

    // Run all property triggers based on current state of the properties.
    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");

  在last-init最后阶段有如下代码:

# Mount filesystems and start core system services.
on late-init
    trigger early-fs

    # Mount fstab in init.{$device}.rc by mount_all command. Optional parameter
    # '--early' can be specified to skip entries with 'latemount'.
    # /system and /vendor must be mounted by the end of the fs stage,
    # while /data is optional.
    trigger fs
    trigger post-fs

    # Load properties from /system/ + /factory after fs mount. Place
    # this in another action so that the load will be scheduled after the prior
    # issued fs triggers have completed.
    trigger load_system_props_action

    # Mount fstab in init.{$device}.rc by mount_all with '--late' parameter
    # to only mount entries with 'latemount'. This is needed if '--early' is
    # specified in the previous mount_all command on the fs stage.
    # With /system mounted and properties form /system + /factory available,
    # some services can be started.
    trigger late-fs

    # Now we can mount /data. File encryption requires keymaster to decrypt
    # /data, which in turn can only be loaded when system properties are present.
    trigger post-fs-data

    # Load persist properties and override properties (if enabled) from /data.
    trigger load_persist_props_action

    # Remove a file to wake up anything waiting for firmware.
    trigger firmware_mounts_complete

    trigger early-boot
   trigger boot

  可见出发了on early-boot和on boot两个Action。

  我们看一下on boot:

on boot
    # basic network init
    ifup lo
    hostname localhost
    domainname localdomain
    ... ...
    class_start core

  在on boot 的最后class_start core 会启动class为core的服务,这些服务包括ueventd、logd、healthd、adbd(disabled)、lmkd(LowMemoryKiller)、servicemanager、vold、debuggerd、surfaceflinger、bootanim(disabled)等。

  回到主题,分析trigger触发器的代码,QueueEventTrigger():位于system/core/init/action.cpp

void ActionManager::QueueEventTrigger(const std::string& trigger) {
    trigger_queue_.push(std::make_unique<EventTrigger>(trigger));
}

  此处QueueEventTrigger函数就是利用参数构造EventTrigger,然后加入到trigger_queue_中。后续init进程处理trigger事件时,将会触发相应的操作。

  再看一下QueueBuiltinAction()函数:同样位于system/core/init/action.cpp

void ActionManager::QueueBuiltinAction(BuiltinFunction func,
                                   const std::string& name) {
    // 创建action
    auto action = std::make_unique<Action>(true);
    std::vector<std::string> name_vector{name};

    // 保证唯一性
    if (!action->InitSingleTrigger(name)) {
        return;
    }

    // 创建action的cmd,指定执行函数和参数
    action->AddCommand(func, name_vector);

    trigger_queue_.push(std::make_unique<BuiltinTrigger>(action.get()));
    actions_.emplace_back(std::move(action));
}

  QueueBuiltinAction函数中构造新的action加入到actions_中,第一个参数作为新建action携带cmd的执行函数;第二个参数既作为action的trigger
name,也作为action携带cmd的参数。

  接下来继续分析main函数:

int main(int argc, char** argv) {

    /* 01. 创建文件系统目录并挂载相关的文件系统 */
    /* 02. 屏蔽标准的输入输出/初始化内核log系统 */
    /* 03. 初始化属性域 */
    /* 04. 完成SELinux相关工作 */•
    /* 05. 重新设置属性 */
    /* 06. 创建epoll句柄 */
    /* 07. 装载子进程信号处理器 */
    /* 08. 设置默认系统属性 */
    /* 09. 启动配置属性的服务端 */
    /* 10. 匹配命令和函数之间的对应关系 */
    /* 11. 解析init.rc*/
    /* 12. 向执行队列中添加其他action */
-------------------------------------------------------------------
    /* 13. 处理添加到运行队列的事件 */
    while (true) {

    // 判断是否有事件需要处理
        if (!waiting_for_exec) {
            // 依次执行每个action中携带command对应的执行函数
     am.ExecuteOneCommand();
        // 重启一些挂掉的进程
            restart_processes();
        }

        // 以下决定timeout的时间,将影响while循环的间隔
        int timeout = -1;
        // 有进程需要重启时,等待该进程重启
        if (process_needs_restart) {
            timeout = (process_needs_restart - gettime()) * 1000;
            if (timeout < 0)
                timeout = 0;
        }

        // 有action待处理,不等待
        if (am.HasMoreCommands()) {
            timeout = 0;
        }

        // bootchart_sample应该是进行性能数据采样
        bootchart_sample(&timeout);

        epoll_event ev;
        // 没有事件到来的话,最多阻塞timeout时间
        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
        if (nr == -1) {
            ERROR("epoll_wait failed: %sn", strerror(errno));
        } else if (nr == 1) {
            //有事件到来,执行对应处理函数
            //根据上文知道,epoll句柄(即epoll_fd)主要监听子进程结束,及其它进程设置系统属性的请求
            ((void (*)()) ev.data.ptr)();
        }
    }
    return 0;
} // end main

  看一下ExecuteOneComand()函数:同样位于system/core/init/action.cpp

void ActionManager::ExecuteOneCommand() {
    // Loop through the trigger queue until we have an action to execute
    // 当前的可执行action队列为空, trigger_queue_队列不为空
    while (current_executing_actions_.empty() && !trigger_queue_.empty()) {
    // 循环遍历action_队列,包含了所有需要执行的命令,解析init.rc获得
        for (const auto& action : actions_) {
            // 获取队头的trigger, 检查actions_列表中的action的trigger,对比是否相同
            if (trigger_queue_.front()->CheckTriggers(*action)) {
                // 将所有具有同一trigger的action加入当前可执行action队列
                current_executing_actions_.emplace(action.get());
            }
        }
        // 将队头trigger出栈
        trigger_queue_.pop();
    }

    if (current_executing_actions_.empty()) {   // 当前可执行的actions队列为空就返回
        return;
    }

    auto action = current_executing_actions_.front(); // 获取当前可执行actions队列的首个action

    if (current_command_ == 0) {
        std::string trigger_name = action->BuildTriggersString();
        INFO("processing action (%s)n", trigger_name.c_str());
    }

    action->ExecuteOneCommand(current_command_);     // 执行当前的命令

    // If this was the last command in the current action, then remove
    // the action from the executing list.
    // If this action was oneshot, then also remove it from actions_.
    ++current_command_;      // 不断叠加,将action_中的所有命令取出
    if (current_command_ == action->NumCommands()) {
        current_executing_actions_.pop();
        current_command_ = 0;
        if (action->oneshot()) {
            auto eraser = [&action] (std::unique_ptr<Action>& a) {
                return a.get() == action;
            };
            actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser));
        }
    }
}

  我们来观察一下init.rc的开头部分:

import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc      // 后面我们即将重点分析zygote进程

  通过ro.zygote的属性import对应的zygote的rc文件。

  澳门新葡萄京娱乐场 1

  我们查看init.zygote64_32.rc:

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    writepid /dev/cpuset/foreground/tasks

service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
    class main
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks

  可以看到zygote的class是main,
它是在on nonencrypted时被启动的,如下:

on boot
    # basic network init
    ifup lo
    hostname localhost
    domainname localdomain
    ... ...
    class_start core

on nonencrypted
    # A/B update verifier that marks a successful boot.
    exec - root cache -- /system/bin/update_verifier nonencrypted
    class_start main
    class_start late_start

  至此,Init.cpp的main函数分析完毕!init进程已经启动完成,一些重要的服务如core服务和main服务也都启动起来,并启动了zygote(/system/bin/app_process64)进程,zygote初始化时会创建虚拟机,启动systemserver等。

发表评论

电子邮件地址不会被公开。 必填项已用*标注