Inicialização do sistema Android (2) - Processo de inicialização do processo Zygote

1. Visão Geral

No Androidsistema DVM( Dalvikmáquina virtual), ARTo processo de serviço do sistema system_server e o processo de aplicativo são todos Zygotecriados pelo processo (e Nativeo programa, ou seja, C/C++o programa desenvolvido pelo processo é initcriado e iniciado pelo processo). ZygoteO processo também é chamado de incubadora. fork(复制进程)O processo de aplicação e system_servero processo são criados na forma de .Desde que o processo será criado ou Zygotequando for iniciado , o processo de aplicação e o processo criado por passagem podem obter uma cópia de instância ou internamente .DVMARTforksystem_serverDVMART

ZygoteUm processo é initcriado quando o processo é iniciado.Inicialmente, Zygoteo nome do processo não é Zygote, mas sim app_process, o nome é /frameworks/base/cmds/app_process/Android.mkdefinido em . ZygoteApós o início do processo, o sistema Linuxsob o sistema pctrlserá chamado app_processe seu nome será alterado para Zygote.

Zygoteé um C/Smodelo. ZygoteComo um servidor, o processo Socketse comunica com outros processos através do método.O "outro processo" aqui se refere principalmente ao processo de serviço do sistema system_server.

No Linuxsistema, forkao chamar uma função para criar um processo filho, a memória do processo pai não será copiada, mas os processos pai e filho compartilham um espaço de memória, e a cópia da memória só será realizada quando o processo filho ou o o processo pai modifica os dados da memória, portanto, o processo pai e o processo filho têm seu próprio espaço de memória. Antes disso, ele será compartilhado apenas como somente leitura.

Copy-on-write ( copy-on-write): O espaço de memória não é realmente alocado até que os dados sejam modificados, que é uma técnica que pode atrasar ou mesmo evitar a cópia de dados. Esta é uma otimização do desempenho do programa e o objetivo é evitar cópias desnecessárias.

ZygoteComo uma incubadora, alguns recursos podem ser carregados antecipadamente, para que forko processo filho gerado possa usar diretamente esses recursos sem recarregar. Por exemplo, system_serverum processo pode usar diretamente funções, bibliotecas compartilhadas, classes comuns e recursos temáticos Zygoteno processo JNI.

ZygoteA inicialização do processo funciona das seguintes coisas:

  • Chame AppRuntime/AndroidRuntime.starto método, crie Javaa máquina virtual e registre JNIo método para ela;
  • Entre na camada JNIde estrutura ZygoteInit.mainda camada chamando o método ;NativeJava
  • iniciar system_serverprocesso;
  • Crie um novo processo de aplicação criando ZygoteServeruma requisição no lado do servidor Sockete ZygoteServer.runSelectLoopesperando por ela através do método ;AMS

O seguinte é Zygoteo diagrama de tempo para inicialização:

Processo de inicialização do zigoto

2 Zygotescript de inicialização

No processo de iniciar o processo init , é mencionado que inito processo irá analisar init.rco arquivo e, em seguida, criar e carregar serviceo processo especificado pelo campo, e o processo é carregado Zygotepelo processo dessa maneira . Use a instrução type no arquivo initpara apresentar o script de inicialização, que é escrito pela linguagem de inicialização ( ):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} 由厂商定义,与平台无关

Pode-se ver que init.rcum arquivo fixo não será importado diretamente, mas ro.zygotearquivos diferentes serão importados de acordo com o conteúdo.

A partir de Android 5.0, começamos a oferecer suporte a 64programas de 1 bit, Zygoteportanto, há uma diferença 32entre 1 bit e 1 64bit, portanto, usamos ro.zygoteo atributo para controlar o uso de diferentes Zygotescripts de inicialização, para que diferentes versões do processo sejam iniciadas , e diferentes versões do processo Zygotesão iniciadas . Existem os seguintes valores :Zygotero.zygote4

  • init.zygote32.rc: ZygoteO programa de execução correspondente ao processo é app_process( 32 bitmodo puro);
  • init.zygote32_64.rc: Inicia dois Zygoteprocessos ( zygotee zygote_secondary), e os programas de execução correspondentes são app_process32(modo principal), app_process64;
  • init.zygote64.rc: ZygoteO programa de execução correspondente ao processo é app_process64( 64 bitmodo puro);
  • init.zygote64_32.rc: Inicia dois Zygoteprocessos ( zygotee zygote_secondary), e os programas de execução correspondentes são app_process64(modo principal), app_process32;

Esses Zygotescripts de inicialização são colocados system/core/rootdirno diretório da seguinte maneira:

propriedade ro.zygotes

Tomando 64o processador de bits como exemplo, init.zygote64_32.rco código é o seguinte:

init.zygote64_32

Existem duas instruções de tipo no script Service, indicando que dois Zygoteprocessos serão iniciados, um é denominado zygote, e o programa de execução é app_process64, como modo principal; o outro é denominado zygote_secondary, e o programa de execução é app_process32, como modo secundário. Outros arquivos de script são semelhantes a este.

Por init.zygote64_32.rcexemplo, o endereço do arquivo de inicialização é /system/bin/app_process64(figura acima) e app_process64o código correspondente está no /frameworks/base/cmds/app_processdiretório de .

Primeiro, dê uma olhada em 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 pode ser visto no código acima, seja app_prcessou app_prcess32ou app_prcess64, o arquivo de origem correspondente é app_main.cpp.

Zygoteprocesso de inicialização de 3 processos

initO processo é iniciado Zygoteprincipalmente chamando a função app_main.cppno arquivo main, entre os quais o processo é iniciado AppRuntimechamando o 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));

ZygoteProcessos forkcriam subprocessos por si mesmos, para que tanto Zygoteo processo quanto seus subprocessos possam entrar na função app_main.cppde , portanto, para distinguir qual processo está atualmente em execução na função,mainmain ele 1julgará argse o parâmetro está incluído no comentário --zygote, se contiver Significa que maina função está rodando no Zygoteprocesso, e o comentário 2está zygotedefinido como true. Da mesma forma, 3julgue argse o parâmetro está incluído no comentário --start-system-server.Se estiver incluído, significa que maina execução de teste da função está em system_serverprocesso e definida como 4no comentário .startSystemServertrue

No comentário 5, se zygoteestiver true, significa que está em execução no zygoteprocesso, e a função no comentário será 6chamada . Herdado de , e não sobrescreveu o método, portanto, o processo inserido em , o código é o seguinte: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");
}

1Chame a função no comentário startVmpara criar Javauma máquina virtual e 2chame startRega função no comentário para Javaregistrar a máquina virtual JNI. 3O valor de na anotação classNameé o parâmetro passado e seu valor é com.android.internal.os.ZygoteInit. Use a função no comentário 4para substituir por , e atribua o valor substituído a , depois localize o comentário de acordo com e chame o método no comentário após localizar . Finalmente, o método será chamado no comentário . Por que usar aqui ? Como o método está escrito na linguagem, a lógica de execução atual está em , que precisa ser chamada por meio de . Desta forma, a camada do quadro é inserida a partir da camada .toSlashClassNameclassName./com/android/internal/os/ZygoteInitslashClassName5slashClassNameZygoteInitZygoteInit6ZygoteInit.main7JNIZygoteInit.mainJNIZygoteInit.mainJavaNativeJNIJavaZygoteNativeJava

Depois de JNIchamar ZygoteInit.maino método, Zygotevocê entra Javana camada de framework. Antes disso, nenhum código entrava Javana camada de framework. Ou seja, você Zygotecriou Javaa camada de framework. ZygoteInit.mainO código do método é o seguinte:

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

Comentários 1pré-carregam classes e recursos. O comentário 2cria um canal no Serverfinal Socketque responde ao ActivityManagerServicepedido Zygotede criação de um novo processo de candidatura. 3Inicie o processo no comentário system_server, para que os serviços do sistema também system_serversejam iniciados pelo processo. 4O método é chamado no comentário ZygoteServer.runSelectLooppara aguardar AMSuma solicitação para criar um novo processo.

Pelo exposto, podemos ver que ZygoteInit.maino método faz principalmente 4duas coisas:

  • pré-carregar classes e recursos ;
  • O Serverlado da criação Socketé utilizado para responder ao ActivityManagerServicepedido de criação de um novo processo de candidatura;
  • Inicie system_servero processo, para que o serviço do sistema também seja system_serveriniciado por ;
  • Aguardar ActivityManagerServicepedido de criação de novo processo de candidatura;

referência

Série [Lançamento do sistema Android 10] – Zygote (incubadora de processos)

Acho que você gosta

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