Zygote 进程启动过程

news2024/12/26 11:54:37

首语

在Android系统中,DVM(Dalvik虚拟机)和ART、应用程序进程以及运行系统的关键服务的SystemServer进程都是由Zygote进程创建的,也可以将其称之为孵化器,它通过fork(复制进程)的形式来创建应用程序进程和SystemServer进程。

Zygote进程是在init进程启动时创建的,起初Zygote的进程名称为"app_process",在frameworks/base/cmds/app_process/Android.bp中定义,Zygote启动后,会将其名称转换为"zygote"或"zygote64"(后面分析源码会讲到)。

Zygote启动脚本

在init.rc文件中采用了Import类型的语句来引入Zygote启动脚本。

import /system/etc/init/hw/init.${ro.zygote}.rc

init.rc不会引入一个固定的rc文件,而是根据属性ro.zygote来引入不同的文件。ro.zygote属性的取值有以下3种:

  • init.zygote32.rc
  • init.zygote64.rc
  • init.zygote64_32.rc

这些Zygote脚本都放在system/core/rootdir目录中。下面分别介绍这些Zygote启动脚本

init.zygote32.rc

表示支持纯32位程序,内容如下:

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 exec_background - system system -- /system/bin/vdc volume abort_fuse
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart media.tuner
    onrestart restart netd
    onrestart restart wificond
    task_profiles ProcessCapacityHigh
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

根据在 init进程启动过程 文章中所描述的Service类型语句的格式,可知,Zygote进程名称为zygote,执行程序为app_process,classname为main,如果audioserver、cameraserver、media等进程终止,就需要restart.

init.zygote64.rc

表示支持64位程序,这个启动脚本在 init进程启动过程 文章中已经进行解释,不在重复讲述。

init.zygote64_32.rc

表示既支持64位程序也支持32位程序,64位为主,32位为辅。现在主流都是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 exec_background - system system -- /system/bin/vdc volume abort_fuse
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart media.tuner
    onrestart restart netd
    onrestart restart wificond
    task_profiles ProcessCapacityHigh MaxPerformance
    critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

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
    task_profiles ProcessCapacityHigh MaxPerformance
    disabled

脚本中由两个service类型语句,说明会启动两个Zygote进程,一个名称位zygote,执行程序为app_process64,作为主模式。另一个名称为zygote_secondary,执行程序为app_process32,作为辅模式。

Zygote进程启动过程

在 init进程启动过程 文章中我们知道init启动Zygote主要是调用app_main.cpp的main函数中的AndroidRuntime的start函数来启动Zygote进程的,首先从app_main.cpp的main函数分析。

Zygote进程都是通过fork自身来创建子进程,这样Zygote进程以及它的子进程都可以进入main函数,因此main函数有区分当前运行在那个进程,根据参数arg是否包含"–zygote"来判断,如果包含则说明当前运行在Zygote进程,zygote = true;,包含"–start-system-server"则说明当前运行在SystemServer进程,startSystemServer = true;。运行在Zygote进程,就会调用AndroidRuntime的start函数(AppRuntime继承于AndroidRuntime,没有实现start函数,所以直接查看AndroidRuntime。

源码路径:frameworks\base\cmds\app_process\app_main.cpp

#if defined(__LP64__)
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
static const char ZYGOTE_NICE_NAME[] = "zygote64";
#else
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
static const char ZYGOTE_NICE_NAME[] = "zygote";
#endif

int main(int argc, char* const argv[])
{
	...
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            //如果当前运行在Zygote进程中,则将zygote设置为true
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            //如果当前运行在SystemServer进程中,则将zygote设置为true
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } 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;
        }
    }
	...
    if (!niceName.isEmpty()) {
        //首语提到Zygote的进程名称为"app_process",启动后会修改为niceName=ZYGOTE_NICE_NAME,ZYGOTE_NICE_NAME会根据系统为zygote64或zygote
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }
  	//运行在Zygote进程
    if (zygote) {
            runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        //application启动模式
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

startVm函数创建虚拟机,再通过startReg注册JNI方法。将className的".“替换为”/",是为了找到ZygoteInit,再调用ZygoteInit的main方法,因为ZygoteInit的main方法是java语言实现的,所以需要通过JNI来调用java,这样Zygote就从Native进入了java框架层

源码路径:frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
   	...
    //启动java虚拟机
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    onVmCreated(env);
	//为java虚拟机注册JNI方法
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }
	...
    //classname=com.android.internal.os.ZygoteInit
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr != NULL);
    env->SetObjectArrayElement(strArray, 0, classNameStr);
	...
    //将className的"."替换为"/"
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    //找到ZygoteInit
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        //找到ZygoteInit的main方法
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            //通过JNI调用ZygoteInit的main方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
    ...
}

分析源码得知,main方法主要做了以下四件事情:

预加载类和资源

Zygote进程启动的时候将系统的一些class(frameworks/base/config/preloaded-classes)、resource(preloaded_drawables/preloaded_color_state_lists/)等加载,后面其它进程需要使用时不需要重新加载,直接调用,加快应用启动速度。加载细节可以深入查看源码。

源码路径:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public static void main(String[] argv) {
    ...
    String zygoteSocketName = "zygote";
    final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
    ...
    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
   }
    ...   
	//调用ZygoteServer创建两个Server端的Socket                            
    zygoteServer = new ZygoteServer(isPrimaryZygote);                            
    if (startSystemServer) {
        //启动SystemServer进程
        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.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.
   //等待AMS请求创建应用程序进程                            
   caller = zygoteServer.runSelectLoop(abiList);  
   if (caller != null) {
         caller.run();
   }                            
}
 static void preload(TimingsTraceLog bootTimingsTraceLog) {
        Log.d(TAG, "begin preload");
        bootTimingsTraceLog.traceBegin("BeginPreload");
        beginPreload();
        bootTimingsTraceLog.traceEnd(); // BeginPreload
        bootTimingsTraceLog.traceBegin("PreloadClasses");
     	//预加载类
        preloadClasses();
        bootTimingsTraceLog.traceEnd(); // PreloadClasses
        bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
        cacheNonBootClasspathClassLoaders();
        bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
        bootTimingsTraceLog.traceBegin("PreloadResources");
     	//预加载资源
        preloadResources();
        bootTimingsTraceLog.traceEnd(); // PreloadResources
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
        nativePreloadAppProcessHALs();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
        maybePreloadGraphicsDriver();
        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
        preloadSharedLibraries();
        preloadTextResources();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();
        endPreload();
        warmUpJcaProviders();
        Log.d(TAG, "end preload");

        sPreloadComplete = true;
    }                            
调用ZygoteServer创建两个Server端的Socket

isPrimaryZygote为true,因为socketName都为zygote,拼接的socket name为"ANDROID_SOCKET_zygote"。完成创建LocalServerSocket。在Zygote进程将SystemServer进程启动后,就会在这个server端的socket等待AMS请求Zygote进程来创建新的应用程序进程。

源码路径:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

 ZygoteServer(boolean isPrimaryZygote) {
        mUsapPoolEventFD = Zygote.getUsapPoolEventFD();

        if (isPrimaryZygote) {
            mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
            mUsapPoolSocket =
                    Zygote.createManagedSocketFromInitSocket(
                            Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
        } else {
            mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);
            mUsapPoolSocket =
                    Zygote.createManagedSocketFromInitSocket(
                            Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
        }

        mUsapPoolSupported = true;
        fetchUsapPoolPolicyProps();
    }

源码路径:frameworks/base/core/java/com/android/internal/os/Zygote.java

private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
public static final StringPRIMARY_SOCKET_NAME  = "zygote";
static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
        int fileDesc;
    	//拼接socket名称
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;

        try {
            //得到socket环境变量的值
            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);
            //创建server端socket
            return new LocalServerSocket(fd);
        } catch (IOException ex) {
            throw new RuntimeException(
                "Error building socket from file descriptor: " + fileDesc, ex);
        }
    }
调用Zygote的forkSystemServer方法启动SystemServer进程。

从SystemServer进程的启动参数来看,SystemServer的进程用户id和用户组id被设置为1000,并且拥有用户组1001~1010、1018、1021、1023的权限,进程名为system_server,启动类名为com.android.server.SystemServer。之后将启动参数封装,并提供给Zygote的forkSystemServer方法,nativeForkSystemServer方法会通过fork函数为当前进程创建一个子进程,就是SystemServer进程,如果forkSystemServer返回的pid=0,表示当前代码运行在新创建的子进程中,执行handleSystemServerProcess方法来处理SystemServer进程。

源码路径:frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
		...
        /* Hardcoded command line to start the system server */
        //SystemServer 启动参数
        String[] args = {
                "--setuid=1000",
                "--setgid=1000",
                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                        + "1024,1032,1065,3001,3002,3003,3005,3006,3007,3009,3010,3011,3012",
                "--capabilities=" + capabilities + "," + capabilities,
                "--nice-name=system_server",
                "--runtime-args",
                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                "com.android.server.SystemServer",
        };
        ZygoteArguments parsedArgs;

        int pid;

        try {
            ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
            try {
                //参数封装
                parsedArgs = ZygoteArguments.getInstance(commandBuffer);
            } catch (EOFException e) {
                throw new AssertionError("Unexpected argument error for forking system server", e);
            }
            commandBuffer.close();
            Zygote.applyDebuggerSystemProperty(parsedArgs);
            Zygote.applyInvokeWithSystemProperty(parsedArgs);

            if (Zygote.nativeSupportsMemoryTagging()) {
                String mode = SystemProperties.get("arm64.memtag.process.system_server", "");
                if (mode.isEmpty()) {
                  /* The system server has ASYNC MTE by default, in order to allow
                   * system services to specify their own MTE level later, as you
                   * can't re-enable MTE once it's disabled. */
                  mode = SystemProperties.get("persist.arm64.memtag.default", "async");
                }
                if (mode.equals("async")) {
                    parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
                } else if (mode.equals("sync")) {
                    parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_SYNC;
                } else if (!mode.equals("off")) {
                    /* When we have an invalid memory tag level, keep the current level. */
                    parsedArgs.mRuntimeFlags |= Zygote.nativeCurrentTaggingLevel();
                    Slog.e(TAG, "Unknown memory tag level for the system server: \"" + mode + "\"");
                }
            } else if (Zygote.nativeSupportsTaggedPointers()) {
                /* Enable pointer tagging in the system server. Hardware support for this is present
                 * in all ARMv8 CPUs. */
                parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI;
            }

            /* Enable gwp-asan on the system server with a small probability. This is the same
             * policy as applied to native processes and system apps. */
            parsedArgs.mRuntimeFlags |= Zygote.GWP_ASAN_LEVEL_LOTTERY;

            if (shouldProfileSystemServer()) {
                parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
            }

            /* Request to fork the system server process */
            //创建一个进程,SystemServer进程
            pid = Zygote.forkSystemServer(
                    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) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            //处理SystemServer进程,SystemServer进程启动过程中详细分析
            return handleSystemServerProcess(parsedArgs);
        }

        return null;
    }    

源码路径:frameworks/base/core/java/com/android/internal/os/Zygote.java

    static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
        ZygoteHooks.preFork();

        int pid = nativeForkSystemServer(
                uid, gid, gids, runtimeFlags, rlimits,
                permittedCapabilities, effectiveCapabilities);

        // Set the Java Language thread priority to the default value for new apps.
        Thread.currentThread().setPriority(Thread.NORM_PRIORITY);

        ZygoteHooks.postForkCommon();
        return pid;
    }
等待AMS来请求Zygote创建新的应用程序进程。

启动SystemServer进程后,会执行ZygoteServer的runSelectLoop方法。

mZygoteSocket就是第二步中创建的Server端socket,获取该socket的fd字段的值添加到fd列表socketFDs中,下面无限循环用来等待AMS请求Zygote进程创建新的应用程序进程,如果pollIndex=0,Zygote进程与AMS建立了连接,通过acceptCommandPeer方法获取ZygoteConnection对象,接着将ZygoteConnection的fd添加到fd列表,以便接收AMS发送的请求,如果poIIIndex不为0,则说明AMS向Zygote进程发送了一个创建应用进程的请求,调用ZygoteConnection类的processCommand方法创建一个新的应用程序进程。

源码路径:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

Runnable runSelectLoop(String abiList) {
        ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
        ArrayList<ZygoteConnection> peers = new ArrayList<>();
		//mZygoteSocket 就是第二步创建的socket
        socketFDs.add(mZygoteSocket.getFileDescriptor());
        peers.add(null);

        mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
		//无限循环等待AMS的请求
        while (true) {
            fetchUsapPoolPolicyPropsWithMinInterval();
            mUsapPoolRefillAction = UsapPoolRefillAction.NONE;

            int[] usapPipeFDs = null;
            StructPollfd[] pollFDs;

            if (mUsapPoolEnabled) {
                usapPipeFDs = Zygote.getUsapPipeFDs();
                pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length];
            } else {
                pollFDs = new StructPollfd[socketFDs.size()];
            }

            int pollIndex = 0;
            //socketFDs转存pollFDs
            for (FileDescriptor socketFD : socketFDs) {
                pollFDs[pollIndex] = new StructPollfd();
                pollFDs[pollIndex].fd = socketFD;
                pollFDs[pollIndex].events = (short) POLLIN;
                ++pollIndex;
            }

            final int usapPoolEventFDIndex = pollIndex;

            if (mUsapPoolEnabled) {
                pollFDs[pollIndex] = new StructPollfd();
                pollFDs[pollIndex].fd = mUsapPoolEventFD;
                pollFDs[pollIndex].events = (short) POLLIN;
                ++pollIndex;

                // The usapPipeFDs array will always be filled in if the USAP Pool is enabled.
                assert usapPipeFDs != null;
                for (int usapPipeFD : usapPipeFDs) {
                    FileDescriptor managedFd = new FileDescriptor();
                    managedFd.setInt$(usapPipeFD);

                    pollFDs[pollIndex] = new StructPollfd();
                    pollFDs[pollIndex].fd = managedFd;
                    pollFDs[pollIndex].events = (short) POLLIN;
                    ++pollIndex;
                }
            }

            int pollTimeoutMs;

            if (mUsapPoolRefillTriggerTimestamp == INVALID_TIMESTAMP) {
                pollTimeoutMs = -1;
            } else {
                long elapsedTimeMs = System.currentTimeMillis() - mUsapPoolRefillTriggerTimestamp;

                if (elapsedTimeMs >= mUsapPoolRefillDelayMs) {
                    pollTimeoutMs = 0;
                    mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
                    mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;

                } else if (elapsedTimeMs <= 0) {
                    pollTimeoutMs = mUsapPoolRefillDelayMs;

                } else {
                    pollTimeoutMs = (int) (mUsapPoolRefillDelayMs - elapsedTimeMs);
                }
            }

            int pollReturnValue;
            try {
                pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }

            if (pollReturnValue == 0) {
                mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
                mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;

            } else {
                boolean usapPoolFDRead = false;

                while (--pollIndex >= 0) {
                    if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
                        continue;
                    }

                    if (pollIndex == 0) {
                        // Zygote server socket
                        //Zygote进程与AMS建立了连接
                        ZygoteConnection newPeer = acceptCommandPeer(abiList);
                        peers.add(newPeer);
                        //ZygoteConnection的fd添加到fd列表,接收来自AMS发送的请求
                        socketFDs.add(newPeer.getFileDescriptor());
                    } else if (pollIndex < usapPoolEventFDIndex) {
                        // Session socket accepted from the Zygote server socket

                        try {
                            ZygoteConnection connection = peers.get(pollIndex);
                            boolean multipleForksOK = !isUsapPoolEnabled()
                                    && ZygoteHooks.isIndefiniteThreadSuspensionSafe
                            //AMS向Zygote进程发送一个创建应用进程的请求
                            final Runnable command =
                                    connection.processCommand(this, multipleForksOK);

                            // 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 processCommand 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 processCommand. This
                                // shows up as a regular POLLIN event in our regular processing
                                // loop.
                                if (connection.isClosedByPeer()) {
                                    connection.closeSocket();
                                    peers.remove(pollIndex);
                                    socketFDs.remove(pollIndex);
                                }
                            }
                            ...
        }
    }

Zygote的forkAndSpecialize方法会调用nativeForkAndSpecialize方法fork应用程序进程,应用程序进程创建完成,pid=0表示在子进程执行,最终执行handleChildProc方法处理应用程序进程,isZygote为false,它传递parsedArgs.mStartChildZygote,实际上应用程序进程启动没有传递"–start-child-zygote"参数,所以它为false。应用程序进程创建传递的参数会在应用程序进程启动文章中看到传递哪些参数,然后调用ZygoteInit类的zygoteInit方法。

源码路径:frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
				...
                if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote
                        || !multipleOK || peer.getUid() != Process.SYSTEM_UID) {
                    //获取参数
                    parsedArgs = ZygoteArguments.getInstance(argBuffer);
                    // Continue using old code for now. TODO: Handle these cases in the other path.
                    //fork app进程
                    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.mIsTopApp, parsedArgs.mPkgDataInfoList,
                            parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
                            parsedArgs.mBindMountAppStorageDirs);

                    try {
                        //新创建子进程执行
                        if (pid == 0) {
                            // in child
                            zygoteServer.setForkChild();

                            zygoteServer.closeServerSocket();
                            IoUtils.closeQuietly(serverPipeFd);
                            serverPipeFd = null;

                            return handleChildProc(parsedArgs, 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, serverPipeFd);
                            return null;
                        }
                    } finally {
                        IoUtils.closeQuietly(childPipeFd);
                        IoUtils.closeQuietly(serverPipeFd);
                    }
                } else {
                    ZygoteHooks.preFork();
                    Runnable result = Zygote.forkSimpleApps(argBuffer,
                            zygoteServer.getZygoteSocketFileDescriptor(),
                            peer.getUid(), Zygote.minChildUid(peer), parsedArgs.mNiceName);
                    if (result == null) {
                        // parent; we finished some number of forks. Result is Boolean.
                        // We already did the equivalent of handleParentProc().
                        ZygoteHooks.postForkCommon();
                        // argBuffer contains a command not understood by forksimpleApps.
                        continue;
                    } else {
                        // child; result is a Runnable.
                        zygoteServer.setForkChild();
                        Zygote.setAppProcessName(parsedArgs, TAG);  // ??? Necessary?
                        return result;
                    }
                }
            }
        }
		...
    }
private Runnable handleChildProc(ZygoteArguments parsedArgs,
            FileDescriptor pipeFd, boolean isZygote) {
        closeSocket();

        Zygote.setAppProcessName(parsedArgs, TAG);

        // End of the postFork event.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        if (parsedArgs.mInvokeWith != null) {
            WrapperInit.execApplication(parsedArgs.mInvokeWith,
                    parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(),
                    pipeFd, parsedArgs.mRemainingArgs);

            // Should not get here.
            throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
        } else {
            if (!isZygote) {
                return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                        parsedArgs.mDisabledCompatChanges,
                        parsedArgs.mRemainingArgs, null /* classLoader */);
            } else {
                return ZygoteInit.childZygoteInit(
                        parsedArgs.mRemainingArgs  /* classLoader */);
            }
        }
}

zygoteInit方法中主要做了两件事,首先调用nativeZygoteInit方法去启动Binder线程池(关于Binder线程池后续会讲到),然后调用RuntimeInit类的applicationInit方法。

源码路径:frameworks\base\core\java\com\android\internal\os\ZygoteInit.java

public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();

        RuntimeInit.commonInit();
    	//Binder线程池启动
        ZygoteInit.nativeZygoteInit();
        return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
                classLoader);
}

applicationInit方法中开始设置参数,并获取应用程序进程的启动类,findStaticMain方法中通过反射获取启动类的main方法,返回MethodAndArgsCaller,最终在ZygoteInit类的main方法中,调用其run方法。

源码路径:frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        // If the application calls System.exit(), terminate the process
        // immediately without running any shutdown hooks.  It is not possible to
        // shutdown an Android application gracefully.  Among other things, the
        // Android runtime shutdown hooks close the Binder driver, which can cause
        // leftover running threads to crash before the process actually exits.
        nativeSetExitWithoutCleanup(true);

        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
        VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges);

        final Arguments args = new Arguments(argv);

        // The end of of the RuntimeInit event (see #zygoteInit).
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        // Remaining arguments are passed to the start class's static main
        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 {
            //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);
        }
        return new MethodAndArgsCaller(m, argv);
}
static class MethodAndArgsCaller implements Runnable {
        /** method to call */
        private final Method mMethod;

        /** argument array */
        private final String[] mArgs;

        public MethodAndArgsCaller(Method method, String[] args) {
            mMethod = method;
            mArgs = args;
        }

        public void run() {
            try {
                mMethod.invoke(null, new Object[] { mArgs });
        ...

补充

在Zygote进程启动过程第中,等待AMS来请求Zygote进程创建新的应用程序进程,其中有说到Binder线程池通过ZygoteInit类的nativeZygoteInit方法启动,下面分析下Binder线程池的启动过程。

Binder线程池启动过程

Binder线程池在Android中扮演着重要的角色,它是Android操作系统的一种进程间通信(IPC)机制。从源码可以看出nativeZygoteInit方法是一个JNI方法(关于JNI,请查看之前文章使用Android Studio开发第一个NDK程序),

源码路径:frameworks\base\core\java\com\android\internal\os\ZygoteInit.java

public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();

        RuntimeInit.commonInit();
        ZygoteInit.nativeZygoteInit();
        return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
                classLoader);
    } 
private static native void nativeZygoteInit();

它对应的C函数是什么呢?在AndroidRuntime类中,从JNINativeMethod数组中可以得知它所对应的函数为com_android_internal_os_ZygoteInit_nativeZygoteInit,在其函数中,gCurRuntime为AndroidRuntime类型的指针,在AndroidRuntime初始化时就创建了,

源码路径:frameworks\base\core\jni\AndroidRuntime.cpp

static AndroidRuntime* gCurRuntime = NULL;
int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env)
{
    const JNINativeMethod methods[] = {
        { "nativeZygoteInit", "()V",
            (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
    };
    return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
        methods, NELEM(methods));
}
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit();
}
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
        mExitWithoutCleanup(false),
        mArgBlockStart(argBlockStart),
        mArgBlockLength(argBlockLength)
{
    init_android_graphics();

    // Pre-allocate enough space to hold a fair number of options.
    mOptions.setCapacity(20);

    assert(gCurRuntime == NULL);        // one per process
    gCurRuntime = this;
}

AppRuntime继承自AndroidRuntime,AppRuntime创建时会调用AndroidRuntime的构造函数,gCurRuntime就会被初始化,它指向AppRuntime,查看AppRuntime的onZygoteInit函数,AppRuntime在app_main类中实现,onZygoteInit函数中调用ProcessState类的

startThreadPool函数启动Binder线程池。

源码路径:frameworks\base\cmds\app_process\app_main.cpp

class AppRuntime : public AndroidRuntime
{
    virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();
    }
}

支持Binder通信的进程都有一个ProcessState类,它里面有一个mThreadPoolStarted变量,用来表示Binder线程池是否已经被启动过,默认值为false,每次调用startThreadPool函数都会先检查这个变量,确保Binder 线程池只会被启动一次,如果未启动,则会将mThreadPoolStarted设置为true,然后调用spawnPooledThread函数来创建线程池的第一个线程,也就是线程池的主线程。可以看到Binder线程池为一个PoolThread,然后调用run函数来启动一个新的线程。

PoolThread类继承了Thread类,调用IPCThreadState的joinThreadPool函数,将当前线程注册到Binder驱动程序中,这样创建的线程就被加入到Binder线程池中,新创建的应用程序进程就可以支持Binder进程间通信了。

源码路径:frameworks/native/libs/binder/ProcessState.cpp

void ProcessState::startThreadPool(
{
    AutoMutex _l(mLock);
    if (!mThreadPoolStarted) {
        if (mMaxThreads == 0) {
            ALOGW("Extra binder thread started, but 0 threads requested. Do not use "
                  "*startThreadPool when zero threads are requested.");
        }

        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}
void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        String8 name = makeBinderThreadName();
        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
        sp<Thread> t = sp<PoolThread>::make(isMain);
        t->run(name.string());
    }
}
class PoolThread : public Thread
{
public:
    explicit PoolThread(bool isMain)
        : mIsMain(isMain)
    {
    }

protected:
    virtual bool threadLoop()
    {
        IPCThreadState::self()->joinThreadPool(mIsMain);
        return false;
    }

    const bool mIsMain;
};

总结

Zygote进程启动过程的时序图如下:

Zygote进程启动时序

Zygote进程启动主要做了如下事情:

  1. 创建AndroidRuntime并调用start函数,启动Zygote进程。
  2. 创建Java虚拟机并为Java虚拟机注册JNI方法。
  3. 通过JNI调用ZygoteInit的main函数进入Zygote的Java框架层。、
  4. 启动SystemServer进程。
  5. 注册socket,并通过runSelectLoop方法等待AMS的请求来创建新的应用程序进程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1306193.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AnythingLLM:基于RAG方案构专属私有知识库(开源|高效|可定制)

一、前言 继OpenAI和Google的产品发布会之后&#xff0c;大模型的能力进化速度之快令人惊叹&#xff0c;然而&#xff0c;对于很多个人和企业而言&#xff0c;为了数据安全不得不考虑私有化部署方案&#xff0c;从GPT-4发布以来&#xff0c;国内外的大模型就拉开了很明显的差距…

Oracle(2-17) RMAN Maintenance

文章目录 一、基础知识1、Retention Policy 保留政策2、Recovery Window - Part 1 恢复窗口-第1部分3、Cross Checking 交叉检查4、The CROSSCHECK Command CROSSCHECK命令5、OBSOLETE VS EXPIRED 过时与过期6、Deleting Backups and Copies 删除备份和副本7、The DELETE Comma…

极狐GitLab CI/CD 变量黑魔法之自定义变量

极狐GitLab CI/CD 变量是指一系列的环境变量&#xff0c;用来帮助我们控制 CI/CD Job 或 Pipeline 的行为&#xff0c;存储一些可以复用的信息&#xff0c;避免在 .gitlab-ci.yml 中形成硬编码。 极狐GitLab CI/CD 变量分为预定义变量(predefined CI/CD variables) 和 自定义变…

图论-并查集

并查集(Union-find Sets)是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题.一些常见的用途有求连通子图,求最小生成树Kruskal算法和最近公共祖先(LCA)等. 并查集的基本操作主要有: .1.初始化 2.查询find 3.合并union 一般我们都会采用路径压缩 这样…

flex布局,换行的元素上下设置间距

要生成的效果图如下&#xff1a; display:flexflex-direction: row;flex-wrap: wrap;当我们使用弹性盒子布局后&#xff0c;默认元素是没有外边距的&#xff0c;紧挨着样式就有点丑&#xff0c;如果想使换行后&#xff0c;元素的外边距有个距离&#xff0c;可以用如下方法解决…

Apache Flink(十二):Flink集群部署-Flink On Yarn

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录

Python学习笔记(四):函数的定义、函数的返回值、None类型、函数说明文档、函数的嵌套调用、局部变量、全局变量、global关键字

目录 一、函数介绍 1. 函数是&#xff1a; 2. 使用函数的好处是&#xff1a; 二、函数的定义&#xff1a; 三、函数的参数 1.传入参数的功能是&#xff1a; 2.函数的传入参数 - 传参定义 3.注意事项&#xff1a; 4.练习&#xff1a;测量体温 四、函数的返回值 1.函数…

Axure元件基本介绍进阶

Axure元件基本介绍进阶 1.Axure元件基本介绍1.在 Axure 中&#xff0c;元件是构建原型的基本构成单元&#xff0c;能够帮助设计师快速创建、重复使用和管理设计元素。以下是 Axure 中元件的基本介绍&#xff1a;1.基本元件&#xff1a; 2.基本元件的使用一.【举例说明】积木&am…

基于 Game Object Conversion 和 SubScene 的 DOTS 开发工作流(干货满满!)

(译前言: Unity DOTS提出了一套全新的开发技术栈, 但目前少有精讲如何结合现有工作流进行开发的资料, 外网 这篇文章 (Game Object Conversion and SubScene) 详细解构了基于 GameObject 和 Subscene 的工作流程和原理, 要求读者对 DOTS/ECS 有基本的了解, 虽然非常之长, 但值得…

8 Buildroot 根文件系统构建

一、根文件系统简介 根文件系统一般也叫做 rootfs&#xff0c;这个是属于 Linux 内核的一部分。 根文件系统首先是一种文件系统&#xff0c;该文件系统不仅具有普通文件系统的存储数据文件的功能&#xff0c;但是相对于普通的文件系统&#xff0c;它的特殊之处在于&#xff0c;…

flutter的ListView和SingleChildScrollView有什么区别?他们的使用场景有什么不一样?

文章目录 简介ListViewSingleChildScrollView使用场景的不同 简介 ListView和SingleChildScrollView都是在Flutter中用于处理滚动内容的组件&#xff0c;但它们有一些关键的区别。 ListView 多个子元素&#xff1a; ListView是一个滚动的可滚动组件&#xff0c;通常用于包含多…

看图识药,python开发实现基于VisionTransformer的119种中草药图像识别系统

中药药材图像识别相关的实践在前面的系列博文中已经有了相应的实践了&#xff0c;感兴趣的话可以自行移步阅读即可&#xff0c;每篇文章的侧重点不同&#xff1a; 《python基于轻量级GhostNet模型开发构建23种常见中草药图像识别系统》 《基于轻量级MnasNet模型开发构建40种常…

HTML中常用表单元素使用(详解!)

Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍HTML中常用表单元素使用以及部分理论知识 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主收将持续更新学习记录获&#xff0c;友友们有任何问题可以在评论区留言 …

云基础软件深化合作,云轴科技ZStack与麒麟软件战略签约

12月8日&#xff0c;云轴科技ZStack与麒麟软件战略合作签约仪式在北京举行&#xff0c;双方对过往紧密合作表达了充分肯定&#xff0c;并就进一步联合技术创新、打造重点行业标杆和持续赋能客户达成高度共识。云轴科技创始人&CEO张鑫和麒麟软件高级副总经理谢文征共同见证双…

112. 路径总和(Java)

目录 解法&#xff1a; 官方解法&#xff1a; 方法一&#xff1a;广度优先搜索 思路及算法 复杂度分析 时间复杂度&#xff1a; 空间复杂度&#xff1a; 方法二&#xff1a;递归 思路及算法 复杂度分析 时间复杂度&#xff1a; 空间复杂度&#xff1a; 给你二叉树的…

【毕业设计】基于STM32的解魔方机器人

1、方案设计 1.采用舵机作为魔方机器人的驱动电机&#xff0c;从舵机的驱动原理可知&#xff1a;舵机运行的速度和控制器的主频没有关系&#xff0c;所以采用单片机和采用更高主频的嵌入式处理器相比在控制效果上没有什么差别。单片机编程过程简单&#xff0c;非常容易上手&am…

c#_sqlserver_三层架构winform学生信息管理及选课系统

基本功能包括管理员登录、注册学生账号、删除学生信息、查找学生信息、发布课程、修改课程、删除课程等。 教师端 登录&#xff1a;管理员登陆&#xff0c;拥有相应账号即可登录&#xff08;后台注册&#xff09;。注册学生账号&#xff1a;管理员可给学生分配学号&#xff0…

Linux Mint编译安装Qemu

文章目录 前言1. 准备Qemu源码包2. 编译安装2.1 首次尝试编译2.2 安装python3-venv2.3 安装sphinx2.4 安装sphinx-rtd-theme2.4 安装ninja2.6 安装编译器 3. 重新编译并安装4. 进行固件仿真4.1 准备固件4.2 Binwalk解析文件4.3 看一下文件结构4.4 安装sasquatch4.5 重新解析文件…

OkHttp: 拦截器和事件监听器

文章目录 1. 拦截器1. 拦截器链2. 实际案例1. 注册为应用拦截器2. 注册为网络拦截器 3. 如何选择用哪种拦截器1. 应用拦截器2. 网络层拦截器3. 重写请求4. 重写响应 4. 可用性 2. 事件监听器1. 请求的生命周期2. EventListener使用案例3. EventListener.Factory4. 调用失败的请…

一、Oracle学习笔记

1.1.1实例的概念实例是一组内存结构和后台进程的集合。oracle适用于大型的应用系统1.1.2实例的构成1.实例中的这部分内存结构叫做系统全局区&#xff08;SGA&#xff09;:存储数据库中的数据、存储数据字典的信息、重做日志、经过解析的SQL代码等一个实例只有一个SGA&#xff1…