【Android源碼分析】Android系統(tǒng)關(guān)鍵服務(wù)啟動簡析

一、關(guān)于Android系統(tǒng)重要的進(jìn)程

(1)、init進(jìn)程:init進(jìn)程是Linux內(nèi)核啟動完成之后,啟動的第一個(gè)用戶進(jìn)程,Android系統(tǒng)就是在這個(gè)進(jìn)程的基礎(chǔ)上啟動起來的,進(jìn)程pid為1。init進(jìn)程通過解析init.rc來陸續(xù)啟動其他關(guān)鍵的系統(tǒng)服務(wù)進(jìn)程---其中最重要的是:ServiceManagerZygoteSystemServer

init進(jìn)程.png

(2)、ServiceManager:主要負(fù)責(zé)添加服務(wù),獲取服務(wù),查找服務(wù)以及當(dāng)某個(gè)服務(wù)意外終止時(shí),對該服務(wù)的資源進(jìn)行回收。
(3)、Zygote進(jìn)程:Zygote是一個(gè)孵化器進(jìn)程,所有的應(yīng)用程序進(jìn)程以及系統(tǒng)服務(wù)進(jìn)程SystemServer都是由Zygote進(jìn)程fork出來的。在Zygote中進(jìn)行添加虛擬機(jī)參數(shù),并將其啟動起來,然后注冊JNI函數(shù)。在Zygote中進(jìn)行預(yù)加載以及初始化核心類庫。最后將SystemServer啟動起來。
(4)、SystemServer:啟動系統(tǒng)各項(xiàng)服務(wù)。

zygote_servicemanager_systemserver.png

二、init.rc腳本語法規(guī)則

service <name> <pathname> [ <argument> ]*   //service的名字,啟動路徑,以及參數(shù)
   <option>      
   <option>
    ...

<name>:
表示此service的名稱
<pathname>:
此service所在的路徑。因?yàn)槭强蓤?zhí)行文件,所以一定有存儲路徑。
<argument>:
啟動service所帶的參數(shù)。
<option>:
對此service的約束選項(xiàng)。
具體請參考:【Android源碼分析】init.rc語法

三、ServiceManager,Zygote,SystemServer的啟動簡析

3.1 ServiceManager

? ? ? ?ServiceManager是Binder機(jī)制中的“DNS服務(wù)器”,負(fù)責(zé)域名(某Binder服務(wù)在ServiceManager注冊時(shí)提供的名稱)IP地址(由底層Binder驅(qū)動分配的值)的解析。
? ? ? ?ServiceManager是在servicemanager.rc(Android8.0)里面描述,并由init進(jìn)程啟動。

/*android-8.0.0_r1\frameworks\native\cmds\servicemanager\servicemanager.rc*/
service servicemanager /system/bin/servicemanager
    class core animation
    user system
    group system readproc
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart audioserver
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart inputflinger
    onrestart restart drm
    onrestart restart cameraserver
    writepid /dev/cpuset/system-background/tasks

? ? ? ?可以看到,Servicemanager是一個(gè)Linux程序。它在設(shè)備中的存儲路徑是:/system/bin/servicemanager,源碼路徑則是:
android-8.0.0_r1\frameworks\native\cmds\servicemanager\servicemanager.c

servicemanager_src_path.png

? ? ? ?ServiceManager所屬的classcore,其他同類的系統(tǒng)進(jìn)程包括ueventd,console(/system/bin/sh),adbd等。根據(jù)core組的特性,這些進(jìn)程會同時(shí)被啟動或停止。另外,critical選項(xiàng)說明它是系統(tǒng)的關(guān)鍵進(jìn)程---意味著如果進(jìn)程不幸在4分鐘內(nèi)異常退出超過4次,則設(shè)備將重啟并進(jìn)入還原模式。當(dāng)ServiceManager每次重啟是,其他關(guān)鍵進(jìn)程如zygote,media,surfaceflinger等也會被restart。

3.2 Zygote

? ? ? ?在Android系統(tǒng)中,所有的應(yīng)用程序進(jìn)程以及系統(tǒng)服務(wù)進(jìn)程SystemServer都是由Zygote進(jìn)程孕育(fork)出來的,因?yàn)锳ndroid系統(tǒng)是基于Linux內(nèi)核的,而在Linux系統(tǒng)中,所有的進(jìn)程都是init進(jìn)程的子孫進(jìn)程,也就是說,所有的進(jìn)程都是直接或者間接地由init進(jìn)程fork出來的。Zygote進(jìn)程也不例外,它是在系統(tǒng)啟動的過程,由init進(jìn)程創(chuàng)建的,在系統(tǒng)啟動腳本android-8.0.0_r1\system\core\rootdir\init.*.rc文件中,我們可以看到啟動Zygote進(jìn)程的腳本命令:摘自【Android Zygote系統(tǒng)進(jìn)程啟動過程分析(Android N)】

/*android-8.0.0_r1\system\core\rootdir\init.*.rc*/例如:init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks


從上面這段腳本描述可以看出:
ServiceName:zygote
Path:/system/bin/app_process
Arguments:-Xzygote /system/bin --zygote --start-system-server

? ? ? ?Zygote所屬classmain,而不是core。和其同class的系統(tǒng)進(jìn)程有netd,debuggerd,rild等。從zygote的path可以看出,它所在的應(yīng)用程序名叫"app_process"。通過指定--zygote參數(shù),app_process可以識別出用戶是否需要啟動zygote。
"app_process"程序源碼路徑在:android-8.0.0_r1\frameworks\base\cmds\app_process\app_main.cpp中。

app_process_path.png

android-8.0.0_r1\frameworks\base\cmds\app_process\Android.mk主要內(nèi)容:

LOCAL_SRC_FILES:= \
    app_main.cpp

LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic

LOCAL_SHARED_LIBRARIES := \
    libdl \
    libcutils \
    libutils \
    liblog \
    libbinder \
    libnativeloader \
    libandroid_runtime \
    $(app_process_common_shared_libs) \

LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain

LOCAL_MODULE:= app_process

"app_process"的源碼路徑在:
android-8.0.0_r1\frameworks\base\cmds\app_process\app_main.cpp
其主要函數(shù):

int main(int argc, char* const argv[])
{
    ...
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));

    // After the parent dir, we expect one or more the following internal
    // arguments :
    //
    // --zygote : Start in zygote mode
    // --start-system-server : Start the system server.
    // --application : Start in application (stand alone, non zygote) mode.
    // --nice-name : The nice name for this process.


    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }

    Vector<String8> args;
    if (!className.isEmpty()) {
        // We're not in zygote mode, the only argument we need to pass
        // to RuntimeInit is the application argument.
        //
        // The Remainder of args get passed to startup class main(). Make
        // copies of them before we overwrite them with the process name.
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);
    } else {
        // We're in zygote mode.
        maybeCreateDalvikCache();

        if (startSystemServer) {
            args.add(String8("start-system-server"));
        }

        char prop[PROP_VALUE_MAX];
        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
                ABI_LIST_PROPERTY);
            return 11;
        }

        String8 abiFlag("--abi-list=");
        abiFlag.append(prop);
        args.add(abiFlag);

        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }

    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }

    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
        return 10;
    }
}

因?yàn)椋诖薸nit.rc指定了--zygote選項(xiàng),因而app_process接下來將啟動"ZygoteInit"并傳入"start-system-server"。
AppRuntime 繼承自AndroidRuntime,所以,runtime.start()函數(shù)對應(yīng)源碼:
android-8.0.0_r1\frameworks\base\core\jni\AndroidRuntime.cpp

AndroidRuntime_path.png

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {//啟動虛擬機(jī)
        return;
    }
    onVmCreated(env);//虛擬機(jī)啟動后的回調(diào)

    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

...

}

除了與裝載各種系統(tǒng)類(具體實(shí)現(xiàn)在ZygoteInit#preload()這個(gè)方法里)外,ZygoteInit的另一個(gè)重要工作就是啟動SystemServer---這是大部分Android系統(tǒng)服務(wù)(由Java語言編寫)的所在地。

3.3 SystemServer(Android的系統(tǒng)服務(wù))

? ? ? ?SystemServer是Android進(jìn)入Laucher前的最后準(zhǔn)備。
? ? ? ?一旦在init.rc中為zygote指定了啟動參數(shù)--start-system-server,那么ZygoteInit就會調(diào)用startSystemServer來啟動SystemServer。

    private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)
            throws Zygote.MethodAndArgsCaller, RuntimeException {
       ...
        /* Hardcoded command line to start the system server */
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

        try {
            parsedArgs = new ZygoteConnection.Arguments(args);
            ...
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            handleSystemServerProcess(parsedArgs);
        }

        return true;
    }

? ? ? ?根據(jù)fork的特性,子進(jìn)程和父進(jìn)程將獲得同樣的代碼環(huán)境。當(dāng)變量pid值為0時(shí),說明是子進(jìn)程,否則是父進(jìn)程;如果是前者的話,則進(jìn)一步調(diào)用handleSystemServerProcess來完成剩下的工作,也是最核心的部分---啟動各種系統(tǒng)服務(wù)。并在一切準(zhǔn)備就緒后進(jìn)入Launcher主界面。

說明:本篇博客,主要為源碼分析、學(xué)習(xí)筆記總結(jié),部分內(nèi)容摘自《深入理解Android內(nèi)核設(shè)計(jì)思想》。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,998評論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,993評論 2 374

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