preface

In the process of research referred to a lot of articles, this source code analysis, may be the most complete Zygote source code analysis of the network

If you think this source analysis is too dry, you can also take a look at the follow-up summary, stamp juejin.cn/post/684490…

The full text overview

We all know that non-specialized Android processes (other than init and Zygote) are children of Zygotefork, including SystemServer, Also from Zygote Fork

This article mainly discusses the following issues

  1. How is the Zygote process started?
  2. How did Zygote fork SystemServer?
  3. How are other common processes forked out?
  4. How is it different from normal App Process?

These questions will be answered in the following source code analysis

Specific source code analysis

How is the Zygote process started

How does Zygote get started

Rc is a reference to zygote.rc, which is not found in the source code, but in the compiled file

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
Copy the code

Let’s focus on the first few lines

Service zygote /system/bin/ app_process-xzygote /system/bin –zygote –start-system-server The zygote executable file should be located in/ system/bin/app_process. The source code should also have an app_process directory, as mentioned in the first Bilibili technical Share. The source code for Zygote is actually the code for app_process

Let’s go ahead and find out

. / frameworks/base/CMDS/app_process/app_main. We from the point of the entry function of app_main CPP

int main(int argc, char* const argv[]) { ... // Create AppRuntime, which is a subclass of 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])); // Add zygote. rc to 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 = true; // Zygote niceName = ZYGOTE_NICE_NAME; Zygote} else if (STRCMP (arg, "--start-system-server") == 0) {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; } } Vector<String8> args; // If it is zygote, the className is null, so this is actually the zygote process if (! Classname.isempty ()) {classname.isempty (); // 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 {// 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) {// Obtain the supported CPU instruction set 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. i < argc; ++i) { args.add(String8(argv[i])); } } if (! Isename ()) {// If niceName is not empty, it indicates zygote runtime.setargv0 (niceName. String (), true /* setProcName */); / / comment here also explains, here is the setup process name} the if (zygote) {/ / if it is zygote model runtime. The start (" com. Android. Internal. OS. ZygoteInit ", args, zygote); // call zygoteInit, And passed on the parameters of the current} else if (className) {/ / if it zygote model runtime. The 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."); }}Copy the code

The purpose of this article is to analyze the flow of Zygote, so we will focus on the logic related to Zygote for the time being

The function finally calls ZygoteInit, so what does this class basically do

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

Following the previous routine, we first find the entry function main

@UnsupportedAppUsage public static void main(String argv[]) { // Server socket class for zygote processes. ZygoteServer zygoteServer = null; // This ensures that thread creation will throw // an error. ZygoteHooks.startZygoteNoThreadCreation(); Zygote goes into its own process group. Try {os.setpgid (0, 0); zygote goes into its own process group. // Set the pgid (Process Group ID) for the zygote Process. `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"))) { Judgment system restart complete MetricsLogger. Histogram (null, "boot_zygote_init", (int) SystemClock. ElapsedRealtime ()); } String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing"; // Determine whether the current process is 64-bit or 32-bit. Set the TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag, TRACE_TAG_DALVIK); bootTimingsTraceLog.traceBegin("ZygoteInit"); RuntimeInit.enableDdms(); / / registered to DDMS server, internal call ` 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; Else if ("--enable-lazy-preload". Equals (argv[I])) {enableLazyPreload = true; } else if (argv[I].startswith (ABI_LIST_ARG)) {argv[I].argist = argv[I]. } 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); If (abiList == null) {// If (socketName = 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(); / / call ZygoteHooks. GcAndFinalize () recycling 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); / / the jni calls to initialize the state of the zygote, whether for isPrimaryZygote ZygoteHooks. StopZygoteNoThreadCreation (); ZygoteServer = new zygoteServer (isPrimaryZygote); zygoteServer = new zygoteServer (isPrimaryZygote); // create zygoteServer, If (startSystemServer) {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 ! // If it is zygote, then r==null, if it is not zygote, that is systemServer, then execute the following code 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); } catch (Throwable ex) {log. e(TAG, "System zygote died with exception", ex); throw ex; } finally { if (zygoteServer ! = null) { zygoteServer.closeServerSocket(); // If an exception occurs, zygote initialization fails We're in the child process and have exited the select loop. Proceed to execute the // command. if (caller ! = null) { caller.run(); }}Copy the code

We have combed out the general process of Zygote, now let’s summarize it

  1. Parse correspondingzyogte.rcThe script
  2. callapp_process/appMain.cpp
  3. Set the process name to zygote
  4. callzygoteInit.javaExample Initialize the Zygote process
  5. JNI callszygoteInit.cppComplete process creation
  6. callrunSelectionLoop()To create a child process that receives messages from other processes

How did Zygote fork SystemServer

As we all know, on Android, zyogte is the first process in the Java world (init is the number one process) and is created directly from exec’s system call. All other processes, including system_server, are children of zygote. Zygote forks system_server from zygote

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) {// If r is not null, it is system_server process r.run(); // Call its run method return; }}... }... }Copy the code

If zygote.rc is true, forkSystemServer is forkSystemServer. If zygote.rc is true, forkSystemServer is forkSystemServer. And executes the Runnable run() method it returns. What does forkSystemServer do

/** * Prepare the arguments and forks for the system server process. * * @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 uses POSIX capabilities instead of the traditional trust model long capabilities = posixCapabilitiesAsBits(// Set process capabilities CAP_IPC_LOCK, // OsConstants.CAP_KILL, // OsConstants.CAP_NET_ADMIN, OsConstants. // Enable network management tasks: OsConstants.CAP_NET_BIND_SERVICE, // Allows binding to ports less than 1024 OsConstants.CAP_NET_BROADCAST, CAP_NET_RAW, // OsConstants.CAP_SYS_MODULE, // Insert and delete kernel module OsConstants.CAP_SYS_NICE, // Allow priority promotion, CAP_SYS_PTRACE, // OsConstants.CAP_SYS_TIME, // OsConstants.CAP_SYS_TTY_CONFIG, // Allow configuration of TTY devices 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); } 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 */ /* Hardcoded command line to start the system Server args*/ String args[] = { "--setuid=1000", / / user id "-- setgid = 1000", / / the user group id "- setgroups = 1001100 2100 3100 4100 5100 6100 7100 8100 9101 0101 8102 1102 3," + "1024103 2106 5300 1300 2300 3300 6300 7300 9301 0" and "-" capabilities = "+ +", "+" capabilities "capabilities, // Process name "--nice-name=system_server", // process name "--runtime-args", "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT, "com.android.server.SystemServer", }; ZygoteArguments parsedArgs = null; int pid; //processId, processId try {parsedArgs = new ZygoteArguments(args); / / / / create ZygoteArguments object, the args resolves to need the parameters of the Zygote. ApplyDebuggerSystemProperty (parsedArgs); Zygote.applyInvokeWithSystemProperty(parsedArgs); boolean profileSystemServer = SystemProperties.getBoolean( "dalvik.vm.profilesystemserver", false); / / associated with Art virtual machine, temporarily do not delve into the if (profileSystemServer) {parsedArgs. MRuntimeFlags | = Zygote. PROFILE_SYSTEM_SERVER; } /* Request to fork the system server process */ pid = zygote.forkSystemServer () 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(); return handleSystemServerProcess(parsedArgs); } return null; }Copy the code

The code ends with a call to zygote.forkSystemServer () to create SystemServer

public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) { ZygoteHooks.preFork(); Resets nice priority for zygote process.resetnicepriority (); Int pid = nativeForkSystemServer(//JNI, Createsystemserver process functions 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; }Copy the code

Then follow along to zygote.cpp in native c++ code

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); // Fork a child process from zygote and return processId... return pid; }Copy the code

Here we put the relevant source analysis finished, we summarize:

  1. parsingzygote.rcTo obtain the related scriptsstartSystemserverProperty field of
  2. callstartSystemServer()
  3. callforkSystemServer()To grant permissions to the current process and set UID and GID
  4. To create ZygoteArgument, callzygote.forkSystemServer
  5. JNI calls native’s functions,nativeForkSystemServerComplete the process fork

How is UASP (unspecialized App Process) forked out

Here we only analyze zygote related source code, complete process analysis of AMS summarized together

In zygoteInit, we finally call the runSelectionLoop() of zyogteServer, and we go into an infinite loop. Let’s look at the code

Runnable runSelectLoop(String abiList) {// Use selcet I/O multiplexing. while (--pollIndex >= 0) { ... if (pollIndex == 0) { // Zygote server socket ZygoteConnection newPeer = acceptCommandPeer(abiList); Add (newPeer); // Add (newPeer); socketFDs.add(newPeer.getFileDescriptor()); } else if (pollIndex < usapPoolEventFDIndex) { // Session socket accepted from the Zygote server socket try { ZygoteConnection connection = peers.get(pollIndex); / / to get to the client connection objects ZygoteConnection final Runnable command = connection. ProcessOneCommand (this); // 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); }}}... }... }}Copy the code

Here, when pollIndex==0, call acceptCommandPeer() to create the server for the sokcet connection. In other conditions, call acceptCommandPeer() to obtain a ZygoteConnect object. And execute its processOneCommand() function, read a sokcet command, and fork out the child process, executing the main function of the child process, which we continue with

Runnable processOneCommand(ZygoteServer zygoteServer) { String args[]; ZygoteArguments parsedArgs = null; FileDescriptor[] descriptors; try { args = Zygote.readArgumentList(mSocketReader); // 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; // Subprocess, use pipes to communicate between processes, FileDescriptor serverPipeFd = null; parsedArgs = new ZygoteArguments(args); // Create Zygote parameter object... 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 The sandbox is what we say at ordinary times isolation mechanism (the sandbox) try {if (pid = = 0) {/ / in the child zygoteServer. SetForkChild (); // Set the mIsForkChild flag to 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); Return null; // If pid>0, set the process id for the child process. } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); }}Copy the code

The zygoteArgs object is created from the parameters passed in, the VM object is created, and handleChildProc() is finally called to create the child process and continue tracing the code

private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, boolean isZygote) { ... if (parsedArgs.mNiceName ! Process.setArgV0(parsedargs.mnicename); TraceEnd (trace.trace_tag_activity_manager); // End of the postFork event.trace.traceend (trace.trace_tag_activity_manager); if (parsedArgs.mInvokeWith ! = null) {// If mInvokeWith is null, start the process with exec's system call... } else { if (! IsZygote) {/ / the zygote model return ZygoteInit. ZygoteInit (parsedArgs. MTargetSdkVersion, parsedArgs mRemainingArgs, null /* classLoader */); } else {/ / zygote model return ZygoteInit. ChildZygoteInit (parsedArgs. MTargetSdkVersion, parsedArgs mRemainingArgs, null /* classLoader */); //zygoteInit is an alternative function, while initializing Zygote process}}}Copy the code

Here we only care about the child fork from the Zyogte process, following the zygoteInit() function

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) { ... RuntimeInit.commonInit(); / / the runtime is initialized ZygoteInit. NativeZygoteInit (); . / / the JNI calls, nativeZygoteInit return RuntimeInit applicationInit (targetSdkVersion, argv, this); // Find the main Appde function and initialize the call}Copy the code

The Runtime is initialized first, and the actual zygote is initialized via JNI

static AndroidRuntime* gCurRuntime = NULL; static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz) { gCurRuntime->onZygoteInit(); AndroidRuntime zygoteInit}Copy the code

This is calling onZygoteInit() from AndroidRuntime, and if you click on it, you can see that it’s a virtual function, so it should be done by a subclass object, and we’ve analyzed it before, AndroidRuntime has another subclass in app_main of app_Process called AppRuntime, so let’s look at that

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(); // Start Bind thread pool thread, set thread name}... };Copy the code

A ProcessState object is created and its startThreadPool() function is called. Trace back to the spawnPooledThread function that is internally called to create and start the thread

Void ProcessState: : spawnPooledThread (bool isMain) {if (mThreadPoolStarted) {/ / thread's open String8 name = makeBinderThreadName(); // Create a Binder thread pool name ALOGV("Spawning new pooled Thread, name=%s\n", name.string()); sp<Thread> t = new PoolThread(isMain); T ->run(name.string()); // Execute thread}}Copy the code

When handleChildProc() is executed, handleParentProc() is called to determine the status of the child process. If PID >0, the child process is successfully created. At this point, the child process and its related threads are ready

Now to sum up

  1. callrunSelectLoop, read the message in a loop
  2. callacceptCommandPeerExample Create a connection object for the Sokcet serverZygoteConnection
  3. callacceptOneCommandRead the message from the Soket
  4. Parses the parameters and creates the virtual machine instance object
  5. callhandleChildProcessHandles the creation of child processes
  6. callzygoteInit.zyogteInit(args...)Pass the parameters in
  7. Call native methods for final initialization
  8. The callback toapp_process/app_main.cpptheAppRuntimeIn concrete implementation
  9. Start the Binder thread pool to complete the child process creation

Extra snacks

ZygoteServer source

The class ZygoteServer was used to analyze the Zygote process

This is done in zygote’s main function

zygoteServer = new ZygoteServer(isPrimaryZygote);
Copy the code

So let’s start with this constructor

/** * 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) {// Determine whether PrimaryZygote mZygoteSocket = according to parameters in zygote.rc Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME); / / give mZygoteSocket PRIMARY_SOCKET_NAME assignment mUsapPoolSocket = Zygote. CreateManagedSocketFromInitSocket ( Zygote.USAP_POOL_PRIMARY_SOCKET_NAME); // assign USAP_POOL_PRIMARY_SOCKET_NAME to mUsapPoolSocket} else {mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME); / / give mZygoteSocket SECONDARY_SOCKET_NAME assignment mUsapPoolSocket = Zygote. CreateManagedSocketFromInitSocket ( Zygote.USAP_POOL_SECONDARY_SOCKET_NAME); FetchUsapPoolPolicyProps (); // assign USAP_POOL_SECONDARY_SOCKET_NAME to mUsapPoolSocket} fetchUsapPoolPolicyProps(); mUsapPoolSupported = true; }Copy the code

The above code is used to retrieve zygote.rc configuration, which involves two sockets, mZygoteSocket and mUsapPoolSocket. There are also two Zygotes involved,PrimaryZygote and SecondZygote

But you may be wondering why zygote.rc doesn’t have one. Let me paste the document again

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
Copy the code

Socket usap_pool_primary stream 660 root system socket usap_pool_primary stream 660 root system

The current version only supports 32 bits of PrimaryZygote, so there are only 32 bits of PrimaryZygote. Let’s see if Pixel 2 is available on Android10 based on source code

Use adb shell to view

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
Copy the code

The 64-bit zygote is PrimaryZygote and the 32-bit Zygote is SecondZygote. Different binaries can be started by different Zygotes and are compatible with both 64-bit and 32-bit programs

Let’s see what the two sockets mentioned above do

/** * 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); . }Copy the code

Here two sokcet createManagedSocketFromInitSocket object creation all call the same function ()

/** 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; 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(); // create file descriptor fd.setint $(fileDesc); Return new LocalServerSocket(fd); } catch (IOException ex) {throw new RuntimeException("Error building Socket from file Descriptor: " + fileDesc, ex); }}Copy the code

Using ADB, we can easily see two SocketFDs related to Zygote

ZygoteHooks

Let’s briefly add a bit of zygoteHooks’ source code analysis to clarify the relationship between Dalvik and ART in the Android10 source code

In the above source code analysis, there are several references to ZygoteHooks

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

We discovered that ZygoteHooks are from the ART package

./art/runtime/native/dalvik_system_ZygoteHooks.cc

static void ZygoteHooks_startZygoteNoThreadCreation(JNIEnv* env ATTRIBUTE_UNUSED,
                                                    jclass klass ATTRIBUTE_UNUSED) {
  Runtime::Current()->SetZygoteNoThreadSection(true);
}
Copy the code

You can see that this function is a JNI interface that internally calls the Runtime SetZygoteNoThreadSection function

./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_;
}
Copy the code

Zygote_no_threads_ = zygote_no_threads_ = zygote_no_threads_ = zygote_no_threads_ = zygote_no_threads_ = zygote_no_threads_ = zygote_no_threads_

./art/runtime/runtime.cc

Runtime::Runtime() : ... zygote_no_threads_(false), ... {... }Copy the code

When the Runtime constructs initialization, first set it to false, which means that by default, the Runtime will start the thread

Where is the IsZygoteNoThreadSection() function that returns zygote_no_threads_ used

./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()) { If IsZygoteNoThreadSection() returns true jclass internal_error = env->FindClass(" Java /lang/InternalError"); CHECK(internal_error ! = nullptr); env->ThrowNew(internal_error, "Cannot create threads in zygote"); // Throw an exception directly, return; / / end of the current function} Thread: : CreateNativeThread daemon = = (env, java_thread stack_size, JNI_TRUE); // Create local thread if not zygote process}Copy the code

This is another JNI interface function that is used to create local threads (as you can guess from the class name and method name). As noted in the comment, only non-Zygote processes will create local threads

StopZygoteNoThreadCreation () function is the same, the same is to set up flag is, set to false, you can to create a thread

Write in the last

Here we basically put zygote involved in the relevant source code analysis, the next article will be related to the SystemServer source code analysis. Because the level is limited, write wrong also please give advice

Originality is hard, persistence is harder.

If you want to continue to see my next share, please let me know by liking, your encouragement is the biggest motivation for me to continue to create!