This article is based on Android 9.0, code repository address: Android_9.0.0_r45
Article source link:
Zygote.java
ZygoteInit.java
ZygoteServer.java
ZygoteConnection.java
RuntimeInit.java
Take a closer look at the Android architecture below to see where Zygote is.
The image above is from Gityuan.
Throughout the entire Android architecture, the bottom Kernel space is Linux Kernel as the core, and the upper user space is composed of the Framework layer composed of C++/Java. The user space and the Kernel space are connected through system calls. The user space is divided into Native world and Java world, connected by JNI technology. The init process in the Native world is the ancestor of all user processes and has a PID of 1. The init process creates Zygote by parsing init.rc, which translates to Zygote in Chinese. It was the first Java process in the Java world, and the first Java process in the Android system.
The first process Zygote creates is System Server, which manages and starts the entire Java Framework layer. Once the System Server is created, Zygote will fully step into the role of a fertilized egg, waiting to reproduce asexually to create the application process. All application processes are fork by Zygote process, it is not unreasonable to call the Java world nuwa.
The Zygote startup process starts from the Native layer, without much analysis of the Native layer, directly into its entry in the Java world zygoteinit.main () :
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
// Mark zygote start. This ensures that thread creation will throw
// an error.
ZygoteHooks.startZygoteNoThreadCreation();
// Zygote goes into its own process group.
// Set the process group ID
// Pid 0 indicates the process group ID of the current process
// Gid 0 indicates that the PID of the current process is used as the process group ID
try {
Os.setpgid(0.0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid (0, 0)", ex);
}
final Runnable caller;
try{... RuntimeInit.enableDdms();/ / enable DDMS
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) { // Parameter parsing
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: "+ argv[i]); }}if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}
// 1. Register server socket, IPC is not a Binder communication
zygoteServer.registerServerSocketFromEnv(socketName);
// 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); // 2. Preload operation
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority(); // Set the thread priority to NORM_PRIORITY.
}
// Do an initial gc to clean up after startup
gcAndFinalize(); // 3. Force a garbage collection
Zygote.nativeSecurityInit();
// Zygote process unmounts root storage spaces.
Zygote.nativeUnmountStorageOnInit();
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) {
Start the SystemServer process
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r ! = null} in the
// child (system_server) process.
if(r ! =null) {
r.run(); // Call SystemServer's main() method with the MethodAndArgsCaller reflection in Runtimeinit.java
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.
// 5. Loop waiting to process client requests
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
zygoteServer.closeServerSocket(); // Close and release the socket connection
}
// 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
The zygoteinit.main () method can be roughly broken down into the following five steps:
registerServerSocketFromEnv
To register server sockets for cross-process communication, Binder communication is not used.preload()
To perform preloading operationsgcAndFinalize()
Take the initiative to do a garbage collection before forkSystemServerforkSystemServer()
To create the SystemServer processrunSelectLoop()
Loop waiting to process the socket request from the client
The above is basically all the mission of Zygote, and the following process will be analyzed in detail.
registerServerSocketFromEnv
> ZygoteServer.java
void registerServerSocketFromEnv(String socketName) {
if (mServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
// Get the socket fd from the environment variable
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc); // Set the file descriptor
mServerSocket = new LocalServerSocket(fd); // Create a server socket
mCloseSocketFd = true;
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex); }}}Copy the code
The file descriptor fd of the socket is first obtained from the environment variable, and then the server LocalServerSocket is created based on the FD for IPC communication. The environment variables here are set when the init process creates the Zygote process.
preload()
> ZygoteInit.java
static void preload(TimingsTraceLog bootTimingsTraceLog) {... preloadClasses();// Preloads and initializes the classes in /system /etc/preloading-classes. preloadResources();// Preloads system resources. nativePreloadAppProcessHALs();// HAL?. preloadOpenGL();// Preload OpenGL. preloadSharedLibraries();// Preload shared libraries, including Android, compiler_RT and Jnigraphics
preloadTextResources(); // Preload text resources
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
// WebViewFactory some initialization work that must be done in the Zygote process for shared memory
WebViewFactory.prepareWebViewInZygote();
warmUpJcaProviders();
sPreloadComplete = true;
}
Copy the code
The preload() method preloads classes, resources, and shared libraries to improve runtime efficiency. Let’s take a look at what’s preloaded.
preloadClasses()
> ZygoteInit.java
private static void preloadClasses(a) {... InputStream is;try {
// /system/etc/preloaded-classes
is = new FileInputStream(PRELOADED_CLASSES);
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
return;
}
try {
BufferedReader br
= new BufferedReader(new InputStreamReader(is), 256);
int count = 0;
String line;
while((line = br.readLine()) ! =null) {
// Skip comments and blank lines.
line = line.trim();
if (line.startsWith("#") || line.equals("")) {
continue;
}
try {
// Load and explicitly initialize the given class. Use
// Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups
// (to derive the caller's class-loader). Use true to force initialization, and
// null for the boot classpath class-loader (could as well cache the
// class-loader of this class in a variable).
Class.forName(line, true.null);
count++;
} catch (ClassNotFoundException e) {
Log.w(TAG, "Class not found for preloading: " + line);
} catch (UnsatisfiedLinkError e) {
Log.w(TAG, "Problem preloading " + line + ":" + e);
} catch(Throwable t) { ...... }}}catch (IOException e) {
Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
} finally{ IoUtils.closeQuietly(is); . }}Copy the code
Only the core logic code is preserved. Read the /system /etc/preloading-classes file and load the classes declared in the file line by line through the class.forname () method. Preloading commonly used classes on your system can certainly improve runtime efficiency, but it’s often a heavy load. A search of the entire repository found a preloaded classes file in the /frameworks/base/config directory. Opening the file was 6558 lines long, which meant loading thousands of classes in advance, which could take a long time. Improved runtime efficiency at the cost of increasing Android startup time.
preloadResources()
> ZygoteInit.java
private static void preloadResources(a) {
final VMRuntime runtime = VMRuntime.getRuntime();
try {
mResources = Resources.getSystem();
mResources.startPreloading();
if (PRELOAD_RESOURCES) {
TypedArray ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_drawables);
intN = preloadDrawables(ar); ar.recycle(); . ar = mResources.obtainTypedArray( com.android.internal.R.array.preloaded_color_state_lists); N = preloadColorStateLists(ar); ar.recycle();if (mResources.getBoolean(
com.android.internal.R.bool.config_freeformWindowManagement)) {
ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_freeform_multi_window_drawables);
N = preloadDrawables(ar);
ar.recycle();
}
}
mResources.finishPreloading();
} catch (RuntimeException e) {
Log.w(TAG, "Failure preloading resources", e); }}Copy the code
From the source, it can be seen that the main loaded resources are:
com.android.internal.R.array.preloaded_drawables
com.android.internal.R.array.preloaded_color_state_lists
com.android.internal.R.array.preloaded_freeform_multi_window_drawables
preloadSharedLibraries()
> ZygoteInit.java
private static void preloadSharedLibraries(a) {
Log.i(TAG, "Preloading shared libraries...");
System.loadLibrary("android");
System.loadLibrary("compiler_rt");
System.loadLibrary("jnigraphics");
}
Copy the code
Three shared libraries, libandroid.so, libcompiler_rt.so and libjnigraphecs.so, are preloaded.
gcAndFinalize()
> ZygoteInit.java
static void gcAndFinalize(a) {
final VMRuntime runtime = VMRuntime.getRuntime();
/* runFinalizationSync() lets finalizers be called in Zygote, * which doesn't have a HeapWorker thread. */
System.gc();
runtime.runFinalizationSync();
System.gc();
}
Copy the code
ForkSystemServer () initiates a GC operation before it.
forkSystemServer()
After actively calling GC, Zygote is ready to do its big thing — fork SystemServer.
> ZygoteInit.java
private static Runnable forkSystemServer(String abiList, String socketName,
......
/* Hardcoded command line to start the system server */// Start parameter String args[] = {"--setuid=1000"."--setgid=1000"."- setgroups = 1001100 2100 3100 4100 5100 6100 7100 8100 9101 0101 8102 1102 3102 4103 2106 5300 1300 2300 3300 6300 7, 30 09301. ""."--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server"// Process name"--runtime-args"."--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer", // Load class name}; ZygoteConnection.Arguments parsedArgs =null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
boolean profileSystemServer = SystemProperties.getBoolean(
"dalvik.vm.profilesystemserver".false);
if (profileSystemServer) {
parsedArgs.runtimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
}
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.runtimeFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
// pid == 0 indicates the child process. Enter the system_server process from here
if (pid == 0) {
if (hasSecondZygote(abiList)) { // If there is a second Zygote
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket(); // Close and release the socket from Zygote copy
return handleSystemServerProcess(parsedArgs); // Complete the rest of the newly created system_server process
}
/** * Note that the fork() function executes once and returns twice (two processes executing the same program twice). * PID > 0 indicates the parent process. Pid = 0 indicates that the child process * is entered, so return null will still execute */
return null;
}
Copy the code
Can see from the start of the above parameters, the uid and gid SystemServer process is 1000, process name is system_server, the last to load the class name is com. The android. Server SystemServer. Prepared after a series of parameters by ZygoteConnection. The Arguments (), then call the Zygote. ForkSystemServer real fork () method according to the child system_server.
> Zygote.java
public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
VM_HOOKS.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
int pid = nativeForkSystemServer(
uid, gid, gids, runtimeFlags, rlimits, permittedCapabilities, effectiveCapabilities);
// Enable tracing as soon as we enter the system_server.
if (pid == 0) {
Trace.setTracingEnabled(true, runtimeFlags);
}
VM_HOOKS.postForkCommon();
return pid;
}
native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
Copy the code
The final fork() is done in the Native layer. Back to ZygoteInit. ForkSystemServer () performed in the fork () after the logic to handle:
if(pid == 0) {...return handleSystemServerProcess(parsedArgs);
}
return null;
Copy the code
In normal logic, these two returns are executed only once, but they are not. The fork() function executes once and returns twice. To be more precise, two processes are executed twice against a single program. When pid == 0, the child process is in the process. When PID > 0, the parent process is in the process. At the beginning of the fork, the data structure of the parent and child processes is basically the same, but then they diverged and executed their own logic. So there will be two times the code snippet above the return value, the child process (system_server) returns the execution handleSystemServerProcess (parsedArgs) as a result, the parent (zygote) will return null. What happens to two different return values? Let’s return to zygoteinit.main () :
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r ! = null} in the
// child (system_server) process.
// r == null indicates zygote process
// r ! = null indicates the system_server process
if(r ! =null) {
r.run();
return; }}// Loop waiting to process client requests
caller = zygoteServer.runSelectLoop(abiList);
Copy the code
The child system_server returns a Runnable, executes r.run(), and returns directly. The parent zygote process returns null, so it does not satisfy the if criteria and continues to execute runSelectLoop. The father and son processes diverged and went about their own business.
Here is to analyze runSelectLoop () and handleSystemServerProcess () these two methods, see the Zygote and SystemServer process this father and son to continue to do what kind of work.
handleSystemServerProcess
Here in fact has been out of the Zygote category, this is ready to be introduced in the next SystemServer source code analysis, but here do not write and feel Zygote introduction is not complete, simply said together.
> ZygoteInit.java
private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
// set umask to 0077 so new files and directories will default to owner-only permissions.
// umask is used to grant permissions to directories or files when you create them initially
Os.umask(S_IRWXG | S_IRWXO);
// Set the current process name to "system_server".
if(parsedArgs.niceName ! =null) {
Process.setArgV0(parsedArgs.niceName);
}
final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
if(systemServerClasspath ! =null) {
// dex optimized operation
performSystemServerDexOpt(systemServerClasspath);
// Capturing profiles is only supported for debug or eng builds since selinux normally
// prevents it.
boolean profileSystemServer = SystemProperties.getBoolean(
"dalvik.vm.profilesystemserver".false);
if (profileSystemServer && (Build.IS_USERDEBUG || Build.IS_ENG)) {
try {
prepareSystemServerProfile(systemServerClasspath);
} catch (Exception e) {
Log.wtf(TAG, "Failed to set up system server profile", e); }}}if(parsedArgs.invokeWith ! =null) { // invokeWith is usually empty
String[] args = parsedArgs.remainingArgs;
// If we have a non-null system server class path, we'll have to duplicate the
// existing arguments and append the classpath to it. ART will handle the classpath
// correctly when we exec a new process.
if(systemServerClasspath ! =null) {
String[] amendedArgs = new String[args.length + 2];
amendedArgs[0] = "-cp";
amendedArgs[1] = systemServerClasspath;
System.arraycopy(args, 0, amendedArgs, 2, args.length);
args = amendedArgs;
}
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(), null, args);
throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
} else {
ClassLoader cl = null;
if(systemServerClasspath ! =null) {
// Create a classloader and assign it to the current thread
cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
Thread.currentThread().setContextClassLoader(cl);
}
/* * Pass the remaining arguments to SystemServer. */
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
/* should never reach here */
}
Copy the code
Set the process name to system_server, perform dex optimization, set the class loader for the current thread, and finally call zygoteinit. ZygoteInit () to continue processing the remaining parameters.
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {...// Redirect System.out and System.err to the Android log.
// Redirect system. out and system. err to Android log
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit(); // Some initialization work
ZygoteInit.nativeZygoteInit(); // Native layer initialization
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader); // Call the entry function
}
Copy the code
Redirect the Log, do some initialization. This part is not detailed, click on the source link given at the beginning of the article, most of the annotations. The last call RuntimeInit. ApplicationInit (), continue to go in and see.
> RuntimeInit.java
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) {...final Arguments args = new Arguments(argv); // Parse the parameters.// Find the main() method of startClass. The startClass here is com. Android. Server. SystemServer
return findStaticMain(args.startClass, args.startArgs, classLoader);
}
Copy the code
The startClass parameter here is com. Android. Server. SystemServer. FindStaticMain look () method name will know that its role is to find the main () function, here is to find a com. Android. Server SystemServer class’s main () method.
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 {
// Find the main() method
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);
}
/* * This throw gets caught in ZygoteInit.main(), which responds * by invoking the exception's run() method. This arrangement * clears up all the stack frames that were Required in setting * up the process. * Returns a Runnable, which in Zygote's main() method executes the run() method *. Previous versions of the run() method * throw an exception caught in the main() method
return new MethodAndArgsCaller(m, argv);
}
Copy the code
Find the main() method and build a Runnable object MethodAndArgsCaller. Where will the Runnable object returned here be executed? To return to the beginning of the article ZygoteInit. The main () function, in forkSystemServer (), the child process execution handleSystemServerProcess () and returns a Runnable object, Zygoteinit.main () executes its run() method.
Let’s look at the Run () method of MethodAndArgsCaller again!
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(a) {
try {
mMethod.invoke(null.new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw newRuntimeException(ex); }}}Copy the code
For one thing, execute method in the argument. This method is com. Android. Server. SystemServer main () method. At this point, SystemServer is ready to go to work.
In older versions of Android, systemServer.main () is not executed this way. Older versions of MethodAndArgsCaller, a subclass of Exception, throw an Exception directly, catch it in the zygoteinit.main () method, and then execute its run() method.
SystemServer specific analysis of the next article, the protagonist of this article or Zygote!
At this point, Zygote has accomplished one of the great things in its life, spawning the SystemServer process. But as “Nu Wa”, the task of making people still can not stop, any application process to create or inseparable from it. ZygoteServer. RunSlectLoop () to set up it and the client before the bridge.
runSelectLoop
> ZygoteServer.java
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
// mServerSocket was created earlier in Zygote
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
// Execute down when there is an event, block when there is no event
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) { // There is a new client connection
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else { // Process client requests
try {
ZygoteConnection connection = peers.get(i);
final Runnable command = connection.processOneCommand(this); . }catch(Exception e) { ...... }}}}Copy the code
MServerSocket is the server socket set up at the beginning of zygoteinit.main () to handle client requests. Whenever you see while(true), you’re bound to have a blocking operation. Os.poll() executes down when there is an event, otherwise it blocks. When a client requests, call ZygoteConnection. ProcessOneCommand () method to deal with.
ProcessOneCommand () has a long source code, and here’s the key:
. pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote, parsedArgs.instructionSet, parsedArgs.appDataDir);try {
if (pid == 0) {
// in child enters the child process
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
} 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; }}finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
Copy the code
Does it look familiar at first? Yes, the logic of this section is similar to that of forkSystemServer(), except that the normal application process is forkandwpecte (). Android_9.0.0_r45: findStaticMain(); android_9.0.0_r45: findStaticMain(); android_9.0.0_r45: findStaticMain()
One more question, the above only analyzed that Zygote received and responded to a client request, so who could that client be? How exactly does it communicate with Zygote? I’m sure there will be a follow-up post on this issue. Check out my Github repository android_9.0.0_r45 and all posts will be synchronized as soon as possible.
conclusion
Here’s a sequence diagram to sum it up:
Finally, I want to talk about how to read AOSP source code and open source project source code. My view is, don’t come up on the dead knock, line by line must all understand. The first thing to do is to sort out the context, to be able to sort out a sequence diagram, and then read it in layers. Why does forkSystemServer() return twice? Of course, for the content beyond the scope of their knowledge, they can also choose to temporarily skip, fight again in the future. And finally, a tech blog! Clear, understand, express, will gradually deepen your understanding of the source, but also share knowledge, feedback to the community, why not?
The next article will tell you more about what the SystemServer process does.
This article first published wechat official account: BingxinshuaiTM, focusing on Java, Android original knowledge sharing, LeetCode problem solving.
More latest original articles, scan code to pay attention to me!