android6.0源码分析之Zygote进程分析

Posted 古冥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android6.0源码分析之Zygote进程分析相关的知识,希望对你有一定的参考价值。

android6.0源码分析之Runtime的初始化一文中,对Zygote进程的初期的Runtime初始化过程进行了分析,在Runtime启动结束后,会对Zygote进程进行初始化,其它Java进程都需要从Zygote进程来fork,而Zygote的初始化是从ZygoteInit的main函数开始的:

//ZygoteInit.java
public static void main(String argv[]) 
    try 
        ...
        //注册zygote socket
        registerZygoteSocket(socketName);
        ...
        //加载资源以及类
        preload();
        ...
        // Disable tracing so that forked processes do not inherit stale tracing tags from
        // Zygote.
        Trace.setTracingEnabled(false);
        //启动system server进程
        if (startSystemServer) 
            startSystemServer(abiList, socketName);
        

        Log.i(TAG, "Accepting command socket connections");
        //循环等待创建进程的socket请求
        runSelectLoop(abiList);
        //关闭server socket
        closeServerSocket();
     catch (MethodAndArgsCaller caller) //截取MethodAndArgsCaller异常
        //执行新进程的main函数
        caller.run();
     catch (RuntimeException ex) 
        Log.e(TAG, "Zygote died with exception", ex);
        closeServerSocket();
        throw ex;
    

首先它会对启动参数进行解析,得到是否需要启动systemserver,或者得到ABI_LIST_ARG参数和socketName参数等,然后则会调用registerZygoteSocket来创建一个LocalServerSocket来与以后需要systemServer创建进程时进行通信,接着调用preload来对VM虚拟机中的DEX类等资源进行加载,然后会调用runSelectLoop来进行循环等待,最后会截取ZygoteInit中抛出的MethodAndArgsCaller异常,并在异常处理时,调用新建进程的main方法实现新进程的启动。下面将对这四个主要的调用分别进行分析。


1、registerZygoteSocket方法分析

//ZygoteInit.java
private static void registerZygoteSocket(String socketName) 
    if (sServerSocket == null) //判断Zygote socket是否已创建
        int fileDesc;
        final String fullSocketName = android_SOCKET_PREFIX + socketName;
        try 
            String env = System.getenv(fullSocketName);
            //获取文件描述符
            fileDesc = Integer.parseInt(env);
         catch (RuntimeException ex) 
            throw new RuntimeException(fullSocketName + " unset or invalid", ex);
        

        try 
            FileDescriptor fd = new FileDescriptor();
            fd.setInt$(fileDesc);
            //创建Zygote socket,它会在runSelectLoop中进行循环等待
            sServerSocket = new LocalServerSocket(fd);
         catch (IOException ex) 
            throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);
        
    

由代码可知,它创建了一个LocalServerSocket,并且它会在runSelectLoop中阻塞等待socket请求,至于runSelectLoop稍后会进行分析。


2、preload方法分析

//ZygoteInit.java
static void preload() 
    Log.d(TAG, "begin preload");
    //加载类
    preloadClasses();
    //加载资源
    preloadResources();
    //加载OpenGL
    preloadOpenGL();
    //加载公共库
    preloadSharedLibraries();
    //加载文本资源
    preloadTextResources();
    // Ask the WebViewFactory to do any initialization that must run in the zygote process,
    // for memory sharing purposes.
    WebViewFactory.prepareWebViewInZygote();
    Log.d(TAG, "end preload");

由代码可知,preload方法主要就是进行类,资源,公共库以及相关的文本资源的加载,主要分析其中的preloadClasses以及preloadSharedLibraries方法:

//ZygoteInit.java
private static void preloadClasses() 
    //获取虚拟机运行时
    final VMRuntime runtime = VMRuntime.getRuntime();

    InputStream is;
    try 
        //初始化文件输入流,路径为"/system/etc/preloaded-classes"
        is = new FileInputStream(PRELOADED_CLASSES);
     catch (FileNotFoundException e) 
        return;
    
    ...
    // Alter the target heap utilization.  With explicit GCs this
    // is not likely to have any effect.
    float defaultUtilization = runtime.getTargetHeapUtilization();
    runtime.setTargetHeapUtilization(0.8f);

    try 
        //通过BufferReader来读取输入流
        BufferedReader br = new BufferedReader(new InputStreamReader(is), 256);

        int count = 0;
        String line;
        //逐行处理
        while ((line = br.readLine()) != null) 
            // Skip comments and blank lines.
            line = line.trim();
            if (line.startsWith("#") || line.equals("")) 
                continue;
            

            try 
                ...
                //加载并显示地初始化给定的类
                Class.forName(line, true, null);
                count++;
             catch (ClassNotFoundException e) 
                ...
            
        
     catch (IOException e) 
        Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
     finally 
        IoUtils.closeQuietly(is);
        // Restore default.
        runtime.setTargetHeapUtilization(defaultUtilization);
        //将类,域,方法等填充到dex缓存中
        runtime.preloadDexCaches();
    

首先,根据”/system/etc/preloaded-classes”来,逐行解析里面的类,最后再将预加载的类填充到VM的dex缓存中,它会调用VMRuntime库的本地方法preloadDexCaches来填充,此方法的具体实现在VM库中。
接下来看preloadSharedLibraries方法:

//ZygoteInit.java
private static void preloadSharedLibraries() 
    Log.i(TAG, "Preloading shared libraries...");

    System.loadLibrary("android");
    System.loadLibrary("compiler_rt");
    System.loadLibrary("jnigraphics");

如代码,它主要进行shared库android,compiler_rt以及jnigraphics的加载。


3、 startSystemServer方法分析

System Server进程是android系统的非常重要的进程,它在Zygote的启动之后就必须启动,所以startSystemServer方法也是Zygote初始化中非常重要的调用:

//ZygoteInit.java
private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException 
    ...
    ZygoteConnection.Arguments parsedArgs = null;
    int pid;

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

        //fork一个systemServer进程
        pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids,
                parsedArgs.debugFlags,null,parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
     catch (IllegalArgumentException ex) 
            throw new RuntimeException(ex);
    

    //处理子进程
    if (pid == 0) 
        if (hasSecondZygote(abiList)) 
            waitForSecondaryZygote(socketName);
        
        //处理system server进程
        handleSystemServerProcess(parsedArgs);
    
    return true;

它首先fork一个systemserver进程,然后再对子进程systemserver进行相关处理,首先来看forkSystemServer方法:

//Zygote.java
public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,int[][] rlimits, 
        long permittedCapabilities, long effectiveCapabilities) 
    VM_HOOKS.preFork();
    //调用native方法
    int pid = nativeForkSystemServer(uid, gid, gids, debugFlags, rlimits, permittedCapabilities, 
            effectiveCapabilities);
    // Enable tracing as soon as we enter the system_server.
    if (pid == 0) 
        Trace.setTracingEnabled(true);
    
    VM_HOOKS.postForkCommon();
    return pid;

这里将通过JNI调用,进入Native代码层,接着分析nativeForkSystemServer方法,它对应的是Native方法是com_android_internal_os_Zygote_nativeForkSystemServer:

//com_android_internal_os_Zygote.cpp
static jint com_android_internal_os_Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid, 
        gid_t gid, jintArray gids,jint debug_flags, jobjectArray rlimits, jlong
        permittedCapabilities,jlong effectiveCapabilities) 
    //fork 相应进程
    pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,debug_flags, rlimits,
        permittedCapabilities, effectiveCapabilities,MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, 
        NULL,NULL, NULL);
    if (pid > 0) 
        gSystemServerPid = pid;

        int status;
        if (waitpid(pid, &status, WNOHANG) == pid) 
            //system server进程died,终止运行时,重启zygote进程
            RuntimeAbort(env);
        
    
    return pid;

它调用了ForkAndSpecializeCommon方法来进行进程的创建,最后对创建结果进行了相应的处理,这里与创建普通进程的区别就是,需要对子进程进行检查,判断system server进程是否died,如果died,则会终止runtime,并重启Zygote进程,接着分析ForkAndSpecializeCommon方法:

//com_android_internal_os_Zygote.cpp
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
        jint debug_flags, jobjectArray javaRlimits,jlong permittedCapabilities, jlong 
        effectiveCapabilities,jint mount_external,jstring java_se_info, jstring java_se_name,
        bool is_system_server, jintArray fdsToClose,jstring instructionSet, jstring dataDir) 
    SetSigChldHandler();
    //fork一个进程
    pid_t pid = fork();

    if (pid == 0) //处理子进程
        // The child process.
        gMallocLeakZygoteChild = 1;
        ...
        SetGids(env, javaGids);

        SetRLimits(env, javaRlimits);

        ...
        rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
        ...
        if (se_info_c_str != NULL) 
            //设置线程名称
            SetThreadName(se_name_c_str);
        
        ...
        //此处会post一个forkChild的消息
        env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
            is_system_server ? NULL : instructionSet);
     else if (pid > 0) 
        // the parent process
    
    return pid;

它首先fork一个子进程,然后对子进程进行处理,最后会post一个forkChild的消息出去,而在ZygoteInit中会对forksystemserver的子进程进行处理,所以,接着看handleSystemServerProcess方法:

//ZygoteInit.java
private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs)
        throws ZygoteInit.MethodAndArgsCaller 
    ...
    if (parsedArgs.invokeWith != null) 
        String[] args = parsedArgs.remainingArgs;

        if (systemServerClasspath != null) 
            String[] amendedArgs = new String[args.length + 2];
            amendedArgs[0] = "-cp";
            amendedArgs[1] = systemServerClasspath;
            System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2,
                parsedArgs.remainingArgs.length);
        

        WrapperInit.execApplication(parsedArgs.invokeWith,parsedArgs.niceName,
            parsedArgs.targetSdkVersion,VMRuntime.getCurrentInstructionSet(), null, args);
     else 
        ClassLoader cl = null;
        if (systemServerClasspath != null) 
            //获取类加载器
            cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
            Thread.currentThread().setContextClassLoader(cl);
        

        //根据参数来启动System server进程
        RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
    

由代码可知,它主要会调用RuntimeInit类的zygoteInit方法来对子进程system server进行启动的处理:

//RuntimeInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller 
    ...
    commonInit();
    nativeZygoteInit();
    applicationInit(targetSdkVersion, argv, classLoader);

其中commonInit主要就是进行一些系统属性的初始化或者重置,这里重点分析nativeZygoteInit和applicationInit方法。


3.1 nativeZygoteInit方法分析

nativeZygoteInit是Native方法,通过JNI调用,它的实现是com_android_internal_os_RuntimeInit_nativeZygoteInit方法:

//AndroidRuntime.cpp
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)

    gCurRuntime->onZygoteInit();

由代码可知,这里会回调App_main.cpp中的onZygoteInit方法:

//App_main.cpp
virtual void onZygoteInit()
    sp<ProcessState> proc = ProcessState::self();
    ALOGV("App process: starting thread pool.\\n");
    proc->startThreadPool();

这里主要就是在进程里面启动线程池,该线程池,是为System server进程创建的,此线程池会为Binder提供支持等,这里不做分析。


3.2 ApplicationInit方法分析

//RuntimeInit.java
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller 

    nativeSetExitWithoutCleanup(true);

    VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
    VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

    final Arguments args;
    try 
        args = new Arguments(argv);
     catch (IllegalArgumentException ex) 
        return;
    
    //invoke system server的main方法
    invokeStaticMain(args.startClass, args.startArgs, classLoader);

由代码可知,它会根据启动的参数以及类加载器来调用InvokeStaticMain方法:

//RuntimeInit.java
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller 
    Class<?> cl;

    try 
        cl = Class.forName(className, true, classLoader);
     catch (ClassNotFoundException ex) ...

    Method m;
    try 
        //获取systemserver的main方法,main方法是用来开始systemserver进程的
        m = cl.getMethod("main", new Class[]  String[].class );
     catch (NoSuchMethodException ex) ...
    ...
    //抛出MethodAndArgsCaller异常,而此异常在ZygoteInit的main方法中会进行扑捉,异常的处理稍后再分析
    throw new ZygoteInit.MethodAndArgsCaller(m, argv);

由代码可知,首先,通过Java的反射机制,借助传入的参数以及类加载器,从而获取systemserver进程的main方法,最后再抛出一个MethodAndArgsCaller的异常,而此异常在ZygoteInit的main方法的最后会进行截取,具体的异常处理稍后在第四节最后再分析,因为普通进程的创建也是通过抛出MethodAndArgsCaller的方法来启动的,至此startsystemserver方法就分析结束了。


4、runSelectLoop方法分析

//ZygoteInit.java
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller 
    //初始化文件描述符组合ZygoteConnection连接组
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

    fds.add(sServerSocket.getFileDescriptor());
    peers.add(null);

    while (true) //循环等待ZygoteSocket请求并进行相应的处理
        ...
        for (int i = pollFds.length - 1; i >= 0; --i) 
            if ((pollFds[i].revents & POLLIN) == 0) 
                continue;
            
            if (i == 0) 
                //这里阻塞等待创建进程的Zygote socket请求
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
             else 
                //执行ZygoteConnection连接
                boolean done = peers.get(i).runOnce();
                if (done) 
                    //处理结束,则将此连接移除
                    peers.remove(i);
                    fds.remove(i);
                
            
        
    

此方法将会永无休止的进行执行,因为Zygote作为Java域的第一个进程,所有的进程都是由它进行fork的,在android的生命过程中,会不断有ZygoteConnection请求,所以,看runSelectLoop方法,它首先是调用acceptCommandPeer方法来获取一个ZygoteConnection连接,然后再调用ZygoteConnection的runOnce方法来执行连接处理,首先来看acceptCommandPeer方法:

//ZygoteInit.java
private static ZygoteConnection acceptCommandPeer(String abiList) 
    try 
        //创建ZygoteConnection连接,注意socket的accept阻塞接收请求
        return new ZygoteConnection(sServerSocket.accept(), abiList);
     catch (IOException ex) 
        throw new RuntimeException("IOException during accept()", ex);
    

由代么可知,这里是阻塞的,只有在ZygoteInit的main方法中最初注册的socket有请求时,才会执行,并会根据得到的socket连接来创建一个ZygoteConnection,所以,来看它的构造函数:

// ZygoteConnection.java
ZygoteConnection(LocalSocket socket, String abiList) throws IOException 
    mSocket = socket;
    this.abiList = abiList;
    //获取socket输出流
    mSocketOutStream = new DataOutputStream(socket.getOutputStream());
    //获取socket输入流
    mSocketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()), 256);
    //设置超时
    mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);

    try 
        peer = mSocket.getPeerCredentials();
     catch (IOException ex) 
        throw ex;
    

此构造函数会创建socket的stream通道,至此ZygoteConnection就创建好了,接着看它的runOnce方法,socket请求一次,runOnce会执行一次:

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller 
    ...
    int pid = -1;
    FileDescriptor childPipeFd = null;
    FileDescriptor serverPipeFd = null;

    try 
        parsedArgs = new Arguments(args);
        if (parsedArgs.abiListQuery) 
            return handleAbiListQuery();
        
        ...
        int [] fdsToClose =  -1, -1 ;
        FileDescriptor fd = mSocket.getFileDescriptor();
        ...
        fd = ZygoteInit.getServerSocketFileDescriptor();
        //fork 进程
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,parsedArgs.appDataDir);
     catch (ErrnoException ex) 
        ...
    

    try 
        if (pid == 0) 
            // in child
            IoUtils.closeQuietly(serverPipeFd);
            serverPipeFd = null;
            //对子进程做相应处理
            handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
            return true;
         else 
            IoUtils.closeQuietly(childPipeFd);
            childPipeFd = null;
            //对父进程做相应处理
            return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
        
     finally 
        IoUtils.closeQuietly(childPipeFd);
        IoUtils.closeQuietly(serverPipeFd);
    

这里,就是创建普通进程的通道,它的分析类似于startSystemServer方法,它在最后同样会进入Java层的子进程的处理handleChildProc方法,最后还是会获取到创建进程的main方法,并且同样也是会抛出一个MethodAndArgsCaller的异常。
不管是创建systemServer进程还是创建普通进程,在处理其子进程时,都会获取创建子进程的main方法,同时最后会抛出一个MethodAndArgsCaller异常,为什么要抛出异常呢,此异常是在ZygoteInit的main函数中调用的,而main函数位于堆栈的最顶层,如果不采用抛异常的方式,而是在invokestaticMain方法中直接执行新建进程的main方法,则会浪费之前函数调用说占用的调用堆栈。接下来对MethodAndArgsCaller的run方法进行分析:

//ZygoteInit.java
public void run() 
    try 
        mMethod.invoke(null, new Object[]  mArgs );
     catch (IllegalAccessException ex) 
            ...
    

其中,mMethod为构造MethodAndArgsCaller时,传入的方法,即之前startSystemServer或者runSelectLoop函数中获得的新建进程的main方法,所以run方法的主要作用就是执行此main方法,即进入新建进程。至此,Zygote进程分析结束,它的主要功能有初始化Runtime、fork system server进程以及通过循环等待Zygote socket的请求,来处理普通进行的创建。下面将给出时序图:


以上是关于android6.0源码分析之Zygote进程分析的主要内容,如果未能解决你的问题,请参考以下文章

Android6.0 SystemServer进程

android6.0源码分析之Camera API1.0初始化

android6.0源码分析之Camera API2.0下的video流程分析

android6.0源码分析之Camera API2.0下的video流程分析

Android系统启动-zygote篇

android6.0源码分析之Camera API2.0下的Capture流程分析