Análisis del código fuente del proceso Android P Zygote

El proceso init es el primer proceso en el espacio de usuario y el proceso zygote es el primer proceso java. El proceso zygote es un proceso secundario del proceso init, y el proceso init ejecuta el proceso zygote analizando el archivo rc.

Zygote es un proceso muy importante en el sistema Android, y su función principal es ejecutar aplicaciones Android. La ejecución de una nueva aplicación en el sistema Android, como la fertilización y división de un óvulo, debe combinarse con el proceso Zygote (que tiene varios elementos y condiciones necesarios para que la aplicación se ejecute, como: una máquina virtual, etc. ) ejecutar.

Proceso Zygote
Cuando el proceso zygote se está ejecutando, inicializará la máquina virtual Art (o Dalvik) y la iniciará. Las aplicaciones de Android están escritas en Java, no pueden ejecutarse directamente en Linux en forma de procesos locales, sino que solo pueden ejecutarse en máquinas virtuales. Además, cada programa de aplicación se ejecuta en su propia máquina virtual. Si el programa de aplicación necesita reiniciarse e iniciar la máquina virtual cada vez que se ejecuta, este proceso llevará bastante tiempo. Por lo tanto, en Android, antes de que se ejecute el programa de aplicación, el proceso de cigoto acorta el tiempo que tarda en ejecutarse el programa de aplicación al compartir el código y la información de memoria de la máquina virtual en ejecución. Además, cargará las clases y los recursos en el marco de trabajo de Android que utilizará la aplicación en la memoria con anticipación, y organizará y formará la información de enlace de los recursos utilizados. Cuando una aplicación de Android recién ejecutada utiliza los recursos necesarios, no es necesario volver a generar la información de enlace de los recursos cada vez, lo que ahorra mucho tiempo y mejora la velocidad de ejecución del programa.

Entonces, ¿cuál es la diferencia entre crear y ejecutar un proceso en el sistema Linux y crear y ejecutar una aplicación a través de zygote en el sistema Android?

Las siguientes imágenes están todas referenciadas del libro "Descubriendo el marco de trabajo de Android" (realmente no quiero dibujar 0.0 yo mismo)


Como se muestra en la figura anterior, el proceso padre A llama a la función fork() para crear un nuevo proceso hijo A'. El proceso A' recién creado comparte la información de la estructura de la memoria y la información de conexión de la biblioteca del proceso principal (tecnología de copia en escritura COW). Luego, el proceso hijo A' llama a exec('B') para cargar el código del nuevo proceso B en la memoria. En este punto, la memoria se reasignará (porque se compartió antes) para ejecutar el programa B cargado, y luego se formará nueva información de conexión de biblioteca para que el proceso B la use solo.


Como se muestra en la figura anterior, el proceso zygote llama a la función fork() para crear un proceso secundario zygote, y el proceso secundario zygote comparte el área de código y la información de enlace del proceso padre zygote. Tenga en cuenta que la nueva aplicación de Android A no recarga el área de código del proceso existente a través de exec(), sino que lo carga dinámicamente en la máquina virtual copiada (la copia del espacio virtual, el espacio físico sigue siendo el mismo). Luego, el proceso del cigoto entregará el proceso de ejecución al método de la clase de aplicación A, y la aplicación de Android comenzará a ejecutarse. La aplicación A recién generada utilizará la información de enlace de la biblioteca y los recursos del proceso de cigoto existente, por lo que se ejecuta muy rápido.


Como se muestra en la figura anterior, después de que se inicia zygote, se inicializa y ejecuta la máquina virtual art (o dalvik), y luego carga las clases y los recursos necesarios en la memoria. Luego llame a fork () para crear un proceso secundario de zygote, y luego el proceso secundario de zygote carga y ejecuta dinámicamente la aplicación Android A. La aplicación en ejecución A utilizará el código de la máquina virtual que zygote ha inicializado y comenzado a ejecutar, y acelerará la operación mediante el uso de las clases y los recursos que se han registrado en la memoria.

COW (Copy on write)
Después de crear un nuevo proceso, el nuevo proceso compartirá el espacio de memoria del proceso padre, es decir, el nuevo proceso hijo copiará toda la información relacionada con el espacio de memoria del proceso padre y la usará. COW es una tecnología para la replicación de memoria. En términos generales, la sobrecarga de copiar la memoria es muy alta, por lo que cuando el proceso secundario creado hace referencia al espacio de memoria del proceso principal, no lo copie, sino que comparta directamente el espacio de memoria del proceso principal. Cuando la información en la memoria compartida necesita ser modificada, el proceso hijo copiará la información de memoria relevante en el proceso padre a su propio espacio de memoria y la modificará.Esta es la tecnología COW (Copy on write).

Después de fork y antes de exec, los dos procesos usan el mismo espacio físico (área de memoria).El segmento de código, el segmento de datos y la pila del proceso hijo apuntan todos al espacio físico del proceso padre, es decir, el virtual. el espacio de los dos es diferente, pero el espacio físico correspondiente es el mismo.

Análisis del código fuente del proceso Zygote
Ejecutado por app_process ZygoteInit La clase
zygote está escrita en java y no puede ser iniciada ni ejecutada directamente por el proceso init. Si desea ejecutar la clase zygote, primero debe crear una máquina virtual y luego ejecutar la clase ZygoteInit en la máquina virtual. Lo que realiza esta tarea es el programa app_process.
Analicemos el proceso de inicio del proceso zygote:
/system/core/rootdir/init.rc

import /init.$(ro.zygote).rc

Si es un sistema de 64 bits, el valor de $(ro.zygote) es "zygote64"
/system/core/rootdir/init.zygote64.rc

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    ...
    class main
    user root
    socket zygote stream 660 root system //Crear /dev/socket/zygote socket
    . ..

Después de que el proceso init analice el archivo init.zygote64.rc anterior, ejecutará el proceso /system/bin/app_process64 y generará un socket /dev/socket/zygote, que ZygoteInit usará para recibir la solicitud AMS A para crear un nuevo solicitud.
El proceso init analiza y ejecuta el proceso del archivo rc, puedes ver mi artículo anterior El proceso de inicio del proceso Init.

La entrada de la función principal del programa app_process64 es la siguiente:

frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{     ......     AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));     ......     // Analizar argumentos de tiempo de ejecución. Deténgase en la primera opción no reconocida.     bool cigoto = falso;     bool startSystemServer = falso;     ......






    while (i < argc) {         const char* arg = argv[i++];         if (strcmp(arg, "--cigoto") == 0) {             cigoto = verdadero;         } else if (strcmp(arg, "--start-system-server") == 0) {             startSystemServer = true;         }          ......     }







    ......
    if (zygote) {         //zygote process         runtime.start("com.android.internal.os.ZygoteInit", args, zygote);     } else if (className) {         //ordinary java process         runtime. start("com.android.internal.os.RuntimeInit", args, zygote);     } } Si es un proceso zygote, ejecute el código ZygoteInit, si es un proceso java normal, ejecute el código RuntimeInit, como el comúnmente Usé el comando am, /system/bin /am es en realidad un script de shell Al observar el código interno, se puede ver que el proceso ordinario de Java se inicia a través de app_process y luego se comunica con AMS. frameworks/base/core/jni/AndroidRuntime.cpp









//AppRuntime hereda de AndroidRuntime
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{     /* inicia la máquina virtual */     JniInvocación jni_invocación;     // ① Carga la biblioteca de la virtual especificada machine (art o dalvik)     jni_invocation.Init(NULL);      JNIEnv* env;     // ② Crear una máquina virtual java     if (startVm(&mJavaVM, &env, zygote) != 0) {         return;     }








    // ③ Registrar la función JNI
    si (startReg(env) < 0) {         return;     }

    ......
    // ④ Ingrese oficialmente al mundo de Java, llame al método principal de ZygoteInit.java
    jclass startClass = env->FindClass(slashClassName);
    ......
    jmethodID startMeth = env->GetStaticMethodID(startClass, " main","([Ljava/lang/String;)V");
    ......
    env->CallStaticVoidMethod(startClass, startMeth, strArray);
    ......
}

①: Cargar la biblioteca del máquina virtual (art o dalvik), y el puntero de función apunta a la función correspondiente a la biblioteca (p. ej.: función JNI_CreateJavaVM)
libnativehelper/JniInvocation.cpp

bool JniInvocation::Init(const char* library) {   //Obtener el nombre de la biblioteca a cargar   library = GetLibrary(library, buffer);

  //Cargar dinámicamente la biblioteca de la máquina virtual correspondiente
  handle_ = dlopen(library, RTLD_NOW);
  ......
  //El puntero de la función JNI_CreateJavaVM_ apunta a la función JNI_CreateJavaVM en la biblioteca de la máquina virtual
  if (!FindSymbol(reinterpret_cast<void**> ( &JNI_CreateJavaVM_),
                  "JNI_CreateJavaVM")) {     return false;   }   .......   return true; } La función GetLibraray() obtiene el nombre de la biblioteca dinámica (libart.so o libdalvik .so), y el dlopen () carga dinámicamente la biblioteca de máquinas virtuales, RTLD_NOW significa vincular todos los símbolos no ubicados inmediatamente antes de regresar, y el puntero de la función FindSysmbol() apunta a la función correspondiente. libnativehelper/JniInvocación.cpp







static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib.2";
static const char* kDebuggableSystemProperty = "ro.debuggable";
static const char* kDebuggableFallback = "0"; // No depurable.
static const char* kLibraryFallback = "libart.so";

const char* JniInvocación::GetLibrary(const char* biblioteca, char* buffer) {     char depurable[PROPERTY_VALUE_MAX];     //获取"ro.debuggable"的属性值     property_get(kDebuggableSystemProperty, debuggable,kDebuggableFallback);


    if (strcmp(debuggable, "1") != 0) {         //Si no es un dispositivo de depuración, el valor de la biblioteca es "libart.so"         library = kLibraryFallback;     } else {         //Si es un dispositivo de depuración , el valor de la biblioteca es " Persisit.sys.dalvik.vm.lib.2" valor de la propiedad         property_get(kLibrarySystemProperty, buffer, kLibraryFallback);     }





    biblioteca de retorno;
}
: Crear marcos de máquina virtual java
/base/core/jni/AndroidRuntime.cpp

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{     JavaVMInitArgs initArgs;     ......     initArgs.version = JNI_VERSION_1_4;     initArgs.opciones = mOptions.editArray();     initArgs.nOpciones = mOpciones.tamaño();     initArgs.ignoreUnrecognized = JNI_FALSO;





    ......
    // Crear una máquina virtual Java
    si (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {         ALOGE("JNI_CreateJavaVM falló\n");         return -1;     }


    return 0;
}

JNI_CreateJavaVM() es una función en JniInvocation.cpp, llamará al puntero de función JNI_CreateJavaVM_() mencionado en ①, y finalmente llamará a la función JNI_CreateJavaVM() en la biblioteca dinámica de la máquina virtual correspondiente para crear la máquina virtual correspondiente. initArgs representa los parámetros de la máquina virtual entrante.
③: Registre las funciones locales de JNI
Primero, familiaricémonos con varias estructuras de datos:
frameworks/base/core/jni/AndroidRuntime.cpp

#define REG_JNI(nombre) {nombre}

struct RegJNIRec {     int (*mProc)(JNIEnv*); }; ...... static const RegJNIRec gRegJNI[] = {     REG_JNI(register_com_android_internal_os_RuntimeInit),     REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),     REG_ JNI(register_android_os_SystemC bloqueo),     REG_JNI (registrar_android_util_EventLog),     REG_JNI (register_android_util_Log),     ...... }; gRegJNI es una matriz de estructuras RegJNIRec, y luego la matriz se inicializa a través de la definición de macro REG_JNI. Por ejemplo, la inicialización del primer elemento de gRegJNI es equivalente a:












gRegJNI[0] = {register_com_android_internal_os_RuntimeInit};

luego, el puntero de la función mProc de la estructura RegJNIRec en gRegJNI[0] apunta a la función anterior register_com_android_internal_os_RuntimeInit, y lo mismo ocurre con otros elementos de la matriz. Sigamos analizando el registro de las funciones locales de JNI.
frameworks/base/core/jni/AndroidRuntime.cpp

int AndroidRuntime::startReg(JNIEnv* env)
{     ......     //Registre la función local de JNI, pase la matriz gRegJNI a     if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {         return -1;     }     ......     devuelve 0; }







static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{     //Recorra y ejecute la función mProc de los elementos en la matriz gRegJNI     //(mProc es un puntero de función, y la matriz ya apuntó al función especificada cuando se inicializa el arreglo)     for (size_t i = 0; i < count; i++) {         if (array[i].mProc(env) < 0) {             return -1;         }     }     return 0; } startReg llamará register_jni_procs para atravesar y llamar a la función mProc en la matriz gRegJNI para tomar el primer elemento como ejemplo, gRegJNI[0].mProc(env) Del análisis anterior, se puede saber que la función llamada register_com_android_internal_os_RuntimeInit(env) en realidad se llama . frameworks/base/core/jni/AndroidRuntime.cpp











    int     };         ......             (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },         { "nativeFinishInit", "()V",     const JNINativeMethod métodos[] = {
{ register_com_android_internal_os_RuntimeInit(JNIEnv* env)     jniRegisterNativeMethods (env, "com/android/internal/os/RuntimeInit",         métodos, NELEM(métodos)); }










Como se puede ver en el código anterior, la función nativeFinishInit asigna la función com_android_internal_os_RuntimeInit_nativeFinishInit Cuando Java llama a la función nativeFinishInit, en realidad llama a la función com_android_internal_os_RuntimeInit_nativeFinishInit en c/c++. Algunos lectores pueden preguntar, cuando java llama a la función jni, la máquina virtual se mapea automáticamente, ¿por qué necesita mapearla usted mismo? Si hay menos funciones jni, esto es factible, pero podemos ver que la matriz gRegJNI es muy grande y hay muchas funciones que deben mapearse.Si todas ellas se asignan a la máquina virtual para el mapeo, la ejecución el rendimiento de la máquina virtual se reducirá considerablemente, por lo que avanzamos Registrar la función JNI, y la máquina virtual puede encontrar directamente la función correspondiente para llamar.
④: Llame a la función principal de ZygoteInit.java a través de la reflexión e ingrese oficialmente al mundo de Java. env->FindClass obtiene el tipo de clase ZygoteInit, env->GetStaticMethodID obtiene el id de función de la función principal, env->CallStaticVoidMethod llama a la función estática principal de ZygoteInit.java.

Funciones de la clase ZygoteInit
Hasta ahora, hemos creado una máquina virtual y cargado la clase ZygoteInit en la máquina virtual. A continuación, se ejecutará la clase ZygoteInit, ¿cuáles son las funciones específicas de la clase ZygoteInit? Se puede resumir aproximadamente de la siguiente manera:

Vincule el socket para recibir la solicitud de ejecución de la nueva aplicación de Android.
Precargue las clases y los recursos utilizados por Android Application Framework.
Inicie y ejecute SystemServer
para procesar la solicitud de ejecución de la nueva aplicación de Android.
La función principal de ZygoteInit:
frameworks/ base/core/java/com /android/internal/os/ZygoteInit.java

public static void main(String argv[]) {     ZygoteServer zygoteServer = new ZygoteServer();     ......     probar{         boolean startSystemServer = false;         String socketName = "zygote";//套接字默认名称zygote         for (int i = 1; i < argv.length; i++) {             if ("start-system-server".equals(argv[i])) {                 startSystemServer = verdadero;            }             ......         }










        // ① Vincular /dev/socket/zócalo zygote para recibir la solicitud de ejecución de la aplicación Android
        zygoteServer.registerServerSocketFromEnv(socketName);
        ......
          
        if (!enableLazyPreload) {             ......             // ② Precargar clases y recursos             precargar (bootTimingsTraceLog);             ......         }




        ......
        if (startSystemServer) {             // ③ fork出system_server子进程            Ejecutable r = forkSystemServer(abiList, socketName, zygoteServer);

            // ③ {@code r == null} significa el proceso padre (cigoto), {@code r != null} en el proceso hijo (system_server)
            if (r != null) {                 // ③ Si es un hijo process (system_server) ejecuta el método run() y regresa, y el proceso padre (cigoto) continúa ejecutando                 r.run();                 return;             }         }




        Log.i(TAG, "Aceptando conexiones de socket de comando");

        // ④ Este sondeo se repetirá infinitamente en el proceso de cigoto, y el proceso secundario bifurcado (proceso de aplicación de Android) saldrá de la persona que
        llama = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {         Log.e(TAG, "System zygote murió con excepción", ex);         throw ex;     } finalmente {         //el proceso system_server y el proceso de aplicación de Android cerrarán el zócalo, zygote todavía está sondeando y escuchando el zócalo en runSelectLoop         zygoteServer.closeServerSocket();     }






    

    // ④ El proceso de la aplicación de Android vendrá aquí y ejecutará el comando correspondiente
    if (caller != null) {         caller.run();     } } ①: vincular el socket para recibir la solicitud de ejecución de los frameworks/base/core de la aplicación de Android /java/com/android/internal/os/ZygoteServer.java





void registerServerSocketFromEnv(String socketName) {     if (mServerSocket == null) {         int fileDesc;         //fullSocketName es "ANDROID_SOCKET_zygote"         final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;         intente {             //Obtenga las variables de entorno de ANDROID_SOCKET_zygote (es decir, /dev/socket /The valor del descriptor de archivo de zygote)             // es la cadena guardada en la variable de entorno por el proceso init al iniciar el proceso de zygote             env = System.getenv(fullSocketName);             fileDesc = Integer.parseInt(env);         } catch (RuntimeException ex ) {             lanzar una nueva RuntimeException(fullSocketName + "no establecido o inválido", por ejemplo);         }         probar {












        

            //Socket de enlace, utilizado más tarde para recibir la solicitud de inicio de la aplicación de Android
            FileDescriptor fd = new FileDescriptor();
            fd.setInt$(fileDesc);
            mServerSocket = new LocalServerSocket(fd);
            mCloseSocketFd = true;
        } catch (IOException ex) {             .. ....         }     } } ②: Clases y recursos de precarga, y el proceso de solicitud bifurcado del proceso de cigoto se puede compartir directamente para acelerar el inicio del proceso de solicitud. frameworks/base/core/java/com/android/internal/os/ZygoteInit.java






precarga de vacío estático (TimingsTraceLog bootTimingsTraceLog) {     ......     preloadClasses();     ......     preloadResources();     ......     nativePreloadAppProcessHALs();     ......     preloadOpenGL();     preloadSharedLibraries( );     preloadTextResources();     ......     } preloadClasses, preloadResources, nativePreloadAppProcessHALs precarga clases y recursos, etc. Los estudiantes interesados ​​pueden obtener más información al respecto. ③: forkSystemServer bifurca el proceso secundario system_server y devuelve Runnable r que puede llamar al método principal en SystemServer y ejecuta el método de ejecución correspondiente, mientras que el proceso principal zygote continúa ejecutando runSelectLoop y escucha las solicitudes de ejecución de aplicaciones de Android. frameworks/base/core/java/com/android/internal/os/ZygoteInit.java















private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {     ......     /* Línea de comando codificada para iniciar el servidor del sistema */     String args[] = {         "--setuid=1000", //usuario id         "--setgid=1000", //id de grupo         ......         "--nice-name=system_server",         ......         "com.android.server.SystemServer",     };     ZygoteConnection.Arguments parsedArgs = null;     int pid;     try {         parsedArgs = new ZygoteConnection.Arguments(args);         ......         //bifurque el proceso secundario system_server y configure el parámetro correspondiente         pid = Zygote.forkSystemServer(










    







                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.runtimeFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectCapabilities);
    } catch (IllegalArgumentException ex) {         throw new RuntimeException(ex );     }     //proceso secundario (system_server)     if (pid == 0) {         ......         //Entonces la r devuelta no es nula, ejecute directamente r.ejecutar         return handleSystemServerProcess(parsedArgs);     }     //Proceso principal (cigoto), la devolución es nula, continuar con Siguiente ejecutar     retorno nulo; }












El método forkSystemServer de ZygoteInit llamará al método forkSystemServer de Zygote.Si es un proceso hijo (system_server), devolverá handleSystemServerProcess(), y el proceso padre (zygote) devolverá nulo.
frameworks/base/core/java/com/android/internal/os/Zygote.java

public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long allowCapabilities, long operatingCapabilities) { ...... int pid = nativeForkSystemServer(uid, gid,     gids     , runtimeFlags,                  rlimits, allowdCapabilities, effectiveCapabilities);     ......     return pid;     } Llame a nativeForkSystemServer para separarse del proceso secundario, nativeForkSystemServer es un método local y el método nativeForkSystemServer se ha asignado a com_android_inter a través de register_com_android_internal_os_Zygote en el método startReg En el método nal_os_Zygote_nativeForkSystemServer, los estudiantes interesados ​​pueden obtener más información al respecto. Después de salir del proceso secundario, el proceso secundario comienza a llamar al método handleSystemServerProcess() frameworks/base/core/java/com/android/internal/os/ZygoteInit.java









Private Static Runnable handlesystemServerProcess (zygoteConnection.arguments PARSEDARGS) {     ......     // De la variable ambiental SystemServerClassPath para obtener la ruta Fraf File Frade F. Inal     String SystemServerClassPath = OS.Getenv ("SystemServerClassPath");     if (SystemServerClassPath! = null) {         //Hacer optimización dex para el paquete jar correspondiente         performSystemServerDexOpt(systemServerClasspath);         …     }







    ......
    ClassLoader cl = null;
    if (systemServerClasspath!= null) {         //Crear un cargador de clases classloader         cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);

        Thread.currentThread().setContextClassLoader(cl);
    }

    return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}

Primero obtenga el classpath de SystemServer del entorno SYSTEMSERVERCLASSPATH y luego use performSystemServerDexOpt para realizar la optimización dex en el paquete jar correspondiente al classpath. Luego cree el cargador de clases correspondiente, que posteriormente se usa para cargar la clase SystemServer, y ZygoteInit.zygoteInit() continúa ejecutándose:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {     ......     //Redirige el flujo de salida estándar y el flujo de error estándar al registro de Android     RuntimeInit.redirectLogStreams();


    ......
    //Método nativo, mapeo de startReg, principalmente para abrir el grupo de subprocesos ProcessState para la comunicación del enlazador
    ZygoteInit.nativeZygoteInit();
    
    devuelve RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}

redirectLogStreams será una entrada estándar, el error stream se reubica en el registro de Android y la función nativeZygoteInit JNI (mapeo startReg) abrirá el grupo de subprocesos ProcessState para la comunicación del enlazador.
Continúe ejecutando RuntimeInit.applicationInit():
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,ClassLoader classLoader) {     ......     // Los argumentos restantes se pasan al     retorno principal estático de la clase de inicio findStaticMain(args.startClass, args.startArgs, classLoader); }继续往下执行:





También vale la pena leer el comentario en inglés sin traducción.

/**
 * Invoca un método estático "main(argv[]) en la clase "className".
 * Convierte varias excepciones fallidas en RuntimeExceptions, con
 * la suposición de que luego harán que la instancia de VM se cierre.
 *
 * @param className Completamente -nombre de clase calificado
 * @param argv Vector de argumento para main()
 * @param classLoader el cargador de clases para cargar {@className} con
 */
protected static Runnable findStaticMain(String className, String[] argv,ClassLoader classLoader) {     Class<?> cl;     ......     //获取到SystemServer的类类型     cl = Class.forName(className, true, classLoader);     ......     Method m;     try {







        //Obtenga la identificación del método del método principal
        m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) {         ......     } catch (SecurityException ex ) {         ......     }     //Este es el valor de retorno de forkSystemServer en ③ r     return new MethodAndArgsCaller(m, argv); } findStaicMain obtiene el tipo de clase de SystemServer y la identificación del método principal en SystemServer. Entonces new MethodAndArgsCaller(m, argv) es el valor de retorno r de forkSystemServer en ③, veamos qué hace r.run. frameworks/base/core/java/com/android/internal/os/RuntimeInit.java









clase estática MethodAndArgsCaller implementa Runnable {     /** método para llamar */     método privado final mMethod;     /** matriz de argumentos */     private final String[] mArgs;



    public MethodAndArgsCaller(Method method, String[] args) {         mMethod = method;         mArgs = argumentos;     }


    public void run() {         try {             //Invoke mMethod static method             mMethod.invoke(null, new Object[] { mArgs });         } catch (IllegalAccessException ex) {            ......         } catch (InvocationTargetException ex) {             . .....         }     } } De lo anterior se puede ver que el método principal de la clase SystemServer se ejecuta a través de la reflexión. Como todos sabemos, el proceso system_server registra y ejecuta los servicios centrales del sistema como AMS, PMS y PKMS, porque este no es el enfoque de este artículo, por lo que los estudiantes interesados ​​pueden seguir aprendiendo más al respecto~ ④: zygoteServer.runSelectLoop( ) Esta encuesta estará en Hay un ciclo infinito en el proceso de cigoto, y el proceso secundario (proceso de aplicación de Android) de la bifurcación saldrá y continuará ejecutando frameworks/base/core/java/com/android/internal/os /ZygoteServer.java













//Habilitar el sondeo y la supervisión del proceso de cigoto. Reciba nuevas conexiones de socket (se creará una nueva ZygoteConnection)
// y lea los comandos de estos enlaces, y ejecute
Runnable runSelectLoop(String abiList) {     ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();     ArrayList<ZygoteConnection > peers = new ArrayList<ZygoteConnection>();

    fds.add(mServerSocket.getFileDescriptor());
    pares.add(null);

    while (verdadero) {         StructPollfd[] pollFds = new StructPollfd[fds.size()];         for (int i = 0; i < pollFds.length; ++i) {             pollFds[i] = new StructPollfd();             encuestaFds[i].fd = fds.get(i);             pollFds[i].events = (corto) POLLIN;         }         try {             //开启轮询             Os.poll(pollFds, -1);         } catch (ErrnoException ex) {             throw new RuntimeException("encuesta fallida", ex);         }         for (int i = pollFds.length - 1; i >= 0; --i) {             if ((pollFds[i].revents & POLLIN) == 0) {                 continuar;             }
















            
            if (i == 0) {//Si se trata de una nueva solicitud de conexión de socket (establecer una nueva conexión)
            //Nuevo enlace ZygoteConnection
            ZygoteConnection newPeer = acceptCommandPeer(abiList);
            //Añadir a la matriz de enlaces
            peers.add(newPeer) ;
            //Añadir a la matriz de descriptores de archivos
            fds.add(newPeer.getFileDesciptor());
            } else {//Si se trata de un enlace de socket previamente establecido (en una conexión existente)
                intente {                     //Obtenga la                     conexión ZygoteConnection ZygoteConnection correspondiente = peers.get(i);                     //ejecutará el comando enviado por ZygoteConnection                     final Runnable command = connection.processOneCommand(this);



                    if (mIsForkChild) {//El proceso secundario va aquí
                        ...
                        //Salir, el comando es el autor de la llamada en ④
                        comando de retorno; 
                    } else {//El proceso principal va aquí, lo anterior es un bucle infinito while, el cigoto el proceso nunca saldrá
                        ...
                        if (connection.isClosedByPeer()) {                             connection.closeSocket();                             peers.remove(i);                             fds.remove(i);                         }                     }                 } catch (Exception e) {                     .... ..                 } finalmente {








                    mIsForkChild = false;
                }
            }     } }
        En resumen, el proceso anterior sondeará el socket de /dev/socket/zygote, si hay un nuevo enlace, creará una nueva ZygoteConnection y agregará el socket correspondiente fd a fds (matriz de consulta redonda



El nombre del método de processOneCommand antes de que Android P fuera runOnce

frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

Proceso ejecutableOneCommand(ZygoteServer zygoteServer) {     String args[];     Argumentos parsedArgs = null;     FileDescriptor[] descriptores;     try {     //读取命令         args = readArgumentList();         descriptores = mSocket.getAncillaryFileDescriptors();     } catch (IOException ex) {         ......     }     ......     parsedArgs = new Arguments(args);     ......     //fork子进程     pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,                 parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,



    







    



    



                parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
                parsedArgs.instructionSet, parsedArgs.appDataDir);

    try {         if (pid == 0) {             // En el proceso secundario (en el proceso de aplicación)             zygoteServer.setForkChild();             ......             return handleChildProc(parsedArgs, descriptors, childPipeFd,                     parsedArgs.startChildZygote);         } else {             / /en el proceso principal (cigoto)             ...             devuelve nulo;         }     } finalmente {         ...     } } Lee el comando de inicio desde el socket actualmente conectado. Si la lectura es exitosa, zygote desembolsará el proceso secundario y devolverá un ejecutable que puede llamar al método principal de la clase de inicio (es decir, la persona que llama en ④)
















Si AMS solicita iniciar el proceso de la aplicación, la clase de inicio es ActivityThread.java, y caller.run() llamará reflexivamente al método principal de ActivityThread.

zygoteServer.setForkChild() establece la variable global mIsForkChild en verdadero.
A continuación analizamos el método handleChildProc()
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,FileDescriptor pipeFd, boolean isZygote) {     //Cerrar el enlace del socket en ZygoteConnection     closeSocket();     ......     if (parsedArgs.niceName != null) {         Process.setArgV0 (parsedArgs.niceName);     }     ......     if (!isZygote) {         return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,null /* classLoader */);     } else {           ......     } } A partir de ZygoteInit.zygoteInit(), es exactamente igual que el código analizado en ③, y el análisis no se repetirá aquí. Lo que se devuelve en ③ es el Runnable que puede llamar al método principal de SystemServer, y lo que es devuelto en ④ es el principal que puede llamar al Runnable del método ActivityThread. Desde entonces, también se ha analizado ZygoteInit.















Resumen
Mencionamos anteriormente que el proceso Zygote es el primer proceso de Java, pero después del análisis de todo el artículo, el proceso de Java en realidad se ejecuta sobre el proceso de C++, pero la máquina virtual de Java protege todo esto. El inicio del proceso zygote es una transición paso a paso del mundo c++ al mundo java, y cada mundo ha hecho sus propios preparativos.

mundo c++ (entrada app_main.cpp):

Cargue dinámicamente la biblioteca dinámica de la máquina virtual e inicie la máquina virtual java.
Registre las funciones locales de JNI para reducir la carga en la máquina virtual.
Cargue ZygoteInit en la máquina virtual java e ingrese oficialmente al mundo java
(entrada ZygoteInit.java):

Enlace sockets para recibir nuevas solicitudes de ejecución de aplicaciones de Android
Precargue recursos de Android para mejorar la velocidad de inicio del proceso de la aplicación
Inicie y ejecute SystemServer (ejecutando AMS, PMS y otros servicios principales)
para procesar nuevas solicitudes de ejecución de aplicaciones de Android
El inicio del proceso de cigoto en realidad no es Los particularmente difíciles son principalmente engorroso. El proceso de análisis del código fuente es aburrido. Solo cuando te calmas puedes ganar algo.
Este artículo ignora muchos detalles, principalmente para presentar el proceso general. Si hay errores, por favor critique y señale ~ Si cree que la escritura es buena, por favor dele un pulgar hacia arriba ~

Supongo que te gusta

Origin blog.csdn.net/s_nshine/article/details/131777256
Recomendado
Clasificación