Android Boot zygote boot

Source: Internet
Author: User
Tags strcmp

The previous post introduced the Init process to start, when parsing init.rc will add zygote to the service list, and finally start, zygote start is the actual app_process program. Zygote is the child process of the INIT process. In the Android system, all applications and system services, includingsystemserver are all zygote fork, and that's why it's called zygote (fertilized egg). Let's look at the description of the. 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  
The service name is: zygote
command to start the service execution:/system/bin/app_process
Parameters of the command:-xzygote/system/bin--zygote--start-system-server
Socket zygote Stream 660: Create a socket named:/dev/socket/zygote, type: StreamApp_main.cppThe main function of zygote is in \frameworks\base\cmds\app_process\app_main.cpp, as follows:
int main (int argc, const char* Const argv[]) {... int i = runtime.addvmarguments (argc, argv);        The returned I will typically be 1 while (I < ARGC) {const char* arg = argv[i++];        if (!parentdir) {//takes value should be/system/bin parentdir = arg;            } else if (strcmp (ARG, "--zygote") = = 0) {zygote = true;        Nicename = "Zygote";        } else if (strcmp (ARG, "--start-system-server") = = 0) {Startsystemserver = true;        } else if (strcmp (ARG, "--application") = = 0) {application = true;        } else if (strncmp (ARG, "--nice-name=", "n") = = 0) {nicename = arg + 12;            } else {className = arg;        Break        }} if (Nicename && *nicename) {setArgv0 (argv0, nicename);    Change the app_process process name to Zygote set_process_name (nicename);    } Runtime.mparentdir = Parentdir; if (zygote) {//Core code Runtime.start ("Com.android.internal.os.ZygoteInit", StartsystemserveR?    "Start-system-server": ""); } else if (className) {//remainder of args get passed to startup class main () Runtime.mclassname = Classna        Me        RUNTIME.MARGC = Argc-i;        RUNTIME.MARGV = argv + i; Runtime.start ("Com.android.internal.os.RuntimeInit", application?)    "Application": "Tool");        } 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; }}
If it runs normally, it will go to Runtime.start ("Com.android.internal.os.ZygoteInit", Startsystemserver? "Start-system-server": ""), as follows:
void Androidruntime::start (const char* className, const char* options) {alogd ("\n>>>>>> Androidrunti Me START%s <<<<<<\n ", ClassName! = NULL?    ClassName: "(unknown)");    Create a Signal pipeline blocksigpipe ();    ...//start virtual machine jnienv* env;    if (STARTVM (&AMP;MJAVAVM, &env)! = 0) {return;    }//Null function onvmcreated (env); Registering Android's native function (JNI interface), registering a function to create a thread (JAVACREATETHREADETC) if (Startreg (env) < 0) {Aloge ("unable to re        Gister all Android natives\n ");    Return    }//Create an java.lang.String array whose content value is: ["Com.android.internal.os.ZygoteInit", "true"] jclass Stringclass;    Jobjectarray Strarray;    Jstring Classnamestr;    Jstring Optionsstr;    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);    Optionsstr = Env->newstringutf (options);        Env->setobjectarrayelement (Strarray, 1, OPTIONSSTR);  /* * Start VM.     This thread becomes the main thread of the VM, and would * not return until the VM exits.    */char* Slashclassname = Toslashclassname (className);    Find Com.android.internal.os.ZygoteInit class Jclass Startclass = Env->findclass (slashclassname);        if (Startclass = = NULL) {aloge ("JAVAVM Unable to locate class '%s ' \ n", slashclassname); /* Keep going */} else {//Find main function of Zygoteinit class Jmethodid Startmeth = Env->getstaticmethodid (Startclass, "Mai        N "," ([ljava/lang/string;) V ");            if (Startmeth = = NULL) {aloge ("JAVAVM Unable to find main () in '%s ' \ n", className); /* Keep going */} else {///Call the main function of the Zygoteinit class, the parameter is Strarray. The first Java class performed by a virtual machine is Zygoteinit.java env->callstaticvoidmethod (startclass, Startmeth, strArray); #if 0 if (Env->exceptioncheck ()) threadexituncaughtexception (env); #endif}}    Free (slashclassname);    ALOGD ("Shutting down vm\n");    if (Mjavavm->detachcurrentthread ()! = JNI_OK) ALOGW ("Warning:unable to detach main thread\n"); if (MJAVAVM-&GT;DESTROYJAVAVM ()! = 0) ALOGW ("WARNING:VM didn't shut down cleanly\n");}
Zygoteinit.javaThe first Java class that a virtual machine executes is Zygoteinit.java, whose main function is as follows:
public static void Main (String argv[]) {try {//Start profiling the zygote initialization.    Samplingprofilerintegration.start ();    A socket interface was created to communicate with Activitymanagerservice registerzygotesocket ();            Loads most of the framework's classes and resources, and shares Eventlog.writeevent (Log_boot_progress_preload_start,systemclock.uptimemillis ()) with the child processes;            Preload ();            Eventlog.writeevent (Log_boot_progress_preload_end, Systemclock.uptimemillis ());            Finish profiling the zygote initialization.            Samplingprofilerintegration.writezygotesnapshot ();            Do a initial GC to clean up after startup GC (); If requested, start system server directly from Zygote if (argv.length! = 2) {throw new Runt            Imeexception (Argv[0] + usage_string); }//Starts Systemserver, where a new process is started if (Argv[1].equals ("Start-system-server")) {Startsystemserver            (); } else if (!argv[1].equals (""))            {throw new RuntimeException (Argv[0] + usage_string);            } log.i (TAG, "accepting command socket connections");            if (Zygote_fork_mode) {runforkmode ();            } else {//infinite loop, waiting for Activitymanagerservice request to create a new application process Runselectloopmode () on the previously created socket interface;        } closeserversocket ();        } catch (Methodandargscaller caller) {Caller.run ();            } catch (RuntimeException ex) {LOG.E (TAG, "Zygote died with exception", ex);            Closeserversocket ();        Throw ex; }    }
Create socket interface
 private            static void Registerzygotesocket () {if (Sserversocket = = null) {int filedesc;                try {//Get SOCKET descriptor String env = system.getenv (android_socket_env);            Filedesc = Integer.parseint (env); } catch (RuntimeException ex) {throw new RuntimeException (android_socket_env + "U            Nset or invalid ", ex); } try {//In a Linux system, all system resources can be considered as files, even memory and CPU, so, like standard disk files or network sockets are naturally thought to be files, which is why Localservers                The argument to the Ocket constructor is a file descriptor.            Sserversocket = new Localserversocket (Createfiledescriptor (FILEDESC)); } catch (IOException ex) {throw new RuntimeException ("Error binding to local Socke            T ' + Filedesc + "'", ex); }        }    }

There are two ways to trigger the socket data read operation in socket programming. One is to use listen () to listen to a port, and then call Read () to go from the port reading the data, which is called a blocking read operation, because when the port has no data, the read () function waits until the data is ready to return The other is to use the Select () function as the parameter of the Select () function for the file descriptor that needs to be monitored, and then automatically trigger an interrupt after the new data appears on the file descriptor, and then read the data on the specified file descriptor in the interrupt handler, which is called a non-blocking read operation . The latter is used in Localserversocket, which is non-blocking read operations.

Pre-load classes and resourcesWhen the Android source code is compiled, the preload-classes file will eventually be packaged in the Framework.jar. Loading these classes is done by calling Preloadclasses () in Zygoteinit. The method of loading is simply to read each row in the Preload-classes list, because each row represents aclass, and then call Class.forName () to load the target class.

The preloadresources () function calls Preloaddrawables () and preloadcolorstatelists () to load two types of resources, respectively. The principle of loading is simply to read these resources into a global variable that will persist as long as the class object is not destroyed. The global variable that holds the drawable resource is mresources, and the type of the variable is the resources class, because the class internally holds a list of drawable resources, so actually caching these drawable resources is within The global variable that holds the color resource is also mresources,and within the resourcesclass There is also a list of color resources.

  static void preload () {        preloadclasses ();        Preloadresources ();    }

Loop Waiting Service
private static void Runselectloopmode () throws Methodandargscaller {//First add Sserversocket to the list of monitored file descriptors Array        list<filedescriptor> FDS = new ArrayList ();        Arraylist<zygoteconnection> peers = new ArrayList ();        filedescriptor[] Fdarray = new Filedescriptor[4];        Fds.add (Sserversocket.getfiledescriptor ());        Peers.add (NULL);        int loopcount = Gc_loop_count;            while (true) {int index;             /* * Call GC () before we block in select ().  * It's work, the has-to-be-done anyway, and it's better * to avoid making every child do It.             It would also * madvise () Any free memory as a side-effect.  * * Don ' t call it every time, because walking the entire * heap was a lot of overhead to free a few             Hundred bytes.                */if (loopcount <= 0) {GC ();            Loopcount = Gc_loop_count;         } else {       loopcount--; The return value of the//selectreadable () function is three. One is-1, which represents an internal error, and the second is 0, which means that there is no processing connection, so a Zygoteconnection object is re-established with the socket service port and waits for the client's request, and the third is greater than 0, which means that there are still pending connection requests.            Therefore, the request needs to be processed first, and no new connection waits need to be established for the time being.                try {Fdarray = Fds.toarray (Fdarray);            index = selectreadable (Fdarray);            } catch (IOException ex) {throw new RuntimeException ("Error in Select ()", ex);            } if (Index < 0) {throw new RuntimeException ("Error in Select ()"); } else if (index = = 0) {//Accept Socket command for Android app zygoteconnection Newpeer = Acceptcommandpeer                ();                Peers.add (Newpeer);            Fds.add (Newpeer.getfiledesciptor ());        } else {Boolean done;                The new application process is hatched based on the zygote process done = Peers.get (index). RunOnce ();                    if (done) {peers.remove (index);                Fds.remove (index);      }      }        }    } 
Fork Create Process

Fork is a system call to a Linux system that replicates the current process and creates a new process. The new process will have exactly the same process information as the original process, except for the process ID. The process information includes the file description list characters that the process opened, the allocated memory, and so on. When the new process is created, two processes will share the allocated memory space until one of them needs to write to the memory, the operating system is responsible for copying a copy of the destination address space, and will write the data to the new address, this is called the Copy-on-write mechanism, that is, " Copy only when writing, which allows the maximum amount of physical memory to be shared across multiple processes. That's why we'll preload the framework's classes and resources, and this way the process can share the framework resources with zygote. Within the operating system, starting a new process consists of three processes.
The first procedure, the kernel creates a process data structure that represents the process that will be started.
The second procedure, the kernel Invoker loader function, reads the program code from the specified program file and loads the program code into the pre-set memory address.
The third procedure, after loading, the kernel points the program pointer to the entrance of the target program's address to begin executing the specified process. Of course, the actual process will take into account more details, but the general idea is so simple.
Because the fork () function is a system call to Linux, the Java layer in Android is simply a JNI encapsulation of the call. ZygoteconnectionClass ofrunOnce ()the function is to create a child process by invoking the fork () function with JNI.

fork call is that it is only called once , but can return two times, it may have three different return values:
    1) in the parent process, fork returns the process ID of the newly created child process,
    2) in the child process, fork returns 0;
    3) If an error occurs, fork returns a negative value;

Zygote has created a socket server, which should not be used by the new process, or there will be multiple processes in the system to receive the socket client's command. Therefore, after the new process is created, you first need to close the socket server in the new process and invoke the main () function of the class file specified in the new process as the entry point for the new process. These are exactly the same as the return value PID after calling the Forkandspecialize () function.



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.