Zygote

Now, that’s a name. Zygote is a daemon whose goal is to launch Apps. The startup of the process is triggered by Init.rc after Service Manager and others but it is actually started by app_process. Here is the sequence used to start such special process

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd

You can see how Zygote is started as a system service. You can see also how app_process is the actual command that starts it.

As we said, Zygote is a daemon which only mission is to launch applications. This means that Zygote is the parent of all App process. When app_process launches Zygote, it creates the first Dalvik VM and calls Zygote’s main () method. Once Zygote starts, it preloads all necessary Java classes and resources, starts System Server and opens a socket /dev/socket/zygote to listen for requests for starting applications. System Server as we saw in previous post is a complete detached process from it’s parent. Once it’s created it goes initializing all the different System Services and starts the Activity Manager (will see this in a later posts). So, how does Zygote start new applications?

Zygote receives a request to launch an App through /dev/socket/zygote. Once it happens it trigger a fork() call. Here is where the virtues of a great design take action. When a process forks, it creates a clone of itself. It replicates itself in another memory space. This is done pretty efficiently. When this happens to Zygote, it creates an exact and clean new Dalvik VM, preloaded with all necessary classes and resources that any App will need. This makes the process of creating a VM and load resources pretty efficiently. But the design goes farther. As we know, Android runs on Linux. The Linux Kernel implements a strategy call Copy On Write (COW). What this means is that during the fork process, no memory is actually copy to another space. It is shared and marked as copy-on-write. Which means that when a process attempt to modify that memory, the kernel will intercept the call and do the copy of that piece of memory. In the case of Android those libraries are not writable. This means that all process forked from Zygote are using the exact same copy of the system classes and resources. Another benefit is the real memory saving. No matter how many applications are started the increase in memory usage will be a lot smaller.

If you are in an early stage of a porting process, Zygote is another big process that you don’t need to start. You can disable it by adding the keyword “disabled” at the end of the boot sequence in init.rc

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
disabled

AlBelow is a picture (from Embedded Android) on where can you place Zygote in the Android Platform

zygote

Android Boot Sequence (from Embedded Android)

Here is the Zygote main() method:

public static void main(String argv[]) {
 try {
     // Start profiling the zygote initialization.
     SamplingProfilerIntegration.start();

    registerZygoteSocket();
    EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
    SystemClock.uptimeMillis());
    preload();
    EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
    SystemClock.uptimeMillis());

    // Finish profiling the zygote initialization.
    SamplingProfilerIntegration.writeZygoteSnapshot();

    // Do an initial gc to clean up after startup
    gc();

    // Disable tracing so that forked processes do not inherit stale tracing tags from
    // Zygote.
    Trace.setTracingEnabled(false);

    // If requested, start system server directly from Zygote
    if (argv.length != 2) {
        throw new RuntimeException(argv[0] + USAGE_STRING);
    }

    if (argv[1].equals("start-system-server")) {
        startSystemServer();
    } else if (!argv[1].equals("")) {
        throw new RuntimeException(argv[0] + USAGE_STRING);
    }

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

    runSelectLoop();

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

Also, see below how Zygote starts the System Server:

/**
 * Prepare the arguments and fork for the system server process.
 */
 private static boolean startSystemServer()
 throws MethodAndArgsCaller, RuntimeException {
 /* Hardcoded command line to start the system server */
 String args[] = {
 "--setuid=1000",
 "--setgid=1000",
 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007",
 "--capabilities=130104352,130104352",
 "--runtime-init",
 "--nice-name=system_server",
 "com.android.server.SystemServer",
 };
 ZygoteConnection.Arguments parsedArgs = null;

int pid;

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

/* Request to fork the system server process */
 pid = Zygote.forkSystemServer(
 parsedArgs.uid, parsedArgs.gid,
 parsedArgs.gids,
 parsedArgs.debugFlags,
 null,
 parsedArgs.permittedCapabilities,
 parsedArgs.effectiveCapabilities);
 } catch (IllegalArgumentException ex) {
 throw new RuntimeException(ex);
 }

/* For child process */
 if (pid == 0) {
 handleSystemServerProcess(parsedArgs);
 }

return true;
 }
Advertisements

8 Responses to “Zygote”

  1. Nice Blog. To go bit deeper, do you know how can we avoid preloading all classes while booting up ?

    • Hi Keestu,
      Thanks for by our comment, yes, you can avoid preloading all libraries so that you can speed up the boot.
      This is not always the best thing to do. The applications using the excluded libraries will take more time to boot.
      In the other hand, it is a good practice if you plan to run Android in a low memory device.
      I will prepare a post to explain how to do that.

  2. I’m starting to learn Substrate, which takes control of the system using the zygote process. Could you do a blog post about how Substrate and Xposed work, and do an example like when and how the system/status/notification bars are first created and where we would hook into to change them dynamically?

  3. Thanks for your commenting.

Trackbacks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: