This article is based on Android6.0 source code analysis
Related source files:
/system/core/rootdir/init.rc
/system/core/rootdir/init.zygote64.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
- Zygote.java
- ZygoteConnection.java
/frameworks/base/core/java/android/net/LocalServerSocket.java
/system/core/libutils/Threads.cpp
Copy the code
Overview of the Zygote process before it starts
File parsing through init.rc starts the Zygote process by starting zygote related services. The import determines which type of Zygote service scripts to start, including 32-bit and 64-bit zygote service scripts
import /init.${ro.zygote}.rc
Copy the code
There are four Zygote-related service scripts in the /system/core/rootdir directory
Zygote32_64. rc // Support 32-bit zygote init.zygote32_64.rc // support both 32-bit and 64-bit zygote. Zygote64_32. rc // Supports 64-bit zygote init.zygote64_32.rc // supports both 64-bit and 32-bit zygote, with 64-bit as the primary and 32-bit as the secondaryCopy the code
The following is an analysis of the Android initialization language for the 64-bit Zygote service script:
service zygote /system/bin/app_process64 -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
writepid /dev/cpuset/foreground/tasks
Copy the code
The zygote process is executed in/ system/bin/app_process64, where the parameters are: -xzygote /system/bin –zygote –start-system-server, classname is main. In addition to creating Zygote during Init process resolution, the Zygote process is also restarted when servicemanager, SurfaceFlinger, or SystemServer processes are killed.
The/system/bin/app_process64 mapping file for: / frameworks/base/CMDS app_process/app_main. CPP
The Zygote process is started
As shown in Figure 1, the Zygote process starts firstapp_main
Of the classmain()
Methods:
// Argv is: -xzygote /system/bin --zygote --start-system-server int main(int argc, char* const argv[]) {// Create an AppRuntime instance, AppRuntime inherits AndoirdRuntime AppRuntime Runtime (argv[0], computeArgBlockSize(argc, argv)); // Ignore the first argument argc--; argv++; Bool zygote = false; bool startSystemServer = false; bool application = false; String8 niceName; String8 className; ++i; // Skip unused "parent dir" argument. while (i < argc) { const char * arg = argv [i++]; If (STRCMP (arg, "--zygote") == 0) {STRCMP (arg, "--zygote") == 0; niceName = ZYGOTE_NICE_NAME; } else if (STRCMP (arg, "--start-system-server") == 0) {// start system-server 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; }} if (zygote) {// If zygote is true, call AndroidRuntime start. And into the "com. Android. Internal. OS. ZygoteInit" runtime parameters. The 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
Androidruntime.start androidRuntime.start androidRuntime.start AndroidRuntime.start androidRuntime.start androidRuntime.start androidRuntime.start And the first parameter of com. Android. Internal. OS. ZygoteInit.
AndroidRuntime.start()
In this method, three main things are done: · Creating virtual machine instances · registering JNI methods · calling the main() method of parameters
// Where className is: com.android.internal.os.ZygoteInit void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) { /* 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 if (startReg(env) < 0) {ALOGE("Unable to register all Android natives\n"); return; } / / / / parse the classname parameter will "com. Android. Internal. OS. ZygoteInit" into "com/android/internal/OS/ZygoteInit" char * slashClassName = toSlashClassName(className); jclass startClass = env->FindClass(slashClassName); JmethodID startMeth = env->GetStaticMethodID(startClass) {} else { "main", "([Ljava/lang/String;)V"); If (startMeth == NULL) {} else {env -> // 3. strArray); } } free(slashClassName); }Copy the code
After making some cuts to the start method, the vm is created by startVm, JNI method is registered by startReg(env), and the className parameter is parsed to execute zygoteinit.main. Each of these states will be examined in the following sections.
1. Create a VM instance
StartVm:
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) { // ... // JNI function bool checkJni = false; property_get("dalvik.vm.checkjni", propBuf, ""); if (strcmp(propBuf, "true") == 0) { checkJni = true; } else if (strcmp(propBuf, "false") ! = 0) { /* property is neither true nor false; fall back on kernel parameter */ property_get("ro.kernel.android.checkjni", propBuf, ""); if (propBuf[0] == '1') { checkJni = true; } } ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF"); if (checkJni) { addOption("-Xcheck:jni"); } // Trace files generated by the VM are mainly used to analyze system problems. The default path is /data/anr/ tetrace.txt parseRuntimeOption("dalvik.vm. Stack-trace-file ", "-xstackTracefile :"); // These parameters need to be adjusted and optimized for different hardware and software environments. ParseRuntimeOption (" Dalvik.vm. Heapstartsize ", heapstartsizeOptsBuf, "-xms ", "4m"); parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m"); parseRuntimeOption( "dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=" ); parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree="); parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree="); parseRuntimeOption( "dalvik.vm.heaptargetutilization", heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization=" ); / /... If (JNI_CreateJavaVM(pJavaVM, pEnv, & initArgs) < 0) {ALOGE("JNI_CreateJavaVM failed\n"); return -1; } return 0; }Copy the code
There is a lot of code in startVm method, but it is mainly divided into three steps, the first step is detection, the second step is to set the software and hardware parameters, and the third step is to initialize the VIRTUAL machine.
2. Registration of JNI methods
startReg
int AndroidRuntime::startReg(JNIEnv* env) { androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc); ALOGV("--- registering native functions ---\n"); env->PushLocalFrame(200); If (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {env -> PopLocalFrame(NULL); return -1; } env->PopLocalFrame(NULL); return 0; Static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env) {for (size_t I = 0; i < count; i++) { if (array[i].mProc(env) < 0) { return -1; } } return 0; }Copy the code
The startReg method is a registry of JNI methods that map JNI and Java layer methods one by one through an array of macro definitions and execute the array-defined methods.
3. Call the zygoteinit. main method
At the end of the androidRuntime.start () method, its zygoteinit.main () method is executed via reflection.
JmethodID startMeth = env->GetStaticMethodID(startClass) {} else { "main", "([Ljava/lang/String;)V"); If (startMeth == NULL) {} else {env -> // 3. strArray); } }Copy the code
Using reflection to execute the zygoteinit. main method is also a first foray into the Java language. So AndroidRuntime’s start method does three things: initialize the VIRTUAL machine, register the JNI method, and execute the Zygoteinit.main method via reflection.
ZygoteInit.main
Zygote process is used to create the management framework layer SystemServer process, but also used to create App process, that is, the application App start create process, is created by the Zygote process, and Zygote create child process will use copy on write technology, That is, the child process directly inherits the existing resources of the parent process. The child process shares the shared resources when reading and copies them when writing. The zygoteinit. main method does four main things: · Register the server socket to receive information about the creation of the child process · preload classes and resources in advance for the child process to share · Create the SystemServer process, which manages the framework layer · Loop listening service socket to create the child process
Public static void main(String argv[]) {try {// Create server Soctet registerZygoteSocket(socketName); // Preload classes and resources preload(); // GC to gcAndFinalize(); If (startSystemServer) {startSystemServer(abiList, socketName); } // Create a child runSelectLoop(abiList) with the service socket; closeServerSocket(); } catch (MethodAndArgsCaller caller) { caller.run(); } catch (RuntimeException ex) { Log.e(TAG, "Zygote died with exception", ex); closeServerSocket(); throw ex; }}Copy the code
RegisterZygoteSocket is used to create server sockets, preload() is used to preload classes and resources, and startSystemServer is used to create SystemServer processes to manage the framework layer. The runSelectLoop method looping listens for the creation of the child process.
1. Register the server Socket
registerZygoteSocket
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) { throw new RuntimeException (fullSocketName + " unset or invalid", ex); } try {// Create server socket FileDescriptor fd = new FileDescriptor(); fd.setInt$(fileDesc); sServerSocket = new LocalServerSocket (fd); } catch (IOException ex) { throw new RuntimeException ( "Error binding to local socket '" + fileDesc + "'", ex); }}}Copy the code
The following runSelectLoop method is used to listen for the socket information on the server to create a child process.
2. Preload resources
preload
static void preload() { preloadClasses(); // preload preloadResources() in /system/etc/ preload-classes; // Preload resources, including drawable and color resources preloadOpenGL(); // Preload OpenGL preloadSharedLibraries(); // Preload shared libraries "Android ","jnigraphics" preloadTextResources(); / / preload text connector resource WebViewFactory. PrepareWebViewInZygote (); // Only for zygote processes, for memory sharing processes}Copy the code
The preloadClasses() method loads classes via class.forname () reflection, PreloadResources load method is mainly located in com. Android. Internal. State Richard armitage rray. Preloaded_drawables and com. The android. Internal. State Richard armitage rray. Preloaded_color_s Tate_lists resources. The advantage of preloading resources is that the preloaded resources can be used directly by the child process when it is copied and created, but the disadvantage is that each created child process has many resources regardless of whether it needs them or not.
3. Start the SystemServer process
startSystemServer
private static boolean startSystemServer(String abiList, String socketName) throws MethodAndArgsCaller, 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 { parsedArgs = new ZygoteConnection . Arguments (args); ZygoteConnection.applyDebuggerSystemProperty(parsedArgs); ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs); 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 systemServer */ pid==0 {if (hasSecondZygote(abiList)) {waitForSecondaryZygote(socketName); } / / work for the remainder of the process of system_server handleSystemServerProcess (parsedArgs); } return true; }Copy the code
Zygote. ForkSystemServer is used to create the SystemServer process that manages the framework. We will look at the start of the SystemServer process in the next article.
4. Cycle and wait for the incubation process
runSelectLoop
Private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {// FileDescriptor array ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>(); // ZygoteConnection ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>(); //sServerSocket is the server of socket communication, that is, zygote process. Save the FDS [0] FDS. Add (sServerSocket. GetFileDescriptor ()); peers.add(null); StructPollfd[] pollFds = new StructPollfd[fds.size()]; while (true) {// StructPollfd array and assign the value of the corresponding position FDS. 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) { throw new RuntimeException ("poll failed", ex); } for (int i = pollFds.length - 1; i >= 0; -- I) {// Use the I/O multiplexing mechanism, when receiving the client to send a connection request or data processing request, then proceed; // Otherwise enter continue to break the loop. if ((pollFds[i].revents & POLLIN) == 0) { continue; } if (i == 0) { ZygoteConnection newPeer = acceptCommandPeer (abiList); peers.add(newPeer); fds.add(newPeer.getFileDesciptor()); } else {// I >0; Boolean done = peers. Get (I).runonce ();} else {// I >0; if (done) { peers.remove(i); fds.remove(i); } } } } }Copy the code
The runSelectLoop method has a polled state, and if an event is received, the runOnce() method is executed:
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { String args []; Arguments parsedArgs = null; FileDescriptor[] descriptors; Args = readentList (); args = readArgumentList(); descriptors = mSocket.getAncillaryFileDescriptors(); } catch (IOException ex) { Log.w(TAG, "IOException on command socket " + ex.getMessage()); closeSocket(); return true; } if (args == null) { // EOF reached. closeSocket(); return true; // 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 (ErrnoException ex) { logAndPrintError(newStderr, "Exception creating pipe", ex); } catch (IllegalArgumentException ex) { logAndPrintError(newStderr, "Invalid zygote arguments", ex); } catch (ZygoteSecurityException ex) { logAndPrintError( newStderr, "Zygote security policy prevents request: ", ex ); } try {if (pid == 0) {ioutils. closeQuietly(serverPipeFd); serverPipeFd = null; handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); // should never get here, the child is expected to either // throw ZygoteInit.MethodAndArgsCaller or exec(). return true; } else {ioutils. closeQuietly(childPipeFd); childPipeFd = null; return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); } } finally { IoUtils.closeQuietly(childPipeFd); IoUtils.closeQuietly(serverPipeFd); }}Copy the code
So in the runSelectLoop method, the listener is constantly communicating with the server socket through the client socket and constantly creating new processes by calling the runOnce method.
conclusion
The Zygote process is as follows:
- Create a virtual machine and register the JNI method
- Register service sockets and pre-load system classes and resources
- Example Create the SystemServer process
- Loop waiting for the incubation process