Android Startup Process Analysis-start of zygote
The previous article took a lot of space to introduce how the init process parses init. rc and how to execute some system services.
So how did we start zygote? What is zygote responsible?
In this article, let's look at it.
Zygote has the following descriptions in inir. rc:
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
We can simply analyze these two sentences,
Service zygote/system/bin/app_process-Xzygote/system/bin -- zygote -- start-system-server
Class main
This means that zygote belongs to the main class.
Zygote is a service whose name is zygote. The command executed at startup is app_process, and the parameter passed is-Xzygote/system/bin -- zygote -- start-system-server.
So, according to our previous analysis theory, let's take a look at what app_process is.
First, go to the framework directory and in base/cmds/app_process, we can see the makefile that generates app_process.
include $(CLEAR_VARS)LOCAL_SRC_FILES:= app_main.cppLOCAL_SHARED_LIBRARIES := libcutils libutils liblog libbinder libandroid_runtimeLOCAL_MODULE:= app_processLOCAL_MULTILIB := bothLOCAL_MODULE_STEM_32 := app_process32LOCAL_MODULE_STEM_64 := app_process64include $(BUILD_EXECUTABLE)
We can see that app_process is executed to generate an application.
Imagine that this service of zygote is always running, but if we look at ps in the adb shell, we cannot find the app_process command to continue running.
Why?
First, we extract a section from the main function of app_process.
While (I <argc) {const char * arg = argv [I ++]; if (strcmp (arg, -- zygote) = 0) {// if from init. if the input parameter in the rc contains -- zygote, zygote = true will be judged; // set zygote to true niceName = ZYGOTE_NICE_NAME; // set niceName to zygote_nice_name to zygote} else if (strcmp (arg, -- start-system-server) = 0) {// if you want to start-system-server, startSystemServer = true; // set startsystemserver to true} else if (strcmp (arg, -- applic Ation) = 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 ;}}
How can we use these parameters?
Next, let's take a look at how the code is used.
If (! NiceName. isEmpty () {// If niceName is not empty, runtime. setArgv0 (niceName. string (); set_process_name (niceName. string (); // call this function to set the process name to zygote} if (zygote) {// zygote must be true runtime. start (com. android. internal. OS. zygoteInit, args); // we entered this judgment} else if (className) {runtime. start (com. android. internal. OS. runtimeInit, args);} else {fprintf (stderr, Error: no class name or -- zygote supplied .); app_usage (); LOG_ALWAYS_FATAL (app_process: no class name or -- zygote supplied .); return 10 ;}
We can see that the runtime calls the start method area to start the zygote. Which of the following is the start of the runtime call?
In the current appruntime, there is no related start function implementation.
Let's take a look at it in his parent class.
class AppRuntime : public AndroidRuntime
What is androidruntime? Is there a start method in it?
AndroidRunTime is implemented in: frameworks/base/core/jni/AndroidRuntime. cpp
We found the start method from it.
951 void AndroidRuntime: start (const char * className, const Vector
& Options) 952 {953 ALOGD (>>>>> START % s uid % d <, 954 className! = NULL? ClassName: (unknown), getuid (); 955956 static const String8 startSystemServer (start-system-server ); 957958/* 959 * 'startsystemserver = true' means runtime is obsolete and not run from960 * init. rc anymore, so we print out the boot start event here.961 */962 for (size_t I = 0; I <options. size (); ++ I) {963 if (options [I] = startSystemServer) {964/* track our progress through the boot sequence * /965 const int progress = 3000; 966 LOG_EVENT_LONG (LOG_BOOT_PROGRESS_START, ns2ms (systemTime (SYSTEM_TIME_MONOTONIC); 967} 968} 969970 const char * rootDir = getenv (ANDROID_ROOT ); 971 if (rootDir = NULL) {972 rootDir =/system; 973 if (! HasDir (/system) {974 LOG_FATAL (No root directory specified, and/android does not exist .); 975 return; 976} 977 setenv (ANDROID_ROOT, rootDir, 1); 978} 979980 // const char * kernelHack = getenv (LD_ASSUME_KERNEL ); 981 // ALOGD (Found LD_ASSUME_KERNEL = '% s', kernelHack); 982983/* start the virtual machine */984 JniInvocation jni_invocation; 985 notify (NULL); 986 JNIEnv * env; 987 if (startVm (& mJavaV M, & env )! = 0) {// create a VM 988 return; 989} 990 onVmCreated (env); 991992/* 993 * Register android functions.994 */995 if (starregulatory (env) <0) {// jni registration method 996 ALOGE (Unable to register all android natives); 997 return; 998} 9991000/* 1001 * We want to call main () with a String array with arguments in it.1002 * At present we have two arguments, the class name and an option string.1003 * Create an array to hold them.1 004 */1005 jclass stringClass; // class Object 1006 jobjectArray strArray; // corresponding to objectArray object 1007 jstring classNameStr; // A string10081009 stringClass = env-> FindClass (java/lang/String); // first, the string class1010 assert (stringClass! = NULL); 1011 strArray = env-> NewObjectArray (options. size () + 1, stringClass, NULL); // a New ObjectArray1012 assert (strArray! = NULL); 1013 classNameStr = env-> NewStringUTF (className); // convert className to UTF8 type 1014 assert (classNameStr! = NULL); 1015 env-> SetObjectArrayElement (strArray, 0, classNameStr); // set the first element of objectarray to classname10161017 for (size_t I = 0; I <options. size (); ++ I) {// convert the subsequent parameters and push them to the strArray. 1018 jstring optionsStr = env-> NewStringUTF (options. itemAt (I ). string (); 1019 assert (optionsStr! = NULL); 1020 env-> SetObjectArrayElement (strArray, I + 1, optionsStr); 1021} 10221023/* 1024 * Start VM. this thread becomes the main thread of the VM, and will1025 * not return until the VM exits.1026 */1027 char * slashClassName = toSlashClassName (className ); // convert className to/in the form of 1028 jclass startClass = env-> FindClass (slashClassName); // search for this class 1029 if (startClass = NULL) {// if not found, we will return NULL1030 LOGE (JavaVM unable to locate class '% s', slashClassName); 1031/* keep going */1032} else {1033 jmethodID startMeth = env-> GetStaticMethodID (startClass, main, 1034 ([Ljava/lang/String;) V); // obtain the main function 1035 if (startMeth = NULL) of the class we found) {1036 ALOGE (JavaVM unable to find main () in '% s', className); 1037/* keep going */1038} else {1039 env-> CallStaticVoidMethod (startClass, startMeth, strArray );// To execute the main function of this class. 10401041 # if 01042 if (env-> ExceptionCheck () 1043 threadExitUncaughtException (env); 1044 # endif1045} 1046} 1047 free (slashClassName ); // free10481049 ALOGD (Shutting down VM); 1050 if (mJavaVM-> DetachCurrentThread ()! = JNI_ OK) 1051 ALOGW (Warning: unable to detach main thread); 1052 if (mJavaVM-> DestroyJavaVM ()! = 0) 1053 ALOGW (Warning: VM did not shut down cleanly); 1054}
Based on the parameters passed, let's take a look at the main function of zygoteInit.
648 public static void main (String argv []) {649 try {650 // Start profiling the zygote initialization.651 SamplingProfilerIntegration. start (); 652653 boolean startSystemServer = false; 654 String socketName = zygote; 655 String abiList = null; 656 for (int I = 1; I <argv. length; I ++) {657 if (start-system-server.equals (argv [I]) {658 startSystemServer = true; // startSystemServer is true659} else if (argv [I]. startsWith (ABI_LIST_ARG) {660 abiList = argv [I]. substring (ABI_LIST_ARG.length (); 661} else if (argv [I]. startsWith (SOCKET_NAME_ARG) {662 socketName = argv [I]. substring (SOCKET_NAME_ARG.length (); 663} else {664 throw new RuntimeException (Unknown command line argument: + argv [I]); 665} 666} 667668 if (abiList = null) {669 throw new RuntimeException (No ABI list supplied .); 670} 671672 registerZygoteSocket (socketName); // registers a socket to communicate with other applications in the system. writeEvent (LOG_BOOT_PROGRESS_PRELOAD_START, 674 SystemClock. uptimeMillis (); 675 preload (); // pre-load some resources 676 EventLog. writeEvent (LOG_BOOT_PROGRESS_PRELOAD_END, 677 SystemClock. uptimeMillis (); 678679 // Finish profiling the zygote initialization.680 SamplingProfilerIntegration. writeZygoteSnapshot (); 681682 // Do an initial gc to clean up after startup683 gc (); 684685 // Disable tracing so that forked processes do not inherit stale tracing tags from686 // Zygote.687 Trace. setTracingEnabled (false); 688689 if (startSystemServer) {// if startSystemServer is true, systemServer690 startSystemServer (abiList, socketName); 691} 692693 Log will be started. I (TAG, Accepting command socket connections); 694 runSelectLoop (abiList); // enters the select loop, used to respond to requests from other applications 695696 closeServerSocket (); 697} catch (MethodAndArgsCaller caller) {698 caller. run (); 699} catch (RuntimeException ex) {700 Log. e (TAG, Zygote died with exception, ex); 701 closeServerSocket (); 702 throw ex; 703} 704}
So, let's make a summary of zygote.
First, zygote creates an appruntime object and calls its start. Subsequent activities are controlled by AppRuntime
Then, call startVM to create the VM and call starregulatory to register the JNI function.
ZygoteInit is called through JNI to enter the java World.
Call registerZygoteSocket to respond to requests from future generations, and call the preload function to pre-load resources.
Call startSystemServer to start the system.
After the start-up of the java World is completed, the select loop is started to process subsequent requests.