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
- How is the Zygote process started?
- How did Zygote fork SystemServer?
- How are other common processes forked out?
- 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
- Parse corresponding
zyogte.rc
The script - call
app_process/appMain.cpp
- Set the process name to zygote
- call
zygoteInit.java
Example Initialize the Zygote process - JNI calls
zygoteInit.cpp
Complete process creation - call
runSelectionLoop()
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:
- parsing
zygote.rc
To obtain the related scriptsstartSystemserver
Property field of - call
startSystemServer()
- call
forkSystemServer()
To grant permissions to the current process and set UID and GID - To create ZygoteArgument, call
zygote.forkSystemServer
- JNI calls native’s functions,
nativeForkSystemServer
Complete 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
- call
runSelectLoop
, read the message in a loop - call
acceptCommandPeer
Example Create a connection object for the Sokcet serverZygoteConnection
- call
acceptOneCommand
Read the message from the Soket - Parses the parameters and creates the virtual machine instance object
- call
handleChildProcess
Handles the creation of child processes - call
zygoteInit.zyogteInit(args...)
Pass the parameters in - Call native methods for final initialization
- The callback to
app_process/app_main.cpp
theAppRuntime
In concrete implementation - 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!