Zygote 进程启动过程

首语

在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的请求来创建新的应用程序进程。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

记录一次chatGPT人机协同实战辅助科研——根据词库自动进行情感分析

有一个Excel中的一列&#xff0c;读取文本判断文本包含积极情感词.txt和消极情感词.txt的个数&#xff0c;分别生成两列统计数据 请将 ‘your_file.xlsx’ 替换为你的Excel文件名&#xff0c;Your Text Column’替换为包含文本的列名。 这个程序首先读取了积极和消极情感词&…

(第68天)DBCA 克隆 PDB

介绍 在前面课程我们讲过使用 DBCA 创建数据库以及搭建 DataGuard 等功能,在多租户这章节,要讲下如何使用 DBCA 克隆 PDB。 18C 开始支持使用 DBCA 在本地 CDB 中克隆 PDB19C 升级支持使用 DBCA 克隆 PDB 到远端 CDB 中19C 升级支持使用 DBCA 重定向迁移 PDB 到远端 CDB 中本…

2023/12/12作业

思维导图 作业&#xff1a; 成果图 代码 #include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { speechernew QTextToSpeech(this); ui->setupUi(this); //一直获取当前时间 idst…

海思越影系列3516DV500/3519DV500/3519AV200/SD3403平台的AI一体化工业相机设计思路

随着工业自动化的发展&#xff0c;生产线对机器视觉的数量要求越来越多&#xff0c;由于数量的增加&#xff0c;视觉系统占的空间也越来越大&#xff0c;给生产线的布局带来困扰。 另一方面随着视觉SOC的发展&#xff0c;越来越多的视觉SOC都逐渐带有一定的算力&#xff0c;一体…

AI全栈大模型工程师(二十八)如何做好算法备案

互联网信息服务算法 什么情况下要备案&#xff1f; 对于B2B业务&#xff0c;不需要备案。 但在B2C领域&#xff0c;一切要视具体情况而定。 如果我们自主训练大型模型&#xff0c;这是必要的。 但如果是基于第三方模型提供的服务&#xff0c;建议选择那些已获得备案并且具有较大…

DevOps - Spug 自动化运维平台

关于Spug 官网&#xff1a;https://spug.cc/ Spug&#xff1a;麻雀&#xff0c;麻雀虽小&#xff0c;五脏俱全。 Spug是面向中小型企业设计的轻量级无Agent的自动化运维平台&#xff0c;整合了主机管理、主机批量执行、主机在线终端、文件在线上传下载、应用发布部署、在线任…

[Angular] 笔记1:开发设置 , 双向绑定

1 设置开发环境 1.1 安装 node 下载 node&#xff0c;因为要使用 npm 工具&#xff0c;教程中使用 Angualr 14, 最新版 node 20 用不了&#xff0c;安装 node 16 就可以。 1.2 安装 Angular CLI Angular CLI 是用于创建 Angular 工程的工具集&#xff0c;使用如下命令&…

redis的深度理解

上篇博客我们说到了redis的基本概念和基本操作&#xff0c;本篇我们就更深入去了解一些redis的操作和概念&#xff0c;我们就从red的主从同步、redis哨兵模式和redis集群三个方面来了解redis数据库 一、主从同步 像MySQL一样&#xff0c;redis是支持主从同步的&#xff0c;而…

面试 JVM 八股文五问五答第二期

面试 JVM 八股文五问五答第二期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1.JVM运行时数据区有几部分?&#xff08;JVM内存布局&#xff09;虚拟机栈和本地方…

nodejs微信小程序+python+PHP社区居民信息管理及数据分析系统-计算机毕业设计推荐django

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

SQL数列

SQL数列 1、数列概述2、SQL数列2.1、简单递增序列2.2、等差数列2.3、等比数列3、SQL数列的应用3.1、连续问题3.2、多维分析1、数列概述 数列是最常见的数据形式之一,实际数据开发场景中遇到的基本都是有限数列。常见的数列例如:简单递增序列、等差数列、等比数列等 如何充分…

汽车IVI中控开发入门及进阶(十一):ALSA音频

前言 汽车中控也被称为车机、车载多媒体、车载娱乐等,其中音频视频是非常重要的部分,音频比如播放各种格式的音乐文件、播放蓝牙接口的音乐、播放U盘或TF卡中的音频文件,如果有视频文件也可以放出音频,看起来很简单,在windows下音乐播放器很多,直接打开文件就能播放各…

记录 | linux安装Manim

linux 安装 Manim sudo apt update sudo apt install build-essential python3-dev libcairo2-dev libpango1.0-dev ffmpeg sudo apt install xdg-utilsconda create manim_py39 python3.9 conda activate manim_py39pip install manim安装好环境后来测试一个例程&#xff0c;…

多维时序 | MATLAB实现BWO-CNN-BiGRU-Multihead-Attention多头注意力机制多变量时间序列预测

多维时序 | MATLAB实现BWO-CNN-BiGRU-Multihead-Attention多头注意力机制多变量时间序列预测 目录 多维时序 | MATLAB实现BWO-CNN-BiGRU-Multihead-Attention多头注意力机制多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现BWO-CNN-B…

向ChatGPT提特殊问题,可提取原始训练数据!

随着ChatGPT等模型的参数越来越大&#xff0c;预训练数据也呈指数级增长。谷歌DeepMind、华盛顿大学、康奈尔大学等研究人员发现,无论是开源还是闭源模型&#xff0c;在训练过程中皆能记住一定数量的原始训练数据样本。 如果使用特定的恶意攻击&#xff0c;便能轻松地从模型中…

Pytorch中Group Normalization的具体实现

Group Normalization (GN) 是一种用于深度神经网络中的归一化方法&#xff0c;它将每个样本划分为小组&#xff0c;并在每个小组内进行标准化。与批归一化&#xff08;Batch Normalization&#xff09;不同&#xff0c;Group Normalization 不依赖于小批量数据&#xff0c;因此…

论文阅读——ScanQA

ScanQA: 3D Question Answering for Spatial Scene Understanding 输入&#xff1a;点云P和问题Q&#xff0c;输出&#xff1a;答案A 点云p由三维坐标点组成。本文模型使用额外的点云特征&#xff1a;点云高度、颜色、法线和多视图图像特征&#xff0c;这些特征将 2D 外观特征投…

SD-WAN架构:优化连接以提升性能

SD-WAN架构主要分为三种类型&#xff0c;分别为本地架构、支持云的架构、支持云的骨干架构。每一种架构都基于它们利用广域网&#xff08;WAN&#xff09;的方式而有其独特的优势。本文将对三种SD-WAN架构进行简要介绍。 SD-WAN本地架构 SD-WAN本地架构是在现场使用SD-WAN盒或…

MATLAB代码:分布式电源接入对配电网影响分析

微♥关注“电击小子程高兴的MATLAB小屋”获取专属优惠 关键词&#xff1a;分布式电源 配电网 评估 仿真平台&#xff1a;MATLAB 主要内容&#xff1a;代码主要做的是分布式电源接入场景下对配电网运行影响的分析&#xff0c;其中&#xff0c;可以自己设置分布式电源接入…

归并排序的实现

一.思想 归并排序是一种基于分治思想的经典排序算法。其主要思想可以总结为以下几个步骤&#xff1a; 分解&#xff08;Divide&#xff09;&#xff1a; 将原始序列划分为若干子序列&#xff0c;直到每个子序列包含一个或零个元素&#xff0c;即认为这些子序列是有序的。 解决…