Android P (9.0) 之Zygote进程源码分析

 

init进程是用户空间的第一个进程,而zygote进程则是第一个java进程。zygote进程是init进程的子进程,init进程通过解析rc文件,运行了zygote进程

zygote是Android系统中一个相当重要的进程,它的主要功能就是执行Android应用程序。在Android系统中运行新的应用,如同卵子受精分裂一样,需要跟Zygote进程(拥有应用程序运行时所需要的各种元素和条件,如:虚拟机等)结合才能执行。

Zygote进程
zygote进程运行时,会初始化Art(或者Dalvik)虚拟机,并启动它Android的应用程序是由Java编写的,它们不能直接以本地进程的形式运行在linux上,只能运行在虚拟机中。并且,每个应用程序都运行在各自的虚拟机中,如果应用程序每次运行都要重新初始化并启动虚拟机,这个过程会耗费相当长时间。因此,在Android中,应用程序运行前,zygote进程通过共享已运行的虚拟机的代码与内存信息,缩短应用程序运行所耗费的时间。并且,它会事先将应用程序要使用的Android Framework中的类和资源加载到内存中,并组织形成所用资源的链接信息。新运行的Android应用程序在使用所需资源时不必每次重新形成资源的链接信息,这回节省大量时间,提高程序运行速度。

那么,在Linux系统中创建并运行一个进程,与在Android系统中通过zygote来创建并运行一个应用程序,两者究竟有何不同呢?

以下图片均参考自《Android框架揭秘》一书(实在不想自己画了 0.0)


如上图所示,父进程A调用fork()函数创建新的子进程A’。新创建的进程A’共享父进程的内存结构信息与库连接信息(COW 写时拷贝技术)。而后子进程A’调用exec(‘B’),将新进程B的代码加载到内存中。此时,将重新分配内存(因为之前是共享的),以便运行被装载的B程序,接着形成新的库连接信息,以供B进程单独使用。


如上图所示,zygote进程调用fork()函数创建出zygote’子进程,子进程zygote’ 共享父进程zygote的代码区与链接信息。注意,新的Android应用程序A 并非通过exec() 来重新装载已有进程的代码区,而是动态的加载到复制的虚拟机上(虚拟空间的复制,物理空间还是同一个)。而后,zygote’进程将执行流程交给应用程序A类的方法,Android应用程序开始运行。新生成的应用程序A会使用已有zygote进程的库与资源的链接信息,所以运行速度很快。


如上图所示,zygote启动后,初始化并运行art(或者dalvik)虚拟机,而后将需要的类与资源加载到内存中。随后调用fork()创建出zygote’子进程,接着zygote’子进程动态加载并运行Android应用程序A。运行的应用程序A会使用zygote已经初始化并启动运行的虚拟机代码,通过使用已记载至内存中的类与资源来加快运行速度。

COW (Copy on write)
在创建新进程后,新进程会共享父进程的内存空间,即新的子进程会复制所有与父进程内存空间相关的信息并使用它。COW就是针对内存复制的一种技术。一般来说,复制内存的开销非常大,因此创建的子进程在引用父进程的内存空间时,不要进行复制,而要直接共享父进程的内存空间。而当需要修改共享内存中的信息时,子进程才会将父进程中相关的内存信息复制到自身的内存空间,并进行修改,这就是COW(Copy on write)技术。

在fork之后exec之前两个进程用的是相同的物理空间(内存区),子进程的代码段、数据段、堆栈都是指向父进程的物理空间,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个

Zygote进程源码分析
由app_process运行ZygoteInit class
zygote由java编写而成,不能直接由init进程启动运行。若想执行zygote类,必须先创建虚拟机,然后在虚拟机上运行ZygoteInit类。执行这一任务的就是app_process程序。
下面我们开始分析zygote进程的启动流程:
/system/core/rootdir/init.rc

import /init.$(ro.zygote).rc

如果是64位系统,$(ro.zygote)的值为"zygote64"
/system/core/rootdir/init.zygote64.rc

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    ...
    class main
    user root
    socket zygote stream 660 root system //创建/dev/socket/zygote套接字
    ...

init进程解析上面的init.zygote64.rc文件后,会执行/system/bin/app_process64进程,并且生成了/dev/socket/zygote套接字,ZygoteInit会用该套接字来接收AMS发来的创建新应用程序的请求。
init进程分析并执行rc文件流程可以看看我的上一篇文章Init进程的启动流程。

app_process64程序的main函数入口如下:

frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
    ......
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    ......
    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    ......

    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } 
        ......
    }

    ......
    if (zygote) {
        //zygote进程
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        //普通java进程
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    }
}

如果是zygote进程就走ZygoteInit代码,如果是普通java进程就走RuntimeInit代码,例如常用的am命令,/system/bin/am实际上是一个shell脚本,查看里面的代码可知是通过app_process来启动普通java进程,然后和AMS进行通信。
frameworks/base/core/jni/AndroidRuntime.cpp

//AppRuntime继承自AndroidRuntime
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
    /* start the virtual machine */
    JniInvocation jni_invocation;
    // ① 加载指定的虚拟机的库(art或者dalvik)
    jni_invocation.Init(NULL); 
    JNIEnv* env;
    // ② 创建java虚拟机
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }

    // ③ 注册JNI函数
    if (startReg(env) < 0) {
        return;
    }

    ......
    // ④ 正式进入java的世界,调用ZygoteInit.java的main方法
    jclass startClass = env->FindClass(slashClassName);
    ......
    jmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
    ......
    env->CallStaticVoidMethod(startClass, startMeth, strArray);
    ......
}

①: 加载虚拟机的库(art或者dalvik),并且函数指针指向库对应的函数(如:JNI_CreateJavaVM函数)
libnativehelper/JniInvocation.cpp

bool JniInvocation::Init(const char* library) {
  //获取要加载库的名称
  library = GetLibrary(library, buffer);

  //动态加载对应的虚拟机库
  handle_ = dlopen(library, RTLD_NOW);
  ......
  //JNI_CreateJavaVM_函数指针指向虚拟机库中的JNI_CreateJavaVM函数
  if (!FindSymbol(reinterpret_cast(&JNI_CreateJavaVM_),
                  "JNI_CreateJavaVM")) {
    return false;
  }
  .......
  return true;
}

GetLibraray()函数获取动态库的名称(libart.so或者libdalvik .so),dlopen()函数动态加载虚拟机库,RTLD_NOW表示返回之前立即链接所有未定位的符号,FindSysmbol()函数指针指向对应的函数。
libnativehelper/JniInvocation.cpp

static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib.2";
static const char* kDebuggableSystemProperty = "ro.debuggable";
static const char* kDebuggableFallback = "0";  // Not debuggable.
static const char* kLibraryFallback = "libart.so";

const char* JniInvocation::GetLibrary(const char* library, char* buffer) {
    char debuggable[PROPERTY_VALUE_MAX];
    //获取"ro.debuggable"的属性值
    property_get(kDebuggableSystemProperty, debuggable,kDebuggableFallback);

    if (strcmp(debuggable, "1") != 0) {
        //如果不是debug设备,library的值为"libart.so"
        library = kLibraryFallback;
    } else {
        //如果是debug设备,library的值为"persisit.sys.dalvik.vm.lib.2"的属性值
        property_get(kLibrarySystemProperty, buffer, kLibraryFallback);
    }

    return library;
}
: 创建java虚拟机
frameworks/base/core/jni/AndroidRuntime.cpp

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
    JavaVMInitArgs initArgs;
    ......
    initArgs.version = JNI_VERSION_1_4;
    initArgs.options = mOptions.editArray();
    initArgs.nOptions = mOptions.size();
    initArgs.ignoreUnrecognized = JNI_FALSE;

    ......
    //创建java虚拟机
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
        ALOGE("JNI_CreateJavaVM failed\n");
        return -1;
    }

    return 0;
}

JNI_CreateJavaVM()是JniInvocation.cpp中的函数,会调用到①中所说的JNI_CreateJavaVM_()函数指针,最后调用到相应虚拟机动态库中的JNI_CreateJavaVM()函数,创建对应的虚拟机。initArgs表示传入的虚拟机参数。
③: 注册JNI本地函数
我们先来熟悉一下几个数据结构:
frameworks/base/core/jni/AndroidRuntime.cpp

#define REG_JNI(name)     { name }

struct RegJNIRec {
    int (*mProc)(JNIEnv*);
};
......
static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_com_android_internal_os_RuntimeInit),
    REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
    REG_JNI(register_android_os_SystemClock),
    REG_JNI(register_android_util_EventLog),
    REG_JNI(register_android_util_Log),
    ......
};

gRegJNI是RegJNIRec结构体数组,然后数组通过REG_JNI宏定义初始化。例如gRegJNI第一个元素的初始化,等同于:

gRegJNI[0] = {register_com_android_internal_os_RuntimeInit};

那么gRegJNI[0]中RegJNIRec结构体的mProc函数指针就指向上面的函数register_com_android_internal_os_RuntimeInit,数组中的其它元素也同理。下面我们继续分析JNI本地函数的注册。
frameworks/base/core/jni/AndroidRuntime.cpp

int AndroidRuntime::startReg(JNIEnv* env)
{
    ......
    //注册JNI本地函数,将gRegJNI数组传入
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        return -1;
    }
    ......
    return 0;
}

static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
    //遍历执行gRegJNI数组中元素的mProc函数
    //(mProc是函数指针,数组初始化的时候已经指向指定的函数)
    for (size_t i = 0; i < count; i++) {
        if (array[i].mProc(env) < 0) {
            return -1;
        }
    }
    return 0;
}

startReg会调用register_jni_procs遍历调用gRegJNI数组中的mProc函数,以第一个元素为例,gRegJNI[0].mProc(env)由上面的分析可知调用的实际是register_com_android_internal_os_RuntimeInit(env)函数。
frameworks/base/core/jni/AndroidRuntime.cpp

int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
{
    const JNINativeMethod methods[] = {
        { "nativeFinishInit", "()V",
            (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
        ......
    };
    //最后会调用到(*env)->RegisterNative()注册
    return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
        methods, NELEM(methods));
}

用上面的代码可知,nativeFinishInit函数映射了com_android_internal_os_RuntimeInit_nativeFinishInit函数,当java调用nativeFinishInit函数时,实际会调用到c/c++中的com_android_internal_os_RuntimeInit_nativeFinishInit函数。有读者可能会问,java调用jni函数时,虚拟机会自动映射,为什么要自己映射呢?如果jni函数比较少,这么做确实可行,但是我们可以看到gRegJNI数组是很庞大的,需要映射的函数也很多,如果全部交给虚拟机映射,会大大降低虚拟机的执行性能,所以我们提前注册JNI函数,虚拟机就可以直接找到对应的函数进行调用。
④: 通过反射调用ZygoteInit.java的main函数,正式进入java的世界。env->FindClass获取ZygoteInit类的类型,env->GetStaticMethodID获取函数main的函数id,env->CallStaticVoidMethod调用ZygoteInit.java的静态函数main。

ZygoteInit类的功能
至此,我们已经创建好了虚拟机,并且将ZygoteInit类装载到了虚拟机。接下来,ZygoteInit类将会被运行,那么ZygoteInit类具体有哪些功能呢?大致概括为如下几点:

绑定套接字,用来接收新Android应用程序运行请求
预加载Android Application Framework 使用的类与资源
启动并运行SystemServer
处理新Android应用程序运行请求
ZygoteInit的main函数:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public static void main(String argv[]) {
    ZygoteServer zygoteServer = new ZygoteServer();
    ......
    try{
        boolean startSystemServer = false;
        String socketName = "zygote";//套接字默认名称zygote
        for (int i = 1; i < argv.length; i++) {
            if ("start-system-server".equals(argv[i])) {
                startSystemServer = true;
           }
            ......
        }

        // ① 绑定/dev/socket/zygote套接字,用来接收Android应用程序运行请求
        zygoteServer.registerServerSocketFromEnv(socketName);
        ......
          
        if (!enableLazyPreload) {
            ......
            // ② 预加载类与资源
            preload(bootTimingsTraceLog);
            ......
        }

        ......
        if (startSystemServer) {
            // ③ fork出system_server子进程
           Runnable r = forkSystemServer(abiList, socketName, zygoteServer);

            // ③ {@code r == null}表示是父进程(zygote),{@code r != null}在子进程(system_server)
            if (r != null) {
                // ③ 如果是子进程(system_server)就执行run()方法,并返回,父进程(zygote)就继续往下执行
                r.run();
                return;
            }
        }

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

        // ④ 这轮询会在zygote进程中无限循环,而fork出的子进程(Android应用进程)会退出来
        caller = zygoteServer.runSelectLoop(abiList);
    } catch (Throwable ex) {
        Log.e(TAG, "System zygote died with exception", ex);
        throw ex;
    } finally {
        //system_server进程和android应用进程会关闭socket,zygote仍然在runSelectLoop中轮询监听socket
        zygoteServer.closeServerSocket();
    }
    

    // ④ Android应用进程会走到这儿,执行相应的命令
    if (caller != null) {
        caller.run();
    }
}

①: 绑定套接字,用来接收运行Android应用运行请求
frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

void registerServerSocketFromEnv(String socketName) {
    if (mServerSocket == null) {
        int fileDesc;
        //fullSocketName为“ANDROID_SOCKET_zygote”
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
        try {
            //获取ANDROID_SOCKET_zygote的坏境变量(即为/dev/socket/zygote的文件描述符的值)
            //是init进程在启动zygote进程时保存到环境变量中的
            String env = System.getenv(fullSocketName);
            fileDesc = Integer.parseInt(env);
        } catch (RuntimeException ex) {
            throw new RuntimeException(fullSocketName + " unset or invalid", ex);
        }
        
        try {
            //绑定socket,在后面用来接收Android应用启动请求
            FileDescriptor fd = new FileDescriptor();
            fd.setInt$(fileDesc);
            mServerSocket = new LocalServerSocket(fd);
            mCloseSocketFd = true;
        } catch (IOException ex) {
            ......
        }
    }
}

②: 预加载类和资源,后面从zygote进程fork出的应用进程可以直接共享,加快应用进程启动速度
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

static void preload(TimingsTraceLog bootTimingsTraceLog) {
    ......
    preloadClasses();
    ......
    preloadResources();
    ......
    nativePreloadAppProcessHALs();
    ......
    preloadOpenGL();
    preloadSharedLibraries();
    preloadTextResources();
    .......
    }

preloadClasses、preloadResources、nativePreloadAppProcessHALs预加载类和资源等等,有兴趣的同学可以深入了解。
③: forkSystemServer fork出system_server子进程,并返回可以调用SystemServer中main方法的Runnable r,并执行对应的run方法,而父进程zygote则继续往下执行runSelectLoop,监听Android应用运行执行请求。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {
    ......
    /* Hardcoded command line to start the system server */
    String args[] = {
        "--setuid=1000", //用户id
        "--setgid=1000", //组id
        ......
        "--nice-name=system_server",
        ......
        "com.android.server.SystemServer",
    };
    
    ZygoteConnection.Arguments parsedArgs = null;
    int pid;
    try {
        parsedArgs = new ZygoteConnection.Arguments(args);
        ......
        //fork出system_server子进程,并且设置对应的参数
        pid = Zygote.forkSystemServer(
                parsedArgs.uid, parsedArgs.gid,
                parsedArgs.gids,
                parsedArgs.runtimeFlags,
                null,
                parsedArgs.permittedCapabilities,
                parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }
    //子进程(system_server)
    if (pid == 0) {
        ......
        //所以返回的r不为null,直接执行r.run
        return handleSystemServerProcess(parsedArgs);
    }
    //父进程(zygote),返回的是null,继续往下执行
    return null;
}

ZygoteInit的forkSystemServer方法会调用Zygote的forkSystemServer方法,如果是子进程(system_server)就返回handleSystemServerProcess(),父进程(zygote)就返回null。
frameworks/base/core/java/com/android/internal/os/Zygote.java

public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
    ......
    int pid = nativeForkSystemServer(uid, gid, gids, runtimeFlags, 
                rlimits, permittedCapabilities, effectiveCapabilities);
    ......
    return pid;
    }

调用nativeForkSystemServer fork出子进程,nativeForkSystemServer是本地方法,在前面已经通过startReg方法中的register_com_android_internal_os_Zygote将nativeForkSystemServer方法映射到com_android_internal_os_Zygote_nativeForkSystemServer方法上,有兴趣的同学可以深入了解一下。
fork出子进程之后,子进程就开始调用handleSystemServerProcess()方法
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
    ......
    //从环境变量SYSTEMSERVERCLASSPATH获取到SystemServer类文件相应jar包的路径
    final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
    if (systemServerClasspath != null) {
        //对相应的jar包做dex优化处理
        performSystemServerDexOpt(systemServerClasspath);
        ......
    }

    ......
    ClassLoader cl = null;
    if (systemServerClasspath != null) {
        //创建类加载器classloader
        cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);

        Thread.currentThread().setContextClassLoader(cl);
    }

    return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}

先从SYSTEMSERVERCLASSPATH环境中获取到SystemServer的classpath,然后使用performSystemServerDexOpt对classpath对应的jar包做dex优化处理。然后创建对应的classloader,后续用来加载SystemServer类,ZygoteInit.zygoteInit()继续往下执行:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
    ......
    //将标准输出流和标准错误流重定向到Android log中
    RuntimeInit.redirectLogStreams();

    ......
    //本地方法,startReg映射,主要是开启ProcessState线程池,用来进行binder通信
    ZygoteInit.nativeZygoteInit();
    
    return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}

redirectLogStreams会将标准输入,错误流重定位到Android log中,nativeZygoteInit JNI函数(startReg映射)会开启ProcessState线程池,用来进行binder通信。
继续往下执行RuntimeInit.applicationInit():
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,ClassLoader classLoader) {
    ......
    // Remaining arguments are passed to the start class's static main
    return findStaticMain(args.startClass, args.startArgs, classLoader);
}

继续往下执行:

没有翻译的英文注释也值得一看哦

/**
 * Invokes a static "main(argv[]) method on class "className".
 * Converts various failing exceptions into RuntimeExceptions, with
 * the assumption that they will then cause the VM instance to exit.
 *
 * @param className Fully-qualified class name
 * @param argv Argument vector for main()
 * @param classLoader the classLoader to load {@className} with
 */
protected static Runnable findStaticMain(String className, String[] argv,ClassLoader classLoader) {
    Class cl;
    ......
    //获取到SystemServer的类类型
    cl = Class.forName(className, true, classLoader);
    ......
    Method m;
    try {
        //获取到main方法的方法id
        m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) {
        ......
    } catch (SecurityException ex) {
        ......
    }
    //这个就是③中forkSystemServer的返回值r
    return new MethodAndArgsCaller(m, argv);
}

findStaicMain获取到SystemServer的类类型,并且获取到SystemServer中的main方法的方法id。然后new MethodAndArgsCaller(m,argv)就是③中forkSystemServer的返回值r,让我们看看r.run做了一些什么。
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

static class MethodAndArgsCaller implements Runnable {
    /** method to call */
    private final Method mMethod;
    /** argument array */
    private final String[] mArgs;

    public MethodAndArgsCaller(Method method, String[] args) {
        mMethod = method;
        mArgs = args;
    }

    public void run() {
        try {
            //通过反射调用mMethod静态方法
            mMethod.invoke(null, new Object[] { mArgs });
        } catch (IllegalAccessException ex) {
           ......
        } catch (InvocationTargetException ex) {
            ......
        }
    }
}

由上可知,就是通过反射执行SystemServer类的main方法。众所周知,system_server进程注册和运行着AMS、PMS、PKMS等核心系统服务,因为这不是本文讲述的重点,所以有兴趣的同学可以继续深入了解一波~
④: zygoteServer.runSelectLoop()这轮询会在zygote进程中无限循环,而fork出的子进程(Android应用进程)会退出并继续往下执行
frameworks/base/core/java/com/android/internal/os/ZygoteServer.java

//开启zygote进程轮询监听。接收新的socket连接(会创建新的ZygoteConnection)
//并且从这些链接中中读取命令,并且执行
Runnable runSelectLoop(String abiList) {
    ArrayList fds = new ArrayList();
    ArrayList peers = new ArrayList();

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

    while (true) {
        StructPollfd[] pollFds = new StructPollfd[fds.size()];
        for (int i = 0; i < pollFds.length; ++i) {
            pollFds[i] = new StructPollfd();
            pollFds[i].fd = fds.get(i);
            pollFds[i].events = (short) POLLIN;
        }
        try {
            //开启轮询
            Os.poll(pollFds, -1);
        } catch (ErrnoException ex) {
            throw new RuntimeException("poll failed", ex);
        }
        for (int i = pollFds.length - 1; i >= 0; --i) {
            if ((pollFds[i].revents & POLLIN) == 0) {
                continue;
            }
            
            if (i == 0) {//如果是新的socket链接请求(建立新连接)
            //新建ZygoteConnection链接
            ZygoteConnection newPeer = acceptCommandPeer(abiList);
            //添加到链接数组中
            peers.add(newPeer);
            //添加到文件描述符数组中
            fds.add(newPeer.getFileDesciptor());
            } else {//如果是之前已经建立的socket链接(在已有连接上)
                try {
                    //获取对应的ZygoteConnection
                    ZygoteConnection connection = peers.get(i);
                    //会执行ZygoteConnection发送过来的命令
                    final Runnable command = connection.processOneCommand(this);

                    if (mIsForkChild) {//子进程走这儿
                        ......
                        //退出,command就是④中的caller
                        return command; 
                    } else {//父进程走这儿,上面是while无限循环,zygote进程永远不会退出
                        ......
                        if (connection.isClosedByPeer()) {
                            connection.closeSocket();
                            peers.remove(i);
                            fds.remove(i);
                        }
                    }
                } catch (Exception e) {
                    ......
                } finally {
                    mIsForkChild = false;
                }
            }
        }
    }
}

上面的流程概括来说,就是会轮询/dev/socket/zygote的socket,如果有新的链接,就新建ZygoteConnection,并将对应的socket fd添加到fds(轮询数组中),继续轮询,如果是新的链接,就重复上面的操作,如果是已经建立的链接,就执行该链接上读取到的command,也就是connection.processOneCommand()方法。

Android P之前processOneCommand的方法名是runOnce

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

Runnable processOneCommand(ZygoteServer zygoteServer) {
    String args[];
    Arguments parsedArgs = null;
    FileDescriptor[] descriptors;
    
    try {
    //读取命令
        args = readArgumentList();
        descriptors = mSocket.getAncillaryFileDescriptors();
    } catch (IOException ex) {
        ......
    }
    
    ......
    parsedArgs = new Arguments(args);
    ......
    
    //fork子进程
    pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.startChildZygote,
                parsedArgs.instructionSet, parsedArgs.appDataDir);

    try {
        if (pid == 0) {
            // 子进程中(应用进程中)
            zygoteServer.setForkChild();
            ......
            return handleChildProc(parsedArgs, descriptors, childPipeFd,
                    parsedArgs.startChildZygote);
        } else {
            //父进程中(zygote)
            ......
            return null;
        }
    } finally {
        ......
    }
}

从当前链接socket中读取启动命令。如果读取成功,zygote将会fork出子进程,并且返回可以调用启动类的main方法的runnable(也就是④中的caller)

如果是AMS请求启动应用进程,启动类就是ActivityThread.java,caller.run()就会反射调用ActivityThread的main方法。

zygoteServer.setForkChild()将mIsForkChild全局变量设为true。
我们接下来分析handleChildProc()方法
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java

private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,FileDescriptor pipeFd, boolean isZygote) {
    //关闭ZygoteConnection中的socket链接
    closeSocket();
    ......
    if (parsedArgs.niceName != null) {
        Process.setArgV0(parsedArgs.niceName);
    }
    ......
    if (!isZygote) {
        return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,null /* classLoader */);
    } else {
          ......
    }
}

从ZygoteInit.zygoteInit()开始就和③中分析的代码一模一样了,这里就不重复分析了,③中返回的是可以调用SystemServer的main方法的Runnable,而④中返回的是可以调用ActivityThread的main方法的Runnable。
自此,ZygoteInit也已经分析完毕。

总结
上面我们提到Zygote进程是第一个java进程,但整篇分析下来,java进程其实也是运行在c++进程之上的,只不过是java虚拟机屏蔽了这一切。zygote进程的启动,是从c++世界一步一步过渡到java世界,每个世界做了自己的准备工作。

c++世界(app_main.cpp入口):

动态加载虚拟机动态库,启动java虚拟机
注册JNI本地函数,减轻虚拟机负担
装载ZygoteInit到java虚拟机,正式进入java世界
java世界(ZygoteInit.java入口):

绑定套接字,用来接收新Android应用程序运行请求
预加载Android资源,提高应用进程启动速度
启动并运行SystemServer(运行AMS、PMS等核心服务)
处理新Android应用程序运行请求
zygote进程启动其实没有特别难的难点,主要是繁琐,源码分析的过程是枯燥无味的,只有静下心来,才能有所收获。
本文忽略了很多细节,主要是介绍大致的流程,如果有错误的地方,还请大家批评指出~ 觉得写的不错也请点个赞~

参考资料:
《Android框架揭秘》
Android4.4的zygote进程
Linux写时拷贝技术(copy-on-write)
 

你可能感兴趣的:(Android)