Android Zygote

1.Zygote

Zygote译为“受精卵”,是Android中SystemServer和几乎所有Java应用的孵化器。SystemServer和Java应用的父进程都是zygote。zygote是一个很重要的服务进程,没有zygote就没有Android,Android的启动也离不开zygote。

zygote的作用:

​ zygote作为Android的虚拟机,最主要的作用就是启动SystemServer进程和fork新的应用进程。

zygote的启动:

zygote是服务进程的别名,zygote是由rc文件定义init启动的服务。从rc文件中可以看出:

①zygote的进程优先级是最高的,priority被设成-20,主要是因为Android的启动非常依赖于SystemServer的启动,而SystemServer也是zygote fork出来的,因此需要将zygote优先级设成最高的。

②zygote在启动时创建了两个socket(zygote和usap_pool_primary),用于进程间的通信。

③zygote是Android非常重要的核心服务之一,当其因异常退出后,init会将其重新启动,并将一些相关的节点和服务重新设置。

zygote的启动实际上分成了两部分:SystemServer的启动、ZygoteServer的启动。两者前面是在同一个进程中执行的,当虚拟机创建完成后才正式分离。

zygote启动的前奏:

#frameworks/base/cmds/app_process/app_main.cpp

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

    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));

    …

    runtime.start( "com.android.internal.os.ZygoteInit", args, zygote);

    …

}

创建AppRuntime,并执行Java代码ZygoteInit类的main方法:

public static void main(String argv[]) { //已简化

    ZygoteServer zygoteServer = null;

    Runnable caller;

    Zygote.initNativeState(isPrimaryZygote);

    zygoteServer = new ZygoteServer( isPrimaryZygote);

    ……

    preload(bootTimingsTraceLog);

    if (startSystemServer) {

        Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

        if (r != null) {

            r.run();

            return;

        }

    }

    caller = zygoteServer.runSelectLoop(abiList);

    if (caller != null) {

        caller.run();

    }

}

ZygoteInit的main()方法是Android启动中的第一个Java进程的主方法。在ZygoteInit中,一般无特殊原因,都会调用preload()方法将Android Java层应用常用的资源预加装,其原因是:

①Android是基于Linux系统开发的,底层就是Linux操作系统,而Linux进程的fork机制有一个特点,就是写时拷贝机制,即fork出来的进程最初是共用一块内存,只有当发生写操作时,才会将对应的内存块进行拷贝修改,而一些只读的内存块则会所有fork出来的进程共享。

②preload()方法所加装的东西主要有以下几类:常用类文件、Resources资源、HALs资源、opengl、webview等。这些资源一般都是只读的,不会进行修改,而且是很多应用都可能会用到的。因此预先加载后所有由zygote fork出来的应用进程都能共用一块内存。

zygote启动时进行preload的作用是什么?zygote作为Android的虚拟机,很多应用(java/kotlin)的资源都是共用的,zygote利用了Linux操作系统的copy-on-write机制,预先加载了常用的资源,然后其他的应用通过fork后,所有的进程都能共享一份只能的资源,而不需要为每个应用进程都单独加载一份。

启动SystemServer:

SystemServer是通过forkSystemServer()方法fork出来并开始执行。

private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) {

    ZygoteArguments parsedArgs = null;

    int pid;

   /* Request to fork the system server process */

    pid = Zygote.forkSystemServer(

                parsedArgs.mUid, parsedArgs.mGid,

                parsedArgs.mGids,

                parsedArgs.mRuntimeFlags,

                null,

                parsedArgs.mPermittedCapabilities,

                parsedArgs.mEffectiveCapabilities);

    /* For child process */

    if (pid == 0) {

        if (hasSecondZygote(abiList)) {

            waitForSecondaryZygote(socketName);

        }

        zygoteServer.closeServerSocket();

        return handleSystemServerProcess( parsedArgs);

    }

    return null;

}

forkSystemServer()中主要做了两件事:①调用Zygote.forkSystemServer()方法去fork一个新的进程出来。②fork()后的子进程是SystemServer进程,则等待zygote的启动完成,并执行真正的SystemServer代码。

// Zygote.java

public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {

    ZygoteHooks.preFork();

    // Resets nice priority for zygote process.

    resetNicePriority();

    int pid = nativeForkSystemServer( uid, gid, gids, runtimeFlags, rlimits, permittedCapabilities, effectiveCapabilities);

    // Enable tracing as soon as we enter the system_server.

    if (pid == 0) {

        Trace.setTracingEnabled(true, runtimeFlags);

    }

    ZygoteHooks.postForkCommon();

    return pid;

}

ZygoteHooks.preFork():将Daemons线程关掉,虚拟机进行一些copy前的处理。

resetNicePriority():将进程的优先级设回普通的级别。

nativeForkSystemServer():调用native层方法去fork一个新的进程。该方法主要调用Linux的fork系统调用,fork一个新的进程,子进程的pid为0,父进程返回子进程的pid值。

ZygoteHooks.postForkCommon():重新启动Daemons线程,虚拟机进行copy后的处理。

fork操作是不会将进程中所有线程拷贝的,只会拷贝当前线程。

Daemons线程是指:①HeapTaskDaemon;②ReferenceQueueDaemon;③FinalizerDaemon;④FinalizerWatchdogDaemon。平时在trace文件(ANR或者其他方式获取的trace文件)中看到Java应用进程都会有这4个线程,这4个线程就是在这里创建的。

再回到ZygoteInit.forkSystemServer()方法,此时两个进程都会返回到此处,然后两个进程到这就分道扬镳了。SystemServer进程将ZygoteServer的socket关闭,然后调用handleSystemServerProcess()方法去执行SystemServer的源码。

handleSystemServerProcess()方法的核心代码:

createSystemServerClassLoader();

ClassLoader cl = sCachedSystemServerClassLoader;

 if (cl != null) {

      Thread.currentThread().setContextClassLoa der(cl);

 }

 return ZygoteInit.zygoteInit( parsedArgs.mTargetSdkVersion,parsedArgs.mRemainingArgs, cl);

先获取classloader,并将其设置为root classloader。然后调用ZygoteInit.zygoteInit()方法去执行。

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {

    RuntimeInit.commonInit();

    ZygoteInit.nativeZygoteInit();

    return RuntimeInit.applicationInit( targetSdkVersion, argv, classLoader);

}

ZygoteInit.nativeZygoteInit()方法为进程创建Binder的环境(ProcessStatae)。

RuntimeInit.applicationInit()方法则会去执行传参进来的类的main()方法,这里就是:com.android.server.SystemServer。

ZygoteInit.forkSystemServer()返回一个runnable,返回到ZygoteInit.main()方法后,SystemServer进程就会继续执行这个runnable。

zygote在fork进程后,使用runnable的方式返回到main()方法后才执行的原因?减少线程堆栈的长度,因为fork后进行执行的内容与之前zygote的堆栈内容并无关系,因此不需要为每个进程都保留前面的堆栈信息,而且还能减少进程的堆栈容量限制。

ZygoteServer.runSelectLoop:

当zygote进程返回到main()方法后,就会继续执行ZygoteServer.runSelectLoop()方法,从名字和注释来看,这个方法应该是一个死循环,是不断进行循环执行命令的方法。

runSelectLoop()方法主要做两件事:

①每次循环都重新构建监听文件列表,主要是ZygoteServer的socket文件(ZygoteServer的socket和其他应用进程连接过来的socket)和usap文件节点。

②监听文件列表,并从中获取命令执行。

一张图看看Zygote的启动流程:

dbeb367eb65049e0889173200bd8aaf0.png

猜你喜欢

转载自blog.csdn.net/zenmela2011/article/details/125330521