android8.1系统启动过程(四) 解析init.rc

事先声明本文为作者本人记录学习使用

其中部分文字或者技术观点摘自https://blog.csdn.net/marshal_zsx/article/details/80600622  这里推荐此作者文章


main(int argc, char** argv)  AOSP/system/core/init/init.cpp

 这三句代码都是new一个Parser(解析器),然后将它们放到一个map里存起来  ServiceParser、ActionParser、ImportParser分别对应service action import的解析

parser.AddSectionParser("service", std::make_unique<ServiceParser>(&sm));
parser.AddSectionParser("on", std::make_unique<ActionParser>(&am));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
...
parser.ParseConfig("/init.rc");

ParseConfig()  AOSP/system/core/init/init_parser.cpp

判断是文件还是Dir或者是File  文件调用ParseConfigFile


ParseConfigFile()  AOSP/system/core/init/init_parser.cpp  

取出数据调用  ParseData(path, data);


ParseData(path, data)  AOSP/platform/system/core/init/init_parser.cpp

取出对应的parser  解析对应的Section

section_parser = section_parsers_[args[0]].get();
std::string ret_err;
if (!section_parser->ParseSection(std::move(args), filename, state.line, &ret_err)) {
  LOG(ERROR) << filename << ": " << state.line << ": " << ret_err;
  section_parser = nullptr;
}

三个parser  这里主要介绍serviceparser

Action  AOSP/system/core/init/action.cpp

Service  AOSP/system/core/init/service.cpp

ImportParser  AOSP/system/core/init/import_parser.cpp


经过以上的解析,系统从各种.rc文件中读取了需要执行的Action和Service,但是还是需要一些额外的配置,也需要加入触发条件准备去触发

main(int argc, char** argv)  AOSP/system/core/rootdir/init.cpp

    QueueEventTrigger用于触发Action,这里触发 early-init事件

    QueueBuiltinAction用于添加Action,第一个参数是Action要执行的Command,第二个是Trigger

...
am.QueueEventTrigger("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(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
am.QueueBuiltinAction(set_kptr_restrict_action, "set_kptr_restrict");
am.QueueBuiltinAction(keychord_init_action, "keychord_init");
am.QueueBuiltinAction(console_init_action, "console_init");
...

QueueEventTrigger()  AOSP/system/core/init/action.cpp

    它并没有去触发trigger,而是构造了一个EventTrigger对象,放到队列中存起来

QueueBuiltinAction()  AOSP/system/core/init/action.cpp

QueueBuiltinAction(BuiltinFunction func, const std::string& name)

    这个函数有两个参数,第一个参数是一个函数指针,第二参数是字符串. 首先是创建一个Action对象,将第二参数作为Action触发条件,将第一个参数作为Action触发后的执行命令,并且又把第二个参数作为命令的参数,最后是将Action加入触发队列并加入Action列表


main(int argc, char** argv)  AOSP/system/core/init/init.cpp

    触发

while (true) {
    // By default, sleep until something happens.
    int epoll_timeout_ms = -1;

    if (do_shutdown && !shutting_down) {
        do_shutdown = false;
        if (HandlePowerctlMessage(shutdown_command)) {
            shutting_down = true;
        }
    }

    if (!(waiting_for_prop || sm.IsWaitingForExec())) {
        am.ExecuteOneCommand();
    }
    if (!(waiting_for_prop || sm.IsWaitingForExec())) {
        if (!shutting_down) restart_processes();

ExecuteOneCommand()  AOSP/system/core/init/action.cpp

    执行一个command,在函数一开始就从trigger_queue_队列中取出一个trigger,然后遍历所有action,找出满足trigger条件的action加入待执行列表current_executing_actions_中,接着从这个列表中取出一个action,执行它的第一个命令,并将命令所在下标自加1. 由于ExecuteOneCommand外部是一个无限循环,因此按照上面的逻辑一遍遍执行,将按照trigger表的顺序,依次执行满足trigger条件的action,然后依次执行action中的命令.


restart_processes()  AOSP/system/core/init/init.cpp

    主要是调用了    ForEachServiceWithFlags  RestartIfNeeded

static void restart_processes()
{
    process_needs_restart_at = 0;
    ServiceManager::GetInstance().ForEachServiceWithFlags(SVC_RESTARTING, [](Service* s) {
        s->RestartIfNeeded(&process_needs_restart_at);
    });
}

ForEachServiceWithFlags()  AOSP/system/core/init/service.cpp

    遍历所有service,找出flags是SVC_RESTARTING的,执行func,也就是传入的RestartIfNeeded

void ServiceManager::ForEachServiceWithFlags(unsigned matchflags,
                                             void (*func)(Service* svc)) const {
    for (const auto& s : services_) {
        if (s->flags() & matchflags) {
            func(s.get());
        }
    }
}

RestartIfNeeded()  AOSP/system/core/init/service.cpp

     这个函数将主要工作交给了Start,也就是具体的启动service,但是交给它之前做了一些判断,也就是5秒内只能启动一个服务,如果有多个服务,那么后续的服务将进入等待

void Service::RestartIfNeeded(time_t* process_needs_restart_at) {
    boot_clock::time_point now = boot_clock::now();
    boot_clock::time_point next_start = time_started_ + 5s;
    if (now > next_start) {
        flags_ &= (~SVC_RESTARTING);
        Start();
        return;
    }

    time_t next_start_time_t = time(nullptr) +
        time_t(std::chrono::duration_cast<std::chrono::seconds>(next_start - now).count());
    if (next_start_time_t < *process_needs_restart_at || *process_needs_restart_at == 0) {
        *process_needs_restart_at = next_start_time_t;
    }
}

Start()  AOSP/system/core/init/service.cpp

    Start是具体去启动服务了,它主要是调用clone或fork创建子进程,然后调用execve执行配置的二进制文件,另外根据之前在.rc文件中的配置,去执行这些配置

bool Service::Start() {

    ... //清空标记,根据service的配置初始化console、SELinux策略等

    LOG(INFO) << "starting service '" << name_ << "'...";

    pid_t pid = -1;
    if (namespace_flags_) {//这个标记当service定义了namespace时会赋值为CLONE_NEWPID|CLONE_NEWNS
        pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr); //以clone方式在新的namespace创建子进程
    } else {
        pid = fork();//以fork方式创建子进程
    }

    if (pid == 0) {//表示创建子进程成功

        ... //执行service配置的其他参数,比如setenv、writepid等

        std::vector<char*> strs;
        ExpandArgs(args_, &strs);//将args_解析一下,比如有${x.y},然后赋值表strs
        if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) { //执行系统调用execve,也就是执行配置的二进制文件,把参数传进去
            PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
        }

        _exit(127);
    }

    if (pid < 0) { //子进程创建失败
        PLOG(ERROR) << "failed to fork for '" << name_ << "'";
        pid_ = 0;
        return false;
    }

    ... //执行service其他参数如oom_score_adjust_,改变service运行状态等
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值