android init進(jìn)程--init.rc解析過程與執(zhí)行

android源碼學(xué)習(xí)目錄

\color{#ea4335}{請(qǐng)先閱讀:}

1.init.rc的解析

從文章android init進(jìn)程可以看出纵朋,init.rc的解析是從init進(jìn)程main函數(shù)中進(jìn)行的潘懊。

    //android 8.0
    //init進(jìn)程main函數(shù)解析init.rc代碼飘哨。 
    //Parser init.rc文件的解析入口  /system/core/init/init_parse.cpp
    Parser& parser = Parser::GetInstance();
    // 1 為解析類添加解析能力
    parser.AddSectionParser("service",std::make_unique<ServiceParser>());
    parser.AddSectionParser("on", std::make_unique<ActionParser>());
    parser.AddSectionParser("import", std::make_unique<ImportParser>());
    std::string bootscript = GetProperty("ro.boot.init_rc", "");  //2 環(huán)境變量里是否有ro.boot.init_rc
    if (bootscript.empty()) {
        parser.ParseConfig("/init.rc");  //3 解析
        parser.set_is_system_etc_init_loaded(
                parser.ParseConfig("/system/etc/init"));  //解析system/etc/init文件夾下左右的rc文件侧戴。
        parser.set_is_vendor_etc_init_loaded(
                parser.ParseConfig("/vendor/etc/init"));
        parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
    } else {
        parser.ParseConfig(bootscript);
        parser.set_is_system_etc_init_loaded(true);
        parser.set_is_vendor_etc_init_loaded(true);
        parser.set_is_odm_etc_init_loaded(true);
    }

這是Android init進(jìn)程解析init.rc文件的代碼,

  1. Parser是init.rc類文件解析的入口,parser.AddSectionParser()函數(shù)是為了添加init.rc類文件解析的能力,會(huì)根據(jù)init.rc文件每一行的內(nèi)容選擇不同的處理器eg:ActionParser,
  2. 代碼2處是判斷是否有啟動(dòng)配置腳本,按照是否有來進(jìn)行解析呢堰,一般都是系統(tǒng)默認(rèn)的,沒有啟動(dòng)配置腳本使用Android系統(tǒng)的init.rc進(jìn)行解析脑又,解析在代碼3處暮胧,ParseConfig函數(shù)就是解析函數(shù)
 //代碼位置 /system/core/init/init_parse.cpp
bool Parser::ParseConfig(const std::string& path) {
    if (is_dir(path.c_str())) {
        return ParseConfigDir(path);
    }
    return ParseConfigFile(path);   //進(jìn)行文件解析锐借,解析的是init.rc
}


bool Parser::ParseConfigFile(const std::string& path) {
    LOG(INFO) << "Parsing file " << path << "...";
    Timer t;
    std::string data;
    if (!read_file(path, &data)) {  //將文件內(nèi)容讀取到data里,
        return false;
    }

    data.push_back('\n'); // TODO: fix parse_config.
    ParseData(path, data);  //內(nèi)容解析函數(shù)往衷,分派給各個(gè)解析類eg:ActionParse
    for (const auto& sp : section_parsers_) {
        sp.second->EndFile(path);
    }
    LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)";
    return true;
}


void Parser::ParseData(const std::string& filename, const std::string& data) {
    //TODO: Use a parser with const input and remove this copy
    std::vector<char> data_copy(data.begin(), data.end());
    data_copy.push_back('\0');

    parse_state state;   //解析過程使用的結(jié)構(gòu)體,/system/core/init/parse.h parse.cpp
    state.filename = filename.c_str();
    state.line = 0;
    state.ptr = &data_copy[0];
    state.nexttoken = 0;

    SectionParser* section_parser = nullptr;
    std::vector<std::string> args;

    for (;;) {
        switch (next_token(&state)) {// 更具next_token讀取state里的內(nèi)容
        case T_EOF:
            if (section_parser) {
                section_parser->EndSection(); //結(jié)束一個(gè)文件的分析钞翔,
            }
            return;
        case T_NEWLINE:   //分析每一行的命令
            state.line++;
            if (args.empty()) {
                break;
            }
            if (section_parsers_.count(args[0])) {
                if (section_parser) {
                    section_parser->EndSection();
                }
                 //根據(jù)args[0]也就是每個(gè)init.rc執(zhí)行邏輯的第一個(gè)參數(shù),選取解析的類席舍,選我們之前添加的ActionParse等
                section_parser = section_parsers_[args[0]].get();
                std::string ret_err;
                if (!section_parser->ParseSection(args, &ret_err)) {  
                    parse_error(&state, "%s\n", ret_err.c_str());
                    section_parser = nullptr;
                }
            } else if (section_parser) {
                std::string ret_err;
                if (!section_parser->ParseLineSection(args, state.filename,
                                                      state.line, &ret_err)) {  //解析一行
                    parse_error(&state, "%s\n", ret_err.c_str());
                }
            }
            args.clear();
            break;
        case T_TEXT:
            args.emplace_back(state.text);
            break;
        }
    }
}

從上面代碼可以看出parseData函數(shù)對(duì)init.rc進(jìn)行了讀取與處理布轿,它根據(jù)讀取的內(nèi)容的每個(gè)模塊(eg:Action是on)選擇解析需要的Parse,后對(duì)init.rc中每個(gè)模塊的每一行進(jìn)行了解析。

1.1:實(shí)際解析類的分析

位置/system/core/init/action.cpp ActionParse

//負(fù)責(zé)根據(jù)讀取的args来颤,生成代碼類中的action
bool ActionParser::ParseSection(const std::vector<std::string>& args,
                                std::string* err) {
    std::vector<std::string> triggers(args.begin() + 1, args.end());
    if (triggers.size() < 1) {
        *err = "actions must have a trigger";
        return false;
    }

    auto action = std::make_unique<Action>(false);
    if (!action->InitTriggers(triggers, err)) {
        return false;
    }

    action_ = std::move(action);
    return true;
}

//解析一行指令汰扭,將command加入到它所屬于的action
bool ActionParser::ParseLineSection(const std::vector<std::string>& args,
                                    const std::string& filename, int line,
                                    std::string* err) const {
    return action_ ? action_->AddCommand(args, filename, line, err) : false;
}

//一個(gè)action解析結(jié)束,將解析的action添加到ActionManager中福铅。
void ActionParser::EndSection() {
    if (action_ && action_->NumCommands() > 0) {
        ActionManager::GetInstance().AddAction(std::move(action_));
    }
}

上述代碼是構(gòu)建action和保存action的處理萝毛,到這里init.rc的一個(gè)action就解析完了。ActionManager是所有action的管理類滑黔,所有解析的action都使用一個(gè) std::vector<std::unique_ptr<Action>> actions_ 集合保存下來笆包。

2.Action的執(zhí)行。

    //1 執(zhí)行action與函數(shù)綁定 /system/core/init/builtins.cpp
    const BuiltinFunctionMap function_map;
    Action::set_function_map(&function_map);
  ....

    //2 這里就是上文對(duì)action解析之后形成的ActionManager類略荡, 
    ActionManager& am = ActionManager::GetInstance();
    //執(zhí)行early-init的action
    am.QueueEventTrigger("early-init");

    //查詢手寫action是否已執(zhí)行
    // 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");

    // Trigger all the boot actions to get us started.
    //執(zhí)行action init
    am.QueueEventTrigger("init");

    // 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.
    std::string bootmode = GetProperty("ro.bootmode", "");  //查詢現(xiàn)在啟動(dòng)的模式
    if (bootmode == "charger") {
        am.QueueEventTrigger("charger");    //在充電執(zhí)行action charger
    } else {
        am.QueueEventTrigger("late-init");  //沒有充電執(zhí)行action late-init
    }

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

    while (true) {   //開始循環(huán)庵佣,執(zhí)行actionManager中的每個(gè)action
        // By default, sleep until something happens.
        int epoll_timeout_ms = -1;

        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
            am.ExecuteOneCommand(); // 執(zhí)行action的command
        }
        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
            restart_processes();  //.rc文件中的service, 與actionManager類似由ServiceManager管理。

            // If there's a process that needs restarting, wake up in time for that.
            if (process_needs_restart_at != 0) {
                epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
                if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
            }

            // If there's more work to do, wake up again immediately.
            if (am.HasMoreCommands()) epoll_timeout_ms = 0;
        }

        epoll_event ev;
        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
        if (nr == -1) {
            PLOG(ERROR) << "epoll_wait failed";
        } else if (nr == 1) {
            ((void (*)()) ev.data.ptr)(); //3
        }
    }
  • 注釋1處action與執(zhí)行函數(shù)進(jìn)行綁定汛兜,就是執(zhí)行那個(gè)action就執(zhí)行那個(gè)函數(shù)巴粪,函數(shù)內(nèi)容是在/system/core/init/builtins.cpp文件中。
  • 在就是執(zhí)行action粥谬,和循環(huán)遍歷執(zhí)行全部的action肛根,
  • 代碼3處用是用了epoll句柄(即epoll_fd)主要監(jiān)聽子進(jìn)程結(jié)束,及其它進(jìn)程設(shè)置系統(tǒng)屬性的請(qǐng)求.這里會(huì)處理action啟動(dòng)的進(jìn)程如果死了會(huì)收到進(jìn)程終止信號(hào)量帝嗡,在進(jìn)行重啟進(jìn)程晶通。了解android init進(jìn)程
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市哟玷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌一也,老刑警劉巖巢寡,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異椰苟,居然都是意外死亡抑月,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門舆蝴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谦絮,“玉大人题诵,你說我怎么就攤上這事〔阒澹” “怎么了性锭?”我有些...
    開封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長叫胖。 經(jīng)常有香客問我草冈,道長,這世上最難降的妖魔是什么瓮增? 我笑而不...
    開封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任怎棱,我火速辦了婚禮,結(jié)果婚禮上绷跑,老公的妹妹穿的比我還像新娘拳恋。我一直安慰自己,他們只是感情好砸捏,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開白布诅岩。 她就那樣靜靜地躺著,像睡著了一般带膜。 火紅的嫁衣襯著肌膚如雪吩谦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天膝藕,我揣著相機(jī)與錄音式廷,去河邊找鬼。 笑死芭挽,一個(gè)胖子當(dāng)著我的面吹牛滑废,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播袜爪,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蠕趁,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了辛馆?” 一聲冷哼從身側(cè)響起俺陋,我...
    開封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎昙篙,沒想到半個(gè)月后腊状,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡苔可,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年缴挖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片焚辅。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡映屋,死狀恐怖苟鸯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情棚点,我是刑警寧澤早处,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站乙濒,受9級(jí)特大地震影響陕赃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜颁股,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一么库、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧甘有,春花似錦诉儒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至滤愕,卻和暖如春温算,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背间影。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來泰國打工注竿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人魂贬。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓巩割,卻偏偏與公主長得像,于是被迫代替她去往敵國和親付燥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子宣谈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容