• [android] init进程 .rc文件中service、action的parsing


    init进程code位置:system/core/init

    system/core/init/README.md,这个文件是描述rc文件语法的。

    在.rc文件中,有3中类型:

    1. service

    2. on(action)

    3. import

    init.cpp

    Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
        Parser parser;
    
        parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, subcontexts));
        parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, subcontexts));
        parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
    
        return parser;
    }
    

      

    以service开头,表示是service;以on开头表示是Action。

    对于service行或者on行,调用ParseSection(),在ParseSection中会创建Servcie或者Action对象。

    然后处理service或者on行后的行(service或者action的子行)。对于每个子行,都会调用ParseLineSection(),在这个函数中,对于service,会执行对应的函数,比如对于writepid,会调用Servcie::ParseWritepid();

    对于action,会执行AddCommand()。

    等这个service或者action的所有子行都parse完后,在parse下一个servcie或者action前(调用ParseSection之前),会call endSection(),这个函数会call EndSection。在EndSection()中,对于service,会执行add service;对于action,会add action到action manager。

    对于service,对应文件是service.cpp;对于action,对应文件是action_parser.cpp。

    parse .rc文件的入口:init.cpp/LoadBootScripts()

    Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
        Parser parser;
    
        parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, subcontexts));
        parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, subcontexts));
        parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
    
        return parser;
    }
    
    static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
        Parser parser = CreateParser(action_manager, service_list);
    
        std::string bootscript = GetProperty("ro.boot.init_rc", "");
        if (bootscript.empty()) {
            parser.ParseConfig("/init.rc");
            if (!parser.ParseConfig("/system/etc/init")) {
                late_import_paths.emplace_back("/system/etc/init");
            }
            if (!parser.ParseConfig("/product/etc/init")) {
                late_import_paths.emplace_back("/product/etc/init");
            }
            if (!parser.ParseConfig("/odm/etc/init")) {
                late_import_paths.emplace_back("/odm/etc/init");
            }
            if (!parser.ParseConfig("/vendor/etc/init")) {
                late_import_paths.emplace_back("/vendor/etc/init");
            }
        } else {
            parser.ParseConfig(bootscript);
        }
    }
    

    ParseData()函数中通过next_token(&state)将一行中的所有单词(以比如空格分隔)走T_TEXT case调用args.emplace_back(state.text)加到args中。当一行结束时( 符),next_token()会返回T_NEWLINE,在T_NEWLINE case中处理这一行。处理完后,将args clear。

    void Parser::ParseData(const std::string& filename, const std::string& data, size_t* parse_errors) {
        // TODO: Use a parser with const input and remove this copy
        std::vector<char> data_copy(data.begin(), data.end());
        data_copy.push_back('');
    
        parse_state state;
        state.line = 0;
        state.ptr = &data_copy[0];
        state.nexttoken = 0;
    
        SectionParser* section_parser = nullptr;
        int section_start_line = -1;
        std::vector<std::string> args;
    
        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 (args.empty()) break;
                    // If we have a line matching a prefix we recognize, call its callback and unset any
                    // current section parsers.  This is meant for /sys/ and /dev/ line entries for
                    // uevent.
                    for (const auto& [prefix, callback] : line_callbacks_) {
                        if (android::base::StartsWith(args[0], prefix)) {
                            end_section();
    
                            if (auto result = callback(std::move(args)); !result) {
                                (*parse_errors)++;
                                LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                            }
                            break;
                        }
                    }
                    if (section_parsers_.count(args[0])) {
                        end_section();
                        section_parser = section_parsers_[args[0]].get();
                        section_start_line = state.line;
                        if (auto result =
                                section_parser->ParseSection(std::move(args), filename, state.line);
                            !result) {
                            (*parse_errors)++;
                            LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                            section_parser = nullptr;
                        }
                    } else if (section_parser) {
                        if (auto result = section_parser->ParseLineSection(std::move(args), state.line);
                            !result) {
                            (*parse_errors)++;
                            LOG(ERROR) << filename << ": " << state.line << ": " << result.error();
                        }
                    }
                    args.clear();
                    break;
                case T_TEXT:
                    args.emplace_back(state.text);
                    break;
            }
        }
    }
    

    service class有一个Action的成员--onrestart_

    在parse一个service时,例如下面的audioserver.rc,对于service里的onrestart行,就是对应一个command。这个command会被add到onrestart_ Action中,是通过如下的方法add的:

    在service.cpp里有一个Service::OptionParserMap::map()函数,根据key onrestart找到其对应的函数:Service::ParseOnrestart(),然后执行这个函数。这个函数会调用Action.cpp中的addcommand函数。

    frameworks/av/media/audioserver/audioserver.rc

    service audioserver /system/bin/audioserver
        class core
        user audioserver
        # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
        group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
        ioprio rt 4
        writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
        onrestart restart vendor.audio-hal-2-0
        # Keep the original service name for backward compatibility when upgrading
        # O-MR1 devices with framework-only.
        onrestart restart audio-hal-2-0
     
    on property:vts.native_server.on=1
        stop audioserver
    on property:vts.native_server.on=0
        start audioserver
    

      

    const Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
        constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
        // clang-format off
        static const Map option_parsers = {
            {"capabilities",
                            {1,     kMax, &Service::ParseCapabilities}},
            {"class",       {1,     kMax, &Service::ParseClass}},
            {"console",     {0,     1,    &Service::ParseConsole}},
            {"critical",    {0,     0,    &Service::ParseCritical}},
            {"disabled",    {0,     0,    &Service::ParseDisabled}},
            {"enter_namespace",
                            {2,     2,    &Service::ParseEnterNamespace}},
            {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::ParseGroup}},
            {"interface",   {2,     2,    &Service::ParseInterface}},
            {"ioprio",      {2,     2,    &Service::ParseIoprio}},
            {"priority",    {1,     1,    &Service::ParsePriority}},
            {"keycodes",    {1,     kMax, &Service::ParseKeycodes}},
            {"oneshot",     {0,     0,    &Service::ParseOneshot}},
            {"onrestart",   {1,     kMax, &Service::ParseOnrestart}},
            {"override",    {0,     0,    &Service::ParseOverride}},
            {"oom_score_adjust",
                            {1,     1,    &Service::ParseOomScoreAdjust}},
            {"memcg.swappiness",
                            {1,     1,    &Service::ParseMemcgSwappiness}},
            {"memcg.soft_limit_in_bytes",
                            {1,     1,    &Service::ParseMemcgSoftLimitInBytes}},
            {"memcg.limit_in_bytes",
                            {1,     1,    &Service::ParseMemcgLimitInBytes}},
            {"namespace",   {1,     2,    &Service::ParseNamespace}},
            {"rlimit",      {3,     3,    &Service::ParseProcessRlimit}},
            {"seclabel",    {1,     1,    &Service::ParseSeclabel}},
            {"setenv",      {2,     2,    &Service::ParseSetenv}},
            {"shutdown",    {1,     1,    &Service::ParseShutdown}},
            {"socket",      {3,     6,    &Service::ParseSocket}},
            {"file",        {2,     2,    &Service::ParseFile}},
            {"user",        {1,     1,    &Service::ParseUser}},
            {"writepid",    {1,     kMax, &Service::ParseWritepid}},
        };
        // clang-format on
        return option_parsers;
    }
    

    Action.cpp中的addcommand函数会根据builtins.cpp中的Map builtin_fucnctions找到对应的函数,比如上面例子中的onrestart restart vendor.audio-hal-2-0,就是根据key restart找到对应的函数do_restart。

    然后会根据找到的这个函数和args等其它参数构造一个Command,然后将这个Command对象add到commands_中。

    const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
        constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
        // clang-format off
        static const Map builtin_functions = {
            {"bootchart",               {1,     1,    {false,  do_bootchart}}},
            {"chmod",                   {2,     2,    {true,   do_chmod}}},
            {"chown",                   {2,     3,    {true,   do_chown}}},
            {"class_reset",             {1,     1,    {false,  do_class_reset}}},
            {"class_restart",           {1,     1,    {false,  do_class_restart}}},
            {"class_start",             {1,     1,    {false,  do_class_start}}},
            {"class_stop",              {1,     1,    {false,  do_class_stop}}},
            {"copy",                    {2,     2,    {true,   do_copy}}},
            {"domainname",              {1,     1,    {true,   do_domainname}}},
            {"enable",                  {1,     1,    {false,  do_enable}}},
            {"exec",                    {1,     kMax, {false,  do_exec}}},
            {"exec_background",         {1,     kMax, {false,  do_exec_background}}},
            {"exec_start",              {1,     1,    {false,  do_exec_start}}},
            {"export",                  {2,     2,    {false,  do_export}}},
            {"hostname",                {1,     1,    {true,   do_hostname}}},
            {"ifup",                    {1,     1,    {true,   do_ifup}}},
            {"init_user0",              {0,     0,    {false,  do_init_user0}}},
            {"insmod",                  {1,     kMax, {true,   do_insmod}}},
            {"installkey",              {1,     1,    {false,  do_installkey}}},
            {"load_persist_props",      {0,     0,    {false,  do_load_persist_props}}},
            {"load_system_props",       {0,     0,    {false,  do_load_system_props}}},
            {"loglevel",                {1,     1,    {false,  do_loglevel}}},
            {"mkdir",                   {1,     4,    {true,   do_mkdir}}},
            // TODO: Do mount operations in vendor_init.
            // mount_all is currently too complex to run in vendor_init as it queues action triggers,
            // imports rc scripts, etc.  It should be simplified and run in vendor_init context.
            // mount and umount are run in the same context as mount_all for symmetry.
            {"mount_all",               {1,     kMax, {false,  do_mount_all}}},
            {"mount",                   {3,     kMax, {false,  do_mount}}},
            {"umount",                  {1,     1,    {false,  do_umount}}},
            {"readahead",               {1,     2,    {true,   do_readahead}}},
            {"restart",                 {1,     1,    {false,  do_restart}}},
            {"restorecon",              {1,     kMax, {true,   do_restorecon}}},
            {"restorecon_recursive",    {1,     kMax, {true,   do_restorecon_recursive}}},
            {"rm",                      {1,     1,    {true,   do_rm}}},
            {"rmdir",                   {1,     1,    {true,   do_rmdir}}},
            {"setprop",                 {2,     2,    {true,   do_setprop}}},
            {"setrlimit",               {3,     3,    {false,  do_setrlimit}}},
            {"start",                   {1,     1,    {false,  do_start}}},
            {"stop",                    {1,     1,    {false,  do_stop}}},
            {"swapon_all",              {1,     1,    {false,  do_swapon_all}}},
            {"symlink",                 {2,     2,    {true,   do_symlink}}},
            {"sysclktz",                {1,     1,    {false,  do_sysclktz}}},
            {"trigger",                 {1,     1,    {false,  do_trigger}}},
            {"verity_load_state",       {0,     0,    {false,  do_verity_load_state}}},
            {"verity_update_state",     {0,     0,    {false,  do_verity_update_state}}},
            {"wait",                    {1,     2,    {true,   do_wait}}},
            {"wait_for_prop",           {2,     2,    {false,  do_wait_for_prop}}},
            {"write",                   {2,     2,    {true,   do_write}}},
        };
        // clang-format on
        return builtin_functions;
    }
    

    对于service来说,只有onrestart才有对应的command,像writepid、group等等其它都是没有对应的command的。 

    对于service定义的command(onrestart),什么时候执行这个command呢?

    这个是在service.cpp中的onrestart_.ExecuteAllCommands()的时候去执行的。

    这个onrestart_.ExecuteAllCommands()对于media进程来说,它没有添加command(如下面的mediaserver.rc),所以不会做什么事情。

    frameworks/av/media/mediaserver/mediaserver.rc

    service media /system/bin/mediaserver
        class main
        user media
        group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
        ioprio rt 4
        writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
    

      

      

      

  • 相关阅读:
    堆栈,堆栈,堆和栈的区别(转贴)
    .net cookie跨域和逗号bug的修复
    转:互联网协议入门
    函数式编程stream.js
    用例子验证w3c的stacklevel在不同浏览器中的显示
    JS创建对象的几种方法
    打开Word时总是出现 “Microsoft Office Word 需要 VBA 宏语言支持来完成此操作
    如何解决闭包只能取得包含函数中任何变量的最后一个值
    转:10个javascript简写/优化技巧
    Nicholas C. Zakas如何面试前端工程师
  • 原文地址:https://www.cnblogs.com/aspirs/p/11405877.html
Copyright © 2020-2023  润新知