Zygote接收到AMS消息到啟動ActivityThread流程

系統(tǒng)啟動過程

啟動Zygote進(jìn)程:
啟動過程開始于Zygote進(jìn)程贡羔,當(dāng)啟動一個應(yīng)用時葵袭,Zygote進(jìn)程會被復(fù)用以創(chuàng)建新的應(yīng)用進(jìn)程涵妥。

這里是ZygoteInit.main的主要作用,它是Zygote進(jìn)程的入口:

public class ZygoteInit {
    public static void main(String argv[]) {
        // ... 省略的一些前期初始化代碼

        // 啟動系統(tǒng)服務(wù)進(jìn)程
        if (startSystemServer) {
            startSystemServer(forkedProcesses);
        }

        // 進(jìn)入Zygote的主循環(huán)
        Runnable caller;
        try {
            caller = zygoteServer.runSelectLoop();
        } catch (Throwable ex) {
          // ... 處理異常
        }

        // 運行子進(jìn)程初始化代碼
        if (caller != null) {
            caller.run();
        }
    }
}
1坡锡、Zygote連接處理:
Zygote進(jìn)程在初始化后會進(jìn)入一個循環(huán)蓬网,等待來自ActivityManagerService(AMS)的進(jìn)程啟動請求块请。這是在runSelectLoop中處理的。

ZygoteServer.runSelectLoop 在后臺等待連接請求:

public class ZygoteServer {
    Runnable runSelectLoop() {
        while (true) {
            // 等待AMS連接
            ZygoteConnection connection = acceptCommandPeer();
            return connection.processOneCommand(); // 這里實際上是處理一個命令
        }
    }
}
2拳缠、處理啟動命令:
在接收到啟動請求后墩新,ZygoteConnection.processOneCommand 方法負(fù)責(zé)處理實際啟動參數(shù)。

public class ZygoteConnection {
    Runnable processOneCommand() {
        // 解析啟動參數(shù)
        Arguments args = readArgumentList();

        // 調(diào)用Zygote來fork新進(jìn)程
        Zygote.forkAndSpecialize(...);

        if (pid == 0) {
            // 子進(jìn)程執(zhí)行到這里
            return handleChildProc(args, descriptors, childPipeFd, newStderr);
        } else {
            // 父進(jìn)程(Zygote進(jìn)程)執(zhí)行到這里
            ...
        }
    }
}
這 就是說窟坐,handleChildProc 方法在子進(jìn)程中被調(diào)用海渊,這里新啟動的進(jìn)程會完成初始化:

3. handleChildProc
handleChildProc 負(fù)責(zé)處理子進(jìn)程的初始化。

public class ZygoteConnection {
    private Runnable handleChildProc(Arguments parsedArgs) {
        // 初始化子進(jìn)程
        return RuntimeInit.wrapperInit(parsedArgs);
    }
}
4. RuntimeInit.wrapperInit
RuntimeInit.wrapperInit 是實際啟動應(yīng)用進(jìn)程的方法哲鸳。

public class RuntimeInit {
    public static Runnable wrapperInit(Arguments args) {
        return applicationInit(args);
    }
    private static Runnable applicationInit(Arguments args) {
        return invokeStaticMain(args.startClass, args.startArgs, null);
    }
    protected static Runnable invokeStaticMain(String className, String[] argv, ClassLoader classLoader) {
        // 反射調(diào)用main方法
        Class<?> cl;
        try {
            cl = Class.forName(className);
            Method m = cl.getMethod("main", new Class[] { String[].class });
            m.invoke(null, new Object[]{argv});
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
        return null;
    }
}
5. ActivityThread.main
以上步驟最終會調(diào)用到ActivityThread.main方法臣疑,這是實際應(yīng)用進(jìn)程的入口。

public class ActivityThread {
    public static void main(String[] args) {
        // 主線程初始化
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        Looper.loop();
    }
}

總結(jié)

整個調(diào)用鏈從Zygote接收啟動參數(shù)到涉及到的主要過程如下:
ZygoteInit.main: 啟動進(jìn)程徙菠,并進(jìn)入等待循環(huán)讯沈。
ZygoteServer.runSelectLoop: 等待并處理啟動請求。
ZygoteConnection.processOneCommand: 解析并fork新的進(jìn)程婿奔。
RuntimeInit.wrapperInit: 完成子進(jìn)程進(jìn)一步初始化缺狠。
RuntimeInit.applicationInit: 通過反射調(diào)用指定類的main方法。
ActivityThread.main: 啟動應(yīng)用主線程萍摊。

接下來看看AMS是怎么傳輸Socket數(shù)據(jù)給Zygote的

在ActivityManagerService(AMS)中挤茄,有關(guān)啟動應(yīng)用進(jìn)程并通過Socket請求發(fā)送給Zygote的部分,主要是通過startProcessLocked方法來實現(xiàn)冰木。這個方法會調(diào)用Process.start方法穷劈,并通過Zygote發(fā)送啟動請求。在啟動參數(shù)中傳遞了android.app.ActivityThread踊沸。

具體的流程如下:

1. ActivityManagerService.startProcessLocked
ActivityManagerService的startProcessLocked方法負(fù)責(zé)啟動新進(jìn)程:

public class ActivityManagerService {
    private boolean startProcessLocked(ProcessRecord app, ...) {
        ...
        // 調(diào)用Process.start來啟動進(jìn)程
        Process.ProcessStartResult startResult = Process.start(
                "android.app.ActivityThread", // 這里指定類名
                app.processName, ...);
        ...
    }
}
2. Process.start
Process.start方法負(fù)責(zé)創(chuàng)建并啟動一個新的應(yīng)用進(jìn)程:

public class Process {
    public static ProcessStartResult start(
            String processClass, // 這里是傳入的 "android.app.ActivityThread"
            String niceName,
            ...
            ) {
        ...
        try {
            return startViaZygote(processClass, niceName, ...);
        } catch (RuntimeException e) {
            ...
        }
    }

    private static ProcessStartResult startViaZygote(
            String processClass,
            String niceName,
            ...
            ) {
        ...
        // 創(chuàng)建啟動參數(shù)列表
        ArrayList<String> argsForZygote = new ArrayList<String>();

        // 傳遞啟動組件類名
        argsForZygote.add("--runtime-args");
        argsForZygote.add("--setuid=" + uid);
        argsForZygote.add("--setgid=" + gid);
        argsForZygote.add("-classpath");
        argsForZygote.add("--nice-name=" + niceName);
        argsForZygote.add(processClass); // 傳入的類名

        // 調(diào)用Zygote來啟動進(jìn)程
        ProcessStartResult result = ZygoteProcess.zygoteSendArgsAndGetResult(
                openZygoteSocketIfNeeded(abi), argsForZygote);
        ...
        return result;
    }
}
3. ZygoteProcess.zygoteSendArgsAndGetResult
這個方法通過Socket將啟動參數(shù)發(fā)送給Zygote進(jìn)程:

public class ZygoteProcess {
    public Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
            // 獲取Zygote進(jìn)程的Socket連接
            DataOutputStream zygoteWriter = zygoteState.mZygoteOutputWriter;

            // 發(fā)送啟動參數(shù)
            for (String arg : args) {
                zygoteWriter.writeBytes(arg + "\n");
            }

            // 獲取啟動結(jié)果
            ProcessStartResult result = new ProcessStartResult();
            result.pid = zygoteState.mZygoteInputStream.readInt();
            ...
            return result;
        } catch (IOException ex) {
            throw new ZygoteStartFailedEx(ex);
        }
    }
}
傳遞給Zygote的參數(shù)
從上述代碼可以看到歇终,Process.start方法最終構(gòu)建了一個參數(shù)列表argsForZygote,其中包括要啟動的類名android.app.ActivityThread逼龟,并通過ZygoteProcess.zygoteSendArgsAndGetResult發(fā)送到Zygote進(jìn)程评凝。

4. 接受請求并啟動進(jìn)程的Zygote代碼
回到之前的細(xì)節(jié):

ZygoteServer.runSelectLoop
Zygote進(jìn)程在啟動后,會進(jìn)入一個循環(huán)等待AMS的請求:

public class ZygoteServer {
    Runnable runSelectLoop() {
        while (true) {
            ZygoteConnection connection = acceptCommandPeer();
            return connection.processOneCommand();
        }
    }
}
ZygoteConnection.processOneCommand
在接受到啟動請求后审轮,Zygote進(jìn)程通過processOneCommand方法處理請求:

public class ZygoteConnection {
    Runnable processOneCommand() {
        // 讀取并解析參數(shù)
        Arguments args = readArgumentList();
        // Fork新的進(jìn)程
        int pid = Zygote.forkAndSpecialize(args);
        if (pid == 0) {
            // 子進(jìn)程處理
            return handleChildProc(args);
        } else {
            // 父進(jìn)程處理
            ...
        }
    }
}

總結(jié)
總結(jié)來說肥哎,關(guān)于傳遞類名android.app.ActivityThread的調(diào)用鏈如下:

ActivityManagerService.startProcessLocked: 調(diào)用Process.start方法,傳入類名android.app.ActivityThread疾渣。
Process.start: 調(diào)用startViaZygote篡诽,構(gòu)建參數(shù)列表并調(diào)用ZygoteProcess.zygoteSendArgsAndGetResult。
ZygoteProcess.zygoteSendArgsAndGetResult: 通過Socket將啟動參數(shù)發(fā)給Zygote進(jìn)程榴捡。
ZygoteServer.runSelectLoop: 接受并處理啟動請求琅豆。
ZygoteConnection.processOneCommand: 解析啟動參數(shù)并fork新進(jìn)程统捶。
handleChildProc: 初始化新進(jìn)程蒿讥,最終調(diào)用RuntimeInit.zygoteInit,并反射調(diào)用ActivityThread.main翰蠢。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市啰劲,隨后出現(xiàn)的幾起案子梁沧,更是在濱河造成了極大的恐慌,老刑警劉巖蝇裤,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件廷支,死亡現(xiàn)場離奇詭異,居然都是意外死亡栓辜,警方通過查閱死者的電腦和手機(jī)恋拍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來藕甩,“玉大人施敢,你說我怎么就攤上這事∠晾常” “怎么了僵娃?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長贩毕。 經(jīng)常有香客問我悯许,道長,這世上最難降的妖魔是什么辉阶? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮瘩扼,結(jié)果婚禮上谆甜,老公的妹妹穿的比我還像新娘。我一直安慰自己集绰,他們只是感情好规辱,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著栽燕,像睡著了一般罕袋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上碍岔,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天浴讯,我揣著相機(jī)與錄音,去河邊找鬼蔼啦。 笑死榆纽,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奈籽,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼饥侵,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了衣屏?” 一聲冷哼從身側(cè)響起躏升,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎狼忱,沒想到半個月后煮甥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡藕赞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年成肘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斧蜕。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡双霍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出批销,到底是詐尸還是另有隱情洒闸,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布均芽,位于F島的核電站丘逸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏掀宋。R本人自食惡果不足惜深纲,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望劲妙。 院中可真熱鬧湃鹊,春花似錦、人聲如沸镣奋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽侨颈。三九已至余赢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間哈垢,已是汗流浹背妻柒。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留温赔,地道東北人蛤奢。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓鬼癣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親啤贩。 傳聞我的和親對象是個殘疾皇子待秃,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

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