「Android研習社」深刻研究源碼:Android10.0系統啓動流程(三):Zygote

前言java

研究過程當中參考了不少的文章,這篇源碼分析,多是全網最全的Zygote源碼分析了android

若是以爲這篇源碼分析太,也能夠先看一下後續的相關總結,戳juejin.im/post/5da532…,及B站視頻講解ios

福利活動c++

Android研習社機械工業出版社聯合發起的贈書活動正在進行中,歡迎你們戳點擊連接參與shell

全文概覽

咱們都知道Android中非特殊進程(除init進程和Zygote進程外的進程,源碼中稱其爲unspecialized app process),都是由Zygotefork出來的子進程,包括SystemServer,也是由Zygote fork出來的bash

這篇文章咱們主要來探討如下幾個問題網絡

  1. Zygote進程是如何啓動的?
  2. Zygote又是如何fork出SystemServer的?
  3. 其餘普通進程又是經過什麼方式被fork出來的?
  4. 跟普通的App process有什麼區別?

這些問題咱們在接下來的源碼分析中來找找答案架構

具體源碼分析

Zygote進程是如何被啓動起來的

咱們首先來看下,Zygote進程是如何被啓動起來的app

咱們仍是首先從init.rc中引用的zygote.rc中入手來看,源碼中是找不到的,咱們從編譯好的文件中找less

WORKING_DIRECTORY/out/target/product/generic_x86/root/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 reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary 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
複製代碼

我們重點來看前面幾行

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server 從這裏,咱們看到zygote的可執行文件所在的位置應該是/system/bin/app_process,那源碼應該也有一個app_process的目錄,上次Bilibili技術分享第一期中也提到了,zygote對應的源碼實際上是app_process的代碼

咱們接着來找到

./frameworks/base/cmds/app_process/app_main.cpp 咱們從app_main的入口函數來看

int main(int argc, char* const argv[])
{
    ...
    
	//建立AppRuntime,AppRuntime是AndroidRuntime的子類對象
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));  //
    // Process command line arguments
    // ignore argv[0]
    argc--;
    argv++;
    ...
    bool known_command = false;

    int i;
    for (i = 0; i < argc; i++) { 
        ...
        runtime.addOption(strdup(argv[i])); //把Zygote.rc中的參數添加到AppRuntime,也就是AndroidRuntime中
        ...
    }

    // 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.rc解析傳進來的參數,進行對比
            zygote = true; //須要執行zygote的指令
            niceName = ZYGOTE_NICE_NAME; //給 nicename 賦值爲zygote
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true; //爲startSystemServer的標誌爲賦值
        } else if (strcmp(arg, "--application") == 0) {
            application = true; //根據參數判斷是否爲application
        } 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;
    //若是是zygote,則className爲空,因此此處其實是判斷是否爲zygote的進程
    if (!className.isEmpty()) { //判斷非zygote模式時,只須要傳遞application的參數
        // 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); if (!LOG_NDEBUG) { String8 restOfArgs; char* const* argv_new = argv + i; int argc_new = argc - i; for (int k = 0; k < argc_new; ++k) { restOfArgs.append("\""); restOfArgs.append(argv_new[k]); restOfArgs.append("\" "); } ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string()); } } else { //classname爲空,當前爲zygote模式 // 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) {//獲取支持的CPU指令集
            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.
        //此處爲zygote模式,須要把全部參數都傳遞過去
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }

    if (!niceName.isEmpty()) {//niceName不爲空,說明是zygote模式
        runtime.setArgv0(niceName.string(), true /* setProcName */);//此處註釋也說明了,這裏是設置進程名
    }

    if (zygote) {//若是是zygote模式
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);//調用zygoteInit函數,並把當前的參數傳遞過去
    } else if (className) {//若是是非zygote模式
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);//調用RuntimeInit函數
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}
複製代碼

這篇文章的目的是分析zygote的流程,那咱們暫時只關心zygote相關的邏輯

函數最後調用了ZygoteInit,咱們看看這個類主要作了什麼

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

按照以前的套路,咱們先找到入口函數main

@UnsupportedAppUsage
    public static void main(String argv[]) {
        // Server socket class for zygote processes.
        ZygoteServer zygoteServer = null; //用來管理和子進程通訊的socket服務端 

        // Mark zygote start. This ensures that thread creation will throw
        // an error.

        ZygoteHooks.startZygoteNoThreadCreation(); 	//這裏其實只是設置一個標誌位,爲建立Java線程時作判斷處理,若是是zygote進程,則不須要開啓線程

        // Zygote goes into its own process group.
        try {
            Os.setpgid(0, 0);  //爲zygote進程設置pgid(Process Group ID),詳見:`https://stackoverflow.com/questions/41498383/what-do-the-identifiers-pid-ppid-sid-pgid-uid-euid-mean`
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to setpgid(0,0)", ex);
        }

        Runnable caller;
        try {
            // Report Zygote start time to tron unless it is a runtime restart
            if (!"1".equals(SystemProperties.get("sys.boot_completed"))) { //獲取系統屬性,判斷系統重啓完成
                MetricsLogger.histogram(null, "boot_zygote_init",
                        (int) SystemClock.elapsedRealtime());
            }

            String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";//判斷當前進程是64位程序仍是32位程序,並設置標記
            TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
                    Trace.TRACE_TAG_DALVIK);
            bootTimingsTraceLog.traceBegin("ZygoteInit");
            RuntimeInit.enableDdms();//註冊到ddms服務端,內部調用`DdmServer.registerHandler()`

            boolean startSystemServer = false;
            String zygoteSocketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
			//對參數進行解析
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) { //參數重包含`start-system-server`
                    startSystemServer = true; //設置標誌爲位true
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = 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)) {
                    zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }
			
            final boolean isPrimaryZygote =  zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);//根據socketName判斷是不是primaryZygote,可能還有secondZygote

            if (abiList == null) { //若是支持架構爲空,直接拋出異常
                throw new RuntimeException("No ABI list supplied.");
            }

            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                        SystemClock.uptimeMillis());
                preload(bootTimingsTraceLog);
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                        SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            } else {
                Zygote.resetNicePriority();
            }

            // Do an initial gc to clean up after startup
            bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
            gcAndFinalize(); //調用ZygoteHooks.gcAndFinalize()進行垃圾回收
            bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC

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


            Zygote.initNativeState(isPrimaryZygote);//jni調用初始化zygote的狀態,是否爲isPrimaryZygote

            ZygoteHooks.stopZygoteNoThreadCreation(); //結束zygote建立,其實內部是調用`runtime`給`zygote_no_threads_`賦值爲false,爲建立本地線程作準備

            zygoteServer = new ZygoteServer(isPrimaryZygote); //建立zygoteServer,爲其餘進程初始化建立時與zygote通訊作準備

            if (startSystemServer) { //判斷是否須要startSystemServer
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);//經過fork的方式開啓zygote的子進程,systemServer,並返回一個Runnale對象
                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {//若是是zygote進程,則r==null,若是不是zygote進程,也就是systemServer進程,則執行下面的代碼
                    r.run();
                    return;
                }
            }

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

            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            caller = zygoteServer.runSelectLoop(abiList); //zygote進程進入死循環中,來獲取子進程發送的消息
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket(); //若是發生異常,則說明zygote初始化失敗,zygoteServer也須要關閉
            }
        }

        // We're in the child process and have exited the select loop. Proceed to execute the // command. if (caller != null) { caller.run(); } } 複製代碼

zygote的大概流程咱們已經梳理完了,如今咱們來總結一下

  1. 解析對應的zyogte.rc腳本
  2. 調用app_process/appMain.cpp
  3. 設置進程名爲zygote
  4. 調用zygoteInit.java初始化zygote進程
  5. JNI調用zygoteInit.cpp完成進程建立
  6. 調用runSelectionLoop(),接收其餘進程發送的消息建立子進程

Zygote是如何fork出SystemServer的

咱們都知道,Android系統中,zyogte進程是Java世界的首個進程(init進程爲頭號進程),是直接經過exec的系統調用建立的,其餘的進程,包括system_server,都是zygote進程的子進程,那咱們接下來從源碼的角度來看一下,zygote是如何forksystem_server

public static void main(String argv[]) {
						...
            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) { //若是r不爲空,說明是system_server進程
                    r.run(); //調用其run方法
                    return;
                }
            }

            ...
        }
				...
    }
複製代碼

由上面的分析咱們看到,根據zygote.rc的參數,解析出是否須要startSystemServer,若是爲true,則調用forkSystemServer來fork出子進程SystemServer,而且執行其返回的Runnable的run()方法,咱們先來看看forkSystemServer具體作了什麼

/**
     * Prepare the arguments and forks for the system server process.
     * 爲forkSystemServer進程準備參數,而且建立system server進程
     *
     * @return A {@code Runnable} that provides an entrypoint into system_server code in the child
     * process; {@code null} in the parent.
     */
    private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
		//Linux使用POSIX capabilities代替傳統的信任狀模型
        long capabilities = posixCapabilitiesAsBits( //設置進程權能
                OsConstants.CAP_IPC_LOCK, //容許鎖定共享內存片斷
                OsConstants.CAP_KILL, //容許對不屬於本身的進程發送信號
                OsConstants.CAP_NET_ADMIN, // 容許執行網絡管理任務:接口、防火牆和路由等
                OsConstants.CAP_NET_BIND_SERVICE, //容許綁定到小於1024的端口
                OsConstants.CAP_NET_BROADCAST, //容許網絡廣播和多播訪問
                OsConstants.CAP_NET_RAW, //容許網絡廣播和多播訪問
                OsConstants.CAP_SYS_MODULE, //插入和刪除內核模塊
                OsConstants.CAP_SYS_NICE, //容許提高優先級,設置其它進程的優先級
                OsConstants.CAP_SYS_PTRACE, //容許配置進程記賬
                OsConstants.CAP_SYS_TIME, //容許改變系統時鐘
                OsConstants.CAP_SYS_TTY_CONFIG, //容許配置TTY設備
                OsConstants.CAP_WAKE_ALARM,
                OsConstants.CAP_BLOCK_SUSPEND
        );
        /* Containers run without some capabilities, so drop any caps that are not available. */
        StructCapUserHeader header = new StructCapUserHeader(
                OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
        StructCapUserData[] data; //用戶權能數據
        try {
            data = Os.capget(header); //獲取進程權能,存儲到data中
        } catch (ErrnoException ex) {
            throw new RuntimeException("Failed to capget()", ex);
        }
        capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);

        /* Hardcoded command line to start the system server */
        /*使用硬編碼的方式定義出啓動system server的參數字符串args*/
        String args[] = {
                "--setuid=1000", //用戶id
                "--setgid=1000",//用戶組id
                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                        + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
                "--capabilities=" + capabilities + "," + capabilities, //進程權能
                "--nice-name=system_server", //進程niceName
                "--runtime-args", 
                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT, 
                "com.android.server.SystemServer",
        };
        ZygoteArguments parsedArgs = null; 

        int pid; //processId,進程id

        try {
            
            parsedArgs = new ZygoteArguments(args);  ////建立ZygoteArguments對象,把args解析爲須要的參數
            Zygote.applyDebuggerSystemProperty(parsedArgs);
            Zygote.applyInvokeWithSystemProperty(parsedArgs);

            boolean profileSystemServer = SystemProperties.getBoolean(
                    "dalvik.vm.profilesystemserver", false);  //跟Art虛擬機相關,暫時不作深究
            if (profileSystemServer) { 
                parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
            }

            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer( //fork建立SystemServer
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) { //pid爲0,則說明是zygote進程,進行最後的收尾工做
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

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

        return null;
    }
複製代碼

代碼最後調用了Zygote.forkSystemServer()來建立SystemServer,咱們接着來跟一下

public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
        ZygoteHooks.preFork();//內部調用ART的Runtime對zygote的線程池的線程進行清理
        // Resets nice priority for zygote process.
        resetNicePriority();
        int pid = nativeForkSystemServer(   //JNI調用,真正建立systemServer進程的函數
                uid, gid, gids, runtimeFlags, rlimits,
                permittedCapabilities, effectiveCapabilities);
        // Enable tracing as soon as we enter the system_server.
        if (pid == 0) {
            Trace.setTracingEnabled(true, runtimeFlags);
        }
        ZygoteHooks.postForkCommon();
        return pid;
    }
複製代碼

接着跟下去,到c++的本地代碼中 zygote.cpp

static jint com_android_internal_os_Zygote_nativeForkSystemServer(
        JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
        jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
        jlong effective_capabilities) {
  ...

  pid_t pid = ForkCommon(env, true,
                         fds_to_close,
                         fds_to_ignore);//從zygote進程fork出子進程,並返回processId
  ...
  return pid;
}
複製代碼

到這裏咱們就把相關源碼分析完了,咱們來總結下:

  1. 解析zygote.rc的相關腳本,獲取startSystemserver的屬性字段
  2. 調用startSystemServer()
  3. 調用forkSystemServer(),爲當前進程賦予權限,並設置UID,GID
  4. 建立ZygoteArgument,調用zygote.forkSystemServer
  5. JNI調用native的函數,nativeForkSystemServer完成進程的fork工做

普通進程(UASP--unspecialized app process),是經過什麼方式被fork出來的

這裏咱們只分析zygote相關的源碼,完整流程等分析AMS時一塊兒總結

zygoteInit中,最後調用了zyogteServer的runSelectionLoop()函數,進入一個無限循環中,咱們來看下代碼

Runnable runSelectLoop(String abiList) { //此處使用了selcet IO複用機制,這個咱們之後專門來分析Linux的IO複用機制
            ...

            while (--pollIndex >= 0) {
                ...

                if (pollIndex == 0) {
                    // Zygote server socket

                    ZygoteConnection newPeer = acceptCommandPeer(abiList);//建立socket鏈接的服務端
                    peers.add(newPeer);
                    socketFDs.add(newPeer.getFileDescriptor());

                } else if (pollIndex < usapPoolEventFDIndex) {
                    // Session socket accepted from the Zygote server socket

                    try {
                        ZygoteConnection connection = peers.get(pollIndex); //獲取到客戶端鏈接對象ZygoteConnection
                        final Runnable command = connection.processOneCommand(this);  //讀取一個sokcet命令,並fork出子進程,執行子進程的main函數

                        // TODO (chriswailes): Is this extra check necessary?
                        if (mIsForkChild) {
                            // We're in the child. We should always have a command to run at this // stage if processOneCommand hasn't called "exec".
                            if (command == null) {
                                throw new IllegalStateException("command == null");
                            }

                            return command;
                        } else {
                            // We're in the server - we should never have any commands to run. if (command != null) { throw new IllegalStateException("command != null"); } // We don't know whether the remote side of the socket was closed or
                            // not until we attempt to read from it from processOneCommand. This
                            // shows up as a regular POLLIN event in our regular processing loop.
                            if (connection.isClosedByPeer()) {
                                connection.closeSocket();
                                peers.remove(pollIndex);
                                socketFDs.remove(pollIndex);
                            }
                        }
                    }
                    ...
            }

            ...
        }
    }
複製代碼

這裏當pollIndex==0先調用acceptCommandPeer()建立sokcet鏈接的服務端,其餘條件下,調用acceptCommandPeer()獲取一個ZygoteConnect對象,並執行其processOneCommand()函數,讀取一個sokcet命令,並fork出子進程,執行子進程的main函數,咱們仍是接着跟一下這個函數

Runnable processOneCommand(ZygoteServer zygoteServer) {
        String args[];
        ZygoteArguments parsedArgs = null;
        FileDescriptor[] descriptors;

        try {
            args = Zygote.readArgumentList(mSocketReader); //從sokcet中讀取參數

            // TODO (chriswailes): Remove this and add an assert.
            descriptors = mSocket.getAncillaryFileDescriptors(); //獲取其附帶的文件描述符
        } catch (IOException ex) {
            throw new IllegalStateException("IOException on command socket", ex);
        }
        ...
        int pid = -1;
        FileDescriptor childPipeFd = null;//子進程,使用管道進行進程間通訊,
        FileDescriptor serverPipeFd = null;

        parsedArgs = new ZygoteArguments(args); //建立Zygote參數對象
        ...
		
        pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
                parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
                parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
                parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion);
                //Forks a new VM instance
                //建立一個新的VM實例對象,也就是咱們平時說的沙盒隔離機制(sandbox)

        try {
            if (pid == 0) {
                // in child
                zygoteServer.setForkChild();//設置標誌位mIsForkChild爲true
                ...
                return handleChildProc(parsedArgs, descriptors, childPipeFd,
                        parsedArgs.mStartChildZygote); //處理子進程的建立
            } else {    
                // In the parent. A pid < 0 indicates a failure and will be handled in
                // handleParentProc.
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                handleParentProc(pid, descriptors, serverPipeFd);//若是pid>0,則爲子進程設置進程號,不然就是建立失敗
                return null;
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }
複製代碼

這裏根據傳遞過來的參數建立zygoteArgs對象,並建立出VM虛擬機對象,最終調用handleChildProc()來建立子進程,繼續跟蹤代碼

private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,
            FileDescriptor pipeFd, boolean isZygote) {
        ...

        if (parsedArgs.mNiceName != null) { //判斷mNiceName不爲空
            Process.setArgV0(parsedArgs.mNiceName); //設置mNiceName爲進程名
        }

        // End of the postFork event.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        if (parsedArgs.mInvokeWith != null) { //判斷參數中mInvokeWith爲空時,使用exec的系統調用開啓進程
           ...
        } else {
            if (!isZygote) { //非zygote模式
                return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                        parsedArgs.mRemainingArgs, null /* classLoader */);
            } else { //zygote模式
                return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
                        parsedArgs.mRemainingArgs, null /* classLoader */); //zygoteInit的備選函數,同時初始化Zygote進程
            }
        }
    }
複製代碼

此處咱們只關心由Zyogte進程fork出子進程的狀況,跟蹤zygoteInit()這個函數

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
        ...
        RuntimeInit.commonInit(); //對runtime進行初始化
        ZygoteInit.nativeZygoteInit(); //JNI調用,nativeZygoteInit
        return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);//找到Appde 主函數並初始化調用
    }
複製代碼

這裏首先的對Runtime進行初始化,而後經過JNI對zygote進行真正的初始化操做,函數代碼以下

static AndroidRuntime* gCurRuntime = NULL;
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit(); //調用AndroidRuntime的zygoteInit
}
複製代碼

這裏是調用了AndroidRuntimeonZygoteInit(),此處點進去能夠看到它是一個虛函數,那麼應該是由的子類對象來作的具體實現,以前咱們也分析過,AndroidRuntimeapp_processapp_main中又一個子類對象AppRuntime,咱們來看一下

public:
    AppRuntime(char* argBlockStart, const size_t argBlockLength)
        : AndroidRuntime(argBlockStart, argBlockLength)
        , mClass(NULL)
    {
    }
    ...
    virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();//開啓Bind線程池線程,設置線程名稱
    }
    ...
};
複製代碼

此處建立了一個ProcessState的對象,並調用了它的startThreadPool()函數,跟蹤下去能夠發現內部調用了spawnPooledThread的函數來建立線程並啓動的

void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) { //判斷線程已開啓
        String8 name = makeBinderThreadName(); //建立Binder線程池名稱
        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
        sp<Thread> t = new PoolThread(isMain); //建立主線程
        t->run(name.string()); //執行線程
    }
}
複製代碼

handleChildProc()這一系列代碼執行完畢後,會調用handleParentProc()對子進程建立狀態進行判斷,若是pid>0則說明建立成功,到此處咱們子進程以及其相關線程就準備完畢了

如今來總結下

  1. 調用runSelectLoop,循環讀取消息
  2. 調用acceptCommandPeer建立Sokcet服務端的鏈接對象ZygoteConnection
  3. 調用acceptOneCommand讀取Soket的消息
  4. 解析參數,並建立虛擬機實例對象
  5. 調用handleChildProcess處理子進程的建立
  6. 調用zygoteInit.zyogteInit(args...)把參數傳遞進去
  7. 調用native方法,進行最終的初始化
  8. 回調到app_process/app_main.cppAppRuntime具體實現中
  9. 開啓Binder線程池,完成子進程建立

額外加餐

ZygoteServer源碼

上面咱們分析Zygote流程時涉及到一個類,ZygoteServer,下面咱們來具體看下,它是如何建立的

在zygote的main函數中是這麼初始化的

zygoteServer = new ZygoteServer(isPrimaryZygote);
複製代碼

那咱們就從這個構造函數入手

/**
     * Initialize the Zygote server with the Zygote server socket, USAP pool server socket, and USAP
     * pool event FD.
     *
     * @param isPrimaryZygote  If this is the primary Zygote or not.
     */
    ZygoteServer(boolean isPrimaryZygote) {
        mUsapPoolEventFD = Zygote.getUsapPoolEventFD();

        if (isPrimaryZygote) { //根據zygote.rc中的參數判斷是不是PrimaryZygote
            mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);//把PRIMARY_SOCKET_NAME賦值給mZygoteSocket
            mUsapPoolSocket =
                    Zygote.createManagedSocketFromInitSocket(
                            Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);//把USAP_POOL_PRIMARY_SOCKET_NAME賦值給mUsapPoolSocket
        } else {
            mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);//把SECONDARY_SOCKET_NAME賦值給mZygoteSocket
            mUsapPoolSocket =
                    Zygote.createManagedSocketFromInitSocket(
                            Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);//把USAP_POOL_SECONDARY_SOCKET_NAME賦值給mUsapPoolSocket
        }

        fetchUsapPoolPolicyProps();

        mUsapPoolSupported = true;
    }
複製代碼

上面的代碼裏主要是把zygote.rc中的配置取出來,其中涉及到了兩個socket,mZygoteSocketmUsapPoolSocket;也涉及到兩個Zygote,PrimaryZygoteSecondZygote

可是你可能會奇怪,我們的zygote.rc中,怎麼沒有這個東西呢?我再把這個文件貼一遍

WORKING_DIRECTORY/out/target/product/generic_x86/root/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 reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary 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
複製代碼

惟一跟primary有關的,是socket usap_pool_primary stream 660 root system,那SecondZygote去哪了呢?

這個跟我們編譯的版本是有關係的,當前編譯的版本中,只支持32爲的應用,因此只有32位的PrimaryZygote,那我們來看一下我根據源碼編譯的Pixel 2的Android10系統中有沒有

使用adb shell 查看

cat init.zygote64_32.rc

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary 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

service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote_secondary stream 660 root system
    socket usap_pool_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks
複製代碼

這裏很清楚的看獲得,64位的zygote是PrimaryZygote,32位的zygote是SecondZygote,不一樣的二進制文件能夠由不一樣的Zygote啓動,同時兼容64位和32位程序

咱們再來看看上面提到的兩個Socket是幹什麼的

/**
     * Listening socket that accepts new server connections.
     */
    private LocalServerSocket mZygoteSocket;

    /**
     * The name of the unspecialized app process pool socket to use if the USAP pool is enabled.
     */
    private LocalServerSocket mUsapPoolSocket;
    
    ...
    ZygoteServer(boolean isPrimaryZygote) {
        ...
        mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
        mUsapPoolSocket = Zygote.createManagedSocketFromInitSocket(Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
        ...
    }
複製代碼

這裏兩個sokcet的對象的建立都調用的同一個函數createManagedSocketFromInitSocket()

/** Prefix prepended to socket names created by init */
    private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
    
    /**
     * Creates a managed LocalServerSocket object using a file descriptor
     * created by an init.rc script.  The init scripts that specify the
     * sockets name can be found in system/core/rootdir.  The socket is bound
     * to the file system in the /dev/sockets/ directory, and the file
     * descriptor is shared via the ANDROID_SOCKET_<socketName> environment
     * variable.
     */
    static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
        int fileDesc;
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;//拼接爲socket的全路徑名
        try {
            String env = System.getenv(fullSocketName);
            fileDesc = Integer.parseInt(env);
        } catch (RuntimeException ex) {
            throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
        }

        try {
            FileDescriptor fd = new FileDescriptor();//建立文件描述符
            fd.setInt$(fileDesc); //把獲取到的fileDesc設置進去
            return new LocalServerSocket(fd); //返回該Socket對象
        } catch (IOException ex) {
            throw new RuntimeException(
                "Error building socket from file descriptor: " + fileDesc, ex);
        }
    }
複製代碼

咱們使用adb來查看下,很容易的查看到兩個Zygote相關的socketFd

ZygoteHooks相關源碼

咱們來簡單補充一點zygoteHooks的源碼分析,分析這個問題的目的在於,理清出Dalvik和ART在Android10源碼中的關係

上面的源碼分析中,有幾個地方調用 ZygoteHooks的相關源碼,咱們來簡單分析下

ZygoteHooks.startZygoteNoThreadCreation() && ZygoteHooks.stopZygoteNoThreadCreation()

咱們發現這個ZygoteHooks實際上是ART包下的

./art/runtime/native/dalvik_system_ZygoteHooks.cc

static void ZygoteHooks_startZygoteNoThreadCreation(JNIEnv* env ATTRIBUTE_UNUSED,
                                                    jclass klass ATTRIBUTE_UNUSED) {
  Runtime::Current()->SetZygoteNoThreadSection(true);
}
複製代碼

能夠看到這個函數是一個JNI的接口,內部調用了RuntimeSetZygoteNoThreadSection函數

./art/runtime/runtime.h

// Whether zygote code is in a section that should not start threads.
bool zygote_no_threads_;

void SetZygoteNoThreadSection(bool val) {
    zygote_no_threads_ = val;
}

bool IsZygoteNoThreadSection() const {
    return zygote_no_threads_;
}
複製代碼

能夠看到這裏其實就是設置了一個標誌爲,源碼註釋中也說明了,該字段是爲了區分處於zygote模式時,不去開啓線程,那咱們來看看這個zygote_no_threads_的字段哪裏使用到了

./art/runtime/runtime.cc

Runtime::Runtime()
    : ...
      zygote_no_threads_(false),
      ...
      {
      ...
          
      }
複製代碼

這裏在Runtime構造初始化時,首先把其設置爲false,也就是默認狀況下,Runtime是會去開啓線程的

再來看看返回zygote_no_threads_IsZygoteNoThreadSection()這個函數在哪裏有使用

./art/runtime/native/java_lang_Thread.cc

static void Thread_nativeCreate(JNIEnv* env, jclass, jobject java_thread, jlong stack_size,
                                jboolean daemon) {
  // There are sections in the zygote that forbid thread creation.
  Runtime* runtime = Runtime::Current();
  if (runtime->IsZygote() && runtime->IsZygoteNoThreadSection()) {//判斷是zygote進程,而且IsZygoteNoThreadSection()返回值爲true時
    jclass internal_error = env->FindClass("java/lang/InternalError");
    CHECK(internal_error != nullptr);
    env->ThrowNew(internal_error, "Cannot create threads in zygote");//直接拋出異常,
    return; //結束當前函數
  }

  Thread::CreateNativeThread(env, java_thread, stack_size, daemon == JNI_TRUE);//若是不是zygote進程,纔去建立本地線程
}
複製代碼

這裏又是一個JNI的接口函數,是用來建立本地線程的(根據類名和方法名也能夠猜到),註釋中也作了說明,只有不是zygote進程時纔會去建立本地線程

stopZygoteNoThreadCreation()函數也是同樣,一樣是設置標誌爲,設置爲false,那麼就能夠去建立線程了

寫在最後

這裏咱們基本上把zygote涉及的相關源碼分析完了,下篇文章講會對SystemServer的相關源碼進行分析。因爲水平有限,寫的不對的還請各位多多指教

原創不易,堅持更難。

若是你想繼續看到我接下來的分享,請經過點讚的方式告訴我,你的鼓勵是我繼續創做的最大動力!

相關文章
相關標籤/搜索