Android Zygote啓動流程源碼解析

Zygote進程是AndroidJava世界的開創者。在android系統中,全部的應用進程和SystemServer進程都是由Zygote進程fork而來。其重要性因而可知一斑。雖然Zygote進程至關於Android系統的根進程,可是事實上它也是由Linux系統的init進程啓動的。各個進程的前後順序爲:java

init進程 –-> Zygote進程 –> SystemServer進程 –>應用進程linux

其中Zygote進程由init進程啓動,SystemServer進程和應用進程由Zygote進程啓動。本文依據6.0源碼,主要分析Zygote進程的啓動流程。init進程在啓動Zygote進程時會調用ZygoteInit#main()。以此爲切入點,一步步分析。android

源碼位置:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java數組

流程概覽

ZygoteInit#main();app

public static void main(String argv[]) {
    try {
        // 設置DDMS可用
        RuntimeInit.enableDdms();
        // 初始化啓動參數
        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]);
            }
        }
        // 註冊socket
        registerZygoteSocket(socketName);
        // 預加載各類資源
        preload();
        ...
        if (startSystemServer) {
            // 啓動SystemServer進程
            startSystemServer(abiList, socketName);
        }
        // 監聽socket,啓動新的應用進程。--後文會講
        runSelectLoop(abiList);
        closeServerSocket();
    } catch (MethodAndArgsCaller caller) {
        // 經過反射調用SystemServer#main()--後文會講
        caller.run();
    } catch (RuntimeException ex) {
        closeServerSocket();
        throw ex;
    }
}

上面是個大概流程,下面會依據源碼一步步解釋。設置DDMS可用以後初始化各類參數,在此以後註冊爲Zygote進程註冊Socket,預加載各類資源,但這些都不是重點!同窗們,重點在於startSystemServer(abiList, socketName)(手敲黑板狀)!下面簡單貼下registerZygoteSocket(socketName)preload()源碼,不感興趣的同窗可直接略過下面兩段代碼。socket

ZygoteInit#registerZygoteSocket()函數

private static void registerZygoteSocket(String socketName) {
    if (sServerSocket == null) {
        int fileDesc;
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
        ...
        FileDescriptor fd = new FileDescriptor();
        fd.setInt$(fileDesc);
        // 不是使用IP和端口、而是使用fd建立socket
        sServerSocket = new LocalServerSocket(fd);
        ...
    }
}

ZygoteInit#registerZygoteSocket()oop

static void preload() {
    preloadClasses(); // 加載所需的各類class文件
    preloadResources(); // 加載資源文件
    preloadOpenGL(); // 初始化OpenGL
    preloadSharedLibraries(); // 加載系統Libraries
    preloadTextResources(); //加載文字資源
    WebViewFactory.prepareWebViewInZygote(); // 初始化WebView
}

啓動SystemServer進程

跟進startSystemServer()ui

private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException {
    long capabilities = posixCapabilitiesAsBits(
        OsConstants.CAP_BLOCK_SUSPEND,
        OsConstants.CAP_KILL,
        ...
    );
    /* 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);

        // 請求fork SystemServer進程
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.debugFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    // pid爲0表示子進程,即SystemServer進程,今後SystemServer進程與Zygote進程分道揚鑣
    if (pid == 0) {
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }

        handleSystemServerProcess(parsedArgs);
    }

    return true;
}

前面一大段都在構造參數,直接進到try中的代碼塊。首先根據args數組構造了一個ZygoteConnection.Arguments,而後根據parsedArgs對象的各類參數調用Zygote#forkSyatemServer()方法fork出第一個子進程,也就是SystemServer進程。最後經過執行handleSystemServerProcess反射調用SystemServer#main()。能夠看到,這段代碼最主要的做用就是forkSystemServer進程。這裏還看不出反射調用的具體細節,下文會一一分析。spa

首先看下構造ZygoteConnection.Arguments對象時,具體都作了哪些工做,尤爲關注Zygote#forkSystemServer()中幾個參數的值。

源碼位置:frameworks/base/core/java/com/android/internal/os/ZygoteConnection$Arguments.java

Arguments(String args[]) throws IllegalArgumentException {
        parseArgs(args);
    }

    private void parseArgs(String args[]) throws IllegalArgumentException {
        int curArg = 0;
        boolean seenRuntimeArgs = false;

        for ( /* curArg */ ; curArg < args.length; curArg++) {
            String arg = args[curArg];

            if (arg.equals("--")) {
                curArg++;
                break;
            } else if (arg.startsWith("--setuid=")) {
                if (uidSpecified) {
                    throw new IllegalArgumentException("Duplicate arg specified");
                }
                uidSpecified = true;
                uid = Integer.parseInt(arg.substring(arg.indexOf('=') + 1));
            } else if (arg.startsWith("--setgid=")) {
                if (gidSpecified) {
                gidSpecified = true;
                gid = Integer.parseInt(arg.substring(arg.indexOf('=') + 1));
            } else if (arg.startsWith("--target-sdk-version=")) {
                targetSdkVersionSpecified = true;
                targetSdkVersion = Integer.parseInt(arg.substring(arg.indexOf('=') + 1));
            } 
            ...
              else if (arg.equals("--runtime-args")) {
                seenRuntimeArgs = true;
            } else if (arg.startsWith("--capabilities=")) {
                capabilitiesSpecified = true;
                String capString = arg.substring(arg.indexOf('=')+1);
                String[] capStrings = capString.split(",", 2);
                if (capStrings.length == 1) {
                    effectiveCapabilities = Long.decode(capStrings[0]);
                    permittedCapabilities = effectiveCapabilities;
                } else {
                    permittedCapabilities = Long.decode(capStrings[0]);
                    effectiveCapabilities = Long.decode(capStrings[1]);
                }
            } else if (arg.startsWith("--setgroups=")) {
                String[] params = arg.substring(arg.indexOf('=') + 1).split(",");
                gids = new int[params.length];
                for (int i = params.length - 1; i >= 0 ; i--) {
                    gids[i] = Integer.parseInt(params[i]);
                }
            } else if (arg.startsWith("--nice-name=")) {
                niceName = arg.substring(arg.indexOf('=') + 1);
            } else {
                break;
            }
        }

        // 保存沒有被解析的參數
        remainingArgs = new String[args.length - curArg];
        System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length);    
    }

對比傳入的args數組,能夠發現:parsedArgs.uid=1000parsedArgs.gid=1000parsedArgs.gids={"1001","1002",..."3007"}parsedArgs.gid=1000parsedArgs.niceName=system_serverparsedArgs.seenRuntimeArgs=true。若是中途結束,保存未解析的參數至remainingArgs數組。 
得到Arguments對象以後,就開始請求建立SystemServer進程。

源碼位置:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

ZygoteInit#handleSystemServerProcess()

private static void handleSystemServerProcess(
        ZygoteConnection.Arguments parsedArgs)
        throws ZygoteInit.MethodAndArgsCaller {

    closeServerSocket();

    if (parsedArgs.niceName != null) {
        Process.setArgV0(parsedArgs.niceName);
    }
    ...
    // 默認爲null
    if (parsedArgs.invokeWith != null) {
        ...
    } else {
        ...
        RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
    }

    /* should never reach here */
}

Zygote建立的子進程默認擁有Zygote進程的Socket對象,而子進程又用不上,因此先調用closeServerSocket()關閉它。上一段參數解析時寫道:parsedArgs.niceName=system_server,在這裏調用Process.setArgV0()設置進程名爲:system_server。因爲parsedArgs.invokeWith屬性默認爲null,最後調用RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl)來進一步啓動SystemServer,這裏的參數parsedArgs.remainingArgs就是上文中保存沒有被解析對象的數組。

源碼位置:frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

RuntimeInit#zygoteInit()

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller {
    // 重定向Log輸出
    redirectLogStreams();
    //初始化運行環境
    commonInit();
    //啓動Binder線程池
    nativeZygoteInit();
    //調用程序入口函數
    applicationInit(targetSdkVersion, argv, classLoader);
}

RuntimeInit#applicationInit()

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {
    // 初始化虛擬機環境
    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
    final Arguments args;
    try {
        args = new Arguments(argv);
    } catch (IllegalArgumentException ex) {
        return;
    }

    // Remaining arguments are passed to the start class's static main
    invokeStaticMain(args.startClass, args.startArgs, classLoader);
}

RuntimeInit#invokeStaticMain()

private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {
    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 {
        // 獲取main方法
        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);
    }

    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

這裏傳入的className就是com.android.server.SystemServer,而後獲取main方法,接着判斷修飾符,必須是static並且必須是public類型。最有意思的莫過於作完這一切以後,拋出了個MethodAndArgsCaller異常。辛苦辛苦各類初始化,各類變着法兒的調用,最後你竟然給我拋個異常!!先別急,這個異常在Zygote#main()方法中捕獲。這麼作的做用是清除應用程序進程建立過程的調用棧。

public static void main(String argv[]) {
    try {
        ...
        startSystemServer(abiList, socketName);
        ...
    } catch (MethodAndArgsCaller caller) {
        caller.run();
    }
}

跟進MethodAndArgsCaller#run(),感受要出大事情!!

public void run() {
        try {
            mMethod.invoke(null, new Object[] { mArgs });
        } catch (IllegalAccessException ex) {
            throw new RuntimeException(ex);
        } catch (InvocationTargetException ex) {
            Throwable cause = ex.getCause();
            if (cause instanceof RuntimeException) {
                throw (RuntimeException) cause;
            } else if (cause instanceof Error) {
                throw (Error) cause;
            }
            throw new RuntimeException(ex);
        }
    }

我就說要出大事情!我就說要出大事情!!我就說要出大事情!!!能夠看到在這裏經過反射調用了com.android.server.SystemServer#main(String[] args)。至此,Zygote進程forSystemServer進程,併成功調用SystemServer#main()

如今SystemServer進程也建立了,main方法也調用了。Zygote進程的使命就此完結了嗎?上文咱們說道:全部的應用進程和SystemServer進程都是由Zygote進程fork而來。如今有關SystemServer進程的已經告一段落,那有關應用進程呢?

讓咱們再次回到ZygoteInit#main()

public static void main(String argv[]) {
      ...
      startSystemServer(abiList, socketName);
      runSelectLoop(abiList);
      closeServerSocket();
}

main方法中前面全部的代碼好像都和應用進程沒有關係,最後一行又是關閉socket,看來和應用進程相關的設置都在runSelectLoop()中,跟進。

監聽Socket,啓動應用進程

ZygoteInit#runSelectLoop()、ZygoteInit#acceptCommandPeer()

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    FileDescriptor[] fdArray = new FileDescriptor[4];
    fds.add(sServerSocket.getFileDescriptor());
    peers.add(null);
    int loopCount = GC_LOOP_COUNT;
    while (true) {
        int index;
        if (loopCount <= 0) {
            gc();
            loopCount = GC_LOOP_COUNT;
        } else {
            loopCount--;
        }

        try {
            fdArray = fds.toArray(fdArray);
            index = selectReadable(fdArray);
        } catch (IOException ex) {
            throw new RuntimeException("Error in select()", ex);
        }

        if (index < 0) {
            throw new RuntimeException("Error in select()");
        } else if (index == 0) {
            ZygoteConnection newPeer = acceptCommandPeer(abiList);
            peers.add(newPeer);
            fds.add(newPeer.getFileDescriptor());
        } else {
            boolean done;
            done = peers.get(index).runOnce();

            if (done) {
                peers.remove(index);
                fds.remove(index);
            }
        }
    }
}

private static ZygoteConnection acceptCommandPeer(String abiList) {
    try {
        return new ZygoteConnection(sServerSocket.accept(), abiList);
    } catch (IOException ex) {
        throw new RuntimeException("IOException during accept()", ex);
    }
}

這裏有個死循環,一直監聽socket,而後調用ZygoteConnection#runOnce(),從函數名runOnce上感受真相就要呼之欲出了,跟進。

源碼位置:frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

ZygoteConnection#runOnce()

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
    String args[];
    args = readArgumentList();
    parsedArgs = new Arguments(args);
     try {
        ...
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                parsedArgs.appDataDir);
    } catch (ErrnoException ex) {
        logAndPrintError(newStderr, "Exception creating pipe", ex);
    } catch (IllegalArgumentException ex) {
        logAndPrintError(newStderr, "Invalid zygote arguments", ex);
    } catch (ZygoteSecurityException ex) {
        logAndPrintError(newStderr,
                "Zygote security policy prevents request: ", ex);
    }

    try {
        if (pid == 0) {
            // in child
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
            handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

            // should never get here, the child is expected to either
            // throw ZygoteInit.MethodAndArgsCaller or exec().
            return true;
        } else {
            // in parent...pid of < 0 means failure
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
        }
    } finally {
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    }
}

和啓動SystemServer進程相似。這裏調用Zygote#forkAndSpecialize()建立應用進程,而參數parsedArgs是經過socket一行行讀出來的。詳見ZygoteConnection#readArgumentList()

private String[] readArgumentList() throws IOException {
    int argc;
    try {
        String s = mSocketReader.readLine();
        if (s == null) {
            return null;
        }
        argc = Integer.parseInt(s);
    } catch (NumberFormatException ex) {
        throw new IOException("invalid wire format");
    }
    if (argc > MAX_ZYGOTE_ARGC) {
        throw new IOException("max arg count exceeded");
    }
    String[] result = new String[argc];
    for (int i = 0; i < argc; i++) {
        result[i] = mSocketReader.readLine();
        if (result[i] == null) {
            // We got an unexpected EOF.
            throw new IOException("truncated request");
        }
    }
    return result;
}

由於尚未看發送Socket消息的源碼,這裏斗膽猜想:應該是uid、gid、niceName等參數。

經過Socket讀取完各類參數以後,調用ZygoteConnection#handleChildProc(),建立完應用程序進程以後就該調用應用程序的入口方法了。跟進。

private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
        throws ZygoteInit.MethodAndArgsCaller {
    // 關閉從Zygote進程複製過來的Socket鏈接  
    closeSocket();
    ZygoteInit.closeServerSocket();
    if (parsedArgs.niceName != null) {
        Process.setArgV0(parsedArgs.niceName);
    }
    ...
    RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */);
}

最後調用RuntimeInit#zygoteInit(),後面的就和SystemServer啓動流程相似。感興趣的同窗自行查看。

總結一下Zygote啓動流程:

  1. 初始化DDMS

  2. 註冊Zygote進程的Socket

  3. 加載classresourceOpenGLWebView等各類資源

  4. forkSystemServer進程

  5. 啓動SystemServer進程

  6. 調用runSelectLoop()一直監聽Socket信息

  7. 收到建立應用程序Socket消息,調用ZygoteConnection#runOnce()。在runOnce()中調用Zygote#forkAndSpecialize()建立應用進程

  8. 啓動應用進程

相關文章
相關標籤/搜索