Zygote service is started in the service_start method of the Init process. This will then run /system/bin/app_process on behalf of zygote.

The analysis in the previous section knew that the dynamic_args parameter was NULL, so execve was eventually called to run the child process.

system/core/init/init.cpp

void service_start(struct service *svc, const char *dynamic_args)
{...pid_t pid = fork();
    if (pid == 0) {...if(! dynamic_args) { ...... }else {
            char *arg_ptrs[INIT_PARSER_MAXARGS+1];
            int arg_idx = svc->nargs;
            char *tmp = strdup(dynamic_args);
            char *next = tmp;
            char *bword;

            /* Copy static parameters */
            memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));

            while((bword = strsep(&next, ""))) {
                arg_ptrs[arg_idx++] = bword;
                if (arg_idx == INIT_PARSER_MAXARGS)
                    break;
            }
            arg_ptrs[arg_idx] = NULL;
            execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
        }
        _exit(127); }... }Copy the code

Execve is defined in the header file unistd.h.

int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
Copy the code

Fork a child process in the parent process and call exec function in the child process to start the new program. There are six exec functions, of which execve is a kernel-level system call. The others (execl, execle, execLP, execv, and execvp) are library functions that call execve.

Execve () is used to execute the file path represented by the filename string. The second argument is passed to the file using an array of Pointers, terminated with a NULL pointer, and the last argument is an array of new environment variables passed to the file.

If the execution succeeds, the function does not return. If the execution fails, -1 is returned. The failure reason is stored in errno.

Then run the program: the out/target/product/hammerhead/system/bin/app_process, it is app_main CPP compilation of binary.

The runtime AppRuntime is created in the app_main main method, the runtime parameters are prepared, and the ZygoteInit Java class is started by calling its start method.

frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{.../ / create AppRuntime
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // Process command line arguments
    / / ignore argv [0]
    argc--;
    argv++;

    int i;
    for (i = 0; i < argc; i++) {
        if (argv[i][0] != The '-') {
            break;
        }
        if (argv[i][1] = =The '-' && argv[i][2] = =0) {
            ++i; // Skip --.
            break;
        }
        runtime.addOption(strdup(argv[i]));
    }

    // Parse the run-time parameters
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // Skip the unused parent directory argument
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") = =0) {
            // Enter this branch
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") = =0) {
            // Enter this branch
            startSystemServer = true;
        } else if (strcmp(arg, "--application") = =0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=".12) = =0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--".2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }

    Vector<String8> args;
    if(! className.isEmpty()) {... }else {
        // In zygote mode
        maybeCreateDalvikCache(a);if (startSystemServer) {
            args.add(String8("start-system-server"));
        }

        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);

        // Pass all remaining arguments to the zygote main() method
        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);
    } else if (className) {
        ......
    } else{... }}Copy the code

Create an AppRuntime object and pass the arguments to the parent constructor AndroidRuntime for initialization.

frameworks/base/cmds/app_process/app_main.cpp

namespace android {
......
class AppRuntime : public AndroidRuntime
{
public:
    AppRuntime(char* argBlockStart, const size_t argBlockLength)
        : AndroidRuntime(argBlockStart, argBlockLength)
        , mClass(NULL) {}... }; }Copy the code

AndroidRuntime class defined in the header file android_runtime/AndroidRuntime h, finally to invoke the start method to start the com. Android. Internal. OS. ZygoteInit.

frameworks/base/include/android_runtime/AndroidRuntime.h

namespace android {

class AndroidRuntime
{
public:
    AndroidRuntime(char* argBlockStart, size_targBlockSize); .void start(const char *classname, const Vector<String8>& options, bool zygote); . }Copy the code

Here is the implementation, located in AndroidRuntime.cpp.

The start method does:

Start the Android runtime. This involves starting the virtual machine and calling the “static void main(String [] args)” method in a class named “className”. The main function is passed two arguments, the class name and the specified option string.

frameworks/base/core/jni/AndroidRuntime.cpp

AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
        mExitWithoutCleanup(false),
        mArgBlockStart(argBlockStart),
        mArgBlockLength(argBlockLength)
{
    SkGraphics::Init(a);// Pre-allocate enough space to accommodate a large number of options.
    mOptions.setCapacity(20);

    assert(gCurRuntime == NULL);        // one per process
    gCurRuntime = this; }...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) {
        return;
    }
    onVmCreated(env);

    /* * Register the Android function */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    /* * Call main() with an array of strings containing arguments. Currently, there are two parameters, the class name and the option string. * Create an array to hold them. * /
    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);
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr ! =NULL);
    env->SetObjectArrayElement(strArray, 0, classNameStr);

    for (size_t i = 0; i < options.size(a); ++i) { jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
        assert(optionsStr ! =NULL);
        env->SetObjectArrayElement(strArray, i + 1, optionsStr);
    }

    /* * Start the VM. This thread becomes the main thread of the VM and does not return until the VM exits. * /
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main"."([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            The jni function starts the ZygoteInit static main method.
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

#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");
}
Copy the code

Start running zygote Service and enter the Java world! In the main function, Zygote service implements the local socket server listening and also starts the System Server process. This is a top priority!

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

public class ZygoteInit {...public static void main(String argv[]) {
        try {
            RuntimeInit.enableDdms();
            // Profiler related: start
            SamplingProfilerIntegration.start();

            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: "+ argv[i]); }}if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }
            // Register the socket server
            registerZygoteSocket(socketName);
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
            // Load resources
            preload();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());

            // Profiler related: end
            SamplingProfilerIntegration.writeZygoteSnapshot();

            // Initial GC clean up after startup
            gcAndFinalize();

            // Disable trace so that the fork process does not inherit outdated trace tags from Zygote
            Trace.setTracingEnabled(false);

            if (startSystemServer) {
                / / start SystemServer
                startSystemServer(abiList, socketName);
            }

            Log.i(TAG, "Accepting command socket connections");
            runSelectLoop(abiList);

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throwex; }}... }Copy the code

Finally, as usual, draw a sequence diagram summary.