We know that the Android system is based on the Linux kernel, and that all processes in the Linux system are sub-processes of the INIT process. Zygote as well. It was created by the INIT process during system startup, in the system startup script init.rc:
<span style= "FONT-SIZE:14PX;" > @init. rcservice zygote/syste/bin/app_process-xzygote/system/bin-zygote--start-system-server class Main socket zygote Stream 666 onrestart restart Surfaceflinger ...</span>
The keyword server tells the init process to create a process called zygote, which executes the/syste/bin/app_process, followed by the arguments passed to the process. The following socket indicates that the zygote requires a socket socket resource called zygote, and the associated file can be seen in the/dev/socket directory after the system starts.
Zygote service process is also called hatching process, in the Linux user space process app_process will do some zygote process start up work, such as Start Runtime Runtime environment, and then call Runtime.start () to perform zygote service. Runtime.start () This function is actually a class function Androidruntime::start () that creates and launches a virtual machine instance to execute the main function of the Com.android.internal.os.ZygoteInit package. This main function will fork a child process to start Systemserver, the parent process as a real incubator exists, whenever the system requires the execution of an Android application, Zygote will receive a socket message fork out a child process to execute the application. Each Android application runs in a Dalvik virtual machine instance, and each virtual machine instance is a separate process space.
@frameworks/base/cmds/app_process/app_main.cpp
<span style= "FONT-SIZE:14PX;" >int Main (int argc, char* argv[]) {Appruntime runtime;//here Appruntime is a subclass of Androidruntime, starting the runtime runtime environment. ...//get parameter/*argv[0] = "-xzygote" argv[1] = "/system/bin" argv[2] = "--zygote" argv[3] = "--start-system-server" Startsystemserver = True*/int i = runtime.addvmarguments (argc. argv);//find parameter first not as a single-start parameter, here is/system/ Binruntime.mparentdir = argv[i++]//Save the directory to the Mparentdir variable setArgsv0 (argv0, "zygote") set_process_name ("zygote"); Runtime.start ("Com.android.internal.os.zygoteInit", Startsystemserver?) "Start-system-server": "");} </span>
Here is the main call Runtime.start () function, we focus on the runtime type is Appruntime, it inherits from the Androidruntime class.
@frameworks/base/cmds/app_process/app_main.cpp
<span style= "FONT-SIZE:14PX;" >class appruntime:public androidruntime{public:appruntime (): Mparentdir (null), Mclassname (null), MClass (null), MARGC (0), MARGV (NULL) {}...const char* getclassname () const {}virtual void onvmcreated (jnienv* env) {}virtual void OnStart Ed () {}virtual void Onzygoteinit () {}virtual void onExit (int code) const char* Mparentdir;const char* Mclassname;jclass mCl As;int margc;const char* const* margv;}; </span>
<span style = "FONT-SIZE:14PX;" > @frameworks/base/include/android_runtime/androidruntime.h@frameworks/base/core/jni/androidruntime.cpp/* static */javavm* ANDROIDRUNTIME::MJAVAVM = null;void androidruntime::start (const char* className, const char* options) {. .. JNIEnv *ENV;STARTVM (&MJAVAVM, &env);//Start the virtual machineonvmcreated (env); Startreg (env);//Register Android functions//Call className Mainchar *slashclassname = Toslashclassname (className); Jclass Startclass = Env->fi Ndclass (slashclassname); Jmethodid Startmeth = Env->getstaticmethodid (Startclass, "main", "([Ljava/lang/string;] V) "Env->callstaticvoidmethod (Startclass, Startmeth, Strarray); free (slashclassname); ...} </span>
This start () function mainly does three things: one is to call STARTVM () to start the virtual machine , and the other is to call Startreg () to register the Jni method; Call the main function of the Com.android.internal.os.ZygoteInit class .
1) STARTVM start the virtual machine
2) Startreg Registration JNI method
3) Start the main function of Com.android.internal.os.ZygoteInit
@frameworks/base/core/java/com/android/internal/os/zygoteinit.java
<span style= "FONT-SIZE:14PX;" >public static void Main (String argv[]) {try {samplingprofilerintegration.start (); Registerzygotesocket ();// Register socketpreloadclasses ();//Load Resource preloadresources (); Samplingprofilterintegration.writezygotesnapshot (); GC (); if (Argv[1].equals ("Start-system-server")) Startsystemserver ();//FORK a new process System_serverif (Zygote_fork_mode) Runforkmode (); Elserunselectloopmode ();// The zygote process enters an infinite loop, performing hatching work closeserversocket ();} catch (Methodandargscaller caller) {Caller.run ();}} </span>
Here is also the main thing to do three things: one is to call the Registerzygotesocket function to create a socket socket used to communicate with Activitymanagerservice The second is to call the Startsystemserver function to start the Systemserver component The third is to call the Runselectloopmode function process an infinite loop on the socket socket created earlier to wait for Activitymanagerservice request to create a new application process.
1) Registerzygotesocket
Fork () Creates a child process, and the parent process returns TRUE. The child process executes the runtimeinit.zygoteinit.
@frameworks/base/core/java/com/android/internal/os/runtimeinit.java
<span style= "FONT-SIZE:14PX;" >public class Zygoteinit {... private static localserversocket sserversocket;private static final String android_ socket_env = "Android_socket_zygote";p rivate static void Registerzygotesocket () {if (Sserversocket = = NULL) {int Filedesc ; String env = system.getenv (android_socket_env);//Get environment variable FILEDESC = integer.parseint (env); sserversocket = new Localserversocket (Createfiledescriptor (Filedesc));}} </span>
here via System.getenv () Gets the value of the environment variable android_socket_env, represented by this file descriptor/dev/socket/zygote. So who set this environment variable? The explanation in the previous analysis that executes the system startup script init.rc init.c file has a Service_start () function that is used to analyze the zygote and create and set the corresponding socket.
<span Style= "FONT-SIZE:14PX;" >void service_start (struct service *svc, const char* Dynamic_args) {... pid = fork (); if (PID = = 0) {struct Socketinfo * Si;...for (si = svc->sockets; si; si = si->next) {int socket_type = (!strcmp (si->type, "stream")? Sock_stream: (!strcmp (Si->type, "Dgram")? Sock_dgram:sock_seqpacket)); int s = Create_socket (Si->name, Socket_type, Si->perm, Si->uid, Si->gid); Publish_socket (Si->name, s);}} ...} #define ANDROID_SOCKET_ENV_PREFIX "android_socket_" #define ANDROID_SOCKET_DIR "/dev/socket" static void Publish_ Socket (const char *name, int fd) {char key[64] = Android_socket_env_prefix;char val[64];strlcpy (key + sizeof (android_ Socket_env_prefix)-1, name, sizeof (key)-sizeof (Android_socket_env_prefix)), snprintf (Val, sizeof (Val), "%d", FD); add _environment (Key, Val);//android_socket_zygote = Valfcntl (fd, F_SETFD, 0);} </span>
Each of these service commands causes the INIT process to call the fork function to create a new process to parse the socket options inside, and then call the Create_socket () function to create a device file in the/dev/socket directory. It then obtains a file descriptor and writes it to the environment variable by Publish_socket (). This writes the file descriptor of the zygote socket to the android_socket_zygote, where the socket file descriptor's Create_socket () function is created, and finally by calling Execve (svc-> Args[0], (char**) Arg_ptrs, (char**) env) to execute zygote executable program, and the environment variable ENV parameter passed. So the Zygoteinit.registerzygotesocket () function can be used to remove the file descriptor directly from the environment variable. If other processes need to open this/dev/socket/zygote file to communicate with the zygote process, you need to connect Localserversocket through the file name.
2) Startsystemserver
@frameworks/base/core/java/com/android/internal/os/zygoteinit.java
<span Style= "FONT-SIZE:14PX;" >private static Boolean Startsystemserver () {String args[] = {"--setuid=1000", "--setgid=1000", "--setgroups= 1001,1002,1003,1004,1005,1006 ... ","--capabilities=13010432,130104352 ","--runtime-init ","--nice-name=system_ Server "," Com.android.server.SystemServer ",}; Zygoteconnection.arguments Parsedargs = Null;parsedargs = new Zygoteconnection.arguments (args); Zygoteconnection.applydebuggersystemproperty (Parsedargs); Zygoteconnection.applyinvokewithsystemproperty (Parsedargs); int pid = Zygote.forksystemserver (ParsedArgs.uid, Parsedargs.gid, parsedargs.gids,parsedargs.debugflags, NULL, Parsedargs.permittedcapabilities, parsedargs.effectivecapabilities)); if (PID = = 0) {//Sub-process handlesystemserverprocess (Parsedargs);} Return true;//Parent process directly returns TRUE}</SPAN>
Here the zygote process starts the Systemserver component by calling the Zygote.forksystemserver () function to create a new process.
<span style= "FONT-SIZE:14PX;" >public class Zygoteinit {.... private static void Handlesystemserverprocess (Zygoteconnection.arguments Parsedargs) {Closeserversocket ();//child process does not need zygote socket, close Fileutils.setumask directly (Fileutils.s_irwxg | Fileutils.s_irwxo);.. Runtimeinit.zygoteinit (Parsedargs.targetsdkversion, Parsedargs.remainingargs);}} </span>
<span style= "FONT-SIZE:14PX;" >public class Runtimeinit {... public static final void zygoteinit (int targetsdkversion, string[] argv) {REDIRECTLOGSTR Eams (); Commoninit (); zygoteinitnative ();//is a native function that mainly completes the initialization of the binder communication mechanism applicationinit (targetsdkversion, argv);} public static final native void Zygoteinitnative ();p rivate static void Applicationinit (int targetsdkversion, string[] Arg V) {vmruntime.getruntime (). Settargetheaputilizatoin (0.75f); Vmruntime.getruntime (). Settargetsdkversion (targetsdkversion); final Arguments Args;args = new Arguments (argv); Invokestaticmain (Args.startclass, Args.startargs);} This className = "com.android.server.SystemServer" private static void Invokestaticmain (String className, string[] argv) {class<?> cl;cl = Class.forName (className); Method m;m = Cl.getmethod ("main", new class[] {string[].class}), .... throw new Zygoteinit.methodandargscaller (M, argv);}} </span>
This runtimeinit.zygoteinit () function mainly performs two operations: one is to invoke zygoteinitnative to perform the initialization of a binder interprocess communication mechanism The second is to call the main function of the Com.android.server.SystemServer class.
(1) Zygoteinitnative:
<span style= "FONT-SIZE:14PX;" > @frameworks/base/core/jni/androidruntime.cppstatic jninativemethod gmethods[] = { .... {"Zygoteinitnative", "() V", (void*) Com_android_internal_os_runtimeinit_zygoteinit}, ....}; static void Com_android_internal_os_runtimeinit_zygoteinit (jnienv* env, Jobject clazz) { gcurruntime-> Onzygoteinit (); is to start binder communication}</span>
<span style= "FONT-SIZE:14PX;" >virtual void Onzygoteinit () {sp<processstate> proc = processstate::self ();//One copy of each process Processstate object, Open Binder Driver if (proc->supportsprocess ()) {Proc->startthreadpool ();//Start a thread for binder communication}}</span>
(2) Systemserver.main:
@frameworks/base/services/java/com/android/server/systemserver.java
<span Style= "FONT-SIZE:14PX;" >public class Systemserver {native public static void Init1 (strig[] args);p ublic static void Main (string[] args) {.... V Mruntime.getruntime (). Settargetheaputilization (0.8f); System.loadlibrary ("Android_servers"); init1 (args);} public static final void Init2 () {Thread thr = new Serverthread (); Thr.setname ("Android.server.ServerThread"); Thr.start ( );}} <span style= "color: #006600;" > @frameworks/base/services/jni/com_android_server_systemserver.cpp</span></span>
<span style= "FONT-SIZE:14PX;" >static void Android_server_systemserver_init1 (jnienv* env, Jobject clazz) {system_init ();} status_t system_init () {sp<processstate> proc (processstate::self ());sp<iservicemanager> SM = Defaultservicemanager ();.. androidruntime* runtime = Androidruntime::getruntime (); jnienv* env = rungime->getjnienv () jclass clazz = Env->findclass ("Com/android/server/systemserver"); JmethodID Methodid = Env->getstaticmethodid (Clazz, "Init2", "() V"), Env->callstaticvoidmethod (Clazz, Methodid); Processstate::self ()->startthreadpool (); Ipcthreadstate::self ()->jointhreadpool (); return NO_ERROR;} </span>
The systemserver main () function first calls the Jni method Init1,init1 () invokes Systemserver's init2, creating a init2 thread in Serverthread to perform some system-critical service startup operations.
<span style= "FONT-SIZE:14PX;" >class Serverthread extends Thread {... public void run () {looper.prepare ();//Critical services ... Servicemanager.addservice (Context.power_service, New Popermanagerservice ()); Activitymanagerservice.main (); Packagemanagerservice.main (context);..}} </span>
So far, Zygote has already forked () The Systemserver component initialization start operation, back to Zygote.main () call Runselectloopmode () Wait for the Activitymanagerservice request to create a new application by entering a loop before creating the socket interface.
3) Runselectloopmode
<span style= "FONT-SIZE:14PX;" >public class Zygoteinit {.... private static void Runselectloopmode () throws Methodandargscaller {arraylist< filedescriptor> FDS = new ArrayList (); Arraylist<zygoteconnection> peers = new ArrayList (); filedescriptor[] Fdarray = new Filedescriptor[4];fds.add (Sserversocket.getfiledescriptor ());p Eers.add (NULL); int Loopcount = gc_loop_count;//10while (true) {Fdarray = Fds.toarray (fdarray); index = selectreadble (Fdarray);// Like a select poll under Linux, the native function if (Index < 0) {...} else if (index = = 0) {//indicates that there is a client connection on zygoteconnection Newpeer = Acceptcomman Dpeer ();p eers.add (Newpeer); Fds.add (Newpeer.getfiledescriptor ());} else {///client sent a request over, to Zygoteconnection's runOnce () function to complete the Boolean done = Peers.get (index). runOnce (); if (do) {Peers.remove (index); fds.remove (index);}}} private static Zygoteconnection Acceptcommandpeer () {... return new zygoteconnection (Sserversocket.accept ());}} </span>
Here the while (true) loop inside calls Selectreadble (), which is a native function, similar to select using the multiplexed I/O model. When returning 0 indicates a client connection, Zygoteconnection represents a client of zygote, whenever Acceptcommandpeer () returns a Zygoteconnection object on the client connection, The zygoteconnection holds the Localsocket object returned by Accpet (). The corresponding file descriptor is then added to the FDS, and the next time it is called SELELCT polling. When the return value is greater than 0, it indicates that there is a data request sent by the client, which is handled by the RunOnce () function of the Zygoteconnection object.
The selectreadable () function corresponds to the native function: Com_android_internal_os_zygoteinit_selectreadable ()
Static Jint com_android_internal_os_zygoteinit_selectreadable (jnienv *env, Jobject clazz, Jobjectarray FDS) {i F (FDS = = null) {jnithrownullpointerexception (env, "FDS = = null"); return-1; } jsize length = Env->getarraylength (FDS); Fd_set Fdset; if (env->exceptionoccurred () = NULL) {return-1; } fd_zero (&fdset); int Nfds = 0; for (Jsize i = 0; i < length; i++) {Jobject fdobj = env->getobjectarrayelement (FDS, i); if (env->exceptionoccurred () = NULL) {return-1; } if (fdobj = = NULL) {continue; } int fd = Jnigetfdfromfiledescriptor (env, fdobj); if (env->exceptionoccurred () = NULL) {return-1; } fd_set (FD, &fdset); if (fd >= nfds) {Nfds = fd + 1; }} int err; do {err = select (Nfds, &fdset, NULL, NULL, NULL); } while (Err < 0 && errno = = EINTR); if (Err < 0) {jnithrowioexception (env, errno); return-1; } for (Jsize i = 0; i < length; i++) {Jobject fdobj = env->getobjectarrayelement (FDS, i); if (env->exceptionoccurred () = NULL) {return-1; } if (fdobj = = NULL) {continue; } int fd = Jnigetfdfromfiledescriptor (env, fdobj); if (env->exceptionoccurred () = NULL) {return-1; } if (Fd_isset (FD, &fdset)) {return (jint) I; }} return-1;}