1. Visão Geral
No Android
sistema DVM
( Dalvik
máquina virtual), ART
o processo de serviço do sistema system_server
e o processo de aplicativo são todos Zygote
criados pelo processo (e Native
o programa, ou seja, C/C++
o programa desenvolvido pelo processo é init
criado e iniciado pelo processo). Zygote
O processo também é chamado de incubadora. fork(复制进程)
O processo de aplicação e system_server
o processo são criados na forma de .Desde que o processo será criado ou Zygote
quando for iniciado , o processo de aplicação e o processo criado por passagem podem obter uma cópia de instância ou internamente .DVM
ART
fork
system_server
DVM
ART
Zygote
Um processo é init
criado quando o processo é iniciado.Inicialmente, Zygote
o nome do processo não é Zygote
, mas sim app_process
, o nome é /frameworks/base/cmds/app_process/Android.mk
definido em . Zygote
Após o início do processo, o sistema Linux
sob o sistema pctrl
será chamado app_process
e seu nome será alterado para Zygote
.
Zygote
é um C/S
modelo. Zygote
Como um servidor, o processo Socket
se 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 Linux
sistema, fork
ao 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.
Zygote
Como uma incubadora, alguns recursos podem ser carregados antecipadamente, para que fork
o processo filho gerado possa usar diretamente esses recursos sem recarregar. Por exemplo, system_server
um processo pode usar diretamente funções, bibliotecas compartilhadas, classes comuns e recursos temáticos Zygote
no processo JNI
.
Zygote
A inicialização do processo funciona das seguintes coisas:
- Chame
AppRuntime/AndroidRuntime.start
o método, crieJava
a máquina virtual e registreJNI
o método para ela; - Entre na camada
JNI
de estruturaZygoteInit.main
da camada chamando o método ;Native
Java
- iniciar
system_server
processo; - Crie um novo processo de aplicação criando
ZygoteServer
uma requisição no lado do servidorSocket
eZygoteServer.runSelectLoop
esperando por ela através do método ;AMS
O seguinte é Zygote
o diagrama de tempo para inicialização:
2 Zygote
script de inicialização
No processo de iniciar o processo init , é mencionado que init
o processo irá analisar init.rc
o arquivo e, em seguida, criar e carregar service
o processo especificado pelo campo, e o processo é carregado Zygote
pelo processo dessa maneira . Use a instrução type no arquivo init
para apresentar o script de inicialização, que é escrito pela linguagem de inicialização ( ):init.rc
Import
Zygote
Android
Android 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.rc
um arquivo fixo não será importado diretamente, mas ro.zygote
arquivos diferentes serão importados de acordo com o conteúdo.
A partir de Android 5.0
, começamos a oferecer suporte a 64
programas de 1 bit, Zygote
portanto, há uma diferença 32
entre 1 bit e 1 64
bit, portanto, usamos ro.zygote
o atributo para controlar o uso de diferentes Zygote
scripts de inicialização, para que diferentes versões do processo sejam iniciadas , e diferentes versões do processo Zygote
são iniciadas . Existem os seguintes valores :Zygote
ro.zygote
4
init.zygote32.rc
:Zygote
O programa de execução correspondente ao processo éapp_process
(32 bit
modo puro);init.zygote32_64.rc
: Inicia doisZygote
processos (zygote
ezygote_secondary
), e os programas de execução correspondentes sãoapp_process32
(modo principal),app_process64
;init.zygote64.rc
:Zygote
O programa de execução correspondente ao processo éapp_process64
(64 bit
modo puro);init.zygote64_32.rc
: Inicia doisZygote
processos (zygote
ezygote_secondary
), e os programas de execução correspondentes sãoapp_process64
(modo principal),app_process32
;
Esses Zygote
scripts de inicialização são colocados system/core/rootdir
no diretório da seguinte maneira:
Tomando 64
o processador de bits como exemplo, init.zygote64_32.rc
o código é o seguinte:
Existem duas instruções de tipo no script Service
, indicando que dois Zygote
processos 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.rc
exemplo, o endereço do arquivo de inicialização é /system/bin/app_process64
(figura acima) e app_process64
o código correspondente está no /frameworks/base/cmds/app_process
diretó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_prcess
ou app_prcess32
ou app_prcess64
, o arquivo de origem correspondente é app_main.cpp
.
Zygote
processo de inicialização de 3 processos
init
O processo é iniciado Zygote
principalmente chamando a função app_main.cpp
no arquivo main
, entre os quais o processo é iniciado AppRuntime
chamando o método :start
Zygote
// /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));
Zygote
Processos fork
criam subprocessos por si mesmos, para que tanto Zygote
o processo quanto seus subprocessos possam entrar na função app_main.cpp
de , portanto, para distinguir qual processo está atualmente em execução na função,main
main
ele 1
julgará arg
se o parâmetro está incluído no comentário --zygote
, se contiver Significa que main
a função está rodando no Zygote
processo, e o comentário 2
está zygote
definido como true
. Da mesma forma, 3
julgue arg
se o parâmetro está incluído no comentário --start-system-server
.Se estiver incluído, significa que main
a execução de teste da função está em system_server
processo e definida como 4
no comentário .startSystemServer
true
No comentário 5
, se zygote
estiver true
, significa que está em execução no zygote
processo, e a função no comentário será 6
chamada . Herdado de , e não sobrescreveu o método, portanto, o processo inserido em , o código é o seguinte:AppRuntime
start
AppRuntime
AndroidRuntime
start
Zygote
AndroidRutime
// /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");
}
1
Chame a função no comentário startVm
para criar Java
uma máquina virtual e 2
chame startReg
a função no comentário para Java
registrar a máquina virtual JNI
. 3
O 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 4
para 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 .toSlashClassName
className
.
/
com/android/internal/os/ZygoteInit
slashClassName
5
slashClassName
ZygoteInit
ZygoteInit
6
ZygoteInit.main
7
JNI
ZygoteInit.main
JNI
ZygoteInit.main
Java
Native
JNI
Java
Zygote
Native
Java
Depois de JNI
chamar ZygoteInit.main
o método, Zygote
você entra Java
na camada de framework. Antes disso, nenhum código entrava Java
na camada de framework. Ou seja, você Zygote
criou Java
a camada de framework. ZygoteInit.main
O 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 1
pré-carregam classes e recursos. O comentário 2
cria um canal no Server
final Socket
que responde ao ActivityManagerService
pedido Zygote
de criação de um novo processo de candidatura. 3
Inicie o processo no comentário system_server
, para que os serviços do sistema também system_server
sejam iniciados pelo processo. 4
O método é chamado no comentário ZygoteServer.runSelectLoop
para aguardar AMS
uma solicitação para criar um novo processo.
Pelo exposto, podemos ver que ZygoteInit.main
o método faz principalmente 4
duas coisas:
- pré-carregar classes e recursos ;
- O
Server
lado da criaçãoSocket
é utilizado para responder aoActivityManagerService
pedido de criação de um novo processo de candidatura; - Inicie
system_server
o processo, para que o serviço do sistema também sejasystem_server
iniciado por ; - Aguardar
ActivityManagerService
pedido de criação de novo processo de candidatura;
referência
Série [Lançamento do sistema Android 10] – Zygote (incubadora de processos)