认识Zygote

485 阅读4分钟

Zygote的父进程是init进程,他孵化了SystemServer进程,以及我们的应用进程。

一、Zygote作用

功能主要是

:启动安卓虚拟机DVM

:启动SystemServer(Android系统进程)

:孵化应用进程

:加载 常用类 JNI函数 主题资源 共享库 等 

Zygote进程和系统其他进程的关系如图所示:

二、Zygote进程启动和应用进程启动

如图所示:

1.Zygote进程启动流程

Zygote是由init进程启动的,init进程是Linux系统启动后用户空间的第一个进程, 首先会去加载init.rc配置文件,然后启动其中定义的系统服务(Zygote,ServiceManager等), Init进程创建Zygote时,会调用app_main.cpp的main() 方法, 启动Zygote后,启动安卓虚拟机,接着在native层中通过jni调用java层的ZygoteInit的main()。

<!--app_main.cpp
int main(int argc, char* const argv[])
{
    //  创建Android运行时对象
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // 代码省略...
    
    // 调用AppRuntime.start方法,
    // 而AppRuntime是AndroidRuntime的子类,并且没有重写start方法
    // 因此调用的是AndroidRuntime的start方法
    runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}
-->

这里一共就做了两件事,第一件创建AppRuntime,第二件调用start方法,详细看一下start方法:

<!--
/*
 * AndroidRuntime.cpp
 * Start the Android runtime. 
 */
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    /* start the virtual machine */
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }

    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {
        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.
     */
    jmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
    env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
-->

startVM -- 启动Java虚拟机 

startReg -- 注册JNI 通过JNI调用Java方法,执行com.android.internal.os.ZygoteInit 的 main 方法。

ZygoteInit .main主要干了4个事情,如下:

<!--
 /*frameworks/base/core/java/com/android/internal/os/ZygoteInit.java*/
 public static void main(String[] argv) {
        ZygoteServer zygoteServer = null;
        ...
        try {
            ...
            // 1.preload提前加载框架通用类和系统资源到进程,加速进程启动
            preload(bootTimingsTraceLog);
            ...
            // 2.创建zygote进程的socket server服务端对象
            zygoteServer = new ZygoteServer(isPrimaryZygote);
            ...
	    // 3.启动SystemServer(Android系统进程)
	    forkSystemServer
	    ...
            // 4.进入死循环,等待AMS发请求过来
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            ...
        } finally {
            ...
        }
        ...
	caller.run();//执行MethodAndArgsCaller包装后的runnable
    }
-->

1.创建了ZygoteServer:这是一个Socket相关的服务,目的是进行跨进程通信。 

2.预加载preload:预加载相关的资源。 

3.创建SystemServer进程: 通过forkSystemServer分裂出了两个进程,一个Zygote进程,一个SystemServer进程。而且由于是分裂的, 所以新分裂出来的进程也拥有虚拟机,也能调用JNI,也拥有预加载的资源,也会执行后续的代码。 

4.执行runSelectLoop():内部是一个while(true)循环,等待AMS创建新的进程的請求消息。(想想Looper.loop()) 

2.Zygote启动应用进程流程

zygote进程通过Socket监听接收AMS的请求,fork创建子应用进程,然后pid为0时进入子进程空间,然后在ZygoteInit#zygoteInit中完成进程的初始化动作。

先看一下ZygoteServer.runSelectLoop

<!--
 /*frameworks/base/core/java/com/android/internal/os/ZygoteServer.java*/
 Runnable runSelectLoop(String abiList) {
     // 进入死循环监听
     while (true) {
        while (--pollIndex >= 0) {
           if (pollIndex == 0) {
             ...
           } else if (pollIndex < usapPoolEventFDIndex) {
             // Session socket accepted from the Zygote server socket
             // 得到一个请求连接封装对象ZygoteConnection
             ZygoteConnection connection = peers.get(pollIndex);
             // processCommand函数中处理AMS客户端请求
             final Runnable command = connection.processCommand(this, multipleForksOK);
             ...
           }
        }
     }
 }
 -->

再通過ZygoteConnection中处理AMS创建新应用进程的请求。

 <!--
 //ZygoteConnection.java
 Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) {
         ...
         // 1.fork创建应用子进程
         pid = Zygote.forkAndSpecialize(...);
         try {
             if (pid == 0) {
                 ...
                 // 2.pid为0,当前处于新创建的子应用进程中,处理请求参数
                 return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
             } else {
                 ...
                 handleParentProc(pid, serverPipeFd);
             }
          } finally {
             ...
          }
 }
 
  private Runnable handleChildProc(ZygoteArguments parsedArgs,
            FileDescriptor pipeFd, boolean isZygote) {
        ...
        // 关闭从父进程zygote继承过来的ZygoteServer服务端地址
        closeSocket();
        ...
        if (parsedArgs.mInvokeWith != null) {
           ...
        } else {
            if (!isZygote) {
                // 继续进入ZygoteInit#zygoteInit继续完成子应用进程的相关初始化工作
                return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                        parsedArgs.mDisabledCompatChanges,
                        parsedArgs.mRemainingArgs, null /* classLoader */);
            } else {
                ...
            }
        }
    }
-->

通过调用 Zygote.forkAndSpecialize()函数来创建子进程,会有一个返回值pid,分别在子进程和父进程各返回一次, 子进程返回 0 ,父进程返回1,通过判断pid为0还是1来判断当前是是父进程还是子进程;默认子进程继承父进程是继承了父进程的一切资源 分叉后的进程会将socket停掉并重新初始化一些数据,但preload的资源和类保和VM留了下来,应用进程继承了Zygote进程所创建的虚拟机, 应用进程的在使用的时候就不需要再去创建,自此新的进程和zygote进程分道扬镳。  

注意:其中包括应用进程的主线程也是在这里从zygote进程继承而来的,应用进程的主线程并不是自己主动创建的新线程。

Zygote启动应用进程的时候不管父进程中有多少个线程,子进程在创建的时候都只有一个线程,对于子进程来说,多出现的线程在子进程中都不复存在, 因为如果其他线程也被复制到子进程,这时在子进程中就会存在一些问题,有时程序在执行的过程中可能会形成死锁,状态不一致等,所以比较安全的做法是在创建子进程的时候,只保留父进程的 主线程,其他都在暂停(此时线程资源是释放的所以不会继承到子进程),子进程启动完后再重启这些线程。

ZygoteInit.zygoteInit 方法完成应用进程初始化:

<!--
/*frameworks/base/core/java/com/android/internal/os/ZygoteInit.java*/
public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        ...
        // 原生添加名为“ZygoteInit ”的systrace tag以标识进程初始化流程
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();
        // 1.RuntimeInit#commonInit中设置应用进程默认的java异常处理机制
        RuntimeInit.commonInit();
        // 2.ZygoteInit#nativeZygoteInit函数中JNI调用启动进程的binder线程池
        ZygoteInit.nativeZygoteInit();
        // 3.RuntimeInit#applicationInit中反射创建ActivityThread对象并调用其“main”入口方法
        return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
                classLoader);
 }
-->

1.设置应用进程默认的java异常处理机制(可以实现监听、拦截应用进程所有的Java crash的逻辑);

2.JNI调用启动进程的binder线程池(注意应用进程的binder线程池资源是自己创建的并非从zygote父进程继承的);

3.通过反射创建ActivityThread对象并调用其“main”入口方法。

最后再看看RuntimeInit.applicationInit做了啥:

<!--
 /*frameworks/base/core/java/com/android/internal/os/RuntimeInit.java*/
 protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
            String[] argv, ClassLoader classLoader) {
        ...
        // 结束“ZygoteInit ”的systrace tag
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        // Remaining arguments are passed to the start class's static main
        return findStaticMain(args.startClass, args.startArgs, classLoader);
  }
  
  protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;
        try {
            // 1.反射加载创建ActivityThread类对象
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
            ...
        }
        Method m;
        try {
            // 2.反射调用其main方法
            m = cl.getMethod("main", new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
            ...
        } catch (SecurityException ex) {
            ...
        }
        ...
        // 3.触发执行以上逻辑
        return new MethodAndArgsCaller(m, argv);
    }
-->

主要就是调用ActivityThread.main方法,从此进入ActivityThread中。

三、参考资料

【Zygote进程的启动 --学习笔记】 blog.csdn.net/qq\_4223721…

【说说你对zygote的理解?】www.cnblogs.com/rxh1050/p/1…

【Zygote Fork机制与资源预加载】www.jianshu.com/p/be384613c…