zoukankan      html  css  js  c++  java
  • [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
    

      

      

      

  • 相关阅读:
    Powershell数据处理
    Powershell About Active Directory Group Membership of a domain user
    Powershell About Active Directory Server
    Oracle Schema Objects——Tables——TableStorage
    Oracle Schema Objects——Tables——TableType
    English Grammar
    Oracle Database Documentation
    Oracle Schema Objects——Tables——Oracle Data Types
    Oracle Schema Objects——Tables——Overview of Tables
    What is Grammar?
  • 原文地址:https://www.cnblogs.com/aspirs/p/11405877.html
Copyright © 2011-2022 走看看