Links to related articles:
1. Android FrameWork - Learning Starter
2. Android FrameWork - Start the Init process
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.java
The Zygote process is composed of init process Created 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
Correspondence Finding /frameworks/base/cmds/app_process/app_main.cpp main Method in Source File
int main(int argc, char* const argv[]) { // AppRuntime inherits Andoird Runtime AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv)); // Filter the first parameter 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; // Skip unused "parent dir" argument. // Analytical parameters while (i < argc) { 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; } } ... //Setting process name if (!niceName.isEmpty()) { runtime.setArgv0(niceName.string()); set_process_name(niceName.string()); } // If zygote, Android Runtime executes com.android.internal.os.ZygoteInit // Look at the script parameters parsed above and execute 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; } }
The first thing is to parse the parameters, and then to /frameworks/base/core/jni/AndroidRuntime.cpp start method:
/* * 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) { ... // Create an instance of a virtual machine /* start the virtual machine */ JniInvocation jni_invocation; jni_invocation.Init(NULL); JNIEnv* env; if (startVm(&mJavaVM, &env, zygote) != 0) { return; } onVmCreated(env); // JNI method registration /* * Register android functions. */ 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 = type of cpu architecture for 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); /* keep going */ } else { // The main method to get ZygoteInit.java 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 { // Execute the main method of ZygoteInit.java to enter the Java world from the Native world env->CallStaticVoidMethod(startClass, startMeth, strArray); } } ... }
Java code runs on the Java virtual machine, and Java communicates with native using JNI. From here we begin to enter the Java world:
public static void main(String argv[]) { try { // Analytical parameters 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 socket s for Zygote for communication registerZygoteSocket(socketName); // Preloading classes and resources preload(); // Start system_server if (startSystemServer) { startSystemServer(abiList, socketName); } // Enter the cycle 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(); // Setting file descriptors fd.setInt$(fileDesc); // Creating Socket's Local Server sServerSocket = new LocalServerSocket(fd); } catch (IOException ex) { ... } } } static void preload() { // Preloading classes in the / system/etc/preloaded-classes file preloadClasses(); // Preload resources, including drawable and color resources preloadResources(); // Preloading OpenGL preloadOpenGL(); // Through the System.loadLibrary() method, // Preload the three shared libraries of "android", "compiler_rt" and "jnigraphics" preloadSharedLibraries(); // Preload text connector resources preloadTextResources(); // For Zygo processes only, for memory-sharing processes WebViewFactory.prepareWebViewInZygote(); } private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, RuntimeException { ... // Set some parameters String args[] = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", "com.android.server.SystemServer", }; ZygoteConnection.Arguments parsedArgs = null; int pid; try { ... // fork creates the system_server process, which will be analyzed later 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 represents a child process, that is, the system_server process if (pid == 0) { // Execute the initialization system_server process 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, the zygote process. Save to fds[0] fds.add(sServerSocket.getFileDescriptor()); peers.add(null); while (true) { // Set a parameter for pollFds, fds.size is 1, that is to say, only sServerSocket.getFileDescriptor() is in pollFds. 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 { // Processing polling status, when pollFds have an event, it executes downward, otherwise it is blocked here Os.poll(pollFds, -1); } catch (ErrnoException ex) { ... } for (int i = pollFds.length - 1; i >= 0; --i) { if (i == 0) { // fds[0], which represents sServerSocket, means that there are client connection requests; // Then create the ZygoteConnection object and add it to fds. ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); //Add to fds. fds.add(newPeer.getFileDesciptor()); } else { // I > 0, which means receiving data from the opposite end through socket and performing corresponding operations boolean done = peers.get(i).runOnce(); if (done) { peers.remove(i); // Remove the file descriptor from fds after processing fds.remove(i); } } } } } boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { String args[]; Arguments parsedArgs = null; FileDescriptor[] descriptors; try { // Read the parameter list sent by the socket client args = readArgumentList(); descriptors = mSocket.getAncillaryFileDescriptors(); } catch (IOException ex) { ... return true; } ... try { // The parameters passed by the binder client are parsed into Arguments object format parsedArgs = new Arguments(args); ... // fork creates a new process 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 executes the logic of the child process IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; // Enter the sub-process flow handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); return true; } else { // PID > 0 executes the logic of the parent process IoUtils.closeQuietly(childPipeFd); childPipeFd = null; return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); } }
I believe a lot of guys have the same feeling as me. At first, some of the code seems obscure and difficult to understand. In fact, at the beginning, there is no need to cut corners in many places. First, we understand the whole process, then we slowly gnaw at the details. In conclusion, the Zygote process is created by the init process parsing init.rc script. Its specific execution source code is the App_main.main method. First, it creates a virtual machine instance, then registers the JNI method. Finally, it enters the Java world through JNI calls to the ZygoteInit.main method. In the Java world, we register socket s for Zygote for interprocess communication, preload some generic classes and resources, start the system_server process, and wait iteratively for incubation to create new processes.
As for how to start the system_server process and how to incubate the new process, we will go back to the specific analysis. At present, we only need to know what zygote has done. Finally, let's consider a question: Why does Android use zygote to incubate the process?