The zygote process is initiated by the first process Init of the Android system. The init process starts when the kernel is loaded and, during startup, it reads a script file init.rc the root directory so that other processes that need to boot up can be started together.
The startup script for the zygote process in script file init.rc is as follows:
Service Zygote/system/bin/app_process-xzygote/system/bin--zygote--start-system-server socket zygote Stream 666
The first line indicates that the zygote process started as a service and that its corresponding application file is/system/bin/app_process. The next four options are the startup parameters of the zygote process. The last parameter, "--start-system-server", indicates that the zygote process needs to start the system process immediately after the boot is complete.
The second line indicates that the zygote process needs to internally create a socket called "zygote" during the boot process. This socket is used to perform interprocess communication, and its access is set to 666, which means that all users can read and write to it.
Let's first analyze how zygote creates a socket called "zygote" in the process of booting.
Since the zygote process is configured to start in the form of a service in script init.rc, the init process starts by invoking the function Service_start to start it, as follows:
void Service_start (struct service *svc, const char *dynamic_args)//SVC is used to describe a service that is about to start, Dynamic_args for null{... pid_t pid ... pid = fork ();//init Process fork out zygote process if (PID = = 0) {//zygote process struct socketinfo *si; ... for (si = svc->sockets; si; si = si->next) {//svc->sockets Describes the socket list of services to be started 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);//na Me for Socket,socket_type stream, create a socket, return a descriptor if (s >= 0) {Publish_socket (si->name, s); The descriptor returned by Create_socket is eventually published to the system by the function Publish_socket} ... setpgid (0, Getpid ()); /* As requested, set our GID, supplemental Gids, and UID */if (svc->gid) {SETgid (Svc->gid); } if (Svc->nr_supp_gids) {setgroups (svc->nr_supp_gids, svc->supp_gids); if (svc->uid) {//Because Svc->uid is empty, all zygote processes have a UID of 0, which remains the root privilege setuid (SVC->UID); } if (!dynamic_args) {if (Execve (Svc->args[0], (char**) Svc->args, (char**) ENV) < 0) {//svc-& Gt;args[0] for/system/bin/app_process,svc->args static start parameter, note that this array has "--start-system-server" ERROR ("Cannot execve ('%s '):%s\n ", Svc->args[0], strerror (errno)); }} else {...} _exit (127); } ......}
We then analyze the implementation of the functions Create_socket and public_socket so that we can see how they create a socket called "zygote" for the zygote process.
The implementation of the function Create_socket is shown below.
int create_socket (const char *name, int type, mode_t perm, uid_t uid, gid_t gid) { struct sockaddr_un addr; int FD, ret; FD = socket (Pf_unix, type, 0);//Create a socket, this socket uses the file descriptor FD description ... memset (&addr, 0, sizeof (addr)); Addr.sun_family = af_unix;//Creates a socket address of type Af_unix, addr, which has a corresponding device file, which is Android_socket_dir/name, as shown in the next line of code snprintf (Addr.sun_path, sizeof (Addr.sun_path), Android_socket_dir "/%s",//name for Zygote,android_socket_dir/ Dev/socket name); ...... ret = bind (FD, (struct sockaddr *) &addr, sizeof (addr))//bind bind the socket described by the file descriptor FD to the socket address addr, we can get a device file /dev/socket/zygote ... Chown (Addr.sun_path, UID, GID)//chown set the device file/dev/socket/zygote user ID, user group ID chmod (addr.sun_path, perm);// chmod set the access rights of the device file/dev/socket/zygote, the parameter perm is 666, because the device file/dev/socket/zygote can be accessed by any user. ...... Return fd;//returns the descriptor}
The function Publish_socket is implemented as follows:
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)) The//key value is Android_socket_zygote snprintf (Val, sizeof (Val), "%d", FD),//FD is a file descriptor pointing to a SOCKET created earlier, The FD is formatted as a string and stored in the variable val add_environment (Key, Val);//Added an environment variable named key to the system, and set its value to Val. This is equivalent to the file description of a SOCKET created earlier characters in an environment variable named "Android_socket_zygote" /* Make sure we don't close-on-exec * /Fcntl ( FD, F_SETFD, 0);}
Below, we will see that the zygote process will create a server-side socket based on the value of the environment variable during the boot process, and wait until the boot is complete. Then wait for the Activtiy Management Service on this server-side socket Activitymangerservice request it to create a new application process.
Go back to Service_start and continue executing the following code:
if (!dynamic_args) { if (Execve (Svc->args[0], (char**) Svc->args, (char**) ENV) < 0) {//svc->args[0] is/ System/bin/app_process,svc->args static startup parameters, note that this array has "--start-system-server" ERROR ("Cannot execve ('%s '):%s\n" , Svc->args[0], strerror (errno)); } }
The application file loaded in the zygote process is system/bin/app_process, so let's start with the entry function for this application file, main, to analyze the start-up process of the zygote process.
int main (int argc, const char* Const argv[]) {//These is global variables in ProcessState.cpp MARGC = argc; MARGV = argv; Marglen = 0; for (int i=0; i<argc; i++) {Marglen + = strlen (Argv[i]) + 1; } marglen--; Appruntime runtime;//created a Appruntime object Runtime const char *arg; const char *argv0; Argv0 = argv[0]; Process command Line arguments//ignore argv[0] argc--; argv++; Everything up to '--' or first non '-' arg goes to the VM int i = runtime.addvmarguments (argc, argv); Next arg is parent directory if (i < argc) {runtime.mparentdir = argv[i++]; }//Next arg is startup classname or "--zygote" if (I < argc) {arg = argv[i++]; if (0 = = strcmp ("--zygote", Arg)) {//The startup parameter has "--zygote" bool Startsystemserver = (i < ARGC)? strcmp (Argv[i], "--start-system-server") = = = 0:false;//startsystemserver Value equals True, indicating that the zygote process needs to start the system process after the boot is complete SetArgv0 (Argv0, "zygote"); Set_process_name ("zygote");//Set process name Zygote Runtime.start ("Com.android.internal.os.ZygoteInit", St Artsystemserver); } else {...} } else {...}}
The member function of the Appruntime class is inherited from its parent class androidruntime, so we continue to analyze the implementation of the member function start of the Androidruntime class.
/** Start the Android runtime. This involves starting the virtual machine* and calling the "static void Main (string[] args)" method in the class* named B Y "ClassName". */void androidruntime::start (const char* className, const bool startsystemserver) {... char* Slashclassname = null;char* cp; jnienv* env;....../* Start the virtual machine */if (STARTVM (&MJAVAVM, &env)! = 0) goto bail;/** Register Android F unctions.*/if (Startreg (env) < 0) {LOGE ("Unable to register all Android natives\n"); goto bail;} /** we want to call main () with a String array with arguments in it.* at present we are only having one argument, the class name . Create an* Array to hold It.*/jclass Stringclass;jobjectarray strarray;jstring classnamestr;jstring Startsystemserverstr;stringclass = Env->findclass ("java/lang/string"); assert (Stringclass! = NULL); StrArray = env- >newobjectarray (2, stringclass, null); assert (Strarray! = null); classnamestr = Env->newstringutf (className); ASSERT (Classnamestr! = NULL); env->setobjectarrayelement (strarray, 0, classnamestr); startsystemserverstr = Env->newstringutf (startSystemServer ?" True ":" "false"); Env->setobjectarrayelement (Strarray, 1, startsystemserverstr);/** Start VM. This thread becomes the main thread of the VM, and will* not return until the VM Exits.*/jclass startclass;jmethodid start Meth;slashclassname = StrDup (ClassName); for (cp = Slashclassname; *CP! = ' + '; cp++) if (*CP = = '. ') *CP = '/'; startclass = Env->findclass (slashclassname); if (Startclass = = NULL) {...} else {startmeth = Env->getsta Ticmethodid (Startclass, "main", "([ljava/lang/string;) V"), if (Startmeth = = NULL) {...} else {env-> Callstaticvoidmethod (Startclass, Startmeth, Strarray); ......}
STARTVM creates a virtual machine instance in the zygote process and then Startreg registers a series of JNI methods in the virtual machine instance, which can refer to the boot process analysis and Dalvik virtual machine Summary of the Dalvik virtual machine.
Finally call the static member function of the Com.android.internal.os.ZygoteInit class main to further start the zygote process. Env->callstaticvoidmethod (Startclass, Startmeth, Strarray) actually explains the execution of the relevant Java code by Dalvik the virtual machine, refer to the operation process analysis of the Dalvik virtual machine.
Then we continue to analyze the implementation of the static member function main of the Com.android.internal.os.ZygoteInit class.
public class Zygoteinit {... public static void main (String argv[]) {try {... registerzygotesocket ();// Create a server-side socket that is used to wait for the Activity Management Service Activitymanagerservice request zygote process to create a new application process ... if (Argv[1].equals ("true")) {startsystemserver ();//start the system process so that it can start the critical services of the systems up} else if (!argv[1]. Equals ("false")) {...} ... if (zygote_fork_mode) {//false ...} else {runselectloopmode ();} ......} catch (Methodandargscaller caller) {...} catch (RuntimeException ex) {...}} ......}
Let's analyze Registerzygotesocket first, as follows:
private static void Registerzygotesocket () { if (Sserversocket = = null) { int filedesc; try { String env = system.getenv (android_socket_env);//Gets the value of an environment variable named "Android_socket_zygote" Filedesc = Integer.parseint (env);//convert it to a file descriptor, we know that this file descriptor is used to describe a socket of type Af_unix. } catch (RuntimeException ex) { throw new RuntimeException ( android_socket_env + "unset or invalid", ex);
} try { sserversocket = new Localserversocket ( createfiledescriptor (FILEDESC));// A server-side socket was created and saved in Zygoteinit static member variable Sserversocket } catch (IOException ex) { throw new RuntimeException ( "Error binding to local socket '" + Filedesc + "'", Ex);}}
Then we analyze the Startsystemserver as follows:
public class Zygoteinit {... private static Boolean startsystemserver () throws Methodandargscaller, runtimeexception {/* hardcoded command line to start the system server */string args[] = {"--setuid=1 ","--setgid=1000 ","--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003 ","-- capabilities=130104352,130104352 ","--runtime-init ","--nice-name=system_server "," Com.android.server.SystemServer ",}; Zygoteconnection.arguments Parsedargs = Null;int pid;try {Parsedargs = new zygoteconnection.arguments (args), .../* Request to fork the system server process */pid = Zygote.forksystemserver (Parsedargs.uid, Parsedargs.gid,parsedargs.gids , DebugFlags, null,parsedargs.permittedcapabilities,parsedargs.effectivecapabilities);//system process UID is IllegalArgumentException ex) {...} /* for child process */if (PID = = 0) {//subprocess, System process handlesystemserverprocess (Parsedargs);//system process, subsequent re-parsing}return true;}. .....}
A string array, args, is first created to hold the startup parameters of the system process. Then call Forksystemserver to create a child process, which is the system process for Android. As you can see, both the user ID and the user group ID of the system process for Android are set to the system shown in 1000,shell.
Return to the static member function of the Com.android.internal.os.ZygoteInit class, main, and continue parsing Runselectloopmode as follows:
public class Zygoteinit {... private static void Runselectloopmode () throws Methodandargscaller {arraylist< filedescriptor> FDS = new ArrayList (); Arraylist<zygoteconnection> peers = new ArrayList (); filedescriptor[] Fdarray = new filedescriptor[4];//first creates an array of socket file descriptors of size 4 Fdarray, which means that the zygote process can handle 4 socket connections at a timeFds.add (Sserversocket.getfiledescriptor ());// Add the Zygoteinit class static member variable Sserversocket as described by the file descriptor of a socket to the socket file descriptor list in FDS peers.add (null); int loopcount = Gc_loop_ Count;while (true) {int Index;......try {Fdarray = Fds.toarray (Fdarray);// The socket file descriptor that is saved in the socket file descriptor list in FDS is transferred to the socket file Descriptor Array Fdarray index = selectreadable (Fdarray);// To monitor if the socket stored in this array has data to read. } catch (IOException ex) {throw new RuntimeException ("Error in Select ()", ex);} if (Index < 0) {throw new RuntimeException ("Error in Select ()"),} else if (index = = 0) {//Received connection, Zygoteconnection Newpee R = Acceptcommandpeer ();p eers.add (Newpeer); Fds.add (Newpeer.getfiledesciptor ());} else {//received the Activity Management Service Activitymanangerservice sent over the Create application process request Boolean done;done = Peers.get (index). runOnce ();// To create an application process if (done) {peers.remove (index); fds.remove (index);}}} ......}
Selectreadable to monitor if the socket stored in this array has data readable, a data-readable means that it receives a connection or a request. If index is 0, it indicates that it has received a connection. Index greater than 0 indicates that a request was received.
Zygote.forksystemserver is called in the static function Startsystemserver in Zygoteinit, and thestatic function in Zygoteinit Runselectloopmode called Selectreadable, are native methods, as follows:
Native public static int forkandspecialize (int uid, int. GID, int[] gids, int debugflags, int[][] rlimits);
static native int selectreadable (filedescriptor[] fds) throws IOException;
We just said that.the static member function of the Com.android.internal.os.ZygoteInit class, Main, is performed by the Dalvik virtual machine interpretation, and then to these native methods, the Jni method is actually executed directly on the local operating system rather than being interpreted by the Dalvik virtual machine The device executes. Refer to the Dalvik virtual machine JNI method for registration process analysis and Dalvik virtual machine summary. The relevant code executes directly on the local operating system as follows:
void Dvmcallmethodv (thread* self, const method* Method, object* obj, bool Fromjni, jvalue* PResult, va_list args) {
...... if (Dvmisnativemethod (method)) { Trace_method_enter (self, method); / * * Because we leave no space for local variables, ' curframe ' points * directly at the method arguments. * /(*method->nativefunc) (Self->curframe, PResult, method, self);//go directly to execute trace_method_exit (self, method); } else { Dvminterpret (self, method, pResult);//Explanation of execution } ...}
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Zygote process Start-up process