20.Android源碼分析--Zygote進(jìn)程啟動流程

Android系統(tǒng)的Zygote進(jìn)程是所有的android進(jìn)程的父進(jìn)程,包括SystemServer和各種應(yīng)用進(jìn)程都是通過Zygote進(jìn)程fork出來的贡羔。而Zygote進(jìn)程則是通過Linux系統(tǒng)的init進(jìn)程啟動的卒密;

android系統(tǒng)中各種進(jìn)程的啟動方式:
init進(jìn)程 –> Zygote進(jìn)程 –> SystemServer進(jìn)程 –>各種應(yīng)用進(jìn)程

  • init進(jìn)程:linux的根進(jìn)程近弟;android系統(tǒng)是基于linux系統(tǒng)的鉴嗤,因此可以算作是整個android操作系統(tǒng)的第一個進(jìn)程盟劫;
  • Zygote進(jìn)程:android系統(tǒng)的根進(jìn)程;主要作用:fork出SystemServer進(jìn)程和各種應(yīng)用進(jìn)程商架;
  • SystemService進(jìn)程:主要是在這個進(jìn)程中啟動系統(tǒng)的各項服務(wù)堰怨,比如ActivityManagerService,PackageManagerService蛇摸,WindowManagerService服務(wù)等等备图;
  • 各種應(yīng)用進(jìn)程:啟動自己編寫的客戶端應(yīng)用時,一般都是重新啟動一個應(yīng)用進(jìn)程赶袄,有自己的虛擬機(jī)與運行環(huán)境揽涮;

本文主要介紹一下Zygote進(jìn)程的啟動流程,關(guān)于SystenServer進(jìn)程和各種應(yīng)用進(jìn)程的啟動方式會在以后的文章中介紹弃鸦。

1. Zygote類的main方法

init進(jìn)程在啟動Zygote進(jìn)程時一般都會調(diào)用ZygoteInit類的main方法绞吁,因此我們這里看一下該方法的具體實現(xiàn)(基于android23源碼);

public static void main(String argv[]) {
        try {
            RuntimeInit.enableDdms();
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();

            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }

            registerZygoteSocket(socketName);
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
            preload();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());

            // Finish profiling the zygote initialization.
            SamplingProfilerIntegration.writeZygoteSnapshot();

            // Do an initial gc to clean up after startup
            gcAndFinalize();

            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false);

            if (startSystemServer) {
                startSystemServer(abiList, socketName);
            }

            Log.i(TAG, "Accepting command socket connections");
            runSelectLoop(abiList);

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }
  • 第一行是調(diào)用enableDdms()唬格,設(shè)置DDMS可用;可以發(fā)現(xiàn)DDMS啟動的時機(jī)還是比較早的颜说,在整個Zygote進(jìn)程剛剛開始要啟動額時候就設(shè)置可用了购岗;
  • 下面的循環(huán)主要是解析main方法的參數(shù)獲取是否需要啟動SystemService進(jìn)程、獲取abi列表门粪、獲取scoket連接名稱 喊积;
    (這里需要注意的是:android系統(tǒng)中進(jìn)程之間通訊的方式是Binder,但是有一個例外是SystemService進(jìn)程與Zygote進(jìn)程之間是通過Socket的方式進(jìn)行通訊的)
  • 然后調(diào)用registerZygoteSocket(String socketName)為Zygote進(jìn)程注冊socket:

2. main方法中調(diào)用的registerZygoteSocket方法

作用是為Zygote進(jìn)程注冊socket

private static void registerZygoteSocket(String socketName) {
        if (sServerSocket == null) {
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
                String env = System.getenv(fullSocketName);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }

            try {
                FileDescriptor fd = new FileDescriptor();
                fd.setInt$(fileDesc);
                sServerSocket = new LocalServerSocket(fd);
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }

3. 接著調(diào)用系統(tǒng)方法preLoad()

通過Zygote fork出SystemServer進(jìn)程:

static void preload() {
        Log.d(TAG, "begin preload");
        preloadClasses();
        preloadResources();
        preloadOpenGL();
        preloadSharedLibraries();
        preloadTextResources();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();
        Log.d(TAG, "end preload");
    }

這其中:
preloadClasses()用于初始化Zygote中需要的class類玄妈;
preloadResources()用于初始化系統(tǒng)資源乾吻;
preloadOpenGL()用于初始化OpenGL;
preloadSharedLibraries()用于初始化系統(tǒng)libraries拟蜻;
preloadTextResources()用于初始化文字資源绎签;
prepareWebViewInZygote()用于初始化webview;

4. 然后調(diào)用startSystemServer(abiList, socket)方法

private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
        long capabilities = posixCapabilitiesAsBits(
            OsConstants.CAP_BLOCK_SUSPEND,
            OsConstants.CAP_KILL,
            OsConstants.CAP_NET_ADMIN,
            OsConstants.CAP_NET_BIND_SERVICE,
            OsConstants.CAP_NET_BROADCAST,
            OsConstants.CAP_NET_RAW,
            OsConstants.CAP_SYS_MODULE,
            OsConstants.CAP_SYS_NICE,
            OsConstants.CAP_SYS_RESOURCE,
            OsConstants.CAP_SYS_TIME,
            OsConstants.CAP_SYS_TTY_CONFIG
        );
        /* 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,1032,3001,3002,3003,3006,3007",
            "--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);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

            /* Request to fork the system server process */
            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);
            }

            handleSystemServerProcess(parsedArgs);
        }

        return true;
    }

** 總結(jié): **
Zygote進(jìn)程mian方法主要執(zhí)行邏輯:

 - 初始化DDMS;

 - 注冊Zygote進(jìn)程的socket通訊酝锅;

 - 初始化Zygote中的各種類诡必,資源文件,OpenGL搔扁,類庫爸舒,Text資源等等蟋字;

 - 初始化完成之后fork出SystemServer進(jìn)程;

 - fork出SystemServer進(jìn)程之后扭勉,關(guān)閉socket連接鹊奖;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市涂炎,隨后出現(xiàn)的幾起案子忠聚,更是在濱河造成了極大的恐慌,老刑警劉巖璧尸,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咒林,死亡現(xiàn)場離奇詭異,居然都是意外死亡爷光,警方通過查閱死者的電腦和手機(jī)垫竞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛀序,“玉大人欢瞪,你說我怎么就攤上這事⌒炻悖” “怎么了遣鼓?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長重贺。 經(jīng)常有香客問我骑祟,道長,這世上最難降的妖魔是什么气笙? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任次企,我火速辦了婚禮,結(jié)果婚禮上潜圃,老公的妹妹穿的比我還像新娘缸棵。我一直安慰自己,他們只是感情好谭期,可當(dāng)我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布堵第。 她就那樣靜靜地躺著,像睡著了一般隧出。 火紅的嫁衣襯著肌膚如雪踏志。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天鸳劳,我揣著相機(jī)與錄音狰贯,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛涵紊,可吹牛的內(nèi)容都是我干的傍妒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼摸柄,長吁一口氣:“原來是場噩夢啊……” “哼颤练!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起驱负,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤嗦玖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后跃脊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宇挫,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年酪术,在試婚紗的時候發(fā)現(xiàn)自己被綠了器瘪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡绘雁,死狀恐怖橡疼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情庐舟,我是刑警寧澤欣除,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站挪略,受9級特大地震影響历帚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜杠娱,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一抹缕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧墨辛,春花似錦、人聲如沸趴俘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寥闪。三九已至太惠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間疲憋,已是汗流浹背凿渊。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人埃脏。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓搪锣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親彩掐。 傳聞我的和親對象是個殘疾皇子构舟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,630評論 2 359

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