Android O: zygote进程分析

本篇博客主要结合Android 8.0的代码,回顾一下zygote进程的流程。


一、解析init.rc
在分析init进程时,我们知道init进程启动后,
会解析init.rc文件,然后创建和加载service字段指定的进程。
zygote进程就是以这种方式,被init进程加载的。

在system/core/rootdir/init.rc的开始部分,可以看到:

.............
//${ro.zygote}由厂商定义,与平台相关
import /init.${ro.zygote}.rc
.............

我们可以看出在不同的平台(32、64及64_32)上,init.rc将包含不同的zygote.rc文件。
在system/core/rootdir目录下,有init.zygote32_64.rc、init.zyote64.rc、
init.zyote32.rc、init.zygote64_32.rc。
不同的zygote.rc内容大致相同,主要区别体现在启动的是32位,还是64位的进程。
init.zygote32_64.rc和init.zygote64_32.rc会启动两个进程,且存在主次之分。

我们看看比较主流的init.zygote64.rc:

//启动的进程地址为/system/bin/app_process64
//参数为-Xzygote /system/bin --zygote --start-system-server
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc
    //会创建一个zygote socket,便于指定权限
    socket zygote stream 660 root system

    //解析service时, 构造了onrestart action对应的一系列command
    //当service被reap时,会执行onrestart对应的command
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks

在之前的博客中,我们分析过init进程的启动。
init进程启动的最后,会产生”late-init”事件。
对应于init.rc文件的内容类似于:

..........
on late-init
    ........
    # Now we can start zygote for devices with file based encryption
    trigger zygote-start 
    ........
..........

进一步触发了zygote-start事件后,就会启动zygote进程了。
对应的init.rc文件类似于:

on zygote-start && property:ro.crypto.state=unencrypted
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    //start对应的映射关系定义于system/core/init/builtins.cpp中
    //调用start对应的处理函数,启动名为zygote的服务
    //即传入前文init.zygote.rc中定义的参数
    start zygote
    start zygote_secondary

关键字start对应的处理函数为do_start,
定义于builtins.cpp中:

static int do_start(const std::vector<std::string>& args) {
    //找到zygote service对应信息
    Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
    if (!svc) {
        LOG(ERROR) << "do_start: Service " << args[1] << " not found";
        return -1;
    }

    //启动对应的进程
    if (!svc->Start())
        return -1;
    return 0;
}

最后,我们来看看service.cpp中定义Start函数:

bool Service::Start() {
    ............
    pid_t pid = -1;
    if (namespace_flags_) {
        pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
    } else {
        //从init进程中,fork出zygote进程
        pid = fork();
    }

    if (pid == 0) {
        ..........
        //当前fork的子进程替换为app_process
        if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
            PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
        }
        .........
    }
    ........

}

二、app_process的main函数
从init.zygote64.rc可以看出,zygote64启动文件的地址为app_process64。

app_process对应的代码定义在frameworks/base/cmds/app_process中,
我们来看看对应的Android.mk:

............
app_process_src_files := \
    app_main.cpp \
............
LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64
............

可以看出,无论平台的版本是什么,都是该目录对应的代码来处理。

接下来我们就看看app_process对应的main函数,
该函数定义于app_main.cpp中。

int main(int argc, char* const argv[])
{
    //log相关代码
    ........

    //AppRuntime定义于app_main.cpp中,继承自AndroidRuntime
    //就是对Android运行环境的一种抽象,类似于java虚拟机对Java程序的作用
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    ..........
    int i;
    //找到解析参数的起点
    for (i = 0; i < argc; i++) {
        ......
    }

    // Parse runtime arguments.  Stop at first unrecognized option.
    // 从这里其实可以看出,通过app_main可以启动zygote、system-server及普通apk进程
    // 这个可以通过init.rc来配置
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    // app_process的名称改为zygote
    String8 niceName;
    // 启动apk进程时,对应的类命
    String8 className;

    ++i; // Skip unused "parent dir" argument.
    //开始解析输入参数
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            //init.zygote64.rc中定义了该字段,表示启动zygote进程
            zygote = true;
            //记录app_process进程名的nice name,即zygote64(平台相关)
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            //init.zygote.rc中定义了该字段, 启动zygote后会启动system-server
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            //表示启动制定进程
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            //可以自己指定进程名
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            //与--application配置,启动指定的类
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }
    ..........
    //准备参数
    Vector<String8> args;
    if (!className.isEmpty()) {
        //启动普通进程
        // We're not in zygote mode, the only argument we need to pass
        // to RuntimeInit is the application argument.
        //
        // The Remainder of args get passed to startup class main(). Make
        // copies of them before we overwrite them with the process name.
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);
        .............
    } else {
        // We're in zygote mode.
        //创建dalvikCache所需的目录,并定义权限
        maybeCreateDalvikCache();

        if (startSystemServer) {
            //增加参数, 默认启动zygote后,就会启动system server
            args.add(String8("start-system-server"));
        }

        //获取平台对应的abi信息
        char prop[PROP_VALUE_MAX];
        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
                ABI_LIST_PROPERTY);
            return 11;
        }

        //参数需要制定abi
        String8 abiFlag("--abi-list=");
        abiFlag.append(prop);
        args.add(abiFlag);

        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.
        for (; i < argc; ++i) {
            //将main函数未处理的参数都递交给zygote main处理
            args.add(String8(argv[i]));
        }
    }

    if (!niceName.isEmpty()) {
       //将app_process的进程名,替换为nice name
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }

    if (zygote) {
        //调用Runtime的start函数, 启动ZygoteInit
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        //启动zygote没有进入这个分支
        //但这个分支说明,通过配置init.rc文件,其实是可以不通过zygote来启动一个进程
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        //error情况
        ...............
    }
}

三、AndroidRuntime的start函数
由于AppRuntime继承自AndroidRuntime,且没有重写start方法,
因此zygote的流程进入到了AndroidRuntime.cpp。

接下来,我们来看看AndroidRuntime的start函数的流程。

3.1、创建Java虚拟机
在AndroidRuntime的start函数中,
第一步工作是创建Java虚拟机。

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) {
    .........
    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);

    JNIEnv* env;
    //创建虚拟机,其中大多数参数由系统属性决定
    //最终,startVm利用JNI_CreateJavaVM创建出虚拟机
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    //回调AppRuntime的onVmCreated函数
    //对于zygote进程的启动流程而言,无实际操作
    onVmCreated(env);
    ......

我们先来看看JniInvocation的Init函数,该函数定义于libnativehelper/JniInvocation.cpp中。

bool JniInvocation::Init(const char* library) {
    ............
    //传入的参数为null, 获取默认library: libart.so
    //通过配置"persist.sys.dalvik.vm.lib.2"属性,
    //可指定默认的so
    library = GetLibrary(library, buffer);

    //获取library对应的句柄
    handle_ = dlopen(library, kDlopenFlags);
    if (handle_ == NULL) {
        //打开失败的处理
        ..........
    }

    //FindSymbol就是通过dlsym获取函数的句柄
    if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
                    "JNI_GetDefaultJavaVMInitArgs")) {
        return false;
    }
    if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
                    "JNI_CreateJavaVM")) {
        return false;
    }
    if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
                    "JNI_GetCreatedJavaVMs")) {
        return false;
    }
    return true;    
}

容易看出JniInvocation的init函数,主要功能就是获取libart.so中函数的句柄。
之后startVm函数创建Java虚拟机时,就会调用so中的函数创建JVM。

3.2、注册JNI函数
我们回到AndroidRuntime的start函数。
初始化JVM后,接下来就会调用startReg函数注册Android相关的功能函数。

...........
//注册JNI函数
if (startReg(env) < 0) {
    ALOGE("Unable to register all android natives\n");
    return;
}

我们跟进一下startReg函数:

int AndroidRuntime::startReg(JNIEnv* env) {
    ..........
    /*
     * This hook causes all future threads created in this process to be
     * attached to the JavaVM.  (This needs to go away in favor of JNI
     * Attach calls.)
     */
    //定义Android创建线程的func
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
    .............
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        ........
        return -1;
    }
    ........
}

从上述代码可以看出,startReg函数中主要是通过register_jni_procs来注册JNI函数。
其中,gRegJNI是一个全局数组,该数组的定义类似于:

static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_com_android_internal_os_RuntimeInit),
    REG_JNI(register_com_android_internal_os_ZygoteInit),
    REG_JNI(register_android_os_SystemClock),
    ............

REG_JNI对应的宏定义及RegJNIRec结构体的定义为:

#ifdef NDEBUG
    #define REG_JNI(name)      { name }
    struct RegJNIRec {
        int (*mProc)(JNIEnv*);
    };
#else
    #define REG_JNI(name)      { name, #name }
    struct RegJNIRec {
        int (*mProc)(JNIEnv*);
        const char* mName;
    };
#endif

根据宏定义可以看出,宏REG_JNI将得到函数名;
定义RegJNIRec数组时,函数名被赋值给RegJNIRec结构体,
于是每个函数名被强行转换为函数指针。
因此,register_jni_procs的参数就是一个函数指针数组,
数组的大小和JNIEnv。

我们来跟进一下register_jni_procs函数:

static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
    for (size_t i = 0; i < count; i++) {
        //执行数组中的函数
        if (array[i].mProc(env) < 0) {
            ............
            return -1;
        }
    }
    return 0;
}

结合前面的分析,容易知道register_jni_procs函数,
实际上就是调用函数指针对应的函数,以进行实际的JNI函数注册。

我们随意举个例子,看看register_com_android_internal_os_RuntimeInit被调用时的情况:

/*
 * JNI registration.
 */

int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
{
    const JNINativeMethod methods[] = {
        { "nativeFinishInit", "()V",
            (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
        { "nativeSetExitWithoutCleanup", "(Z)V",
            (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
    };
    return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
        methods, NELEM(methods));
}

可以看到,这实际上是自己定义JNI函数并进行动态注册的标准写法。

3.3、反射启动ZygoteInit
在介绍完AndroidRuntime.cpp中注册JNI的工作后,
我们将思路拉回到它的start函数。

........
/*
* Start VM.  This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
//替换string为实际路径
//例如:将"com.android.internal.os.ZygoteInit"
//替换为"com/android/internal/os/ZygoteInit"
char* slashClassName = toSlashClassName(className);

//找到class文件
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
    ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
    /* keep going */
} else {
    //通过反射找到ZygoteInit的main函数
    jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
        "([Ljava/lang/String;)V");
    if (startMeth == NULL) {
        ALOGE("JavaVM unable to find main() in '%s'\n", className);
        /* keep going */
    } else {
        //调用ZygoteInit的main函数
        env->CallStaticVoidMethod(startClass, startMeth, strArray);
    }
    .......
}
........

可以看到,在AndroidRuntime的最后,将通过反射调用ZygoteInit的main函数。
至此,zygote进程进入了java世界。
其实我们仔细想一想,就会觉得zygote的整个流程实际上是非常符合实际情况的。
在Android中,每个进程都运行在对应的虚拟机上,因此zygote首先就负责创建出虚拟机。
然后,为了反射调用java代码,必须有对应的JNI函数,于是zygote进行了JNI函数的注册。
当一切准备妥当后,zygote进程才进入到了java世界。

四、ZygoteInit的main函数
现在我们跟进ZygoteInit.java的main函数。

public static void main(String argv[]) {
    //创建ZygoteServer对象
    ZygoteServer zygoteServer = new ZygoteServer();

    // Mark zygote start. This ensures that thread creation will throw
    // an error.
    // 调用native函数,确保当前没有其它线程在运行
    // 主要还是处于安全的考虑
    ZygoteHooks.startZygoteNoThreadCreation(); 

    // Zygote goes into its own process group.
    try {
        Os.setpgid(0, 0);
    } catch (ErrnoException ex) {
        throw new RuntimeException("Failed to setpgid(0,0)", ex);
    }

    try {
        .........
        // enable DDMS
        RuntimeInit.enableDdms();
        // Start profiling the zygote initialization.
        // 开始性能统计
        SamplingProfilerIntegration.start();

        boolean startSystemServer = false;
        String socketName = "zygote";
        String abiList = null;
        boolean enableLazyPreload = false;
        //解析参数,得到上述变量的值
        for (int i = 1; i < argv.length; i++) {
            ............
        }

        if (abiList == null) {
            throw new RuntimeException("No ABI list supplied.");
        }

        //4.1: 注册server socket
        zygoteServer.registerZygoteSocket(socketName);

        // In some configurations, we avoid preloading resources and classes eagerly.
        // In such cases, we will preload things prior to our first fork.
        if (!enableLazyPreload) {
            .........
            // 4.2: 默认情况,预加载信息
            preload(bootTimingsTraceLog);
        .........
        } else {
            //如注释,延迟预加载
            //变更Zygote进程优先级为NORMAL级别
            //第一次fork时才会preload
            Zygote.resetNicePriority();
        }

        // Finish profiling the zygote initialization.
        // 结束对zygote的性能统计
        // 实际上是想统计预加载的性能
        SamplingProfilerIntegration.writeZygoteSnapshot();

        // Do an initial gc to clean up after startup
        ...........
        //如果预加载了,很有必要GC一波
        gcAndFinalize();
        ...........

        //以下均是安全相关的内容

        // Zygote process unmounts root storage spaces.
        // unmount root storage spaces,
        // 那么其它进程就无法访问了
        Zygote.nativeUnmountStorageOnInit();

        // Set seccomp policy
        // 加载seccomp的过滤规则
        // 所有 Android 软件都使用系统调用(简称为 syscall)与 Linux 内核进行通信
        // 内核提供许多特定于设备和SOC的系统调用,让用户空间进程(包括应用)可以直接与内核进行交互
        // 不过,其中许多系统调用Android未予使用或未予正式支持
        // 通过seccomp,Android可使应用软件无法访问未使用的内核系统调用
        // 由于应用无法访问这些系统调用,因此,它们不会被潜在的有害应用利用
        // 该过滤器安装到zygote进程中,由于所有Android应用均衍生自该进程
        // 因而会影响到所有应用
        Seccomp.setPolicy();

        //允许有其它线程了
        ZygoteHooks.stopZygoteNoThreadCreation();

        if (startSystemServer) {
            //4.3: 启动system server
            startSystemServer(abiList, socketName, zygoteServer);
        }
        ..............
        //4.4: zygote进程进入无限循环,处理请求
        zygoteServer.runSelectLoop(abiList);

        zygoteServer.closeServerSocket();
    } catch (Zygote.MethodAndArgsCaller caller) {
        //通过反射调用新进程函数的地方
        //后续介绍新进程启动时,再介绍
        caller.run();
    } catch (Throwable ex) {
        .......
        zygoteServer.closeServerSocket();
        throw ex;
    }
}

上面是ZygoteInit的main函数的主干部分,除了安全相关的内容外,
最主要的工作就是注册server socket、预加载、启动system server
及进入无限循环处理请求消息。
接下来,我们进一步分析这几个步骤对应的工作。

4.1、 创建server socket
Android O将server socket相关的工作抽象到ZygoteServer.java中了。
我们来看看其中的registerZygoteSocket函数:

void registerZygoteSocket(String socketName) {
    if (mServerSocket == null) {
        int fileDesc;

        //ANDROID_SOCKET_PREFIX为"ANDROID_SOCKET_"
        //此处的socket name,就是zygote
        final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
        try {
            //记得么?在init.zygote.rc被加载时,指定了名为zygote的socket
            //在进程被创建时,就会创建对应的文件描述符,并加入到环境变量中
            //因此,此时可以取出对应的环境变量
            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();
            //获取zygote socket的文件描述符
            fd.setInt$(fileDesc);
            //将socket包装成一个server socket
            mServerSocket = new LocalServerSocket(fd);
        } catch (IOException ex) {
            throw new RuntimeException(
                    "Error binding to local socket '" + fileDesc + "'", ex);
        }
    }
}

来看看LocalServerSocket的代码:

public LocalServerSocket(String name) throws IOException
{
    impl = new LocalSocketImpl();

    //创建SOCKET_STREAM类型的AF_UNIX socket
    impl.create(LocalSocket.SOCKET_STREAM);

    localAddress = new LocalSocketAddress(name);
    //绑定到指定地址
    impl.bind(localAddress);

    //开始监听
    impl.listen(LISTEN_BACKLOG);
}

至此,zygote进程创建Server socket的工作结束。

4.2、 预加载
在这部分,我们简单看看预加载的内容

static void preload(BootTimingsTraceLog bootTimingsTraceLog) {
    .........
    //Pin ICU Data, 获取字符集转换资源等
    beginIcuCachePinning();
    .........
    //读取文件system/etc/preloaded-classes,然后通过反射加载对应的类
    //一般由厂商来定义,有时需要加载数千个类,启动慢的原因之一
    preloadClasses();
    ..........
    //负责加载一些常用的系统资源
    preloadResources();
    ........
    //图形相关的
    preloadOpenGL();
    .......
    //一些必要库
    preloadSharedLibraries();
    //语言相关的字符信息
    preloadTextResources();
    // Ask the WebViewFactory to do any initialization that must run in the zygote process,
    //for memory sharing purposes.
    WebViewFactory.prepareWebViewInZygote();
    endIcuCachePinning();

    //安全相关的
    warmUpJcaProviders();
    Log.d(TAG, "end preload");

    sPreloadComplete = true;
}

为了让系统实际运行时更加流畅,在zygote启动时候,调用preload函数进行了一些预加载操作。
Android 通过zygote fork的方式创建子进程。
zygote进程预加载这些类和资源,在fork子进程时,仅需要做一个复制即可。
这样可以节约子进程的启动时间。
同时,根据fork的copy-on-write机制可知,有些类如果不做改变,甚至都不用复制,
子进程可以和父进程共享这部分数据,从而省去不少内存的占用。

4.3、 启动SystemServer进程
再来看看启动System Server的流程:

private static boolean startSystemServer(String abiList, String socketName,
        ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller, RuntimeException {
    //准备capabilities参数
    .......
    /* Hardcoded command line to start the system server */
    String args[] = {
        "--setuid=1000",
        "--setgid=1000",
        "--setgroups=.........",
        "--capabilities=" + capabilities + "," + capabilities,
        "--nice-name=system_server",
        "--runtime-args",
        "com.android.server.SystemServer",
    };
    ZygoteConnection.Arguments parsedArgs = null;

    int pid;

    try {
        //将上面准备的参数,按照ZygoteConnection的风格进行封装
        parsedArgs = new ZygoteConnection.Arguments(args);
        ...........

         //通过fork"分裂"出system server,具体的过程在介绍system server时再分析
         /* Request to fork the system server process */
         pid = Zygote.forkSystemServer(
                 parsedArgs.uid, parsedArgs.gid,
                 parsedArgs.gids,
                 parsedArgs.debugFlags,
                 null,
                 parsedArgs.permittedCapabilities,
                 parsedArgs.effectiveCapabilities);
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException(ex);
    }

    /* For child process */
    if (pid == 0) {
        ............
    //处理32_64和64_32的情况
    if (hasSecondZygote(abiList)) {
            waitForSecondaryZygote(socketName);
        }

        // fork时会copy socket,
        //system server需要主动关闭
        zygoteServer.closeServerSocket();

        //system server进程处理自己的工作
        handleSystemServerProcess(parsedArgs);
    }

    return true;
}

Zygote进程启动system server进程又是一个比较大的话题,
后期我们单独介绍。

4.4、 处理请求信息
创建出SystemServer进程后,zygote进程调用ZygoteServer中的函数runSelectLoop,
处理server socket收到的命令。

void runSelectLoop(String abiList) throws MethodAndArgsCaller {
    ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
    ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

    //首先将server socket加入到fds
    fds.add(mServerSocket.getFileDescriptor());
    peers.add(null);

    while (true) {
        //每次循环,都重新创建需要监听的pollFds
        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;
            }
            //server socket最先加入fds, 因此这里是server socket收到数据
            if (i == 0) {
                //收到新的建立通信的请求,建立通信连接
                ZygoteConnection newPeer = acceptCommandPeer(abiList);
                //加入到peers和fds, 即下一次也开始监听
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
                //其它通信连接收到数据,runOnce执行对应命令
                boolean done = peers.get(i).runOnce();
                if (done) {
                    //对应通信连接不再需要执行其它命令,关闭并移除,
                    //即下一次不再监听
                    peers.remove(i);
                    fds.remove(i);
                }
            }
        }
    }
}

从上面代码可知,初始时fds中仅有server socket,因此当有数据到来时,将执行i等于0的分支。
此时,显然是需要创建新的通信连接,因此acceptCommandPeer将被调用。

private ZygoteConnection acceptCommandPeer(String abiList) {
    try {
        //socket编程中,accept()调用主要用在基于连接的套接字类型,比如SOCK_STREAM和SOCK_SEQPACKET
        //它提取出所监听套接字的等待连接队列中第一个连接请求,创建一个新的套接字,并返回指向该套接字的文件描述符
        //新建立的套接字不在监听状态,原来所监听的套接字的状态也不受accept()调用的影响
        return new ZygoteConnection(mServerSocket.accept(), abiList);
    } catch (IOException ex) {
        throw new RuntimeException(
                "IOException during accept()", ex);
    }
}

从上面的代码,可以看出acceptCommandPeer调用了server socket的accpet函数。
于是当新的连接建立时,zygote将会创建出一个新的socket与其通信,
并将该socket加入到fds中。
因此,一旦通信连接建立后,fds中将会包含有多个socket。

当poll监听到这一组sockets上有数据到来时,就会从阻塞中恢复。
于是,我们需要判断到底是哪个socket收到了数据。

在runSelectLoop中采用倒序的方式轮询。
由于server socket第一个被加入到fds,因此最后轮询到的socket才需要处理新建连接的操作;
其它socket收到数据时,仅需要调用zygoteConnection的runonce函数执行数据对应的操作。

若一个连接处理完所有对应消息后,该连接对应的socket和连接等将被移除。

五、结束语
以上是自己对zygote进程的一些分析,
我们知道了zygote如何由init进程加载后,一步一步地进入到java世界。
在此我们没有详细分析所有的流程细节,但有了上述的认知框架后,
应该可以较为容易的分析具体的问题。

猜你喜欢

转载自blog.csdn.net/gaugamela/article/details/79308863