概述

转载请注明出处:https://blog.csdn.net/wangzaieee/article/details/84774298

众所周知,init进程是Android系统的第一个用户进程,Android启动流程大致如下:

init进程主要提供以下几个功能:

  • 挂载文件系统、生成部分设备节点、创建目录
  • 属性服务
  • 处理子进程终止
  • 分析和运行init.rc(等等rc文件)

init进程代码路径为 system/core/init/init.cpp。今天我们主要是分析Android P的init的代码,其实各个版本的代码稍有不同,但是万变不离其宗。

init进程的启动调试可以查看本文。

init进程源码分析

init.cpp文件main函数部分源码:

......mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");mkdir("/dev/pts", 0755);mkdir("/dev/socket", 0755);mount("devpts", "/dev/pts", "devpts", 0, NULL);#define MAKE_STR(x) __STRING(x)mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));// Don't expose the raw commandline to unprivileged processes.chmod("/proc/cmdline", 0440);mount("sysfs", "/sys", "sysfs", 0, NULL);mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));......

上述代码会生成/dev、/proc、/sys等目录并挂载相应的文件系统,还会生成/dev/kmsg等静态设备节点。编译Android系统源码时,在生成的根文件系统中,并不存在/dev、/proc、/sys这类目录,他们是系统运行时的目录,由init进程在运行时生成,当系统终止时,它们就会消失。

system/core/init/init.cpp

......//初始化内核日志打印环境(上面已经创建了/dev/kmsg设备节点)InitKernelLogging(argv); ......

system/core/init/log.cpp

void InitKernelLogging(char* argv[]) {    // Make stdin/stdout/stderr all point to /dev/null.    int fd = open("/sys/fs/selinux/null", O_RDWR);    ......    dup2(fd, 0);//0表示stdin(标准输入流)    dup2(fd, 1);//1表示stdout(标准输出流)    dup2(fd, 2);//2表示stderr(标准错误流)    if (fd > 2) close(fd);    android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter);}

上述代码将stdin、stdout、stderr全部重定向到/sys/fs/selinux/null(黑洞)中了,下面我们继续分析InitLogging函数
logging.cpp部分源码

void InitLogging(char* argv[], LogFunction&& logger, AbortFunction&& aborter) {  SetLogger(std::forward<LogFunction>(logger));  SetAborter(std::forward<AbortFunction>(aborter));  ......}void SetLogger(LogFunction&& logger) {  std::lock_guard<std::mutex> lock(LoggingLock());  Logger() = std::move(logger);}void SetAborter(AbortFunction&& aborter) {  std::lock_guard<std::mutex> lock(LoggingLock());  Aborter() = std::move(aborter);}

由上述代码可知,Logger()代表的是InitLogging传入的KernelLogger函数,Aborter()代表的的是InitAborter函数。KernelLogger是通过系统调用open和write /dev/kmsg 设备节点来输出内核日志信息,然后系统发生致命错误时,会调用InitAborter来重启系统。有兴趣的同学可以深入研究下。

属性服务

现在我们来分析init进程很重要的一个功能属性服务
system/core/init/init.cpp

......property_init();//初始化属性服务......

在Android系统中,所有的进程共享系统设置值,为此提供一个名称为属性的保存空间。init进程调用property_init函数,在共享内存区域中创建并初始化属性域。而后通过执行进程所提供的API访问属性域中的设置值。但更改属性域时,要预先向init进程提交值变更申请,然后init进程处理该申请,并修改属性值(用propert_set()和property_get()来处理)

system/core/init/init.cpp

......epoll_fd = epoll_create1(EPOLL_CLOEXEC);//创建轮询的描述符......start_property_service();//开启属性服务......

epoll_create1用来创建轮询监听子进程终止和属性变更请求的文件描述符,后面会看到监听子进程终止套接字fd和属性变更请求套接字fd通过epoll_ctl注册到epoll_fd中,然后通过epoll_wait监听轮询这两个fd。

start_property_service()开启属性服务。
system/core/init/property_service.cpp

void start_property_service() {    ......    //创建用于接收属性变更请求的socket (/dev/socket/property_service)    property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,false, 0666, 0, 0, nullptr);    ......        listen(property_set_fd, 8);//同时可以监听八个请求    //注册property_set_fd到epoll_fd    register_epoll_handler(property_set_fd, handle_property_set_fd);}

如前所述,属性值的更改仅能在init进程中进行,即一个进程若想修改属性值,必须向init进程提交申请,为此init进程生成“/dev/socket/property_service”套接字,以接收其它进程提交的申请。

注册属性变更socket文件描述符(fd)到epoll_fd
system/core/init/init.cpp

void register_epoll_handler(int fd, void (*fn)()) {    epoll_event ev;    ev.events = EPOLLIN; //触发事件是当文件描述符可读时    ev.data.ptr = reinterpret_cast<void*>(fn); //触发后的回调函数    //注册属性socket fd到epoll_fd    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {        PLOG(ERROR) << "epoll_ctl failed";    }}

register_epoll_handler函数主要的作用是注册属性socket文件描述符到轮询描述符epoll_fd,当property_set_fd可读时,会调用上面register_epoll_handler函数的第二个参数(处理函数handle_property_set_fd())

system/core/init/property_service.cpp

static void handle_property_set_fd() {    ......    uint32_t cmd = 0;    if (!socket.RecvUint32(&cmd, &timeout_ms)) {//读取命令        return;    }    switch (cmd) {    case PROP_MSG_SETPROP: {        char prop_name[PROP_NAME_MAX];        char prop_value[PROP_VALUE_MAX];        //读取属性名和属性值        if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||         !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms))        {          return;        }        ......        //设置属性值        uint32_t result = HandlePropertySet(prop_name, prop_value,socket.source_context(), cr, &error);        break;      }    case PROP_MSG_SETPROP2:     ......

当监听到属性变更时,从socket读取命令和属性名与属性值,设置新的属性或者更改属性值。HandlePropertySet最后会调用ActionManager::QueuePropetyChange将属性变更(属性触发器)添加到已触发队列中,最后会执行相应command命令(init.rc中定义的command),后面init.rc的解析与执行会讲解相关内容。

处理子进程终止

现在我们来讲解init进程的另外一个重要功能,处理子进程终止。
system/core/init/init.cpp

......sigchld_handler_init();//注册子进程死亡监听socket......

system/core/init/sigchld_hanlder.cpp

void sigchld_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) {        PLOG(FATAL) << "socketpair failed in sigchld_handler_init";    }    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));    act.sa_handler = SIGCHLD_handler;//收到SIGCHLD信号后的处理函数    act.sa_flags = SA_NOCLDSTOP;    sigaction(SIGCHLD, &act, 0);//注册SIGCHLD信号    ReapAnyOutstandingChildren();    //注册signal_read_fd到epoll_fd    register_epoll_handler(signal_read_fd, handle_signal);}

当init子进程意外终止时,会向init进程发送SIGCHLD信号,这个时候会调用SIGCHLD_handler这个处理函数。
system/core/init/sigchld_hanlder.cpp

static void SIGCHLD_handler(int) {    if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {        PLOG(ERROR) << "write(signal_write_fd) failed";    }}

SIGCHLD_handler的作用是当init进程接收到SIGCHLD信号时,往signal_write_fd中写入数据,这个时候套接字对中的另外一个signal_read_fd就可读了。

通过register_epoll_handler(这个函数上面已经分析过了)将signal_read_fd注册到epoll_fd中,当signal_read_fd可读时,会调用register_epoll_handler的第二个参数(handle_signal处理函数)。

handle_signal()函数分析
system/core/init/sigchld_hanlder.cpp

static void handle_signal() {    // 清空signal_read_fd中的数据    char buf[32];    read(signal_read_fd, buf, sizeof(buf));    ReapAnyOutstandingChildren();//见下}void ReapAnyOutstandingChildren() {    while (ReapOneProcess()) {//见下    }}static bool ReapOneProcess() {    ......    //等待子进程终止    auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); });    ......    //获取到终止子进程对应的Service对象    service = ServiceList::GetInstance().FindService(pid, &Service::pid);    ......    //处理退出后的后续事项    service->Reap(siginfo);    ......}

收到子进程的SIGCHLD信号后,找出该进程对应的Service对象,调用Reap函数。

service->Reap处理退出后进程的事项,如下:
system/core/init/service.cpp

void Service::Reap(const siginfo_t& siginfo) {    //如果标志位是onshot或者是重启的子进程就杀掉整个进程组    if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) {        KillProcessGroup(SIGKILL);    }        // Oneshot processes go into the disabled state on exit,    // except when manually restarted.    if ((flags_ & SVC_ONESHOT) && !(flags_ & SVC_RESTART)) {        flags_ |= SVC_DISABLED;    }    ......    //后续Init进程重启子进程会通过这个标志位来判断是否需要重启该子进程    flags_ |= SVC_RESTARTING;    ......    return;}

当init进程收到子进程意外终止SIGCHLD信号后,会根据对应进程Service对象的flags_标志位来判断该进程能不能重启,如果需要重启,就给flags_标志位添加SVC_RESTARTING标志位。

init.rc文件语法

现在我们来简单介绍一些init.rc的语法,为后面解析rc文件做铺垫。
system/core/rootdir/init.rc

on early-init    # Set init and its forked children's oom_adj.    write /proc/1/oom_score_adj -1000    ......    mkdir /dev/memcg 0700 root system    ......    start ueventd #开启ueventd服务#属性服务,当vold.decrypt=trigger_reset_main时,就执行class_reset mainon property:vold.decrypt=trigger_reset_main    class_reset main    #ueventd服务service ueventd /sbin/ueventd    class core    critical    seclabel u:r:ueventd:s0    shutdown critical

init.rc大致分为两部分,一部分是以"on"关键字开头的动作列表(action list),另一部分是以"service"关键字开头的服务列表(service list)。借助系统环境变量或者Linux命令,动作列表用于创建所需目录,以及为特定文件指定权限,开启指定服务等。服务列表用于记录启动服务需要启动的一些程序。

on 段落中,记录action触发时,执行的命令。(可以在rc文件中通过trigger命令触发,或者程序中触发)
on property:=段落中,记录属性值改变时执行的命令。
service [ ]段落中,关键字service后的第一个字符表示服务的名称,第二个字符串表示服务的路径。下面几行是服务附加内容,用于配合服务使用。主要包含运行权限,条件以及重启相关选项。service的启动通过动作列表触发时来启动相应的服务。

例如servicemanager服务的启动,如下:

on post-fs    # start essential services    start logd    start servicemanager    ......

Android P服务都是单独的rc文件,通过命令find可以进行搜索。

小提示:查找文件是最好配合findgerp等命令,死记路径不可取,如查找servicemanager.rc文件,find frameworks/ -name servicemanager.rc -type f

了解Android Init Language(Android 初始化语言,rc文件)语法,可看官方文档。如果没有梯子,可查看源码目录下的system/core/init/README.md文件。

AIL包含五种类型的声明,如下:

  • Actions (动作)
  • Commands (命令)
  • Services (服务)
  • Options (选项)
  • Import (输入)

Actions
Actions是一系列命令的别名,通过一个触发器(trigger)来决定何时执行。当以on为开头的事件发生时。若该aciton尚未添加至待执行的队列中,则将其加入到队列最后,队列中的action依次执行,aciton中的命令也依次执行。
Actions的形式是:

on <trigger>    <command>    <command>    <command>

Triggers
Triggers(触发器)是一个字符串,与on关键字配用,用来匹配某种类型的事件并执行一个action。
触发器细分为事件触发器属性触发器

事件触发器是由"trigger"命令或者init可执行文件中的QueueEventTrigger()函数触发的字符串。它们采用简单字符串的形式,例如’early-init’或’boot’。

属性触发器是当属性将值更改为给定新值或者将值更改为任何新值时触发的字符串。它们分别采用’property: ='和’property: =*'的形式
Commands

命令 含义
class_start < serviceclass > 启动该类下的所有服务
exec < path > [< argument> *] Fork 并执行一个程序,这将阻塞init进程直到程序执行完毕
insmod < path > 加载指定模块
start < service > 启动一个尚未启动的服务,是异步启动的
…<还有很多命令请查看官方文档 README.md>

Services
Services由init进程启动,当它们退出时重启(可选)。Services表现形式为:

servcie <name> <pathname> [ <argument> ]*    <option>    <option>    ...

Options

选项 意义
disable init进程启动的所有进程被包含在名称为“类”的运行组中。进程所属的类被启动时,若指定进程为disabled,该进程将不会被执行,只要按照名称明确指定后才能启动
user < username > 在执行服务签改变用户名。若未设定,则默认为root
oneshot 服务退出后不再重启
class < name > 在执行服务前为其指定所属的类名。当一个类启动或退出时,其包含的所有服务可以一同启动或停止。若未指定,服务默认为“default”类
onrestart 当服务重启时执行一个命令

Import
import
解析init配置文件,扩展当前配置。如果path是目录,则将目录中的每个文件解析成配置文件。它不是递归的,不会解析嵌套目录。

解析并执行init.rc文件

system/core/init/init.cpp

//am中的actions_成员变量用来保存action list(动作列表)ActionManager& am = ActionManager::GetInstance();//sm中的service_成员变量用来保存service list(服务列表)ServiceList& sm = ServiceList::GetInstance();//解析rc文件,并将动作和服务分别添加到am和sm中LoadBootScripts(am, sm);

LoadBootScripts解析rc文件,将动作和服务添加到am的动作列表和sm的服务列表中去。
system/core/init/init.cpp

static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {    //创建解析器    Parser parser = CreateParser(action_manager, service_list);    ......    //解析init.rc文件    parser.ParseConfig("/init.rc");    ......}Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {    Parser parser;    //添加ServiceParser触发器    parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, subcontexts));    //添加ActionParser触发器    parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, subcontexts));    //添加ImportParser触发器    parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));    return parser;}void Parser::AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser) {    //以键值对的形式添加到section_parsers_中    section_parsers_[name] = std::move(parser);}

分别将service(ServiceParser),on(ActionParser)和import(ImportParser)以键值对的形式添加到section_parsers_中。这三个Parser都继承自SectionParser,可以看到这里使用了组合和面向抽象编程的设计原则,将具体的解析器和解析行为解耦。下面会分析它们是如何使用相同的代码,不同的解析器解析不同的关键字(on,service,import等)。

现在分析ParseConfig("/init.rc")方法
system/core/init/parser.cpp

//ParseConfig->ParseConfigFilebool Parser::ParseConfigFile(const std::string& path, size_t* parse_errors) {    ......    //ReadFile将init.rc文件转换为config_contents字符串    auto config_contents = ReadFile(path);    ......    //解析config_contents字符串    ParseData(path, *config_contents, parse_errors);    ......}void Parser::ParseData(const std::string& filename, const std::string& data, size_t* parse_errors) {    std::vector<char> data_copy(data.begin(), data.end());    data_copy.push_back('\0');    parse_state state;    .......    state.ptr = &data_copy[0];    ......    std::vector<std::string> args;    //lambda表达式,函数的引用,每次解析新的一行之前    //都会调用这个将上一行解析的结果放到对应的数组中    auto end_section = [&] {//⑤        if (section_parser == nullptr) return;        if (auto result = section_parser->EndSection(); !result) {            (*parse_errors)++;            LOG(ERROR) << filename << ": " << section_start_line << ": " << result.error();        }        //重置        section_parser = nullptr;        section_start_line = -1;    };    for (;;) {        switch (next_token(&state)) { // ①            case T_EOF:                end_section();// ⑤ 上一行的解析工作                return;            case T_NEWLINE: // ⑦                state.line++;                ......                if (section_parsers_.count(args[0])) {//②                    end_section(); // ⑤ 上一行解析的收尾工作                    section_parser = section_parsers_[args[0]].get();                    section_start_line = state.line;                    auto result = section_parser->                        ParseSection(std::move(args), filename, state.line); // ③                } else if (section_parser) {                    auto result = section_parser->                        ParseLineSection(std::move(args), state.line); // ④                args.clear();                break;            case T_TEXT: // ⑥                args.emplace_back(state.text);                break;        }    }}

下面我们分析一下,ParseData是如何解析的:
①: next_token扫描init.rc中的token
找到其中的文件结束(EOF)、文本(TEXT)、新行(NEWLINE),其中的空格’ ‘、’\t’、’\r’会被忽略掉;对于TEXT,空格’ ‘、’\t’、’\r’、’\n’都是TEXT的结束标志。

例如:service ueventd /system/sbin/ueventd 中有三个TEXT (“servcie”、“ueventd”、"/system/sbin/") 这些都会加入到args[]数组中⑥,然后就是⑦解析args数组

②: 会判断args[]第一个字符是不是on、service或import
如果是就拿到对应的解析器,例如是service开头的新行,section_parser就是对应之前添加的ServcieParser解析器,并且执行③,否则就执行④
③: 这里会执行ServiceParser解析器的ParseSection代码
会新建一个Service对象,变量名service_
④: 这里会执行ServiceParser解析器的ParseLineSection代码
这里是解析service下面附带的option(例如oneshot,class等等),并将这些属性添加到Service对象中),

小提示: 如果args[0]是"on",section_parser对应的就是ActionParser;如果是"import",section_parser对应的就是ImportParser;本文只会分析ServiceParser,另外两个解析器,读者可以参照着分析。

⑤: 解析完一个Service对象后
end_section()中的section_parser->EndSection()将Service对象添加到Service List(services_)中,并且重置section_parser = null,为解析下一个Service做准备。

system/core/init/service.cpp 分析③的代码:

Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args,                                            const std::string& filename, int line) {    const std::string& name = args[1];    ......    std::vector<std::string> str_args(args.begin() + 2, args.end());    //新建一个Service对象,args[1]表示服务名,后面的是运行参数    service_ = std::make_unique<Service>(name, restart_action_subcontext, str_args);    return Success();}

system/core/init/service.cpp 分析④的代码:

Result<Success> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) {    return service_ ? service_->ParseLine(std::move(args)) : Success();}Result<Success> Service::ParseLine(const std::vector<std::string>& args) {    static const OptionParserMap parser_map;    //找到service中option对应的函数    auto parser = parser_map.FindFunction(args);    if (!parser) return parser.error();    //执行相应的函数,添加对应的属性到Service对象中    return std::invoke(*parser, this, args);}

下面我们看一下paser_map中option和函数名的对应关系。
system/core/init/service.cpp

static const Map option_parsers = {        ......        {"class",       {1,     kMax, &Service::ParseClass}},        {"console",     {0,     1,    &Service::ParseConsole}},        {"disabled",    {0,     0,    &Service::ParseDisabled}},        ......        {"oneshot",     {0,     0,    &Service::ParseOneshot}},        {"onrestart",   {1,     kMax, &Service::ParseOnrestart}},        ......        {"user",        {1,     1,    &Service::ParseUser}},    };

这个我们分析oneshot为例,oneshot对应的函数是Service::ParseOneshot。

Result<Success> Service::ParseOneshot(const std::vector<std::string>& args) {    flags_ |= SVC_ONESHOT;    return Success();}

std::invoke调用这个函数后,会将SVC_ONESHOT添加到这个Service对象中,当这个服务意外终止时,init进程会根据这个标志位而不去重启这个Service。

system/core/init/service.cpp 分析⑤的代码

Result<Success> ServiceParser::EndSection() {    if (service_) {        ......        //service_对象存在的时候,就添加到service list中        service_list_->AddService(std::move(service_));    }    return Success();}void ServiceList::AddService(std::unique_ptr<Service> service) {    //将服务添加到Service List(services_)中    services_.emplace_back(std::move(service));}

到这里一个服务就解析完成了,on和import依葫芦画瓢,可以自行分析。

on开头的使用ActionParser解析器解析,该解析器的ParseSection方法主要是生成action对象,并将action对象添加到actions_数组中,ParseLineSection方法主要是解析command对应的函数,然后添加到action对象的commands_数组中。细心的读者可能已经发现,ServiceParser的ParseLineSection是直接执行option对应函数,而ActionParser是将对应函数保存到commands_数组中,当Action触发时,才会依次执行command函数。

我们继续往下分析源码
system/core/init/init.cpp

// 解析init.rc文件,上面已经分析完LoadBootScripts(am, sm);......// ① 触发early-init Actionam.QueueEventTrigger("early-init");// ② 新建一个"wait_for_coldboot_done"触发器,并且触发该触发器am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");......// ③ 触发"init",触发器am.QueueEventTrigger("init");

①: 使用QueueEventTrigger方法触发early-init(还有一种触发方式是在rc文件中使用trigger命令,如trigger early-init)
system/core/init/action_manager.cpp

void ActionManager::QueueEventTrigger(const std::string& trigger) {    event_queue_.emplace(trigger);}

event_queue_是一个保存以触发事件的队列,QueueEventTrigger(“early-init”)就表示触发了"early-init"事件
system/core/init/action_manager.h

std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_;

system/core/init/action.h

using EventTrigger = std::string;using PropertyChange = std::pair<std::string, std::string>;using BuiltinAction = class Action*;

event_queue_可以存储三种触发器,EventTrigger(事件触发器,如on early-init),PropertyChange(属性触发器,如on property: = ),例如:属性服务监听到属性变更请求时会添加该触发器,BuiltinAction(内建触发器,代码实时添加的,不在rc文件中配置)

②:创建内置触发器,并且触发
system/core/init/action_manager.cpp

void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {    //创建内置action对象    auto action = std::make_unique<Action>(true, nullptr, "", 0, name, std::map<std::string, std::string>{});    std::vector<std::string> name_vector{name};    //添加func到action对象的commands_数组中    action->AddCommand(func, name_vector, 0);    //触发内置触发器    event_queue_.emplace(action.get());    //添加action对象到action list(actions_数组中)    actions_.emplace_back(std::move(action));}

③:触发事件触发器 on init

继续向下分析,就是依次执行已经触发的触发器action对象的command命令,并且监听属性服务和子进程的终止。
system/core/init/init.cpp

while (true) {    ......    // ①     am.ExecuteOneCommand();    ......    // ②    auto next_process_restart_time = RestartProcesses();    ......    // ③    int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));    }

①:依次执行已触发aciton的command命令
system/core/init/action_manager.cpp

void ActionManager::ExecuteOneCommand() {    // Loop through the event queue until we have an action to execute    while (current_executing_actions_.empty() && !event_queue_.empty())    {        for (const auto& action : actions_) {            //如果该触发(event,就是前面说的三个触发器)匹配到当前action,就添加到current_excuting_actions_队列中            if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },event_queue_.front())) {                current_executing_actions_.emplace(action.get());            }        }        //从已触发事件弹出        event_queue_.pop();    }    //如果没有可执行action,就直接返回    if (current_executing_actions_.empty()) {        return;    }    auto action = current_executing_actions_.front();    ......    //每次执行一个命令    action->ExecuteOneCommand(current_command_);    // If this was the last command in the current action, then remove    // the action from the executing list.    ++current_command_;//命令索引加一    //如果是当前action最后一个命令,就从执行列表中移除action    if (current_command_ == action->NumCommands()) {        current_executing_actions_.pop();        current_command_ = 0;        ......        }    }}

从触发事件队列event_queue_中取出一个触发事件,从actions_中寻找匹配的action,然后添加到当前正在执行事件的队列current_executing_actions_中,取出aciton,依次执行action中commands_数组中的命令。遍历的执行上述操作,直至event_queue_和current_executing_actions_为空。

system/core/init/action.cpp

oid Action::ExecuteOneCommand(std::size_t command) const {    Command cmd = commands_[command];    //每次调用一个command命令    ExecuteCommand(cmd);}void Action::ExecuteCommand(const Command& command) const {    ......    auto result = command.InvokeFunc(subcontext_);    ......}

②:重启需要重启的子进程
system/core/init/init.cpp

static std::optional<boot_clock::time_point> RestartProcesses() {    ......    for (const auto& s : ServiceList::GetInstance()) {        //如果是需要重启的服务,会添加SVC_RESTARTING标志位,前面已经介绍过        if (!(s->flags() & SVC_RESTARTING)) continue;        ......        //重启进程        if (auto result = s->Start(); !result) {            LOG(ERROR) << "Could not restart process '" << s->name() << "': " << result.error();        }        ......}

③:上面通过epoll_ctl注册了属性服务和子进程终止,现在通过epoll_wait来真正的监听。当有属性申请和子进程终止时,就执行前面分析的对应的处理函数。

总结

init进程的三大功能:属性服务、处理子进程终止、解析与运行init.rc文件到这里就介绍完毕了。

属性服务和处理子进程终止的共同点

  • 都要通过epoll_fd轮询监听
  • 都要依赖解析init.rc文件得到的数据结构

属性服务和处理子进程终止的不同点

  • 遇到属性变更请求时,会将对应的属性触发器添加到ActionManager的event_queue_(已触发事件队列中),然后执行需要执行的command数组
  • 遇到子进程终止时,会遍历判断Service List(services_)的服务需不需要重启

本文难点就在于解析init.rc文件,因为使用了组合和面向抽象编程的设计思想,所以代码不是很直观,但是解耦后的代码对于后期维护和扩展有很大的好处,值得我们学习。分别使用ActionParser、ServiceParser、ImportParser来解析init.rc中分别以on、service、import关键字开头的配置文件,分别保存到对应的数组中。然后属性服务可以触发on property:(属性触发器),ActionManager::QueueEventTrigger可以触发on early-init(事件触发器),最后就依次执行已经触发的action。

第一次写分析源码类的文章,写完发现长到自己都看不下去,如果觉得写得还不错,请点个赞吧~

参考:
《Android框架揭秘》
Android Init进程源码分析

最怕你抱怨,又不去改变

更多相关文章

  1. 属性动画(Property Animation)
  2. Android(安卓)7.0 Camera架构源码分析1 - CameraService启动
  3. Android(安卓)自定义进度条
  4. Android(安卓)多进程编程 15问15答!
  5. Android(安卓)属性系统(翻译)
  6. selector修改TextView点击后的颜色属性
  7. Android系统的启动流程(转载)
  8. android_qqApk反编译/android小工具/ddms截屏
  9. 懒人爱家务_Android中的Selector的用法

随机推荐

  1. Android零基础入门第8节:HelloWorld,我的第
  2. Android(安卓)Log Analysis转
  3. android系统学习笔记四
  4. android升级的问题
  5. ubuntu 平台 FFmpeg Android(安卓).so文
  6. android中的maven配置
  7. android中layer-list
  8. Android: Support Libraries for Android
  9. Android(安卓)性能参数获取
  10. 2.28学习内容,android,dialog自定义宽高、i