This series introduces the Init, Zygote, SystemServer, and Launcher involved in the startup process of the Android system. Text analysis source code based on Android8.0 source code.

Zygote (incubator), the system DVM, ART, application process and SystemServer process are created by Zygote, of which SystemServer is often encountered in application layer development, because the application layer APP process is created through the SystemServer process.

Zygote startup script

CPP parses the configuration information in init.rc. This process is called Zygote startup script. The process includes the following:

  1. Introducing the init. Zygote. Xx. Rc: In Android8.0 system startup process _init (1), init function parsing part, explains five syntax formats of the init.rc configuration file, including the import statement introduced to expand the configuration file. Imported through the import statement, as shown below
import /init.${ro.zygote}.rc
Copy the code
  1. Zygote: zygote: zygote: zygote: zygote: zygote: zygote: zygote: zygote: zygote: zygote: zygote: zygote
\system\core\rootdir\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
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    ....
    writepid /dev/cpuset/foreground/tasks
Copy the code
\system\core\rootdir\init.zygote32_64.rc
service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20
    user root
    group root readproc
    .....
    writepid /dev/cpuset/foreground/tasks

service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
    class main
    priority -20
    user root
    group root readproc
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks

Copy the code

Zygote64_32. rc init.zygote32_64.rc init.zygote64_32.rc init.zygote64_32.rc

  • Service: in init.rc, use “service” to indicate that the statement is service and start a service process.
  • Zygote: The process name is zygote.
  • /system/bin: Start zygote with the /system/bin/app_process application. This verifies that zygote was not originally named Zygote, but app_procress. When zygote started, Linux changed it to Zygote.
  • –zygote, –start–system–server: parameters used to start zygote, which can be used in the main function of app_main. CPP.
  • -socket-name=zygote: indicates that the socket is named zygote.
  • Class main: Declare Zygote as the main service. Init starts Zygote with ForEachServiceInClass by looking for the Zygote process classname main.
  • Socket XXX: indicates that a socket needs to be created for the service.
  • Onrestart XXX: specifies the command to be executed when Zygote is restarted

Introduction to the Zygote process startup process

2.1 app_main. CPP

In Android 8.0, init is used to start Zygote at frameworks\base\ CMDS \app_process\app_main. CPP.

frameworks\base\cmds\app_process\app_main.cpp

int main(int argc, char* const argv[])
{
 while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true; // If the Zygote process is currently running, the variable Zygote is set totrue
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true; // If the SystemServer process is running, the startSystemServer variable is set totrue
        } else if (strcmp(arg, "--application") == 0) {
            application = true; // The current process is the application process, the variable application is set totrue}.. }if(zygote) {// If zygote is running, start runtime.start("com.android.internal.os.ZygoteInit", args, zygote); }}Copy the code

Source code analysis is as follows:

  • Zyogte and its children fork themselves to create a child process. This allows Zygote and its children to enter the main function of app_main. CPP. If the arG starts with “–” or does not start with “-“, enter it as a simple judgment.

Everything up to ‘–‘ or first non ‘-‘ arg goes to the vm. … // –zygote : Start in zygote mode // –start-system-server : Start the system server. // –application : Start in application (stand alone, non zygote) mode. // –nice-name : The nice name for this process.

Check whether the ARG contains “–zygote”, “–start-system-server”, “–application”, or other parameters to determine which process is running.

  • Start the process: If the variable zygote is true, the following method is called to start the zygote process.
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
Copy the code

2.2 AndroidRuntime. CPP

\frameworks\base\core\jni\AndroidRuntime.cpp
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
	...
	/* 1 start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if(startVm(&mJavaVM, &env, zygote) ! = 0) {return;
    }
    onVmCreated(env);

    /** 2 Register android functions.*/
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return; }}... ClassNameStr = env->NewStringUTF(className); . / / 4 className "." Char * slashClassName = toSlashClassName(className! = NULL ? className :""); ZygoteInit jclass startClass = env->FindClass(slashClassName);if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } elseJmethodID startMeth = env->GetStaticMethodID(startClass,"main"."([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else{//7. Call ZygoteInit's main method via JNI. ZygoteInit is written in Java because it is Native. env->CallStaticVoidMethod(startClass, startMeth, strArray);#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
    free(slashClassName);

    ALOGD("Shutting down VM\n");
    if(mJavaVM->DetachCurrentThread() ! = JNI_OK) ALOGW("Warning: unable to detach main thread\n");
    if(mJavaVM->DestroyJavaVM() ! = 0) ALOGW("Warning: VM did not shut down cleanly\n");
Copy the code

Source code analysis:

  • Preparation for startup: In notes 1 and 2, create a Java VIRTUAL machine with startVm and register JNI methods for the Java virtual machine with startReg.
  • Find the ZygoteInit class: In note 3, 4, 5 and 6 will com.. Android OS. ZygoteInit to com/android/OS/ZygoteInit and assignment to slashClassName, find ZygoteInit through slashClassName main method;
  • Call the ZygoteInit class: Once the class is found, call the main method of ZygoteInit using the JNI method in comment 7 to enter the Java layer runtime environment.

2.3 ZygoteInit. Java

frameworks\base\core\java\com\android\internal\os\ZygoteInit.java public static void main(String argv[]) { ... ZygoteServer ZygoteServer = new ZygoteServer(); . / / 2. Create a server socket, and the name of zygote zygoteServer. RegisterServerSocket (socketName); //3. Preload classes and resources preload(bootTimingsTraceLog); . Start the SystemServer processif (startSystemServer) {
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
                // {@code r == null} inthe parent (zygote) process, and {@code r ! = null}in the
                // child (system_server) process.
                if(r ! = null) { r.run();return;
                }
            }
	 Log.i(TAG, "Accepting command socket connections"); //5. Wait for the AMS requestcaller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex); throw ex; } finally { zygoteServer.closeServerSocket(); }}...Copy the code

The main method of ZygoteInit does the following: 1. Create a Socket server named “Zygote” and wait for AMS to request Zygote to create a new process. 2, preload classes and Resources, including drawable, color, OpenGL and text linker Resources, save to a global static variable Resources, the next time reading system Resources from the static variable priority search; 3. Start the SystemServer process. 4. Wait for AMS’s request to create a new application process using the runSelectLoop() method.

1.registerServerSocket

frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
void registerServerSocket(String socketName) {
        if(mServerSocket == null) { int fileDesc; Final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; ANDROID_SOCKET_zygote String env = system.getenv (fullSocketName); fileDesc = Integer.parseInt(env); } catch (RuntimeException ex) { throw new RuntimeException(fullSocketName +" unset or invalid", ex); } try {//3. Create a FileDescriptor using fileDesc: fd FileDescriptor fd = new FileDescriptor(); fd.setInt$(fileDesc); MServerSocket = new LocalServerSocket(fd); } catch (IOException ex) { throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex); }}}Copy the code

2. Preload classes and resources

frameworks\base\core\java\com\android\internal\os\ZygoteInit.java static void preload(TimingsTraceLog bootTimingsTraceLog) { ... //1. Preload preloadClasses() in /system/etc/ preload-classes; . Preload drawble and color preloadResources(); . / / 3. Through JNI calls, preload the underlying resources nativePreloadAppProcessHALs (); . //4. Preload the OpenGL resource preloadOpenGL(); . //5. Preload shared libraries:"android"."compiler_rt"."jnigraphics"preloadSharedLibraries(); //6. Preload the text linker resource preloadTextResources(); . //7. In zygote, warmUpJcaProviders(); . }Copy the code

3. Start the SystemServer process

frameworks\base\core\java\com\android\internal\os\ZygoteServer.java private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) { ... String args[] = {//1."--setuid=1000"."--setgid=1000"."- setgroups = 1001100 2100 3100 4100 5100 6100 7100 8100 9101 0101 8102 1102 3103 2300 1300 2300 3300 6300 7300 9301 0"."--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server"."--runtime-args"."com.android.server.SystemServer"}; ZygoteConnection.Arguments parsedArgs = null; int pid; try { parsedArgs = new ZygoteConnection.Arguments(args); ZygoteConnection.applyDebuggerSystemProperty(parsedArgs); ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs); /* Request to fork the system server process */ //2. Pid = Zygote. ForkSystemServer (parseDargs. uid, parseDargs. gid, ParseDargs. gids, ParseDargs. debugFlags) null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } /* For child process */ //3. If pid is 0, it is running in a new child processif (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName); } zygoteServer.closeServerSocket(); //4. Process the SystemServer processreturn handleSystemServerProcess(parsedArgs);
        }
        return null;
    }
Copy the code

4. RunSelectLoop ()

frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
 /**
     * Runs the zygote process's select loop. Accepts new connections as * they happen, and reads commands from connections one spawn-request'S * worth at a time. * Running in Zygote process, waiting for a new connection, */ Runnable runSelectLoop(String abiList) {ArrayList<FileDescriptor> FDS = new ArrayList<FileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); / / 1. Will the FDS ServerSocket added to the collection. The add (mServerSocket. GetFileDescriptor ()); peers.add(null); 2. Start an endless loop and wait for AMS requestswhile (trueStructPollfd[] 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 {
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex); } //4. Iterate through the pollFds informationfor (int i = pollFds.length - 1; i >= 0; --i) {
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue; } //5. If the pid is 0, the socket is connected.if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                }else{/6. If not equal to 0, AMS requests Zyogte process to create a new process ZygoteConnection Connection = peers. final Runnablecommand= connection.processOneCommand(this); }... }Copy the code