Zygote进程启动过程分析

1,260 阅读9分钟

zygote进程定义

Init进程是Android系统中用户空间的第一个进程, 它最重要的工作就是创建zygote进程。而在Android系统中,所有应用程序的进程以及系统服务进程SystemServer都是由Zygote进程孕育出来的。所有Zygote的地位非同小可,本文就分析它的启动过程。

Android系统启动后运行的第一个进程是init进程,它的目录在system/core/init/init.cpp 在这里会进行启动属性服务以及解析init.rc文件,init.rc文件是android系统的配置文件,它如下格式所示:

system/core/rootdir/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

每一个service命令都会促使init进程调用fork函数来创建一个新的进程,这里service用于通知init进程创建名zygote的进程,这个zygote进程执行程序的路径为/system/bin/app_process,后面的则是要传给app_process的参数。class main指的是zygote的class name为main。

zygote要执行的程序是system/bin/app_process这样会进入main函数。在main中会执行AppRuntime的start来进一步启动zygote。

frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
……
runtime.start("com.android.internal.os.ZygoteInit",
                startSystemServer ? "start-system-server" : "");
……
}

这里的runtime是AppRuntime的实例,AppRuntime是继承自AndroidRuntime,这里的start方法就是在AndroidRuntime里定义的。

//启动android运行时 这包括了启动虚拟机和调用callName所定义的静态main方法 这里时指com.android.internal.os.ZygoteInit

frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const char* options)
{
    ……
   JNIEnv* env;
    if (startVm(&mJavaVM, &env) != 0) {//启动虚拟机
        return;
    }
    onVmCreated(env);

    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {//在虚拟机中注册function
        ALOGE("Unable to register all android natives\n");
        return;
    }
    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);//找到ZygoteInit类
    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");//调用静态main方法
    }
}

Zygote进程在启动时会创建JavaVM,因此通过fock而创建的应用程序进程和SystemServer进程可以在内部获取一个JavaVM的实例拷贝.在启动zygote时传递进来的类为com.android.internal.os.ZygoteInit,这里通过反射的方式来调用其main方法进一步完成启动初始化的过程。

//在AndroidRuntime的start方法通过反射调用的
public static void main(String argv[]) {
   try {
       // Start profiling the zygote initialization.
       SamplingProfilerIntegration.start();

       registerZygoteSocket();//注册zygote本地Socket服务 监听来自AMS的创建应用进程请求
       EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
           SystemClock.uptimeMillis());
       preload();//预加载 一些资源,类等
       ……
       if (argv[1].equals("start-system-server")) {
           startSystemServer();//启动SystemServer进程
       } 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;
   }
}

在zygote的初始化中,做了以下几件事件:

  1. 通过registerServerSocket创建zygote的socket服务,它是一个LocalSocketServer用来等待AMS请求zygote创建应用进程的请求。
  2. 监听socket服务,等待AMS创建应用程序的请求
  3. 创建SystemServer进程

值得注意的是,无论是创建systemServer进程还是创建应用进程,最终都会通过捕获MethodAndArgsCaller异常来执行参数指定的class的main方法,后面我们分析SystemServer启动及应用进程的启动时就会看到。

这里我们接着看看注册socket服务的代码,它仅仅是创建了LocalServerSocket的本地socket对象

private static void registerZygoteSocket() {
    if (sServerSocket == null) {
        int fileDesc;
        try {
            String env = System.getenv(ANDROID_SOCKET_ENV);
            fileDesc = Integer.parseInt(env);
        } catch (RuntimeException ex) {
            throw new RuntimeException(
                    ANDROID_SOCKET_ENV + " unset or invalid", ex);
        }

        try {
            sServerSocket = new LocalServerSocket(
                    createFileDescriptor(fileDesc));
        } catch (IOException ex) {
            throw new RuntimeException(
                    "Error binding to local socket '" + fileDesc + "'", ex);
        }
    }
}

SystemServer进程的创建流程

这里我们重点关注SystemServer的创建流程,继续关注startSystemServer

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,1032,3001,3002,3003,3006,3007",
        "--capabilities=" + capabilities + "," + capabilities,
        "--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);//fork 出systemServer进程
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    /* For child process */
    if (pid == 0) {
        handleSystemServerProcess(parsedArgs);//在子进程中调用
    }

    return true;
}

在startSystemServer中仅仅fork出进程后随后进一步在handleSystemServerProcess中进一步对SystemServer进行初始化

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

private static void handleSystemServerProcess(//进一步处理SystemServer进程的相关工作
        ZygoteConnection.Arguments parsedArgs)
        throws ZygoteInit.MethodAndArgsCaller {

    closeServerSocket();//关闭从父进程继承来的socket

    // set umask to 0077 so new files and directories will default to owner-only permissions.
    Libcore.os.umask(S_IRWXG | S_IRWXO);

    if (parsedArgs.niceName != null) {
        Process.setArgV0(parsedArgs.niceName);
    }

    if (parsedArgs.invokeWith != null) {
        WrapperInit.execApplication(parsedArgs.invokeWith,
                parsedArgs.niceName, parsedArgs.targetSdkVersion,
                null, parsedArgs.remainingArgs);
    } else {
        /*
            * Pass the remaining arguments to SystemServer.
            */
        //此时的remainingArgs就是”com.android.server.SystemServer”
        RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
    }

    /* should never reach here */
}

这里进一步调用zygoteInit进行初始化工作

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

public static final void zygoteInit(int targetSdkVersion, String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
    if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");

    redirectLogStreams();

    commonInit();
    nativeZygoteInit();//zygote本地初始化 
    applicationInit(targetSdkVersion, argv);////应用层的初始化 
}

首先我们来看第一个方法nativeZygoteInit的调用,这个方法时在AndroidRuntime中定义的,具体是

/frameworks/base/core/jni/AndroidRuntime.cpp

static void
 com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit();
}

这里的onZygoteInit是调用其子类AppRuntime的方法,zygote的启动就是通过这个类调用start方法来执行的。

frameworks/base/cmds/app_process/app_main.cpp

virtual void onZygoteInit()
{
    // Re-enable tracing now that we're no longer in Zygote.
    atrace_set_tracing_enabled(true);

    sp<ProcessState> proc = ProcessState::self();
    ALOGV("App process: starting thread pool.\n");
    proc->startThreadPool();
}

ProcessState对于binder机制非常重要,这里主要是初始化SystemServer进程的的binder环境,这样在其进程中就可以通过binder同其他进程进行通信了。

下面我们来看看第二个方法applicationInit,这个方法第二个参数包含了调用了类的信息及相关方法的参数,这里就是com.android.server.SystemServer和main方法

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

private static void applicationInit(int targetSdkVersion, String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
        ……
        // Remaining arguments are passed to the start class's static main
        invokeStaticMain(args.startClass, args.startArgs);
 }

这个方法内部会调用invokeStaticMain方法。

//这个方法最终会抛出异常MethodAndArgsCaller触发其run方法的调用,具体见ZygoteInit的main方法
private static void invokeStaticMain(String className, String[] argv)
        throws ZygoteInit.MethodAndArgsCaller {
    Class<?> cl;

    try {
        cl = Class.forName(className);//获取类信息 可能是SystemServer或者ActivityThread
    } catch (ClassNotFoundException ex) {
    }

    Method m;
    try {
        m = cl.getMethod("main", new Class[] { String[].class });//获取对应类的main方法
    } catch (){} 
        
    /*
        * This throw gets caught in ZygoteInit.main(), which responds
        * by invoking the exception's run() method. This arrangement
        * clears up all the stack frames that were required in setting
        * up the process.
        */
    //抛出异常,通过MethodAndArgsCaller的run方法会去调用main方法
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

MethodAndArgsCaller的定义如下,这里我们重点看看run方法,run方法的实现很简单只是对main方法进行调用。即调用SystemServer的main方法完成SystemServer进程的创建和启动。

public static class MethodAndArgsCaller extends Exception
        implements Runnable {
    /** method to call */
    private final Method mMethod;//调用的方法,这里就是main方法了

    /** argument array */
    private final String[] mArgs;//参数
……
    public void run() {
        try {
            mMethod.invoke(null, new Object[] { mArgs });
        }catch(){…} 
    }
}

应用进程的创建启动过程

接下来我们分析应用进程创建和启动的过程,这个过程中需要AMS的介入,不过这里我们重点关注应用进程的创建和启动过程,而不需要关注整个流程的太多细节。熟悉AMS的应该知道,当我们点击Launcher启动应用程序后 最终会通过AMS的startProcessLocked方法来为我们的应用程序创建进程,而其内部会进一步调用startProcessLocked来完成,所以我们重点看那startProcessLocked方法。

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

private final void startProcessLocked(ProcessRecord app,
            String hostingType, String hostingNameStr) {
	……
	// Start the process.  It will either succeed and return a result containing
	            // the PID of the new process, or else throw a RuntimeException.
    Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
            app.processName, uid, uid, gids, debugFlags, mountExternal,
            app.info.targetSdkVersion, app.info.seinfo, null);
	……
}

这个方法会通过Process的start方法类完成进程的创建,这里我们传递ActivityThread的类名,再我们创建完应用进程后需要就是调用其内部的main方法完成启动过程。下面我们继续去看下进程是如何创建的。

frameworks/base/core/java/android/os/Process.java

public static final ProcessStartResult start(final String processClass,
                                final String niceName,
                                int uid, int gid, int[] gids,
                                int debugFlags, int mountExternal,
                                int targetSdkVersion,
                                String seInfo,
                                String[] zygoteArgs) {
    try {
        return startViaZygote(processClass, niceName, uid, gid, gids,debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
    } catch (ZygoteStartFailedEx ex) {   }
}

Process的start方法很简单,调用startViaZygote,从其名称来看就是通过zygote来创建我们应用进程了。这里的processClass就是我们的ActivityThread类,niceName是进程名称。startViaZygote通过将这一些参数打包到一个ArrayList变量中然后调用zygoteSendArgsAndGetResult,并将打包的参数传递给它。这个方法负责将这些参数通过socket传递给zygote.

private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
            throws ZygoteStartFailedEx {
    openZygoteSocketIfNeeded();
    try {
        sZygoteWriter.write(Integer.toString(args.size()));
        sZygoteWriter.newLine();

        int sz = args.size();
        for (int i = 0; i < sz; i++) {
            String arg = args.get(i);
            if (arg.indexOf('\n') >= 0) {
                throw new ZygoteStartFailedEx(
                        "embedded newlines not allowed");
            }
            sZygoteWriter.write(arg);
            sZygoteWriter.newLine();
        }

        sZygoteWriter.flush();

        // Should there be a timeout on this?
        ProcessStartResult result = new ProcessStartResult();
        result.pid = sZygoteInputStream.readInt();
        ……
    } catch (IOException ex) {
    }
}

这个方法首先通过openZygoteSocketIfNeeded方法来打开同zygote通信的socket,并用该socket创建一个BufferedWriter对象sZygoteWrite,随后通过sZygoteWrite将参数发送给zygote,同时创建一个ProcessStartResult对象,用来保存创建的进程信息。

对于zygote端我们知道,当zygote启动后会先注册一个LocalSocketServer服务,然后通过runSelectLoop等待来自AMS创建进程的请求。这里我们就需要看看runSelectLoop方法。

private static void runSelectLoop() throws MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
    FileDescriptor[] fdArray = new FileDescriptor[4];
    ……
    while (true) {
        int index;
        ……
        if (index < 0) {
            throw new RuntimeException("Error in select()");
        } else if (index == 0) {
            ZygoteConnection newPeer = acceptCommandPeer();
            peers.add(newPeer);
            fds.add(newPeer.getFileDesciptor());
        } else {
            boolean done;
            done = peers.get(index).runOnce();

            if (done) {
                peers.remove(index);
                fds.remove(index);
            }
        }
    }
}

runSelectLoop方法主要负责处理客户端的连接请求和客户端的消息处理,当index==0是说明有新的客户端连接,index>0则说明有消息到来,index指定了客户端的连接索引。同时会调用runOnce对消息机型处理。

//zygote收到客户端AMS的信息进行处理
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
    String args[];
    Arguments parsedArgs = null;
    ……
    try {
        args = readArgumentList();//读取客户端发送的消息 得到参数列表
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {  }
    ……
    try {
        parsedArgs = new Arguments(args);
        ……
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName);//创建应用进程
    } catch () {}
    ……
    try {
        if (pid == 0) {
            ……
            //继续处理子进程 这里面最终会抛出ZygoteInit.MethodAndArgsCaller来触发其run方法的调用
            handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
            // should never get here, the child is expected to either
            // throw ZygoteInit.MethodAndArgsCaller or exec().
            return true;
        } else {………}
    } finally {        }
}

在这个方法中首先通过readArgumentList方法读取客户端发送的消息,得到参数列表,随后根据参数创建应用进程,随后进一步调用handleChildProc进一步完成子进程的创建。在这个方法中最终会抛出MethodAndArgsCaller异常来触发run方法的调用,就如SystemServer进程那样。

private void handleChildProc(Arguments parsedArgs,
        FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
        throws ZygoteInit.MethodAndArgsCaller {

    ……
    if (parsedArgs.invokeWith != null) {
        WrapperInit.execStandalone(parsedArgs.invokeWith,
                parsedArgs.classpath, className, mainArgs);
    } else {
    ……
        try {
            ZygoteInit.invokeStaticMain(cloader, className, mainArgs);//最终会调用invokeStaticMain方法抛出异常
        } catch (RuntimeException ex) {
            logAndPrintError(newStderr, "Error starting.", ex);
        }
    }
}

这个方法会调用invokeStaticMain,这个方法我们在SystemServer启动时候分析过,这里就不再分析了。最终会调用ActivityThread的main方法完成应用进程的启动。