Inicio del sistema Android (2) - Proceso de inicio del proceso Zygote

1. Información general

En Androidel sistema, DVM( Dalvikmáquina virtual) y ARTel proceso de servicio del sistema system_server y el proceso de aplicación son Zygotecreados por el proceso (y Nativeel programa, es decir, C/C++el programa desarrollado por el proceso es initcreado e iniciado por el proceso). ZygoteEl proceso también se denomina incubadora. fork(复制进程)El proceso de aplicación y system_serverel proceso se crean en forma de. Dado que el proceso se creará o Zygotecuando se inicie , el proceso de aplicación y el proceso creado al pasar pueden obtener una copia de instancia de o internamente .DVMARTforksystem_serverDVMART

ZygoteUn proceso se initcrea cuando se inicia el proceso Inicialmente, Zygoteel nombre del proceso no es Zygote, sino que app_processel nombre se /frameworks/base/cmds/app_process/Android.mkdefine en . ZygoteDespués de que comience el proceso, el sistema Linuxbajo el sistema pctrlse llamará app_processy su nombre se cambiará a Zygote.

Zygotees un C/Smodelo ZygoteComo servidor, el proceso Socketse comunica con otros procesos a través del método. El "otro proceso" aquí se refiere principalmente al proceso de servicio del sistema system_server.

En Linuxel sistema, forkal llamar a una función para crear un proceso hijo, la memoria del proceso padre no se copiará, pero los procesos padre e hijo comparten un espacio de memoria, y la copia de memoria solo se realizará cuando el proceso hijo o el El proceso principal modifica los datos de la memoria, por lo tanto, el proceso principal y el proceso secundario tienen su propio espacio de memoria. Antes de eso, solo se compartirá como de solo lectura.

Copy-on-write ( copy-on-write): el espacio de memoria no se asigna realmente hasta que se modifican los datos, que es una técnica que puede retrasar o incluso evitar la copia de datos. Esta es una optimización del rendimiento del programa, y ​​el propósito de esto es evitar copias innecesarias.

ZygoteComo incubadora, algunos recursos se pueden cargar por adelantado, de modo que forkel proceso secundario generado pueda usar directamente estos recursos sin recargar. Por ejemplo, system_serverun proceso puede usar directamente funciones, bibliotecas compartidas, clases comunes y recursos temáticos Zygoteen el proceso JNI.

ZygoteEl inicio del proceso funciona de la siguiente manera:

  • Llame AppRuntime/AndroidRuntime.startal método, cree Javauna máquina virtual y registre JNIel método para ello;
  • Ingrese a la capa del marco desde la capa llamando JNIal método ;ZygoteInit.mainNativeJava
  • proceso de inicio system_server;
  • Cree un nuevo proceso de aplicación creando ZygoteServeruna solicitud en el lado del servidor Sockety ZygoteServer.runSelectLoopesperándola a través del método ;AMS

El siguiente es Zygoteel diagrama de tiempo para el arranque:

Proceso de inicio de Zygote

2 Zygoteguión de inicio

En el proceso de iniciar el proceso de inicio , se menciona que initel proceso analizará init.rcel archivo y luego creará y cargará serviceel proceso especificado por el campo, y el proceso lo cargará Zygoteel proceso de esta manera . Use la declaración de tipo en el archivo initpara introducir el script de inicio, que está escrito por el lenguaje de inicialización ( ):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} 由厂商定义,与平台无关

Se puede observar que init.rcno se importará directamente un archivo fijo, sino que ro.zygotese importarán diferentes archivos según el contenido.

A partir de Android 5.0, comenzamos a admitir 64programas de 1 bit, Zygotepor lo que existe una diferencia 32entre 1 bit y 1 64bit, por lo que usamos ro.zygoteel atributo para controlar el uso de diferentes Zygotescripts de inicio, de modo que se inicien diferentes versiones del proceso . y Zygotese inician diferentes versiones del Zygoteproceso ro.zygote, se tienen los siguientes valores 4:

  • init.zygote32.rc: ZygoteEl programa de ejecución correspondiente al proceso es app_process( 32 bitmodo puro);
  • init.zygote32_64.rc: Inicia dos Zygoteprocesos ( zygotey zygote_secondary), y los programas de ejecución correspondientes son app_process32(modo principal), app_process64;
  • init.zygote64.rc: ZygoteEl programa de ejecución correspondiente al proceso es app_process64( 64 bitmodo puro);
  • init.zygote64_32.rc: Inicia dos Zygoteprocesos ( zygotey zygote_secondary), y los programas de ejecución correspondientes son app_process64(modo principal), app_process32;

Estos Zygotescripts de inicio se colocan system/core/rootdiren el directorio de la siguiente manera:

propiedad de ro.cigotos

Tomando 64el procesador de bits como ejemplo, init.zygote64_32.rcel código es el siguiente:

init.zygote64_32

Hay dos declaraciones de tipo en el script , que indican que se iniciarán Servicedos procesos, uno se llama y el programa de ejecución es como modo principal; el otro se llama y el programa de ejecución es como modo secundario. Otros archivos de script son similares a este.Zygotezygoteapp_process64zygote_secondaryapp_process32

Tomemos init.zygote64_32.rc, por ejemplo, su dirección de archivo de inicio es /system/bin/app_process64(figura superior), y app_process64el código correspondiente está en /frameworks/base/cmds/app_processel directorio de .

Primero, eche un vistazo a 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
...

Como se puede ver en el código anterior, ya sea app_prcesso app_prcess32o app_prcess64, el archivo fuente correspondiente es app_main.cpp.

Zygoteproceso de inicio de 3 procesos

initEl proceso se inicia Zygoteprincipalmente llamando a la función app_main.cppen el archivo main, entre los cuales el proceso se inicia AppRuntimellamando al método :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));

ZygoteLos procesos forkcrean subprocesos por sí mismos, por lo que tanto Zygoteel proceso como sus subprocesos pueden ingresar a la función app_main.cppde , por lo tanto, para distinguir qué proceso se está ejecutando actualmente en la función,mainmain1 juzgará si argel parámetro está incluido en el comentario. --zygote, si contiene It, significa que mainla función se está ejecutando en Zygoteel proceso y el comentario 2se zygoteestablece en true. De la misma manera, juzgue si 3el parámetro está incluido en el comentario . Si está incluido, significa que la ejecución de prueba de la función está en proceso y se establece en el comentario .arg--start-system-servermainsystem_server4startSystemServertrue

En el comentario 5, si zygotees true, significa que actualmente se está ejecutando en el proceso, y se llamará zygotea la función en el comentario . Heredado de , y no anuló el método, por lo tanto, el proceso ingresado en , el código es el siguiente:6AppRuntimestartAppRuntimeAndroidRuntimestartZygoteAndroidRutime

// /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");
}

1Llame a la función en el comentario startVmpara crear Javauna máquina virtual y 2llame startRega la función en el comentario para Javaregistrar la máquina virtual JNI. 3El valor de en la anotación classNamees el parámetro pasado y su valor es com.android.internal.os.ZygoteInit. Use la función en el comentario 4para reemplazar con , y asigne el valor reemplazado a , luego busque en el comentario de acuerdo con y llame al método en el comentario después de encontrar . Finalmente, el método será llamado en el comentario . ¿Por qué usar aquí ? Debido a que el método está escrito en el idioma, la lógica de ejecución actual está en , que debe llamarse a través de . De esta forma, se entra en la capa del marco desde la capa .toSlashClassNameclassName./com/android/internal/os/ZygoteInitslashClassName5slashClassNameZygoteInitZygoteInit6ZygoteInit.main7JNIZygoteInit.mainJNIZygoteInit.mainJavaNativeJNIJavaZygoteNativeJava

Después JNIde llamar ZygoteInit.mainal método, Zygoteingresa Javaa la capa del marco. Antes de eso, ningún código ingresó Javaa la capa del marco. En otras palabras, usted Zygotecreó Javala capa del marco. ZygoteInit.mainEl código del método es el siguiente:

// /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();
        }
    }
	...
}

Los comentarios 1precargan clases y recursos. El comentario 2crea un canal al Serverfinal Socketque responde a ActivityManagerServicela solicitud Zygotepara crear un nuevo proceso de solicitud. 3Inicie el proceso en el comentario , de modo que el proceso también inicie system_serverlos servicios del sistema . El método se llama en el system_servercomentario para esperar una solicitud para crear un nuevo proceso.4ZygoteServer.runSelectLoopAMS

De lo anterior, podemos ver que ZygoteInit.mainel método hace principalmente 4dos cosas:

  • precargar clases y recursos ;
  • El Serverlado de la creación Socketse utiliza para responder a ActivityManagerServicela solicitud de crear un nuevo proceso de solicitud;
  • Inicie system_serverel proceso, para que el servicio del sistema también sea system_serveriniciado por ;
  • Esperando ActivityManagerServiceuna solicitud para crear un nuevo proceso de solicitud;

referencia

Serie [Lanzamiento del sistema Android 10]: Zygote (incubadora de procesos)

Supongo que te gusta

Origin blog.csdn.net/xingyu19911016/article/details/127686947
Recomendado
Clasificación