Android進(jìn)程的創(chuàng)建

在上一篇《Zygote啟動(dòng)流程》中已經(jīng)了解到硅急,ZygoteInit.java的main函數(shù)中會(huì)去創(chuàng)建ServerSocket时甚,創(chuàng)建應(yīng)用進(jìn)程時(shí)泻仙,AMS會(huì)連接ServerSocket發(fā)起創(chuàng)建進(jìn)程的請(qǐng)求屑那。因此AMS是Socket Client端拱镐,Zygote是Socket Server端艘款,創(chuàng)建進(jìn)程時(shí),Client連接Server端發(fā)起創(chuàng)建進(jìn)程的請(qǐng)求沃琅。

一哗咆、Client端(AMS)

首先來(lái)了解下AMS發(fā)起創(chuàng)建進(jìn)程請(qǐng)求的流程,以下是流程時(shí)序圖益眉。

AMS發(fā)送啟動(dòng)應(yīng)用時(shí)序圖

在調(diào)用AMS的startProcessLocked函數(shù)來(lái)向Zygote發(fā)起fork進(jìn)程的求情晌柬,在AMS中startProcessLocked函數(shù)最終會(huì)調(diào)用startProcess函數(shù),首先看下startProcess函數(shù)郭脂。

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

private ProcessStartResult startProcess(String hostingType, String entryPoint,
            ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
            String seInfo, String requiredAbi, String instructionSet, String invokeWith,
            long startTime) {
        try {
            ......
            final ProcessStartResult startResult;
            if (hostingType.equals("webview_service")) {
                ......
            } else {
                startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith,
                        new String[] {PROC_START_SEQ_IDENT + app.startSeq});
            }
            ......
        } finally {
            ......
        }
    }

startProcess函數(shù)接著會(huì)調(diào)用Process的start函數(shù)來(lái)發(fā)起fork進(jìn)程請(qǐng)求年碘,接下來(lái)研究下Process的start函數(shù)。

/frameworks/base/core/java/android/os/Process.java

public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int runtimeFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String invokeWith,
                                  String[] zygoteArgs) {
        return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
    }

Process的start函數(shù)又跳轉(zhuǎn)到ZygoteProcess.start函數(shù)朱庆。

/frameworks/base/core/java/android/os/ZygoteProcess.java

public final Process.ProcessStartResult start(final String processClass,
                                                  final String niceName,
                                                  int uid, int gid, int[] gids,
                                                  int runtimeFlags, int mountExternal,
                                                  int targetSdkVersion,
                                                  String seInfo,
                                                  String abi,
                                                  String instructionSet,
                                                  String appDataDir,
                                                  String invokeWith,
                                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, false /* startChildZygote */,
                    zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            ......
        }
    }

繼續(xù)跳轉(zhuǎn)到startViaZygote函數(shù)

private Process.ProcessStartResult startViaZygote(final String processClass,
                                                      final String niceName,
                                                      final int uid, final int gid,
                                                      final int[] gids,
                                                      int runtimeFlags, int mountExternal,
                                                      int targetSdkVersion,
                                                      String seInfo,
                                                      String abi,
                                                      String instructionSet,
                                                      String appDataDir,
                                                      String invokeWith,
                                                      boolean startChildZygote,
                                                      String[] extraArgs)
                                                      throws ZygoteStartFailedEx {
        ArrayList<String> argsForZygote = new ArrayList<String>();

        .....
        //初始化進(jìn)程的啟動(dòng)參數(shù)列表argsForZygote邏輯
        synchronized(mLock) {
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

接下來(lái)先看下openZygoteSocketIfNeeded函數(shù)盛泡,該函數(shù)主要是調(diào)用ZygoteState.connect函數(shù)連接ZygoteInit.main函數(shù)中創(chuàng)建的ServerSocket,這個(gè)在《Zygote啟動(dòng)流程》中已經(jīng)說(shuō)過(guò)娱颊,ZygoteState就是ZygoteProcess的一個(gè)靜態(tài)內(nèi)部類傲诵,主要是維持Zygote進(jìn)程socket服務(wù)的連接邏輯,ZygoteState.connet函數(shù)也是連接socket箱硕。

private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");

        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
                primaryZygoteState = ZygoteState.connect(mSocket);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
            }
            maybeSetApiBlacklistExemptions(primaryZygoteState, false);
            maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
        }
        if (primaryZygoteState.matches(abi)) {
            return primaryZygoteState;
        }

        // The primary zygote didn't match. Try the secondary.
        if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
            try {
                secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
            } catch (IOException ioe) {
                throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
            }
            maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
            maybeSetHiddenApiAccessLogSampleRate(secondaryZygoteState);
        }

        if (secondaryZygoteState.matches(abi)) {
            return secondaryZygoteState;
        }

        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
    }

再看下zygoteSendArgsAndGetResult函數(shù)拴竹。

private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
            ......
            //將要?jiǎng)?chuàng)建的應(yīng)用進(jìn)程啟動(dòng)參數(shù)傳給ZygoteState對(duì)象中
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;

            writer.write(Integer.toString(args.size()));
            writer.newLine();

            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                writer.write(arg);
                writer.newLine();
            }

            writer.flush();
            Process.ProcessStartResult result = new Process.ProcessStartResult();

            //通過(guò)Socket讀取Zygote建成功的進(jìn)程PID
            // Socket 對(duì)端的請(qǐng)求在 ZygoteInit.runSelectLoop中進(jìn)行處理
            result.pid = inputStream.readInt();
            result.usingWrapper = inputStream.readBoolean();

            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
    }

二、Server端(Zygote)

AMS發(fā)起創(chuàng)建進(jìn)程請(qǐng)求剧罩,Zygote端接受請(qǐng)求的流程栓拜。《Zygote啟動(dòng)流程》中已經(jīng)分析了ZygoteInit.main函數(shù)會(huì)創(chuàng)建ServerSocket惠昔,且在ZygoteServer.java.runSelectLoop等待AMS連接和發(fā)起請(qǐng)求幕与。

Zygote創(chuàng)建進(jìn)程時(shí)序圖

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public static void main(String argv[]) {
    ......
    try {
        ......
        //創(chuàng)建Server Socket
        zygoteServer.registerServerSocketFromEnv(socketName);
        ......
        //等待AMS socket連接,請(qǐng)求fork新進(jìn)程
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with exception", ex);
        throw ex;
    } finally {
        zygoteServer.closeServerSocket();
    }
    ......
}

ZygoteInit.main函數(shù)中會(huì)調(diào)用zygoteServer.registerServerSocketFromEnv創(chuàng)建一個(gè)LocalServerSocket對(duì)象镇防,該對(duì)象封裝了ServerSocket邏輯啦鸣。 zygoteServer.runSelectLoop(abiList)函數(shù)會(huì)調(diào)用LocalServerSocket.accept函數(shù)和ZygoteConnection.processOneCommand函數(shù),accept函數(shù)等待客戶端的連接来氧,processOneCommand函數(shù)處理fork進(jìn)程邏輯诫给,這個(gè)在《Zygote啟動(dòng)流程》已經(jīng)了解過(guò)。

ZygoteConnection.processOneCommand函數(shù)主要執(zhí)行這三個(gè)操作:

  • 1.調(diào)用 Zygote.forkAndSpecialize 進(jìn)行進(jìn)程復(fù)制操作
  • 2.調(diào)用 handleChildProc 處理新建進(jìn)程資源初始化啦扬,如創(chuàng)建 Binder 線程池中狂,啟動(dòng)一個(gè)主線程消息隊(duì)列
  • 3.調(diào)用 handleParentProc 將新建進(jìn)程的 PID 返回給 system_server,表示創(chuàng)建結(jié)果扑毡。

frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

Runnable processOneCommand(ZygoteServer zygoteServer) {
    ......
    //fork 進(jìn)程胃榕,
    //pid == 0:新進(jìn)程,調(diào)用handleChildProc
    //pid != 0:當(dāng)前進(jìn)程瞄摊,調(diào)用handleParentProc
    pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
            parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
            parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
            parsedArgs.instructionSet, parsedArgs.appDataDir);

    try {
        if (pid == 0) {
            // in child
            // 創(chuàng)建出的新進(jìn)程
            zygoteServer.setForkChild();

            zygoteServer.closeServerSocket();//關(guān)閉socket
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;

            return handleChildProc(parsedArgs, descriptors, childPipeFd,
                    parsedArgs.startChildZygote);
        } else {
            // In the parent. A pid < 0 indicates a failure and will be handled in
            // handleParentProc.
            // 父進(jìn)程將在這里進(jìn)行處理
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            handleParentProc(pid, descriptors, serverPipeFd);
            return null;
        }
    } finally {
        ......
    }
}

Zygote.forkAndSpecialize函數(shù)>Zygote.forkAndSpecialize>Zygote.nativeForkAndSpecialize來(lái)fork進(jìn)程勤晚。

public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
          int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) {
        VM_HOOKS.preFork();
        // Resets nice priority for zygote process.
        resetNicePriority();
        int pid = nativeForkAndSpecialize(
                  uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                  fdsToIgnore, startChildZygote, instructionSet, appDataDir);
        ......
    }

fork進(jìn)程返回pid == 0則是新進(jìn)程枉层,會(huì)調(diào)用zygoteServer.closeServerSocket();關(guān)閉socket,還會(huì)調(diào)用handleChildProc函數(shù)執(zhí)行ZygoteInit.zygoteInit()赐写。

private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
            FileDescriptor pipeFd, boolean isZygote) {
        closeSocket();
        ......
        if (parsedArgs.invokeWith != null) {
            ......
        } else {
            if (!isZygote) {// 新建應(yīng)用進(jìn)程時(shí)isZygote=false
                return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,
                        null /* classLoader */);
            } else {
                return ZygoteInit.childZygoteInit(parsedArgs.targetSdkVersion,
                        parsedArgs.remainingArgs, null /* classLoader */);
            }
        }
    }

ZygoteInit.zygoteInit()主要邏輯:

  • 1.nativeZygoteInit啟動(dòng)App進(jìn)程的Binder線程池
  • 2.applicationInit反射執(zhí)行ActivityThread.main函數(shù)
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
        ......
        ZygoteInit.nativeZygoteInit();//初始化Binder線程
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

RuntimeInit.applicationInit>RuntimeInit.findStaticMain>RuntimeInit.MethodAndArgsCaller 就是利用反射調(diào)用main函數(shù)鸟蜡。

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
        ......
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }
protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;

        try {
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }

        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException(
                    "Missing static main on " + className, ex);
        } catch (SecurityException ex) {
            throw new RuntimeException(
                    "Problem getting static main on " + className, ex);
        }

        int modifiers = m.getModifiers();
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException(
                    "Main method is not public and static on " + className);
        }

        /*
         * This throw gets caught in ZygoteInit.main(), which responds
         * by invoking the exception's run() method. This arrangement
         * clears up all the stack frames that were required in setting
         * up the process.
         */
        return new MethodAndArgsCaller(m, argv);
    }
static class MethodAndArgsCaller implements Runnable {
        ......
        public void run() {
            try {
                mMethod.invoke(null, new Object[] { mArgs });
            } catch (IllegalAccessException ex) {
                throw new RuntimeException(ex);
            } catch (InvocationTargetException ex) {
                ......
            }
        }
    }

我們來(lái)驗(yàn)證下,可以在Activity.onCreate函數(shù)中執(zhí)行Log.d(TAG, Log.getStackTraceString(new Throwable()));函數(shù)打印堆棧挺邀。

堆棧順序

ZygoteInit.main>ZygoteInit$MethodAndArgsCaller.run>Method.invoke>ActivityThread.main

該堆棧跟分析的流程一致揉忘。代碼如下:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "[lynnlee]";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, Log.getStackTraceString(new Throwable()));
    }
}

ActivityOncreate函數(shù)打印堆棧結(jié)果:

com.lynnlee.myapplication D/[lynnlee]: java.lang.Throwable
        at com.lynnlee.myapplication.MainActivity.onCreate(MainActivity.java:19)
        at android.app.Activity.performCreate(Activity.java:6309)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1114)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2467)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2574)
        at android.app.ActivityThread.access$1000(ActivityThread.java:166)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1411)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5563)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:853)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:737)

參考資料
https://blog.csdn.net/weixin_34335458/article/details/87992608
《Android進(jìn)階解密》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市端铛,隨后出現(xiàn)的幾起案子泣矛,更是在濱河造成了極大的恐慌,老刑警劉巖禾蚕,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件您朽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡换淆,警方通過(guò)查閱死者的電腦和手機(jī)哗总,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)倍试,“玉大人讯屈,你說(shuō)我怎么就攤上這事∠叵埃” “怎么了涮母?”我有些...
    開(kāi)封第一講書人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)躁愿。 經(jīng)常有香客問(wèn)我叛本,道長(zhǎng),這世上最難降的妖魔是什么彤钟? 我笑而不...
    開(kāi)封第一講書人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任来候,我火速辦了婚禮,結(jié)果婚禮上样勃,老公的妹妹穿的比我還像新娘。我一直安慰自己性芬,他們只是感情好峡眶,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著植锉,像睡著了一般辫樱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上俊庇,一...
    開(kāi)封第一講書人閱讀 52,255評(píng)論 1 308
  • 那天狮暑,我揣著相機(jī)與錄音鸡挠,去河邊找鬼。 笑死搬男,一個(gè)胖子當(dāng)著我的面吹牛拣展,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播缔逛,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼备埃,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了褐奴?” 一聲冷哼從身側(cè)響起按脚,我...
    開(kāi)封第一講書人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎敦冬,沒(méi)想到半個(gè)月后辅搬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脖旱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年堪遂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夯缺。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蚤氏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出踊兜,到底是詐尸還是另有隱情竿滨,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布捏境,位于F島的核電站于游,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏垫言。R本人自食惡果不足惜贰剥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望筷频。 院中可真熱鬧蚌成,春花似錦、人聲如沸凛捏。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)坯癣。三九已至瓶盛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惩猫。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工芝硬, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人轧房。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓拌阴,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親锯厢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子皮官,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359