Android10 Framework—Zygote-1.启动引导

108 阅读15分钟

概述

Zygote中文翻译为“受精卵”,正如其名,它主要用于孵化子进程。在Android系统中有以 下两种程序:

  • java应用程序,主要基于ART虚拟机,所有的应用程序apk都属于这类
  • native程序,也就是利用C或C++语言开发的程序,如bootanimation

所有的Java应用程序进程及系统服务SystemServer进程都由Zygote进程通过Linux的fork()函数孵化出来的,这也就是为什么把它称为Zygote的原因,因为他就像一个受精卵,孵化出无数子进程,而native程序则由Init程序创建启动。Zygote进程最初的名字不是“zygote”而 是“app_process”,这个名字是在Android.mk文件中定义的。

Zgyote是Android中的第一个art虚拟机,他通过socket的方式与其他进程进行通信,这里的“其他进程” 其实主要是系统进程——SystemServer。

Zygote是一个C/S模型,Zygote进程作为服务端,它主要负责创建Java虚拟机,加载系统资源,启 动SystemServer进程,以及在后续运行过程中启动普通的应用程序,其他进程作为客户端向它发 出“孵化”请求,而Zygote接收到这个请求后就“孵化”出一个新的进程。比如,当点击Launcher里 的 应用程序图标去启动一个新的应用程序进程时,这个请求会到达框架层的核心服务 ActivityManagerService中,当AMS收到这个请求后,它通过调用Process类发出一个“孵化”子进 程的Socket请求,而Zygote监听到这个请求后就立刻fork一个新的进程出来

通信架构.png

入口

在“Android Framework—Init进程-14.启动服务”一文中已详细讲解过init进程是如何通过如下配置文件启动Zygote服务的

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    socket usap_pool_primary stream 660 root system
    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

/system/bin/app_process64为zygote服务的可执行文件,通过查看相关的mk文件查找zygote服务的入口文件为app_main.cpp

//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

AppRuntime

AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));

在main函数中首先会创建AppRuntime,AppRuntime继承AndroidRuntime,AndroidRuntime是一个非常重要的类,那么什么是Runtime?归纳起来的意思就是,Runtime 是支撑程序运行的基础库,它是与语言绑定在一起的,比如:

  • C Runtime:就是C standard lib, 也就是我们常说的libc。(有意思的是, Wiki会自动 将“C runtime” 重定向到 “C Standard Library”)
  • Java Runtime: 同样,Wiki将其重定向到” Java Virtual Machine”, 这里当然包括Java 的支撑 类库(.jar)
  • AndroidRuntime: 显而易见,就是为Android应用运行所需的运行时环境。这个环境包括以下东 东:
    • Dalvik VM: Android的Java VM, 解释运行Dex格式Java程序。每个进程运行一个虚拟机(什 么叫运行虚拟机?说白了,就是一些C代码,不停的去解释Dex格式的二进制码(Bytecode),把 它们转成机器码(Machine code),然后执行,当然,现在大多数的Java 虚拟机都支持JIT, 也就是说,bytecode可能在运行前就已经被转换成机器码,从而大大提高了性能。过去一个普 遍的认识是Java 程序比C,C++等静态编译的语言慢,但随着JIT的介入和发展,这个已经完全 是过去时了,JIT的动态性运行允许虚拟机根据运行时环境,优化机器码的生成,在某些情况 下,Java甚至可以比C/C++跑得更快,同时又兼具平台无关的特性,这也是为什么Java如今如 此流行的原因之一吧)。
    • Android的Java 类库, 大部分来自于 Apache Hamony, 开源的Java API 实现,如 java.lang, java.util, java.net. 但去除了AWT, Swing 等部件。
    • JNI: C和Java互调的接口。
    • Libc: Android也有很多C代码,自然少不了libc,注意的是,Android的libc叫 bionic C

因此AppRuntime在Android系统中就是应用程序运行的基础环境,AppRuntime自身还实现了如下内容

//cmds/app_process/app_main.cpp

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

    void setClassNameAndArgs(const String8& className, int argc, char * const *argv) {
        mClassName = className;
        for (int i = 0; i < argc; ++i) {
             mArgs.add(String8(argv[i]));
        }
    }

    virtual void onVmCreated(JNIEnv* env)
    {
        if (mClassName.isEmpty()) {
            return; // Zygote. Nothing to do here.
        }

        /*
         * This is a little awkward because the JNI FindClass call uses the
         * class loader associated with the native method we're executing in.
         * If called in onStarted (from RuntimeInit.finishInit because we're
         * launching "am", for example), FindClass would see that we're calling
         * from a boot class' native method, and so wouldn't look for the class
         * we're trying to look up in CLASSPATH. Unfortunately it needs to,
         * because the "am" classes are not boot classes.
         *
         * The easiest fix is to call FindClass here, early on before we start
         * executing boot class Java code and thereby deny ourselves access to
         * non-boot classes.
         */
        char* slashClassName = toSlashClassName(mClassName.string());
        mClass = env->FindClass(slashClassName);
        if (mClass == NULL) {
            ALOGE("ERROR: could not find class '%s'\n", mClassName.string());
        }
        free(slashClassName);

        mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
    }

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

        AndroidRuntime* ar = AndroidRuntime::getRuntime();
        ar->callMain(mClassName, mClass, mArgs);

        IPCThreadState::self()->stopProcess();
        hardware::IPCThreadState::self()->stopProcess();
    }

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

    virtual void onExit(int code)
    {
        if (mClassName.isEmpty()) {
            // if zygote
            IPCThreadState::self()->stopProcess();
            hardware::IPCThreadState::self()->stopProcess();
        }

        AndroidRuntime::onExit(code);
    }


    String8 mClassName;
    Vector<String8> mArgs;
    jclass mClass;
};
  • mClassName:指定要启动的java类名
  • mClass:如果mClassName存在,在onVmCreated中会找到mClassName对应的class
  • mArgs:启动mClassName时传递的启动参数

其它实现方法在后续的分析中会被调用到,然后再做进一步分析。

static AndroidRuntime* gCurRuntime = NULL;

AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
        mExitWithoutCleanup(false),
        mArgBlockStart(argBlockStart),
        mArgBlockLength(argBlockLength)
{
    SkGraphics::Init();

    // Pre-allocate enough space to hold a fair number of options.
    mOptions.setCapacity(20);

    assert(gCurRuntime == NULL);        // one per process
    gCurRuntime = this;
}

在AndroidRuntime的构造函数中会将AppRuntime实例赋值给gCurRuntime,gCurRuntime在代码中作为一个全局单例对象使用,它代表虚拟机实例,因此一个进程中只会有一个虚拟机实例。

main

// Everything up to '--' or first non '-' arg goes to the vm.
//
// The first argument after the VM args is the "parent dir", which
// is currently unused.
//
// After the parent dir, we expect one or more the following internal
// arguments :
//
// --zygote : Start in zygote mode
// --start-system-server : Start the system server.
// --application : Start in application (stand alone, non zygote) mode.
// --nice-name : The nice name for this process.
//
// For non zygote starts, these arguments will be followed by
// the main class name. All remaining arguments are passed to
// the main method of this class.
//
// For zygote starts, all remaining arguments are passed to the zygote.
// main function.
//
// Note that we must copy argument string values since we will rewrite the
// entire argument block when we apply the nice name to argv0.
//
// As an exception to the above rule, anything in "spaced commands"
// goes to the vm even though it has a space in it.

这段注释说明了/system/bin/app_process64这个可执行程序的用法

app_process [java-options] cmd-dir start-class-name [options]

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
  • java-options:在'--'开头的参数或者第一个非'-'参数之前的字符串都是需要传递给虚拟机的java选项(Everything up to '--' or first non '-' arg goes to the vm)
  • cmd-dir:在java-options后面的第一个参数为可执行程序的工作根目录(After the parent dir)
  • start-class-name:指定启动的类名
  • options:其它选项
    • --zygote : 启动zygote进程
    • --start-system-server : 启动system server进程
    • --application : 启动应用程序进程
    • --nice-name : 指定进程名称
const char* spaced_commands[] = { "-cp", "-classpath" };
// Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
bool known_command = false;

int i;
for (i = 0; i < argc; i++) {
    if (known_command == true) {
      runtime.addOption(strdup(argv[i]));
      // The static analyzer gets upset that we don't ever free the above
      // string. Since the allocation is from main, leaking it doesn't seem
      // problematic. NOLINTNEXTLINE
      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) {
      if (strcmp(argv[i], spaced_commands[j]) == 0) {
        known_command = true;
        ALOGV("app_process main found known command '%s'", argv[i]);
      }
    }

    if (argv[i][0] != '-') {
        break;
    }
    if (argv[i][1] == '-' && argv[i][2] == 0) {
        ++i; // Skip --.
        break;
    }

    runtime.addOption(strdup(argv[i]));
    // The static analyzer gets upset that we don't ever free the above
    // string. Since the allocation is from main, leaking it doesn't seem
    // problematic. NOLINTNEXTLINE
    ALOGV("app_process main add option '%s'", argv[i]);
}

有了上面的说明后,这段就比较好理解了:它其实就是解析出参数中的java-options,然后调用addOption添加到虚拟机中

void AndroidRuntime::addOption(const char* optionString, void* extraInfo)
{
    JavaVMOption opt;
    opt.optionString = optionString;
    opt.extraInfo = extraInfo;
    mOptions.add(opt);
}

紧接着继续解析参数,将options内容都解析到如下局部变量中

// Parse runtime arguments.  Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;

++i;  // Skip unused "parent dir" argument.
while (i < argc) {
    const char* arg = argv[i++];
    if (strcmp(arg, "--zygote") == 0) {
        zygote = true;
        niceName = ZYGOTE_NICE_NAME;
    } else if (strcmp(arg, "--start-system-server") == 0) {
        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) {
        className.setTo(arg);
        break;
    } else {
        --i;
        break;
    }
}

根据是否有className设置向args中添加不同的启动参数,值得注意的是如果className存在好会调用setClassNameAndArgs将ClassName和args保存到runtime中

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);

    if (!LOG_NDEBUG) {
      String8 restOfArgs;
      char* const* argv_new = argv + i;
      int argc_new = argc - i;
      for (int k = 0; k < argc_new; ++k) {
        restOfArgs.append(""");
        restOfArgs.append(argv_new[k]);
        restOfArgs.append("" ");
      }
      ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
    }
} else {
    // We're in zygote mode.
    maybeCreateDalvikCache();

    if (startSystemServer) {
        args.add(String8("start-system-server"));
    }

    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;
    }

    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) {
        args.add(String8(argv[i]));
    }
}

指定进程名称

if (!niceName.isEmpty()) {
    runtime.setArgv0(niceName.string(), true /* setProcName */);
}

main方法会完成如下进程的启动

  • zygote进程启动
  • 指定className启动

他们都是通过调用AndroidRuntime的start方法进行启动

if (zygote) {
    runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
    runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
    fprintf(stderr, "Error: no class name or --zygote supplied.\n");
    app_usage();
    LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}

AndroidRuntime.start

在start方法的最终目的是调用ZygoteInit的main方法或启动指定的className,但是在此之前会进行如下初始化工作:

  • 创建虚拟机
  • 注册JNI函数,因为zygote启动后会进入Android的Java世界,后续的Java应用程序都会通过JNI调用c/c++层
  • 最后通过JNI调用到Zygote的Java世界
/*static*/ JavaVM* AndroidRuntime::mJavaVM = NULL;

/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
    return;
}

调用startVm创建虚拟机,创建的虚拟机实例对象为mJavaVM,以及JNIEnv指针env。

onVmCreated(env);

调用onVmCreated,AppRuntime中覆盖实现了此方法

  • zygote进程:什么都不做
  • 指定className:会找到className对应的class
/*
 * Register android functions.
 */
if (startReg(env) < 0) {
    ALOGE("Unable to register all android natives\n");
    return;
}

调用startReg注册android系统的所有JNI函数

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_com_android_internal_os_AtomicDirectory),
    REG_JNI(register_com_android_internal_os_FuseAppLoop),
};

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

/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
    ...

    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
        return -1;
    }

    ...

    return 0;
}

这里会循环调用gRegJNI数组中定义的mProc函数,mProc实际就是REG_JNI宏中定义的方法名

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));
}

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));
}

JNI方法又会调用jniRegisterNativeMethods

MODULE_API int jniRegisterNativeMethods(C_JNIEnv* env, const char* className,
    const JNINativeMethod* gMethods, int numMethods)
{
    JNIEnv* e = reinterpret_cast<JNIEnv*>(env);

    ALOGV("Registering %s's %d native methods...", className, numMethods);

    scoped_local_ref<jclass> c(env, findClass(env, className));
    ALOG_ALWAYS_FATAL_IF(c.get() == NULL,
                         "Native registration unable to find class '%s'; aborting...",
                         className);

    int result = e->RegisterNatives(c.get(), gMethods, numMethods);
    ALOG_ALWAYS_FATAL_IF(result < 0, "RegisterNatives failed for '%s'; aborting...",
                         className);

    return 0;
}

最后所有的JNI方法都会被注册到JNIEnv中,而这个JNIEnv对象就是前面创建虚拟机时所创建的。

/*
 * We want to call main() with a String array with arguments in it.
 * At present we have two arguments, the class name and an option string.
 * Create an array to hold them.
 */
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;

stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);

for (size_t i = 0; i < options.size(); ++i) {
    jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
    assert(optionsStr != NULL);
    env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}

这个代码块是为后续启动zygote进程或者指定的className准备启动参数:

  • 创建strArray数组并分配空间
  • 如果className存在,则将其放在数组的第 0 位置
  • 最后将options中所有参数依次放入strArray数组
    char* slashClassName = toSlashClassName(className != NULL ? className : "");
    jclass startClass = env->FindClass(slashClassName);
    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");
        if (startMeth == NULL) {
            ALOGE("JavaVM unable to find main() in '%s'\n", className);
            /* keep going */
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }

最后会找到com.android.internal.os.ZygoteInit或com.android.internal.os.RuntimeInit的main方法进行启动,并传递启动参数strArray,这样一来就进入到Java世界了。

startVm创建虚拟机

/*static*/ JavaVM* AndroidRuntime::mJavaVM = NULL;

/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
    return;
}

这里我们重点分析一下虚拟机的创建,上面是调用虚拟机创建的相关代码。

//libnativehelper/JniInvocation.cpp

bool JniInvocationImpl::Init(const char* library) {
#ifdef __ANDROID__
  char buffer[PROP_VALUE_MAX];
#else
  char* buffer = NULL;
#endif
  library = GetLibrary(library, buffer);
  handle_ = OpenLibrary(library);
  if (handle_ == NULL) {
    if (strcmp(library, kLibraryFallback) == 0) {
      // Nothing else to try.
      ALOGE("Failed to dlopen %s: %s", library, GetError().c_str());
      return false;
    }
    // Note that this is enough to get something like the zygote
    // running, we can't property_set here to fix this for the future
    // because we are root and not the system user. See
    // RuntimeInit.commonInit for where we fix up the property to
    // avoid future fallbacks. http://b/11463182
    ALOGW("Falling back from %s to %s after dlopen error: %s",
          library, kLibraryFallback, GetError().c_str());
    library = kLibraryFallback;
    handle_ = OpenLibrary(library);
    if (handle_ == NULL) {
      ALOGE("Failed to dlopen %s: %s", library, GetError().c_str());
      return false;
    }
  }
  if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_GetDefaultJavaVMInitArgs_),
                  "JNI_GetDefaultJavaVMInitArgs")) {
    return false;
  }
  if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_CreateJavaVM_),
                  "JNI_CreateJavaVM")) {
    return false;
  }
  if (!FindSymbol(reinterpret_cast<FUNC_POINTER*>(&JNI_GetCreatedJavaVMs_),
                  "JNI_GetCreatedJavaVMs")) {
    return false;
  }
  return true;
}

jni_invocation.Init方法做了如下工作:

  • 在app_process进程中动态加载动态库libart.so,libart.so是Android Art虚拟机库
    • GetLibrary:得到动态库名
    • OpenLibrary:打开动态库返回动态库句柄
  • 找到动态库中下面函数地址,创建虚拟机时会使用到这些函数
    • 名为JNI_GetDefaultJavaVMInitArgs的函数地址,保存到JNI_GetDefaultJavaVMInitArgs_中
    • 名为JNI_CreateJavaVM的函数地址,保存到JNI_CreateJavaVM_中
    • 名为JNI_GetCreatedJavaVMs_的函数地址,保存到JNI_GetCreatedJavaVMs中
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
    //startVM的前半部分是在处理虚拟机的启动参数,处理完配置参数后,会调用libart.so提供
    的一个接口:JNI_CreateJavaVM函数
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
      ALOGE("JNI_CreateJavaVM failed\n");
      return -1;
    }
}

前面大部分都是处理虚拟机的启动参数以及属性设置,startVm最核心的代码就是调用JNI_CreateJavaVM方法,JNI_CreateJavaVM调用的就是前面找到的函数地址,其实现源码位于art/runtime/jni/java_vm_ext.cc中

//art/runtime/jni/java_vm_ext.cc

extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
  ScopedTrace trace(__FUNCTION__);
  const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);
  if (JavaVMExt::IsBadJniVersion(args->version)) {
    LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;
    return JNI_EVERSION;
  }
  RuntimeOptions options;
  for (int i = 0; i < args->nOptions; ++i) {
    JavaVMOption* option = &args->options[i];
    options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo));
  }
  bool ignore_unrecognized = args->ignoreUnrecognized;
  if (!Runtime::Create(options, ignore_unrecognized)) {
    return JNI_ERR;
  }

  // Initialize native loader. This step makes sure we have
  // everything set up before we start using JNI.
  android::InitializeNativeLoader();

  Runtime* runtime = Runtime::Current();
  bool started = runtime->Start();
  if (!started) {
    delete Thread::Current()->GetJniEnv();
    delete runtime->GetJavaVM();
    LOG(WARNING) << "CreateJavaVM failed";
    return JNI_ERR;
  }

  *p_env = Thread::Current()->GetJniEnv();
  *p_vm = runtime->GetJavaVM();
  return JNI_OK;
}

JNI_CreateJavaVM中调用Runtime::Create创建单例的Runtime对象,runtime负责提供art虚拟机的运行时 环境

bool Runtime::Create(RuntimeArgumentMap&& runtime_options) {
  // TODO: acquire a static mutex on Runtime to avoid racing.
  if (Runtime::instance_ != nullptr) {
    return false;
  }
  instance_ = new Runtime;
  Locks::SetClientCallback(IsSafeToCallAbort);
  if (!instance_->Init(std::move(runtime_options))) {
    // TODO: Currently deleting the instance will abort the runtime on destruction. Now This will
    // leak memory, instead. Fix the destructor. b/19100793.
    // delete instance_;
    instance_ = nullptr;
    return false;
  }
  return true;
}

然后调用其init方法来初始化虚拟机

bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
  ...

  //创建堆管理对象
  heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize),
                     runtime_options.GetOrDefault(Opt::HeapGrowthLimit),
                     runtime_options.GetOrDefault(Opt::HeapMinFree),
                     runtime_options.GetOrDefault(Opt::HeapMaxFree),
                     runtime_options.GetOrDefault(Opt::HeapTargetUtilization),
                      ...
                     )

  //创建java虚拟机对象
  std::string error_msg;
  java_vm_ = JavaVMExt::Create(this, runtime_options, &error_msg);
  if (java_vm_.get() == nullptr) {
    LOG(ERROR) << "Could not initialize JavaVMExt: " << error_msg;
    return false;
  }


  //连接主线程
  // ClassLinker needs an attached thread, but we can't fully attach a thread without creating
  // objects. We can't supply a thread group yet; it will be fixed later. Since we are the main
  // thread, we do not get a java peer.
  Thread* self = Thread::Attach("main", false, nullptr, false);
  CHECK_EQ(self->GetThreadId(), ThreadList::kMainThreadId);

  //创建类连接器
  if (UNLIKELY(IsAotCompiler())) {
    class_linker_ = new AotClassLinker(intern_table_);
  } else {
    class_linker_ = new ClassLinker(
        intern_table_,
        runtime_options.GetOrDefault(Opt::FastClassNotFoundException));
  }
  if (GetHeap()->HasBootImageSpace()) {
    //初始化类连接器
    bool result = class_linker_->InitFromBootImage(&error_msg);
    if (!result) {
      LOG(ERROR) << "Could not initialize from image: " << error_msg;
      return false;
    }
  }

}
  1. new gc::heap(),创建Heap对象,这是虚拟机管理对内存的起点。
  2. new JavaVmExt(),创建Java虚拟机实例。
  3. Thread::attach(),attach主线程
  4. 创建ClassLinker
  5. 初始化ClassLinker,成功attach到runtime环境后,创建ClassLinker实例负责管理java class

到这里,虚拟机的创建和初始化就完成了

Runtime* runtime = Runtime::Current();

*p_env = Thread::Current()->GetJniEnv();
*p_vm = runtime->GetJavaVM();

虚拟机的创建完成后调用Current方法返回前面创建的Runtime单例对象,最后返回JavaVM虚拟机对象和当前线程的JNIEnv对象,注册JNI函数时会使用到JNIEnv(前面已经讲解过),值得注意的是:

  • JavaVM每个进程只有一个
  • JNIEnv每个线程有一个

官方注释如下

/*
 * Initialize the VM.
 *
 * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
 * If this call succeeds, the VM is ready, and we can start issuing
 * JNI calls.
 */
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
    ALOGE("JNI_CreateJavaVM failed\n");
    return -1;
}