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:

  1. registerServerSocketFromEnvTo register server sockets for cross-process communication, Binder communication is not used.
  2. preload()To perform preloading operations
  3. gcAndFinalize()Take the initiative to do a garbage collection before forkSystemServer
  4. forkSystemServer()To create the SystemServer process
  5. runSelectLoop()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!