2

前言

由于源码分析的代码量比较大,大部分博客网站的内容显示页面都比较窄,显示出来的效果都异常丑陋,所以您也可以直接查看 《 Thinking in Android 》 来阅读这边文章,希望这篇文章能帮你梳理清楚 “Zygote 进程的原理”


核心源码

关键类 路径
init.rc system/core/rootdir/init.rc
init.cpp system/core/init/init.cpp
init.zygote64.rc system/core/rootdir/init.zygote64.rc
builtins.cpp system/core/init/builtins.cpp
service.cpp system/core/init/service.cpp
app_main.cpp frameworks/base/cmds/app_process/app_main.cpp
AndroidRuntime.cpp frameworks/base/core/jni/AndroidRuntime.cpp
JniInvocation.cpp libnativehelper/JniInvocation.cpp
LocalServerSocket.cpp frameworks/base/core/java/android/net/LocalServerSocket.java
ZygoteInit.java frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
ZygoteServer.java frameworks/base/core/java/com/android/internal/os/ZygoteServer.java


Zygote 简介

在 Android 系统中,JavaVM(Java 虚拟机)应用程序进程以及运行系统关键服务的 SystemServer 进程都是由 Zygote 来创建的,我们也将它称为 孵化器。它通过 fock (复制进程)的形式来创建 "应用程序进程""SystemServer 进程",由于 Zygote 进程在启动时会创建 JavaVM,因此通过 fock 而创建的 "应用程序进程" 和 "SystemServer 进程" 可以在内部获取一个 JavaVM 的实例拷贝


一、Zygote

1.1 触发

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

system/core/rootdir/init.rc 中,可以看到:

// system/core/rootdir/init.rc

import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc    // ${ro.zygote} 由厂商定义,与平台相关

1.2 init.xx.rc

在不同的平台(32、64 及 64_32)上,init.rc 将包含不同的 zygote.rc 文件。

system/core/rootdir 目录下:

init.zygote32_64.rcinit.zyote64.rcinit.zyote32.rcinit.zygote64_32.rc 四个文件。

Ul3y7R.png

init.zygote32.rc

zygote 进程对应的执行程序是 app_process (纯 32bit 模式)

init.zygote64.rc

zygote 进程对应的执行程序是 app_process64 (纯 64bit 模式)

init.zygote32_64.rc

启动两个 zygote 进程 (zygote 和 zygote_secondary),对应的执行程序分别是 app_process32 (主模式)、app_process64

init.zygote64_32.rc

启动两个 zygote 进程 (zygote 和 zygote_secondary),对应的执行程序分别是 app_process64 (主模式)、app_process32

那么,为什么要定义这么多种情况?

这主要是因为 Android 5.0 以后开始支持 64 位程序,为了兼容 32 位和 64 位才这样定义。不同的 zygote.rc 内容大致相同,主要区别体现在启动的是 32 位,还是 64 位的进程。init.zygote32_64.rcinit.zygote64_32.rc 会启动两个进程,且存在主次之分。

这里拿 64 位处理器为例,init.zygote64_32.rc 的代码如下所示:

/* 
 * 进程名称是 zygote
 * 运行的二进制文件在 /system/bin/app_process64
 * 启动参数是 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
 */
service zygote /system/bin/app_process64 
               -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system                     // 创建一个 socket,名字叫 zygote
    socket usap_pool_primary stream 660 root system
    onrestart write /sys/android_power/request_state wake    // onrestart 指当进程重启时执行后面的命令
    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    // 创建子进程时,向 /dev/cpuset/foreground/tasks 写入 pid

// 另一个 service:zygote_secondary
service zygote_secondary /system/bin/app_process32
                    -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote_secondary stream 660 root system
    socket usap_pool_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks

1.3 start zygote

既然定义了此 service 用于启动 Zygote,那么是在什么地方启动的呢?在探讨 init 的时候,我们分析过:init 进程启动的最后,会处理 late-init 事件。

// system/core/init/init.cpp

int SecondStageMain(int argc, char** argv) {

    // Don't mount filesystems or start core system services in charger mode.
    std::string bootmode = GetProperty("ro.bootmode", "");
    if (bootmode == "charger") {
        am.QueueEventTrigger("charger");
    } else {
        am.QueueEventTrigger("late-init");
    }

    return 0;

}

对应于 init.rc 配置文件中,我们找到如下代码:

// system/core/rootdir/init.rc

# Mount filesystems and start core system services.
on late-init
    ... ...

    # Now we can start zygote for devices with file based encryption
    trigger zygote-start        // 触发了 zygote-start 事件后,就会启动 zygote 进程
    ... ...

# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
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  // 调用 start 对应的处理函数,启动名为 zygote 的服务(传入前文 init.zygote.rc 中定义的参数)
    start zygote_secondary
    
on zygote-start && property:ro.crypto.state=unsupported
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
    # A/B update verifier that marks a successful boot.
    exec_start update_verifier_nonencrypted
    start netd
    start zygote
    start zygote_secondary

start 命令有一个对应的执行函数 do_start() ,定义在 /system/core/init/builtins.cpp 中。

// system/core/init/builtins.cpp

// Builtin-function-map start
const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
    constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
    // clang-format off
    static const Map builtin_functions = {
        ... ...

        {"start",                   {1,     1,    {false,  do_start}}},

        ... ...
    };
    // clang-format on
    return builtin_functions;
}

我们看下 do_start()

// system/core/init/builtins.cpp

static Result<Success> do_start(const BuiltinArguments& args) {
    Service* svc = ServiceList::GetInstance().FindService(args[1]);    // 找到 zygote service 对应信息
    if (!svc) return Error() << "service " << args[1] << " not found";
    if (auto result = svc->Start(); !result) {                         // 启动对应的进程
        return Error() << "Could not start service: " << result.error();
    }
    return Success();
}

do_start() 首先是通过 FindService()service 数组 中遍历,根据名字匹配出对应的 service,然后调用 service 的 Start() 函数。

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

// system/core/init/service.cpp

Result<Success> Service::Start() {
    ... ...

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

    ... ...
}

Start() 函数主要是 fork 出一个新进程,然后执行 service 对应的二进制文件,并将参数传递进去,下面我们以 init.zygote64.rc 为例进行分析。


二、app_process

init.zygote64.rc 启动文件的地址为 /system/bin/app_process64

UlFo0e.png

app_process64 对应的代码定义在 frameworks/base/cmds/app_process目录下。

我们来看看对应的 Android.mk

// frameworks/base/cmds/app_process

LOCAL_PATH:= $(call my-dir)
... ...

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_processapp_process32 还是 app_process64,对应的源文件都是 app_main.cpp

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

2.1 app_main.main()

app_main.cppmain() 函数中,主要做的事情就是 参数解析。这个函数有 两种 启动模式:

zygote 模式,也就是初始化 zygote 进程,传递的参数有 "--start-system-server --socket-name=zygote",前者表示启动 SystemServer,后者指定 socket 的名称。

application 模式,也就是启动普通应用程序,传递的参数有 "class 名字"以及 "class 带的参数"。

两者最终都是调用 AppRuntime 对象start() 函数,加载 ZygoteInitRuntimeInit 两个 Java 类,并将之前整理的参数传入进去。

接下来正式开始 main 函数的分析。

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

int main(int argc, char* const argv[])
{
    // 将参数 argv 放到 argv_String 字符串中,然后打印出来
    // 之前 start zygote 传入的参数是 -Xzygote /system/bin --zygote --start-system-server
    if (!LOG_NDEBUG) {
      String8 argv_String;
      for (int i = 0; i < argc; ++i) {
        argv_String.append("\"");
        argv_String.append(argv[i]);
        argv_String.append("\" ");
      }
      ALOGV("app_process main with argv: %s", argv_String.string());
    }
    
    // AppRuntime 定义于 app_main.cpp 中,继承自 AndroidRuntime
    // 就是对 Android 运行环境的一种抽象,类似于 java 虚拟机对 Java 程序的作用
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    argc--;
    argv++;

    // 这两个参数是 Java 程序需要依赖的 Jar 包,相当于 import
    const char* spaced_commands[] = { "-cp", "-classpath" };
    bool known_command = false;

    int i;
    for (i = 0; i < argc; i++) {        // 找到解析参数的起点
        if (known_command == true) {    // 将 spaced_commands 中的参数额外加入 VM
          runtime.addOption(strdup(argv[i]));
          ALOGV("app_process main add known option '%s'", argv[i]);
          known_command = false;
          continue;
        }

        for (int j = 0;
             j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
             ++j) {
          // 比较参数是否是 spaced_commands 中的参数
          if (strcmp(argv[i], spaced_commands[j]) == 0) {
            known_command = true;
            ALOGV("app_process main found known command '%s'", argv[i]);
          }
        }

        // 如果参数第一个字符是'-',直接跳出循环,之前传入的第一个参数是 -Xzygote,所以执行到这儿就跳出了
        if (argv[i][0] != '-') {
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }

        runtime.addOption(strdup(argv[i]));
        ALOGV("app_process main add option '%s'", argv[i]);
    }

    // 从这里其实可以看出,通过 app_main 可以启动 zygote、system-server 及普通 apk 进程
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;     // app_process 的名称改为 zygote
    String8 className;    // 启动 apk 进程时,对应的类名

    ++i;
    // 跳过一个参数,之前跳过了 -Xzygote,这里继续跳过 /system/bin ,也就是所谓的 "parent dir"
    while (i < argc) {    // 开始解析输入参数
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {    // 表示是 zygote 启动模式
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;       // 这个值根据平台可能是 zygote64 或 zygote
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;          // init.zygote.rc 中定义,启动 zygote 后会启动 system-server
        } else if (strcmp(arg, "--application") == 0) {
            application = true;                // 表示是 application 启动模式,也就是普通应用程序
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);          // 进程别名,可以自己指定进程名
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);              // 与 --application 配置,启动指定的类,application 启动的 class
            break;
        } else {
            --i;
            break;
        }
    }

    // 准备参数
    Vector<String8> args;
    if (!className.isEmpty()) {      // className 不为空,说明是 application 启动模式
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);
        ... ...

    } else {    // zygote 启动模式
        // We're in zygote mode.
        maybeCreateDalvikCache();          // 创建 Dalvik 的缓存目录并定义权限

        if (startSystemServer) {           // 增加 start-system-server 参数
            args.add(String8("start-system-server"));
        }

        char prop[PROP_VALUE_MAX];         // 获取平台对应的 abi 信息
        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;
        }

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

        for (; i < argc; ++i) {
            args.add(String8(argv[i]));    // 将剩下的参数加入 args
        }
    }

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

    if (zygote) {                          // 调用 Runtime 的 start 函数, 启动 ZygoteInit
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {                // 启动 zygote 没有进入这个分支
        // 但这个分支说明,通过配置 init.rc 文件,其实是可以不通过 zygote 来启动一个进程,
        // 如果是 application 启动模式,则加载 RuntimeInit。
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        // error 情况
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}

现在我们知道 Zygote 是通过 runtime.start() 函数启动,此处的 runtimeAppRuntime

2.2 AndroidRuntime

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

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

class AppRuntime : public AndroidRuntime
{
public:
    AppRuntime(char* argBlockStart, const size_t argBlockLength)
        : AndroidRuntime(argBlockStart, argBlockLength)
        , mClass(NULL)
    {
    }
    ... ...

}

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

2.2.1 创建 Java 虚拟机

// frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ... ...    // 打印一些日志,获取 ANDROID_ROOT 环境变量

    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);    // 初始化 JNI,加载 libart.so
    JNIEnv* env;

    // 创建虚拟机,其中大多数参数由系统属性决定,最终 startVm 利用 JNI_CreateJavaVM 创建出虚拟机
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }

    // 回调 AppRuntime 的 onVmCreated 函数
    // 对于 zygote 进程的启动流程而言,无实际操作,表示虚拟创建完成,但是里面是空实现
    onVmCreated(env);
    ... ...

}

2.2.2 注册 JNI 函数

// frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ... ...
    /* 01. 创建 Java 虚拟机 */
    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {         // 注册 JNI 函数
        ALOGE("Unable to register all android natives\n");
        return;
    }
    ... ...

}

startReg() 首先是设置了 Android 创建线程的处理函数,然后创建了一个 200 容量的局部引用作用域,用于确保不会出现 OutOfMemoryException,最后就是调用 register_jni_procs() 进行 JNI 注册。

我们跟进源码看下:

// frameworks/base/core/jni/AndroidRuntime.cpp

/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
    ATRACE_NAME("RegisterAndroidNatives");

    // 定义 Android 创建线程的 func:javaCreateThreadEtc,这个函数内部是通过 Linux 的 clone 来创建线程的
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);       

    ALOGV("--- registering native functions ---\n");

    env->PushLocalFrame(200);    // 创建一个 200 容量的局部引用作用域,这个局部引用其实就是局部变量

    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {    // 注册 JNI 函数
        env->PopLocalFrame(NULL);
        return -1;
    }

    env->PopLocalFrame(NULL);    // 释放局部引用作用域

    return 0;
}

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

// frameworks/base/core/jni/AndroidRuntime.cpp

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),
    ... ...

};

我们挑一个 register_com_android_internal_os_ZygoteInit_nativeZygoteInit,这实际上是自定义 JNI 函数并进行 动态注册 的标准写法。

内部是调用 JNI 的 RegisterNatives,这样注册后,Java 类 ZygoteInitnative 方法 nativeZygoteInit 就会调用 com_android_internal_os_ZygoteInit_nativeZygoteInit 函数。

// frameworks/base/core/jni/AndroidRuntime.cpp

int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env)
{
    const JNINativeMethod methods[] = {
        { "nativeZygoteInit", "()V",
            (void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
    };
    return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
        methods, NELEM(methods));
}

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() 函数:

// frameworks/base/core/jni/AndroidRuntime.cpp

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) {    // 调用 mProc
#ifndef NDEBUG
            ALOGD("----------!!! %s failed to load\n", array[i].mName);
#endif
            return -1;
        }
    }
    return 0;
}

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

2.2.3 反射启动 ZygoteInit

继续分析 AndroidRuntime.cppstart 函数:

// frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    /* 01. 创建 Java 虚拟机*/
    /* 02. 注册 JNI 函数 */
    --- --- --- --- --- --- ---
    // 替换 string 为实际路径
    // 例如:将 "com.android.internal.os.ZygoteInit" 替换为 "com/android/internal/os/ZygoteInit"
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);    // 找到 class 文件
    if (startClass == NULL) {
        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
        /* keep going */
    } else {
        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");    // 通过反射找到 ZygoteInit 的 main 函数
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);    // 调用 ZygoteInit 的 main() 函数
            ... ...
        }
    }
    free(slashClassName);

    ALOGD("Shutting down VM\n");
    if (mJavaVM->DetachCurrentThread() != JNI_OK)    // 退出当前线程
        ALOGW("Warning: unable to detach main thread\n");
    if (mJavaVM->DestroyJavaVM() != 0)               // 创建一个线程,该线程会等待所有子线程结束后关闭虚拟机
        ALOGW("Warning: VM did not shut down cleanly\n");
}

main() 函数最后,将 通过反射调用 ZygoteInit 的 main() 方法

至此,zygote 进程正式进入了 java 世界。

其实我们仔细想一想,就会觉得 zygote 的整个流程实际上是非常符合实际情况的。

      1、在 Android 中,每个进程都运行在对应的虚拟机上,因此 zygote 首先就负责创建出虚拟机。
      2、然后,为了反射调用 java 代码,必须有对应的 JNI 函数,于是 zygote 进行了 JNI 函数的注册。
      3、当一切准备妥当后,zygote 进程才进入到了 java 世界。


三、ZygoteInit

现在我们跟进 ZygoteInitmain() 函数。

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

public class ZygoteInit {
    ... ...

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

        // 调用 native 函数,确保当前没有其它线程在运行,主要还是处于安全的考虑
        ZygoteHooks.startZygoteNoThreadCreation();
        ... ...

        Runnable caller;
        try {
            ... ...

            RuntimeInit.enableDdms();

            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            boolean enableLazyPreload = false;
            // 解析参数,得到上述变量的值
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if ("--enable-lazy-preload".equals(argv[i])) {
                    enableLazyPreload = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }
            
            if (!enableLazyPreload) {
                bootTimingsTraceLog.traceBegin("ZygotePreload");
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                        SystemClock.uptimeMillis());
                preload(bootTimingsTraceLog);    // 默认情况,预加载信息
                EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                        SystemClock.uptimeMillis());
                bootTimingsTraceLog.traceEnd(); // ZygotePreload
            } else {
                // 延迟预加载,变更 Zygote 进程优先级为 NORMAL 级别,第一次 fork 时才会 preload
                Zygote.resetNicePriority();
            }
            ... ...

            if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);    // fork systemserver
                if (r != null) {
                    r.run();
                    return;
                }
            }
            Log.i(TAG, "Accepting command socket connections");

            caller = zygoteServer.runSelectLoop(abiList);    // zygote 进程进入无限循环,处理请求
        } catch (Throwable ex) {
            throw ex;
        } finally {
            zygoteServer.closeServerSocket();
        }

        if (caller != null) {
            caller.run();
        }
    }
}

Zygote.main() 函数除了安全相关的内容外,最主要的工作就是 注册 server socket预加载启动 systemserver进入无限循环处理请求消息

3.1 预加载

我们看看 预加载 的逻辑:

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

public class ZygoteInit {

    static void preload(TimingsTraceLog bootTimingsTraceLog) {
        beginPreload();
        preloadClasses();            // 读取文件 system/etc/preloaded-classes,然后通过反射加载对应的类
        cacheNonBootClasspathClassLoaders();
        preloadResources();          // 负责加载一些常用的系统资源
        nativePreloadAppProcessHALs();
        maybePreloadGraphicsDriver();
        preloadSharedLibraries();    // 一些必要库
        preloadTextResources();      // 语言相关的字符信息
        WebViewFactory.prepareWebViewInZygote();
        endPreload();
        warmUpJcaProviders();        // 安全相关的

        sPreloadComplete = true;
    }

}

为了让系统实际运行时更加流畅,在 zygote 启动时候,调用 preload() 函数进行了一些 预加载操作

Android 通过 Zygote fork 的方式创建 子进程。Zygote 进程预加载这些类和资源,在 fork 子进程时,仅需要做一个复制即可。这样可以节约子进程的启动时间。

同时,根据 fork 的 copy-on-write 机制,有些类如果不做改变,甚至都不用复制,子进程可以和父进程共享这部分数据,从而省去不少内存的占用。

3.2 启动 SystemServer 进程

再来看看启动 SystemServer 的流程:

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

public class ZygoteInit {

    private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {
        long capabilities = posixCapabilitiesAsBits(
                OsConstants.CAP_IPC_LOCK,
                OsConstants.CAP_KILL,
                OsConstants.CAP_NET_ADMIN,
                OsConstants.CAP_NET_BIND_SERVICE,
                OsConstants.CAP_NET_BROADCAST,
                OsConstants.CAP_NET_RAW,
                OsConstants.CAP_SYS_MODULE,
                OsConstants.CAP_SYS_NICE,
                OsConstants.CAP_SYS_PTRACE,
                OsConstants.CAP_SYS_TIME,
                OsConstants.CAP_SYS_TTY_CONFIG,
                OsConstants.CAP_WAKE_ALARM,
                OsConstants.CAP_BLOCK_SUSPEND
        );
        ... ...

        /* Hardcoded command line to start the system server */
        String args[] = {
                "--setuid=1000",
                "--setgid=1000",
                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                        + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
                "--capabilities=" + capabilities + "," + capabilities,
                "--nice-name=system_server",
                "--runtime-args",
                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                "com.android.server.SystemServer",
        };
        ZygoteArguments parsedArgs = null;

        int pid;

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

            boolean profileSystemServer = SystemProperties.getBoolean(
                    "dalvik.vm.profilesystemserver", false);
            if (profileSystemServer) {
                parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
            }

            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(            // 通过 fork "分裂" 出 system_server
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

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

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

        return null;
    }

}

3.3 处理请求信息

创建出 SystemServer 进程后,调用 ZygoteServer.runSelectLoop(),处理 server socket 收到的命令

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

class ZygoteServer {

    Runnable runSelectLoop(String abiList) {
        ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

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


        while (true) {
            fetchUsapPoolPolicyPropsWithMinInterval();
            
            int[] usapPipeFDs = null;
            StructPollfd[] pollFDs = null;    // 每次循环,都重新创建需要监听的 pollFds        
            ... ...

            int pollIndex = 0;
            for (FileDescriptor socketFD : socketFDs) {
                pollFDs[pollIndex] = new StructPollfd();
                pollFDs[pollIndex].fd = socketFD;
                pollFDs[pollIndex].events = (short) POLLIN;    // 关注事件到来
                ++pollIndex;
            }
            ... ...

            try {
                Os.poll(pollFDs, -1);    // 等待事件到来
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }

            boolean usapPoolFDRead = false;
            
            // 注意这里是倒序的,即优先处理已建立链接的信息,后处理新建链接的请求
            while (--pollIndex >= 0) {
                if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
                    continue;
                }

                // server socket 最先加入 fds, 因此这里是 server socket 收到数据
                if (pollIndex == 0) {
                    // Zygote server socket
                    // 收到新的建立通信的请求,建立通信连接
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    // 加入到 peers 和 socketFDs, 即下一次也开始监听
                    peers.add(newPeer);
                    socketFDs.add(newPeer.getFileDescriptor());

                } else if (pollIndex < usapPoolEventFDIndex) {
                    ... ... // 其他通信连接收到数据
                }
            }
            ... ...

        }
    }

}

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

我们看看 acceptCommandPeer() 方法:

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

class ZygoteServer {

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

    protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
            throws IOException {
        return new ZygoteConnection(socket, abiList);
    }

}

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

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

四、总结

Zygote 启动流程到此结束,共做了如下几件事:

✎  1. 创建 AppRuntime 并调用其 start() 方法,启动 Zygote 进程。
✎  2. 创建 JavaVM 并为 JavaVM 注册 JNI
✎  3. 通过 JNI 调用 ZygoteInitmain() 函数进入 Zygote 的 Java 层
✎  4. 通过 registerZygoteSocket() 函数创建 服务端 Socket,预加载类和资源,并通过 runSelectLoop() 函数等待如 ActivityManagerService 等的请求。
✎  5. 启动 SystemServer 进程。


DeepCoder
569 声望3.2k 粉丝

One blog for recorded and shared, Android system development.