Links to related articles:

1. Android FrameWork – Learning Launcher

2. Android FrameWork – Start the Init process after startup

3. Android FrameWork – Start the Zygote process after startup

Related source files:

/system/core/rootdir/init.rc /frameworks/base/cmds/app_process/App_main.cpp /frameworks/base/core/jni/AndroidRuntime.cpp  /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java /frameworks/base/core/java/com/android/internal/os/ZygoteConnection.javaCopy the code

The Zygote process is created by the init process by parsing the init.rc file.

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd
Copy the code

Corresponding to find/frameworks/base/CMDS app_process/app_main. The main method of CPP source file

Int main(int argc, char* const argv[]) {// AppRuntime extends to AndoirdRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // Filter the first argument argc--; argv++; // Everything up to '--' or first non '-' arg goes to the vm. // // The first argument after the VM args is the "parent dir", which // is currently unused. // // After the parent dir, we expect one or more the following internal // arguments : // // --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. // // For non zygote starts, these arguments will be followed by // the main class name. All remaining arguments are passed to // the main method of this class. // // For zygote starts, all remaining arguments are passed to the zygote. // main function. // // Note that we must copy argument string values since we will rewrite the // entire argument block when we apply the nice name to argv0. // Parse runtime arguments. Stop at first unrecognized option. bool zygote = false; bool startSystemServer = false; bool application = false; String8 niceName; String8 className; ++i; While (I < argc) {const char* arg = argv[I ++]; const char* arg = argv[I ++]; if (strcmp(arg, "--zygote") == 0) { zygote = true; niceName = ZYGOTE_NICE_NAME; } 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; }}... // Set the process name if (! niceName.isEmpty()) { runtime.setArgv0(niceName.string()); set_process_name(niceName.string()); } / / if the zygote, AndroidRuntime implement com. Android. Internal. OS. ZygoteInit / / see the above analytic script parameters is performed here. if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", args, zygote); } else if (className) { runtime.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."); return 10; }}Copy the code

The above analytical parameters is first, and then came to/frameworks/base/core/jni/AndroidRuntime. The start method of CPP:

/* * Start the Android runtime. This involves starting the virtual machine * and calling the "static void main(String[] args)" method in the class * named by "className". * * Passes the main function two arguments, the class name and the specified * options string. */ void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { ... /* Start the virtual machine invocation */ jni_Invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env, zygote) ! = 0) { return; } onVmCreated(env); If (startReg(env) < 0) {ALOGE("Unable to Register all android natives\n"); return; } /* * We want to call main() with a String array with arguments in it. * At present we have two arguments, the class name and an option string. * Create an array to hold them. */ jclass stringClass; jobjectArray strArray; jstring classNameStr; // strArray= new String[options.size() + 1]; stringClass = env->FindClass("java/lang/String"); strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL); // strArray[0] = "com.android.internal.os.ZygoteInit" classNameStr = env->NewStringUTF(className); env->SetObjectArrayElement(strArray, 0, classNameStr); // strArray[1] = "start-system-server"; // strArray[2] = "-- ABi-list = CPU architecture type of system response "; for (size_t i = 0; i < options.size(); ++i) { jstring optionsStr = env->NewStringUTF(options.itemAt(i).string()); env->SetObjectArrayElement(strArray, i + 1, optionsStr); } // slashClassName = "com/android/internal/os/ZygoteInit" char* slashClassName = toSlashClassName(className); jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); JmethodID 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 { Env ->CallStaticVoidMethod(startClass, startMeth, strArray);}...}Copy the code

Java code is running on Java VIRTUAL machine, and Java and native communication using JNI, from here we start to enter the Java world:

Public static void main(String argv[]) {try {Boolean startSystemServer = false; String socketName = "zygote"; String abiList = null; for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { startSystemServer = 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]); }}... // Register the socket for Zygote to communicate registerZygoteSocket(socketName); // Preload classes and resources preload(); // Start system_server if (startSystemServer) {startSystemServer(abiList, socketName); } // Enter loop mode and wait for the incubation process runSelectLoop(abiList); closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { closeServerSocket(); throw ex; } } private static void registerZygoteSocket(String socketName) { if (sServerSocket == null) { int fileDesc; final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; try { String env = System.getenv(fullSocketName); fileDesc = Integer.parseInt(env); } catch (RuntimeException ex) { ... } try { FileDescriptor fd = new FileDescriptor(); // Set the file descriptor fd.setint $(fileDesc); SServerSocket = new LocalServerSocket(fd); } catch (IOException ex) { ... }} static void preload() {// preloadClasses() in /system/etc/ preload-classes; // preloadResources, including drawable and color resources preloadResources(); // preloadOpenGL preloadOpenGL(); // Use system.loadLibrary () to preload "Android ", "compiler_rt", "jnigraphics" preloadSharedLibraries(); // Preload the text linker resource preloadTextResources(); / / only for zygote process, used in the process of memory sharing WebViewFactory. PrepareWebViewInZygote (); } private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException { ... String args[] = {"--setuid=1000", "--setgid=1000", "-- setgroups = 1001100 2100 3100 4100 5100 6100 7100 8100 9101 0101 8102 1103 2300 1300 2300 3300 6300 7", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", "com.android.server.SystemServer", }; ZygoteConnection.Arguments parsedArgs = null; int pid; try { ... // create the system_server process. Pid = Zygote.forkSystemServer(parsedargs. uid, ParseDargs. gid, ParseDargs. gids, ParseDargs. debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities); } catch (IllegalArgumentException ex) { throw new RuntimeException(ex); } // pid == 0 Namely system_server process the if (pid = = 0) {/ / perform initialization process of system_server handleSystemServerProcess (parsedArgs); } return true; } private static void runSelectLoop(String abiList) throws MethodAndArgsCaller { ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); // sServerSocket is created in registerZygoteSocket, i.e. zygote process. Save the FDS [0] FDS. Add (sServerSocket. GetFileDescriptor ()); peers.add(null); While (true) {// Set the pollFds parameter, FDS. Size is 1, . That is to say pollFds inside only sServerSocket getFileDescriptor () StructPollfd [] pollFds = new StructPollfd [FDS. The size ()]; for (int i = 0; i < pollFds.length; ++i) { pollFds[i] = new StructPollfd(); pollFds[i].fd = fds.get(i); pollFds[i].events = (short) POLLIN; PollFds = pollFds = pollFds = pollFds = pollFds = pollFds = pollFds = pollFds = pollFds = pollFds } catch (ErrnoException ex) { ... } for (int i = pollFds.length - 1; i >= 0; -- I) {if (I == 0) {// FDS [0], which represents sServerSocket, means that there is a client connection request; // Create a ZygoteConnection object and add it to the FDS. ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); // Add to fds.fds.add (newPeer. GetFileDesciptor ()); } else {// I >0; Boolean done = peers. Get (I).runonce ();} else {// I >0; if (done) { peers.remove(i); // Remove the file descriptor FDS. Remove (I); } } } } } boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { String args[]; Arguments parsedArgs = null; FileDescriptor[] descriptors; Args = readentList (); args = readArgumentList(); descriptors = mSocket.getAncillaryFileDescriptors(); } catch (IOException ex) { ... return true; }... // Parse Arguments into Arguments object format parsedArgs = new Arguments(args); . Pid = Zygote. ForkAndSpecialize (parsedargs.uid, parsedargs.gid, Parsedargs.gids, parsedargs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet, parsedArgs.appDataDir); } catch (Exception e) { ... } try {if (pid == 0) {// pid == 0 Ioutils. closekey (serverPipeFd); serverPipeFd = null; // Enter the child process flow handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); return true; } else {// pid>0 Execute logic ioutils. closeQuietly(childPipeFd); childPipeFd = null; return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); }}Copy the code

I’m sure many of you feel the same way. At first, some of the code looks obscure. In fact, there is no need to kill a lot of places at the beginning, we first understand the whole process, behind the specific details and then slowly gnaw. To sum up: The Zygote process is created by the init process parsing init.rc script. The source code for the Zygote process is the app_main. main method, which first creates a virtual machine instance and then registers the JNI method. Finally, enter the Java world through a JNI call to the zygoteinit.main method. In the Java world we would register sockets for Zygote for interprocess communication, preload some generic classes and resources, start the system_server process, and cycle to incubate and create new processes.

How to start the system_server process and how to incubate new processes will be discussed later. For now, we just need to know what Zygote does. Finally, why does Android use Zygote to incubate processes?

Video address: pan.baidu.com/s/1j_wgzITc…

Video password: JJ4B