Android system startup (2) - Zygote process startup process

1 Overview

In Androidthe system, DVM( Dalvikvirtual machine) and ARTsystem service process system_server and application process are all Zygotecreated by the process (and Nativethe program, that is, C/C++the program developed by the process is initcreated and started by the process). ZygoteThe process is also called the incubator. fork(复制进程)The application process and system_serverthe process are created in the form of . Since the process will create or Zygotewhen it starts , the application process and process created by passing can obtain an instance copy of or internally .DVMARTforksystem_serverDVMART

ZygoteA process is initcreated when the process starts. Initially, Zygotethe name of the process is not Zygote, but rather app_process, the name is /frameworks/base/cmds/app_process/Android.mkdefined in . ZygoteAfter the process starts, the system Linuxunder the system pctrlwill be called app_process, and its name will be changed to Zygote.

Zygoteis a C/Smodel. ZygoteAs a server, the process Socketcommunicates with other processes through the method. The "other process" here mainly refers to the system service process system_server.

In Linuxthe system, forkwhen calling a function to create a child process, the memory of the parent process will not be copied, but the parent and child processes share a memory space, and the memory copy will only be performed when the child process or the parent process modifies the memory data, thus, The parent process and the child process have their own memory space. Before then, it will only be shared as read-only.

Copy-on-write ( copy-on-write): The memory space is not actually allocated until the data is modified, which is a technique that can delay or even avoid copying data. This is an optimization of program performance, and the purpose of this is to avoid unnecessary copies.

ZygoteAs an incubator, some resources can be loaded in advance, so that forkthe spawned child process can directly use these resources without reloading. For example, system_servera process can directly use functions, shared libraries, common classes, and theme resources Zygotein the process JNI.

ZygoteProcess startup works the following things:

  • Call AppRuntime/AndroidRuntime.startmethod, create Javavirtual machine and register JNImethod for it;
  • Enter the framework layer from the layer by JNIcalling the method ;ZygoteInit.mainNativeJava
  • start system_serverprocess;
  • Create a new application process by ZygoteServercreating a request on the server side Socketand ZygoteServer.runSelectLoopwaiting for it through the method ;AMS

The following is Zygotethe timing diagram for startup:

Zygote startup process

2 Zygotestartup script

In the process of starting the init process , it is mentioned that initthe process will parse init.rcthe file, and then create and load servicethe process specified by the field, and the process is loaded Zygoteby the process in this way . Use the type statement in the file initto introduce the startup script, which is written by the initialization language ( ):init.rcImportZygoteAndroidAndroid Init Language

// /system/core/rootdir/init.rc
import /init.environ.rc
import /init.usb.rc
import /init.${
    
    ro.hardware}.rc
import /vendor/etc/init/hw/init.${
    
    ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${
    
    ro.zygote}.rc  // ${ro.zygote} 由厂商定义,与平台无关

It can be seen that init.rca fixed file will not be imported directly, but ro.zygotedifferent files will be imported according to the content.

Starting from Android 5.0, we began to support 641-bit programs, Zygoteso there is a difference 32between 1-bit and 1 64-bit, so we use ro.zygotethe attribute to control the use of different Zygotestartup scripts, so that different versions of the process are started , and different versions of the process Zygoteare started . There are the following values :Zygotero.zygote4

  • init.zygote32.rc: ZygoteThe execution program corresponding to the process is app_process(pure 32 bitmode);
  • init.zygote32_64.rc: Start two Zygoteprocesses ( zygoteand zygote_secondary), and the corresponding execution programs are app_process32(main mode), app_process64;
  • init.zygote64.rc: ZygoteThe execution program corresponding to the process is app_process64(pure 64 bitmode);
  • init.zygote64_32.rc: Start two Zygoteprocesses ( zygoteand zygote_secondary), and the corresponding execution programs are app_process64(main mode), app_process32;

These Zygotestartup scripts are placed system/core/rootdirin the directory as follows:

ro.zygotes property

Taking 64the bit processor as an example, init.zygote64_32.rcthe code is as follows:

init.zygote64_32

There are two type statements in the script Service, indicating that two Zygoteprocesses will be started, one is named zygote, and the execution program is app_process64, as the main mode; the other is named zygote_secondary, and the execution program is app_process32, as the secondary mode. Other script files are similar to this.

Take init.zygote64_32.rcfor example, its startup file address is /system/bin/app_process64(above figure), and app_process64the corresponding code is in /frameworks/base/cmds/app_processthe directory of .

First, take a look at Android.mk:

// /frameworks/base/cmds/app_process/Android.mk
LOCAL_PATH:= $(call my-dir)
....
app_process_src_files := \
     app_main.cpp \
...
LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64
...

As can be seen from the above code, whether it is app_prcessor app_prcess32or app_prcess64, the corresponding source file is app_main.cpp.

3 Zygoteprocess startup process

initThe process is started Zygotemainly by calling the function app_main.cppin the file main, among which the process is started by AppRuntimecalling the method :startZygote

// /frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
    
    
   ...
    while (i < argc) {
    
    
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
    
     // 1
            // 如果当前运行在Zygote进程中,则将zygote设置为true
            zygote = true; // 2
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
    
     // 3
            // 如果当前运行在system_server进程中,则将startSystemServer设置为true
            startSystemServer = true; // 4
        } 
        ...
    }
    ...
    if (!niceName.isEmpty()) {
    
    
        runtime.setArgv0(niceName.string(), true /* setProcName */);
    }
	// 如果运行在zygote进程中
    if (zygote) {
    
     // 5
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote); // 6
    } 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.");
    }
}
 AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));

ZygoteProcesses forkcreate sub-processes by themselves, so that both Zygotethe process and its sub-processes can enter the function app_main.cppof , therefore, in order to distinguish which process is currently running in the function,mainmain it will 1judge argwhether the parameter is included in the comment --zygote, if it contains It means that mainthe function is running in Zygotethe process, and the comment 2is zygoteset to true. In the same way, judge whether 3the parameter is included in the comment . If it is included, it means that the function trial run is in the process, and set to in the comment .arg--start-system-servermainsystem_server4startSystemServertrue

At the comment 5, if zygoteis true, it means that it is currently running in zygotethe process, and the function at the comment will be 6called . Inherited from , and did not override the method, therefore, the process entered in , the code is as follows:AppRuntimestartAppRuntimeAndroidRuntimestartZygoteAndroidRutime

// /frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    
    
    ...
    /* start the virtual machine 启动Java虚拟机 */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
    
     // 1
        return;
    }
    onVmCreated(env);

    /*
     * Register android functions. 为Java虚拟机注册JNI方法
     */
    if (startReg(env) < 0) {
    
     // 2
        ALOGE("Unable to register all android natives\n");
        return;
    }

    ...
    // 从app_main的main函数得知className为com.android.internal.os.ZygoteInit
    classNameStr = env->NewStringUTF(className); // 3
    assert(classNameStr != NULL);
    env->SetObjectArrayElement(strArray, 0, classNameStr);

    for (size_t i = 0; i < options.size(); ++i) {
    
    
        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
        assert(optionsStr != NULL);
        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    }

    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     * 将className的"."替换为"/"
     */
    char* slashClassName = toSlashClassName(className != NULL ? className : ""); // 4
    // 找到 zygoteInit
    jclass startClass = env->FindClass(slashClassName); // 5
    if (startClass == NULL) {
    
    
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
    
    
        // 找到ZygoteInit的main函数
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
                                                     "([Ljava/lang/String;)V"); // 6
        if (startMeth == NULL) {
    
    
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
    
    
            // 通过JNI调用ZygoteInit的main方法
            env->CallStaticVoidMethod(startClass, startMeth, strArray); // 7

            #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->DestroyJavaVM() != 0)
        ALOGW("Warning: VM did not shut down cleanly\n");
}

1Call the function in the comment startVmto create Javaa virtual machine, and 2call startRegthe function in the comment to Javaregister the virtual machine JNI. 3The value of in the annotation classNameis the parameter passed in, and its value is com.android.internal.os.ZygoteInit. Use the function at the comment 4to replace with , and assign the replaced value to , then find at the comment according to , and call the method at the comment after finding . Finally, the method will be called at the comment . Why use here ? Because the method is written in the language, the current running logic is in , which needs to be called through . In this way, the frame layer is entered from the layer .toSlashClassNameclassName./com/android/internal/os/ZygoteInitslashClassName5slashClassNameZygoteInitZygoteInit6ZygoteInit.main7JNIZygoteInit.mainJNIZygoteInit.mainJavaNativeJNIJavaZygoteNativeJava

After JNIcalling ZygoteInit.mainthe method, Zygoteyou enter Javathe framework layer. Before that, no code entered Javathe framework layer. In other words, you Zygotecreated Javathe framework layer. ZygoteInit.mainThe method code is as follows:

// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
    
    
    // ZygoteServer是Zygote进程的Socket通讯服务端的管理类
    ZygoteServer zygoteServer = null;
    ...
    Runnable caller;
    try {
    
    
        if (!enableLazyPreload) {
    
    
            bootTimingsTraceLog.traceBegin("ZygotePreload");
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                                SystemClock.uptimeMillis());
            preload(bootTimingsTraceLog); // 1
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                                SystemClock.uptimeMillis());
            bootTimingsTraceLog.traceEnd(); // ZygotePreload
        } else {
    
    
            Zygote.resetNicePriority();
        }
        
        ...
        zygoteServer = new ZygoteServer(isPrimaryZygote); // 2
		
        if (startSystemServer) {
    
    
            Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); // 3
            // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
            // child (system_server) process.
            if (r != null) {
    
    
                r.run();
                return;
            }
        }

        Log.i(TAG, "Accepting command socket connections");

        // The select loop returns early in the child process after a fork and
        // loops forever in the zygote.
        caller = zygoteServer.runSelectLoop(abiList); // 4
    } catch (Throwable ex) {
    
    
        Log.e(TAG, "System zygote died with exception", ex);
        throw ex;
    } finally {
    
    
        if (zygoteServer != null) {
    
    
            zygoteServer.closeServerSocket();
        }
    }
	...
}

Comments 1preload classes and resources. The comment 2creates a channel on the Serverend Socketthat responds to ActivityManagerServicerequest Zygoteto create a new application process. 3Start the process at the comment system_server, so that the system services will also system_serverbe started by the process. 4The method is called at comment ZygoteServer.runSelectLoopto wait for AMSa request to create a new process.

From the above, we can see that ZygoteInit.mainthe method mainly does 4two things:

  • preload classes and resources ;
  • The creation Serverside Socketis used to respond to ActivityManagerServicethe request to create a new application process;
  • Start system_serverthe process, so that the system service will also system_serverbe started by ;
  • Waiting for ActivityManagerServicea request to create a new application process;

reference

[Android 10 System Launch] Series – Zygote (Process Incubator)

Guess you like

Origin blog.csdn.net/xingyu19911016/article/details/127686947