深入了解Android讀書筆記——深入理解init

源碼Android10

init 概述

init進(jìn)程是Linux系統(tǒng)中用戶空間的第一個(gè)進(jìn)程力试,進(jìn)程號(hào)固定為1跋核。啟動(dòng)代碼在 system/core/init/main.cpp

int main(int argc, char** argv) {
#if __has_feature(address_sanitizer)
    __asan_set_error_report_callback(AsanReportCallback);
#endif

    if (!strcmp(basename(argv[0]), "ueventd")) {//不清楚何時(shí)調(diào)用
        return ueventd_main(argc, argv);
    }

    if (argc > 1) {
        if (!strcmp(argv[1], "subcontext")) {//不清楚何時(shí)調(diào)用
            android::base::InitLogging(argv, &android::base::KernelLogger);
            const BuiltinFunctionMap function_map;

            return SubcontextMain(argc, argv, &function_map);
        }

        if (!strcmp(argv[1], "selinux_setup")) {
            return SetupSelinux(argv);
        }

        if (!strcmp(argv[1], "second_stage")) {
            return SecondStageMain(argc, argv);
        }
    }

    return FirstStageMain(argc, argv);
}

已知調(diào)用順序:FirstStageMain --> SetupSelinux --> SecondStageMain

  • FirstStageMain : 掛載及創(chuàng)建基本的文件系統(tǒng)绞惦,并設(shè)置合適的訪問(wèn)權(quán)限; 關(guān)閉默認(rèn)控制臺(tái)輸出偷霉,并初始化內(nèi)核級(jí)log; 掛載 system拘哨、cache疤苹、data 等系統(tǒng)分區(qū)
  • SetupSelinux : 設(shè)置SELinux安全策略
  • SecondStageMain : 核心步驟习勤,下面詳細(xì)解釋

SecondStageMain

SecondStageMain 方法在 system/core/init/init.cpp 中踪栋,下面只列出了核心代碼

int SecondStageMain(int argc, char** argv) {
    
    ...
    
    //初始化屬性服務(wù),并從指定文件讀取屬性
    property_init();
    
    ...
    
    //epoll 中注冊(cè)signalfd,主要是為了創(chuàng)建handler處理子進(jìn)程終止信號(hào)(SIGCHLD)
    InstallSignalFdHandler(&epoll);
    
    ...
    
    //解析init.rc文件图毕,文件在 system/core/rootdir 目錄下
    LoadBootScripts(am, sm);

    ...
    
    //執(zhí)行rc文件中觸發(fā)器為on early-init的語(yǔ)句
    am.QueueEventTrigger("early-init");

     ...
     
    //執(zhí)行rc文件中觸發(fā)器為on init的語(yǔ)句
    am.QueueEventTrigger("init");

    ...

    // 當(dāng)處于充電模式夷都,則charger加入執(zhí)行隊(duì)列;否則late-init加入隊(duì)列予颤。
    std::string bootmode = GetProperty("ro.bootmode", "");
    if (bootmode == "charger") {
        am.QueueEventTrigger("charger");
    } else {
        am.QueueEventTrigger("late-init");
    }

    
    ...

    while (true) {
        // By default, sleep until something happens.
        auto epoll_timeout = std::optional<std::chrono::milliseconds>{};

        if (do_shutdown && !shutting_down) {//關(guān)機(jī)重啟
            do_shutdown = false;
            if (HandlePowerctlMessage(shutdown_command)) {
                shutting_down = true;
            }
        }

        if (!(waiting_for_prop || Service::is_exec_service_running())) {//囤官?
            am.ExecuteOneCommand();
        }
        if (!(waiting_for_prop || Service::is_exec_service_running())) {//重啟進(jìn)程
            if (!shutting_down) {
                auto next_process_action_time = HandleProcessActions();

                // If there's a process that needs restarting, wake up in time for that.
                if (next_process_action_time) {
                    epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
                            *next_process_action_time - boot_clock::now());
                    if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
                }
            }

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

        if (auto result = epoll.Wait(epoll_timeout); !result) {//循環(huán)等待事件發(fā)生
            LOG(ERROR) << result.error();
        }
    }

    return 0;
}

屬性服務(wù)

一般而言,系統(tǒng)或者某些應(yīng)用程序會(huì)把自己的一些屬性存儲(chǔ)在注冊(cè)表中(注冊(cè)表可以存儲(chǔ)一些類似key/value的鍵值對(duì))蛤虐,即使系統(tǒng)重啟或者應(yīng)用程序重啟党饮,它還能根據(jù)之前在注冊(cè)表中設(shè)置的屬性,進(jìn)行相應(yīng)的初始化工作驳庭。Android平臺(tái)也提供了類似的機(jī)制刑顺,稱為屬性服務(wù)。應(yīng)用程序可以通過(guò)這個(gè)屬性機(jī)制查詢或者設(shè)置屬性饲常。

property_init()system/core/init/property_service.cpp 文件中

信號(hào)處理

在Linux內(nèi)核中蹲堂,如父進(jìn)程不等待子進(jìn)程的結(jié)束直接退出,會(huì)導(dǎo)致子進(jìn)程在結(jié)束后變成僵尸進(jìn)程贝淤,占用系統(tǒng)資源柒竞。為此,init進(jìn)程專門安裝了SIGCHLD信號(hào)接收器霹娄,當(dāng)某些子進(jìn)程退出時(shí)發(fā)現(xiàn)其父進(jìn)程已經(jīng)退出能犯,則會(huì)向init進(jìn)程發(fā)送SIGCHLD信號(hào)鲫骗,init進(jìn)程調(diào)用回調(diào)方法handle_signal()來(lái)回收僵尸子進(jìn)程。

init.rc

nit.rc文件在 system/core/rootdir 目錄下

Action

Action: 通過(guò)觸發(fā)器trigger踩晶,即以on開頭的語(yǔ)句來(lái)決定執(zhí)行相應(yīng)的service的時(shí)機(jī)执泰,具體有如下時(shí)機(jī):

on early-init; 在初始化早期階段觸發(fā);
on init; 在初始化階段觸發(fā)渡蜻;
on late-init; 在初始化晚期階段觸發(fā)术吝;
on boot/charger: 當(dāng)系統(tǒng)啟動(dòng)/充電時(shí)觸發(fā),還包含其他情況茸苇,此處不一一列舉排苍;
on property:<key>=<value>: 當(dāng)屬性值滿足條件時(shí)觸發(fā);

Service

服務(wù)Service学密,以 service開頭淘衙,由init進(jìn)程啟動(dòng),一般運(yùn)行在init的一個(gè)子進(jìn)程腻暮,所以啟動(dòng)service前需要判斷對(duì)應(yīng)的可執(zhí)行文件是否存在彤守。init生成的子進(jìn)程,定義在rc文件哭靖,其中每一個(gè)service在啟動(dòng)時(shí)會(huì)通過(guò)fork方式生成子進(jìn)程具垫。

例如: service servicemanager /system/bin/servicemanager代表的是服務(wù)名為servicemanager,服務(wù)執(zhí)行的路徑為/system/bin/servicemanager试幽。

Command

下面列舉常用的命令

class_start <service_class_name>: 啟動(dòng)屬于同一個(gè)class的所有服務(wù)筝蚕;
start <service_name>: 啟動(dòng)指定的服務(wù),若已啟動(dòng)則跳過(guò)铺坞;
stop <service_name>: 停止正在運(yùn)行的服務(wù)
setprop <name> <value>:設(shè)置屬性值
mkdir <path>:創(chuàng)建指定目錄
symlink <target> <sym_link>: 創(chuàng)建連接到<target>的<sym_link>符號(hào)鏈接起宽;
write <path> <string>: 向文件path中寫入字符串;
exec: fork并執(zhí)行康震,會(huì)阻塞init進(jìn)程直到程序完畢燎含;
exprot <name> <name>:設(shè)定環(huán)境變量;
loglevel <level>:設(shè)置log級(jí)別
trigger command :觸發(fā)命令

Options

Options是Service的可選項(xiàng)腿短,與service配合使用

disabled: 不隨class自動(dòng)啟動(dòng)屏箍,只有根據(jù)service名才啟動(dòng);
oneshot: service退出后不再重啟橘忱;
user/group: 設(shè)置執(zhí)行服務(wù)的用戶/用戶組赴魁,默認(rèn)都是root;
class:設(shè)置所屬的類名钝诚,當(dāng)所屬類啟動(dòng)/退出時(shí)颖御,服務(wù)也啟動(dòng)/停止,默認(rèn)為default;
onrestart:當(dāng)服務(wù)重啟時(shí)執(zhí)行相應(yīng)命令潘拱;
socket: 創(chuàng)建名為/dev/socket/<name>的socket
critical: 在規(guī)定時(shí)間內(nèi)該service不斷重啟疹鳄,則系統(tǒng)會(huì)重啟并進(jìn)入恢復(fù)模式
default: 意味著disabled=false,oneshot=false芦岂,critical=false瘪弓。

參考

http://gityuan.com/2016/02/05/android-init/
https://www.imgeek.org/article/825358229
https://juejin.cn/post/6998441504364560420/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市禽最,隨后出現(xiàn)的幾起案子腺怯,更是在濱河造成了極大的恐慌,老刑警劉巖川无,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件呛占,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡懦趋,警方通過(guò)查閱死者的電腦和手機(jī)晾虑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)仅叫,“玉大人走贪,你說(shuō)我怎么就攤上這事』蟀牛” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵继找,是天一觀的道長(zhǎng)遂跟。 經(jīng)常有香客問(wèn)我,道長(zhǎng)婴渡,這世上最難降的妖魔是什么幻锁? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮边臼,結(jié)果婚禮上哄尔,老公的妹妹穿的比我還像新娘。我一直安慰自己柠并,他們只是感情好岭接,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著臼予,像睡著了一般鸣戴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上粘拾,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天窄锅,我揣著相機(jī)與錄音,去河邊找鬼缰雇。 笑死入偷,一個(gè)胖子當(dāng)著我的面吹牛追驴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播疏之,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼殿雪,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了体捏?” 一聲冷哼從身側(cè)響起冠摄,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎几缭,沒想到半個(gè)月后河泳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡年栓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年拆挥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片某抓。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡纸兔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出否副,到底是詐尸還是另有隱情汉矿,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布备禀,位于F島的核電站洲拇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏曲尸。R本人自食惡果不足惜赋续,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望另患。 院中可真熱鬧纽乱,春花似錦、人聲如沸昆箕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)鹏倘。三九已至敛熬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間第股,已是汗流浹背应民。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诲锹。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓繁仁,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親归园。 傳聞我的和親對(duì)象是個(gè)殘疾皇子黄虱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

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