zygote process of android frameworks

The zygote process is the originator of each application process. The process of each app is created by the zygote process, that is, the parent process of the app process is the zygote process.

When the system starts, the bootloader is loaded, the kernel is started, and the init process is created. In the init process, init.rc is parsed. init.rc contains the service to start the zygote process, and then the zygote process is started.

In Linux, a process is created by fork(). Except for some kernel core data of the child process that is different from the parent process, the rest of the data and memory are shared with the parent process. The child process that is created by fork() The return value is 0, and the return value of the parent process is the pid of the parent process.

1.init.rc

In init.rc, files are introduced through the import method, and the imported files are controlled through the properties of ro.zygote

\system\core\rootdir\init.rc
import /init.${ro.zygote}.rc

The settable values of the attribute value of ro.zygote are: zygote32, zygote32_64, zygote64, zygote64_32, so there are four zygote-related rc files in the system/core/rootdir/ directory

zygote32: 32-bit mode

zygote32_64: Mainly 32-bit mode, supplemented by 64-bit mode

zygote64:64-bit mode

zygote64_32: Mainly 64-bit mode, supplemented by 32-bit mode

zygote32 is the same as zygote64, except that zygote64 executes the process of app_process64; the difference between zygote32 and zygote32_64 is that zygote32_64 starts the process of zygote_secondary

init.zytote32.rc

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    priority-20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks

init.zygote32_64.rc

service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority-20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks

service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
    class main
    priority-20
    user root
    group root readproc reserved_disk
    socket zygote_secondary stream 660 root system
    socket usap_pool_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks

Take zygote32 as an example.

2. The source code path of app_process is under frameworks/base/cmds/app_process. There is only app_main.cpp file. Let’s look at its main method directly.

int main(int argc, char* const argv[])
{
  .....................
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));//Create AppRuntime instance
   .....................
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

     + + i; // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i + + ];
        if (strcmp(arg, "--zygote") == 0) {/will enter this branch
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;//niceName=zygote
        } else if (strcmp(arg, "--start-system-server") == 0) {//Will 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;
        }
    }
    .....................
    if (zygote) {//Enter this branch
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\
");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

In the main method, it mainly creates the runtime, parses the parameters, and then passes com.android.internal.os.ZygoteInit to runtime.start.

\frameworks\base\core\jni\AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8> & amp; options, bool zygote)
{
    ............
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);//Initialize art
    JNIEnv* env;
    if (startVm( & amp;mJavaVM, & amp;env, zygote) != 0) {//Start the virtual machine
        return;
    }
    onVmCreated(env);

    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {//Register jni
        ALOGE("Unable to register all android natives\
");
        return;
    }

   .....................
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\
", 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'\
", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);//jni reflection, calling java from C, c++, here startClass is ZygoteInit, that is, calling the main method of ZygoteInit.java
     .............


}

Initialize art in AndroidRuntime::start, start the virtual machine, register jni, and then enter the main method of ZygoteInit.java through the CallStaticVoidMethod method. Here is just a brief introduction to the process. For detailed analysis, please see my other article “The Principle of Android Calling Jar Through the Bin Binary Program”

Before Android 4.4, the Dalvik virtual machine was used. In Android 5.0, the Art virtual machine was used instead of Dalvik. The Dalvik virtual machine is also a Java virtual machine, except that it executes dex files instead of class files, and the dalvik virtual machine contains a parser to execute dex bytecodes and dynamically convert dex bytecodes at runtime. Costing local machine code and then executing it obviously has efficiency issues. If the local machine code is directly executed without conversion at runtime, the efficiency will be improved, so art mainly solves this problem. During application installation, ART directly converts dex into local machine code, so the installation speed of APP after Android 5.0 is obviously slower than before, but the operating efficiency has also been significantly improved. In app installation, it is mainly executed through the service of PackageManagerServer by requesting the installd process.

3. Let’s look at the main method of ZygoteInit.java

frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static void main(String argv[]) {
        ............................
        for (int i = 1; i < argv.length; i + + ) {
            if ("start-system-server".equals(argv[i])) {//Enter this branch
                startSystemServer = true;
            } else if ("--enable-lazy-preload".equals(argv[i])) {
                enableLazyPreload = true;
            } else if (argv[i].startsWith(ABI_LIST_ARG)) {//Enter this branch
                abiList = argv[i].substring(ABI_LIST_ARG.length());
            } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
            } else {
                throw new RuntimeException("Unknown command line argument: " + argv[i]);
            }
        }

        final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);//isPrimaryZygote is true, socketname is: zygote

        if (abiList == null) {
            throw new RuntimeException("No ABI list supplied.");
        }
        ............................
        //Create socket
        Zygote.initNativeState(isPrimaryZygote);

        ZygoteHooks.stopZygoteNoThreadCreation();

        zygoteServer = new ZygoteServer(isPrimaryZygote);

        if (startSystemServer) {
            Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);//Create process, [see section 3.1]

            // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
            // child (system_server) process.
            if (r != null) {
                r.run();
                return;
            }
        }
............................
    if (caller != null) {
        caller.run();
    }
}

Section 3.1

private static Runnable forkSystemServer(String abiList, String socketName,
        ZygoteServer zygoteServer) {
    .....................
    String args[] = {//Configuration parameters
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                     + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
            "--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server",
            "--runtime-args",
            "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
            "com.android.server.SystemServer",
    };
    ZygoteArguments parsedArgs = null;

    int pid;

    try {
        parsedArgs = new ZygoteArguments(args);
        Zygote.applyDebuggerSystemProperty(parsedArgs);
        Zygote.applyInvokeWithSystemProperty(parsedArgs);

        boolean profileSystemServer = SystemProperties.getBoolean(
                "dalvik.vm.profilesystemserver", false);
        if (profileSystemServer) {
            parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
        }

        //Create a process through native fork()
        pid = Zygote.forkSystemServer(
                parsedArgs.mUid, parsedArgs.mGid,
                parsedArgs.mGids,
                parsedArgs.mRuntimeFlags,
                null,
                parsedArgs.mPermittedCapabilities,
                parsedArgs.mEffectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    /* For child process */
    if (pid == 0) {//The return value is 0 is the child process
        if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }

        zygoteServer.closeServerSocket();
        return handleSystemServerProcess(parsedArgs);
    }

    return null;
}
private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
    //Check whether the parameters are configured for mInvokeWith, so parsedArgs.mInvokeWith==null, enter the else branch
    if (parsedArgs.mInvokeWith != null) {
        String[] args = parsedArgs.mRemainingArgs;
        // If we have a non-null system server class path, we'll have to duplicate the
        // existing arguments and append the classpath to it. ART will handle the classpath
        // correctly when we exec a new process.
        if (systemServerClasspath != null) {
            String[] amendedArgs = new String[args.length + 2];
            amendedArgs[0] = "-cp";
            amendedArgs[1] = systemServerClasspath;
            System.arraycopy(args, 0, amendedArgs, 2, args.length);
            args = amendedArgs;
        }

        WrapperInit.execApplication(parsedArgs.mInvokeWith,
                parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
                VMRuntime.getCurrentInstructionSet(), null, args);

        throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
    } else {
        createSystemServerClassLoader();
        ClassLoader cl = sCachedSystemServerClassLoader;
        if (cl != null) {
            Thread.currentThread().setContextClassLoader(cl);
        }

        /*
         * Pass the remaining arguments to SystemServer.
         */
        return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                parsedArgs.mRemainingArgs, cl);//ZygoteInit.zygoteInit mainly configures log and trace and initializes zygote
    }

    /* should never reach here */
}

ZygoteInit.zygoteInit configures log and trace, initializes zygote through jni, and then calls RuntimeInit.findStaticMain

frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
protected static Runnable findStaticMain(String className, String[] argv,
        ClassLoader classLoader) {
    Class<?>cl;

    try {
        cl = Class.forName(className, true, classLoader); //Through parameter configuration, it can be traced that className is com.android.server.SystemServer
    } catch (ClassNotFoundException ex) {
        throw new RuntimeException(
                "Missing class when invoking static main " + className,
                ex);
    }

    Method m;
    try {
        m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) {
        throw new RuntimeException(
                "Missing static main on " + className, ex);
    } catch (SecurityException ex) {
        throw new RuntimeException(
                "Problem getting static main on " + className, ex);
    }
    return new MethodAndArgsCaller(m, argv);
}

The main method of ZygoteInit.java includes the calls of each function, which mainly do three things: create a socket, create a process, and call the main method of com.android.server.SystemServer through reflection.

4. com.android.server.SystemServer.main()

frameworks\base\services\java\com\android\server\SystemServer.java
public static void main(String[] args) {
    new SystemServer().run();
}
private void run() {
    try {
        .....................................
        //Set some attribute values
        .............................
        //Configure the running environment
        VMRuntime.getRuntime().clearGrowthLimit();
        .....................
        Looper.prepareMainLooper();//Open looper
        Looper.getMainLooper().setSlowLogThresholdMs(
                SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
        System.loadLibrary("android_servers");//Load libandroid_servers.so

        // Debug builds - allow heap profiling.
        if (Build.IS_DEBUGGABLE) {
            initZygoteChildHeapProfiling();
        }

        // Check whether we failed to shut down last time we tried.
        // This call may not return.
        performPendingShutdown();

        // Initialize the system context.
        createSystemContext();//Create context

        //Add SystemServiceManager to the service list
        mSystemServiceManager = new SystemServiceManager(mSystemContext);
        mSystemServiceManager.setStartInfo(mRuntimeRestart,
                mRuntimeStartElapsedTime, mRuntimeStartUptime);
        LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
        // Prepare the thread pool for init tasks that can be parallelized
        SystemServerInitThreadPool.get();
    } finally {
        traceEnd(); // InitBeforeStartServices
    }

    //Start the core service, which will probably start more than 90 services
    try {
        traceBeginAndSlog("StartServices");
        startBootstrapServices();
        startCoreServices();
        startOtherServices();
        SystemServerInitThreadPool.shutdown();
    } catch (Throwable ex) {
        Slog.e("System", "****************************************** *");
        Slog.e("System", "************ Failure starting system services", ex);
        throw ex;
    } finally {
        traceEnd();
    }
    ....................................................
    // Loop forever.
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

5. Summary: zygote is a very important process. All application processes rely on it to create. The startup of zygote is achieved by parsing init.rc, executing the app_process program through the parameters carried by rc, and then registering art and configuring Virtual machine parameters, start the virtual machine, register jni, create socket, call fork() through jni to create a new process, execute it through reflection to SystemServer.main, and finally start the system, there are about 90 kinds of core services required.

If you want to learn more programming, please follow the official account: android full access

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. CS entry skill treeLinux introductionFirst introduction to Linux 37041 people are learning the system