Analyse du processus de démarrage Android 8.1 (3)

Processus de démarrage du système Android (2) Analyse du processus Zygote

Articles connexes
Architecture du système Android et répertoire du code source du système
Processus de démarrage du système Android (1) Analyse du processus d'initialisation

Préface

Dans le dernier article, nous avons analysé le processus d'initialisation. Il y a trois choses principales à faire dans le processus d'initialisation. L'une d'elles est de créer le processus Zygote. Alors, qu'est-ce que le processus Zygote et que fait-il ? Cet article vous apportera les réponses à ces questions.

1. Introduction au Zygote

Dans le système Android, JavaVM (Java Virtual Machine), les processus d'application et les processus SystemServer qui exécutent les services clés du système sont tous créés par le processus Zygote, que nous appelons également un incubateur. Il crée des processus d'application et des processus SystemServer sous forme de fock (processus de copie). Étant donné que le processus Zygote crée JavaVM au démarrage, les processus d'application et les processus SystemServer créés via fock peuvent obtenir une copie d'instance de JavaVM en interne.
Nous avons déjà évoqué dans l'article précédent l'initialisation du démarrage de Zygote, nous n'entrerons donc pas dans les détails ici. Cet article analyse principalement le processus de démarrage d'Android 7.0 Zygote.

2.Analyse AppRuntime

Nous avons appris de l'article précédent que lorsque init démarre zygote, il appelle principalement le démarrage d'AppRuntime dans la fonction principale de app_main.cpp pour démarrer le processus zygote. Nous allons commencer l'analyse à partir de la fonction principale de app_main.cpp, comme indiqué ci-dessous .

frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
    
    
...

    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
   ...
     Vector<String8> args;
    if (!className.isEmpty()) {
    
    
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);
    } else {
    
    
        // We're in zygote mode.
        maybeCreateDalvikCache();
        if (startSystemServer) {
    
    
            args.add(String8("start-system-server"));//1
        }
        char prop[PROP_VALUE_MAX];
        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
    
    
            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
                ABI_LIST_PROPERTY);
            return 11;
        }
        String8 abiFlag("--abi-list=");
        abiFlag.append(prop);
        args.add(abiFlag);
        for (; i < argc; ++i) {
    
    
            args.add(String8(argv[i]));
        }
    }
    if (!niceName.isEmpty()) {
    
    
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }
    if (zygote) {
    
    
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);//2
    } 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.");
        return 10;
    }
}

Remarque 1 : Si startSystemServer est vrai (la valeur par défaut est vraie), placez "start-system-server" dans le paramètre de démarrage args.
La note 2 est appelée. Ici, la fonction start du runtime est appelée pour démarrer le processus zygote, et args est transmis. Après avoir démarré le processus zygote, le processus zygote démarrera le processus SystemServer. Nous savons que runtime fait référence à AppRuntime, et la déclaration AppRuntime est également dans app_main.cpp. Il hérite d'AndroidRuntime, c'est-à-dire que lorsque nous appelons start, nous appelons en fait la fonction start d'AndroidRuntime :

frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    
    
    ...
    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
    
    //1
        return;
    }
    onVmCreated(env);
    if (startReg(env) < 0) {
    
    //2
        ALOGE("Unable to register all android natives\n");
        return;
    }
    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;

    stringClass = env->FindClass("java/lang/String");
    assert(stringClass != NULL);
    //创建数组
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    assert(strArray != NULL);
    //从app_main的main函数得知className为com.android.internal.os.ZygoteInit
    classNameStr = env->NewStringUTF(className);
    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);
    }
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    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");//3
        if (startMeth == NULL) {
    
    
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
    
    
        //通过JNI调用ZygoteInit的main函数
            env->CallStaticVoidMethod(startClass, startMeth, strArray);//4

#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
  ...
}

La fonction startVm est appelée au commentaire 1 pour créer JavaVm, et la fonction startReg est appelée au commentaire 2 pour enregistrer JNI pour JavaVm. Le code du commentaire 3 est utilisé pour trouver la fonction principale de ZygoteInit, où startClass est connu sous le nom de com.android.internal.os.ZygoteInit à partir de la fonction principale de app_main. La note 4 appelle la fonction principale de ZygoteInit via JNI. Étant donné que la fonction principale de ZygoteInit est écrite en Java, elle doit être appelée via JNI.

3. Couche de framework Java de Zygote

Après avoir appelé la fonction principale de ZygoteInit via JNI ci-dessus, Zygote est entré dans la couche de framework Java. Aucun code n'était entré dans la couche de framework Java auparavant. En d'autres termes, Zygote a créé la couche de framework Java.

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

 public static void main(String argv[]) {
    
    
       ...
        try {
    
    
         ...       
            //注册Zygote用的Socket
            registerZygoteSocket(socketName);//1
           ...
           //预加载类和资源
           preload();//2
           ...
            if (startSystemServer) {
    
    
            //启动SystemServer进程
                startSystemServer(abiList, socketName);//3
            }
            Log.i(TAG, "Accepting command socket connections");
            //等待客户端请求
            runSelectLoop(abiList);//4
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
    
    
            caller.run();
        } catch (RuntimeException ex) {
    
    
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

La note 1 utilise la fonction registerZygoteSocket pour créer un Socket côté serveur. Ce Socket est utilisé pour attendre qu'ActivityManagerService demande à Zygote de créer un nouveau processus d'application. La note 2 est utilisée pour précharger les classes et les ressources. La note 3 est utilisée pour démarrer le processus SystemServer, de sorte que les services clés du système seront également démarrés par le processus SystemServer. La note 4 appelle la fonction runSelectLoop pour attendre les demandes des clients. De là, nous savons que la fonction principale de ZygoteInit fait principalement quatre choses. Ensuite, nous analyserons les principaux événements un par un.

s'inscrireZygoteSocket

Voyons d'abord ce que fait la fonction registerZygoteSocket

   private static void registerZygoteSocket(String socketName) {
    
    
        if (sServerSocket == null) {
    
    
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {
    
    
                String env = System.getenv(fullSocketName);
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
    
    
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }
            try {
    
    
                FileDescriptor fd = new FileDescriptor();
                fd.setInt$(fileDesc);
                sServerSocket = new LocalServerSocket(fd);//1
            } catch (IOException ex) {
    
    
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }

La note 1 est utilisée pour créer LocalServerSocket, qui est le Socket côté serveur. Lorsque le processus Zygote démarre le processus SystemServer, il attendra sur le Socket de ce serveur qu'ActivityManagerService demande au processus Zygote de créer un nouveau processus d'application.

Démarrer le processus SystemServer

Regardez ensuite la fonction startSystemServer, le code est le suivant.

 private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
    
    
...
        /* Hardcoded command line to start the system server */
         /*1*/
        String args[] = {
    
    
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

        try {
    
    
            parsedArgs = new ZygoteConnection.Arguments(args);//2
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

            /*3*/
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
    
    
            throw new RuntimeException(ex);
        }
        if (pid == 0) {
    
    
            if (hasSecondZygote(abiList)) {
    
    
                waitForSecondaryZygote(socketName);
            }

            handleSystemServerProcess(parsedArgs);//4
        }

        return true;
    }

Le code du commentaire 1 est utilisé pour créer le tableau args. Ce tableau est utilisé pour enregistrer les paramètres de démarrage pour le démarrage de SystemServer. On peut voir que l'ID utilisateur et l'ID de groupe d'utilisateurs du processus SystemServer sont définis sur 1000 ; et il a groupes d'utilisateurs 1001, 1010, 1018 et 1021. , 1032, 3001 , 3010 autorisations ; le nom du processus est system_server ; le nom de la classe à démarrer est com.android.server.SystemServer. Encapsulez le tableau args dans un objet Arguments dans la note 2 et appelez-le pour la fonction forkSystemServer dans la note 3. La note 3 appelle forkSystemServer de Zygote, qui crée principalement un processus enfant dans le processus actuel via la fonction fork. Si le pid renvoyé est 0, cela signifie qu'il est exécuté dans le processus enfant nouvellement créé, puis exécutez handleSystemServerProcess à la note 4 pour démarrer SystemServer. processus.

runSelectLoop

Après avoir démarré le processus SystemServer, entrez enfin la fonction runSelectLoop, comme indiqué ci-dessous.

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    
    
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        fds.add(sServerSocket.getFileDescriptor());//1
        peers.add(null);

        while (true) {
    
    
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) {
    
    //2
                pollFds[i] = new StructPollfd();
                pollFds[i].fd = fds.get(i);
                pollFds[i].events = (short) POLLIN;
            }
            try {
    
    
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
    
    
                throw new RuntimeException("poll failed", ex);
            }
            for (int i = pollFds.length - 1; i >= 0; --i) {
    
    //3
                if ((pollFds[i].revents & POLLIN) == 0) {
    
    
                    continue;
                }
                if (i == 0) {
    
    
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);//4
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
    
    
                    boolean done = peers.get(i).runOnce();//5
                    if (done) {
    
    
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }

Le sServerSocket dans la note 1 est le Socket côté serveur que nous avons créé dans la fonction registerZygoteSocket. Appelez sServerSocket.getFileDescriptor() pour obtenir la valeur du champ fd du Socket et ajoutez-le à la liste fds. Ensuite, la boucle infinie est utilisée pour attendre qu'ActivityManagerService demande au processus Zygote de créer un nouveau processus d'application. La note 2 transfère les informations stockées dans fds vers le tableau pollFds via traversée. Enfin, parcourez pollFds au commentaire 3. Si i==0, cela signifie que le serveur Socket est connecté au client, c'est-à-dire que le processus Zygote actuel a établi une connexion avec ActivityManagerService. Ensuite, dans le commentaire 4, obtenez la classe ZygoteConnection via la fonction acceptCommandPeer et ajoutez-la aux pairs de la liste de connexions Socket, puis ajoutez le fd du ZygoteConnection à la liste fd fds afin que la requête envoyée par ActivityManagerService puisse être reçue. Si la valeur de i est supérieure à 0, cela signifie qu'ActivityManagerService a envoyé une demande de création d'un processus de candidature au processus Zygote, puis a appelé la fonction runOnce de ZygoteConnection au commentaire 5 pour créer un nouveau processus de candidature. Et après une création réussie, cette connexion sera effacée de la liste de connexions Socket peers et de la liste fd fds.

4. Résumé du processus Zygote

C'est tout pour le processus de démarrage de Zygote. Le processus Zygote a effectué les choses suivantes :
1. Créez AppRuntime et appelez sa méthode start pour démarrer le processus Zygote.
2. Créez une JavaVM et enregistrez JNI pour la JavaVM.
3. Appelez la fonction principale de ZygoteInit via JNI pour accéder à la couche de framework Java de Zygote.
4. Créez un socket serveur via la fonction registerZygoteSocket et attendez la demande d'ActivityManagerService via la fonction runSelectLoop.
5. Démarrez le processus SystemServer.

Documents de référence
« Analyse de scénarios du code source du système Android »
« Compréhension approfondie d'Android Volume 1 »
« Compréhension approfondie du système Android »

Je suppose que tu aimes

Origine blog.csdn.net/a13821684483/article/details/103050494
conseillé
Classement