ART Runtime創建(一)--整體流程

一. Zygote啟動過程中的創建虛擬機過程

Zygote的代碼位于/framework/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
    ...
    //[1.1]
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));

    ... // handle args

    if (zygote) {
        //[1.2]
        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.");
        return 10;
    }
}

main方法中省略的代碼中主要在處理傳入的參數, 從而確定當前是否要執行zygote的邏輯以及啟動zygote時是否需要啟動system_server, 這里主要兩個關鍵調用:

  1. AppRuntime runtime(...)這行代碼創建了一個AppRuntime對象,AppRuntime繼承自AndroidRuntime
  2. runtime.start(...)調用AppRuntime的start方法,由于AppRuntime并沒有重寫父類的start方法,所以這里實際調用的是AndroidRuntime::start(...)

1.1 AndroidRuntime

AppRuntime的定義就在app_main.cpp中,其構造函數為:

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

可以看到AppRuntime的構造函數沒做任何事,主要就是調用父類AndroidRuntime的構造函數, AndroidRuntime定義在/framework/base/include/android_runtime/AndroidRuntime.h,對應的源文件在/framework/base/core/jni/AndroidRuntime.cpp

//全局變量
static AndroidRuntime* gCurRuntime = NULL;

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

    // mOptions的類型是:Vector<JavaVMOption>
    mOptions.setCapacity(20);

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

1.2 AndroidRuntime::start

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ... //設置ANDROID_ROOT


    /* 啟動虛擬機 */
    //[1.3]
    JniInvocation jni_invocation;
    //[1.4]
    jni_invocation.Init(NULL);
    JNIEnv* env;
    //[1.5], mJavaVM是AndroidRuntime的static變量,初始化為NULL
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    //[1.6]
    onVmCreated(env);

    /* 注冊android相關的jni方法 */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    ... //調用com.android.internal.os.ZygoteInit或者RuntimeInit的main方法

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

1.3 JniInvocation::JniInvocation

JniInvocation::JniInvocation() :
    handle_(NULL),
    JNI_GetDefaultJavaVMInitArgs_(NULL),
    JNI_CreateJavaVM_(NULL),
    JNI_GetCreatedJavaVMs_(NULL) {

  LOG_ALWAYS_FATAL_IF(jni_invocation_ != NULL, "JniInvocation instance already initialized");
  jni_invocation_ = this;
}

JniInvocation類的頭文件和源文件分別在/libnativehelper/include/nativehelper/JniInvocation.h,/libnativehelper/JniInvocation.cpp.
JniInvocation中有三個重要的變量:

  • JNI_CreateJavaVM_(創建虛擬機實例)
  • JNI_GetCreatedJavaVMs_(獲取創建的虛擬機實例)
  • JNI_GetDefaultJavaVMInitArgs_(獲取虛擬機的默認初始化參數)

這三個變量是標準的Java虛擬機的接口,也就是說實現了這個三個接口,就可以實現一個Java虛擬機,具體可參考羅升陽的博客.
JniInvocation的構造函數中初始化這三個變量為NULL

1.4 JniInvocation::Init

bool JniInvocation::Init(const char* library) {
#ifdef __ANDROID__
  char buffer[PROP_VALUE_MAX];
#else
  char* buffer = NULL;
#endif
  //由于傳入的library是NULL,所以最后實際獲取到的library是libart.so
  library = GetLibrary(library, buffer);
  const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
  handle_ = dlopen(library, kDlopenFlags);
  if (handle_ == NULL) {
    ... //打開libart.so失敗,直接返回;如果打開其他library失敗,則嘗試打開libart.so
  }
  //尋找并導出JNI_GetDefaultJavaVMInitArgs_
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
                  "JNI_GetDefaultJavaVMInitArgs")) {
    return false;
  }
  //尋找并導出JNI_CreateJavaVM_
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
                  "JNI_CreateJavaVM")) {
    return false;
  }
  //尋找并導出JNI_GetCreatedJavaVMs_
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
                  "JNI_GetCreatedJavaVMs")) {
    return false;
  }
  return true;
}

bool JniInvocation::FindSymbol(void** pointer, const char* symbol) {
  *pointer = dlsym(handle_, symbol);
  ... // handle error
  return true;
}

JniInvocation::Init的主要工作就是通過dlopen函數打開libart.so,之后利用dlsym函數尋找并導出Java虛擬機的三個接口,這樣就可以通過這三個接口創建并訪問虛擬機

1.5 AndroidRuntime::startVm

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
    ... //解析啟動參數

    initArgs.version = JNI_VERSION_1_4;
    initArgs.options = mOptions.editArray();
    initArgs.nOptions = mOptions.size();
    initArgs.ignoreUnrecognized = JNI_FALSE;

     /**
     * 創建虛擬機, 每一個進程有一個JavaVM*, 每一個線程有一個JNIEnv*
     */
    //[1.5.1]
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
        ALOGE("JNI_CreateJavaVM failed\n");
        return -1;
    }

    return 0;
}

Android::startVm主要做了兩項工作:

  1. 解析虛擬機啟動參數
  2. 調用JNI_CreateJavaVM創建虛擬機.源碼的注釋中清楚地說明了創建虛擬機后每一個進程都應該具有一個JavaVM指針,而每一個線程都具有一個JNIEnv指針.JNI_CreateJavaVM實現在/libnativehelper/JniInvocation.cpp中,其主要邏輯就是返回之前從libart.so中導出的JNI_CreateJavaVM_接口,即JNI_CreateJavaVM的真正實現是由libart.so完成的

1.5.1 JniInvocation::JNI_CreateJavaVM

extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
  return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
}

jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
  return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
}

JNI_CreateJavaVM_就是之前在JniInvocation::Init中導出的函數指針

1.6 AppRuntime::onVmCreated

AndroidRuntime::onVmCreated是一個虛方法,AndroidRuntime類并沒有實現這個方法,具體實現是由子類AppRuntime實現

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

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

從代碼中可以看出,如果是Zygote的啟動,則onVmCreated實際什么也沒有做

二. libart.so中的JNI_CreateJavaVM

libart.so的代碼都位于/art目錄下,而JNI_CreateJavaVM定義在/art/runtime/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);
  //檢查Jni版本號
  if (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;
  //[2.1] 創建Runtime
  if (!Runtime::Create(options, ignore_unrecognized)) {
    return JNI_ERR;
  }

  //初始化native loader, 確保在使用JNI之前所需的環境都已經設置好
  android::InitializeNativeLoader();

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

  //獲取JNIEnv和JavaVM,返回給上層
  *p_env = Thread::Current()->GetJniEnv();
  *p_vm = runtime->GetJavaVM();
  return JNI_OK;
}

2.1 Runtime::Create

代碼位于/art/runtime/runtime.cc

bool Runtime::Create(const RuntimeOptions& raw_options, bool ignore_unrecognized) {
  RuntimeArgumentMap runtime_options;
  //首先調用ParseOptions,之后再調用另一個重載版本的Create
  return ParseOptions(raw_options, ignore_unrecognized, &runtime_options) &&
      Create(std::move(runtime_options));
}

bool Runtime::Create(RuntimeArgumentMap&& runtime_options) {
  if (Runtime::instance_ != nullptr) {
    return false;
  }
  instance_ = new Runtime;
  //調用Runtime::Init(), [2.1.1]
  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;
}

ParseOptions()最終會調用ParsedOptions::DoParse方法(/art/runtime/parsed_options.cc),主要就是用來解析傳入的啟動參數,這里暫時先不分析其主要邏輯.從代碼中可以看到Create函數主要操作視調用Runtime::Init函數

2.1.1 Runtime::Init

bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
  RuntimeArgumentMap runtime_options(std::move(runtime_options_in));
  ScopedTrace trace(__FUNCTION__);

  MemMap::Init();
  using Opt = RuntimeArgumentMap;
  QuasiAtomic::Startup();

  //創建OatFileManager, OatFileManager主要用來加載oat文件
  oat_file_manager_ = new OatFileManager;

  Thread::SetSensitiveThreadHook(runtime_options.GetOrDefault(Opt::HookIsSensitiveThread));
  Monitor::Init(runtime_options.GetOrDefault(Opt::LockProfThreshold));

  //從傳入的參數中初始化boot_class_path_string_, class_path_string_, patchoat_executable_等變量
  //創建monitor_list_, monitor_pool_, thread_list_, intern_table_
  //繼續獲取一些基本變量
  ...

  //查看參數中是否指定了解釋執行,如果指定,則告知虛擬機所有代碼都是解釋執行
  if (runtime_options.GetOrDefault(Opt::Interpret)) {
    GetInstrumentation()->ForceInterpretOnly();
  }

  //仍然是從傳入的參數中初始化一些基礎變量, 并獲取CompilerFilter
  ...

  //創建堆Heap
  heap_ = new gc::Heap(...);
  if (!heap_->HasBootImageSpace() && !allow_dex_file_fallback_) {
    LOG(ERROR) << "Dex file fallback disabled, cannot continue without image.";
    return false;
  }

  ... //獲取dump_gc_performance_on_shutdown_, 配置Jdwp

  //創建JIT選項,JIT是7.0中新增的,用來提升代碼執行效率
  jit_options_.reset(jit::JitOptions::CreateFromRuntimeArguments(runtime_options));
  //如果此時是dex2oat程序,dex2oat執行時也會創建一個Runtime用來編譯dex文件,此時不需要開啟JIT選項
  if (IsAotCompiler()) {
    jit_options_->SetUseJitCompilation(false);
    jit_options_->SetSaveProfilingInfo(false);
  }

  //創建lamba_box_table, arena_pool_, jit_arena_pool_, 如果是64位架構且當前是dex2oat, 獲取low_4gb_arena_pool_
  ...
  //創建線性分配器linear_alloc_,LinearAlloc創建時會用到上面創建的low_4gb_arena_pool_(64位架構且是dex2oat時)或者arena_pool_
  linear_alloc_.reset(CreateLinearAlloc());

  BlockSignals();
  //初始化SIGSEGV信號處理函數為HandleUnexpectedSignal
  InitPlatformSignalHandlers();

  //arm, arm64, x86, mips, mips64, thumb2, x86_64架構下,
  //implicit_null_checks_ = true
  //implicit_so_checks_ !(RUNNING_ON_MEMORY_TOOL && kMemoryToolIsValgrind)
  ....

  ... //處理no_sig_chain = false時的情況(no_sig_chain在之前根據傳入的參數獲取)

  //創建JavaVMExt
  java_vm_ = new JavaVMExt(this, runtime_options);

  //創建線程TLS
  Thread::Startup();
  //attach線程, 創建Thread對象,初始化Thread對象
  Thread* self = Thread::Attach("main", false, nullptr, false);

  // Set us to runnable so tools using a runtime can allocate and GC by default
  self->TransitionFromSuspendedToRunnable();

  // 驗證heap
  GetHeap()->EnableObjectValidation();

  //創建ClassLinker
  class_linker_ = new ClassLinker(intern_table_);
  if (GetHeap()->HasBootImageSpace()) {
    ...
    bool result = class_linker_->InitFromBootImage(&error_msg);
    ...
    if (boot_class_path_string_.empty()) {
      // 如果bootclasspath沒有顯示指定,則從加載的dex文件列表中進行構造,這里的dex文件列表是系統構建時已經創建好的眾多預加載的文件
      ...
    }
    // 在intern_table_中添加boot image space;將boo image space添加到當前ClassLinker的ClassTable中
    ...
  } else {
    ....
    if (!class_linker_->InitWithoutImage(std::move(boot_class_path), &error_msg)) {
      return false;
    }
    ...
  }

  ... //MethodTrace, ProfilerOptions, Trace

  //提前分配一個OutOfMemoryError
  self->ThrowNewException("Ljava/lang/OutOfMemoryError;",
                          "OutOfMemoryError thrown while trying to throw OutOfMemoryError; "
                          "no stack trace available");
  pre_allocated_OutOfMemoryError_ = GcRoot<mirror::Throwable>(self->GetException());
  self->ClearException();

  //提前分配一個NoClassDefFoundError
  self->ThrowNewException("Ljava/lang/NoClassDefFoundError;",
                          "Class not found using the boot class loader; no stack trace available");
  pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>(self->GetException());
  self->ClearException();

  ... //從傳入的參數中獲取native_bridge_file_name

  return true;
}

Runtime::Init方法代碼量較大,整個過程中創建或者初始化了很多工具組件如MemMap, QuasiAtomic等,并且從傳入的參數依次獲取了一些基礎變量如boot_class_path_string_, class_path_string_等,之后還設置信號處理函數等,不過整體來看Init方法的主要邏輯很清楚,分別做了以下幾件事:

  1. 創建OatFileManager對象,OatFileManager是在7.0中新增的工具類,Runtime在解析讀取oat文件都是通過這個工具類完成
  2. 創建了Heap(整個創建過程比較冗長,復雜)
  3. 根據傳入參數配置JIT選項,如果當前是dex2oat則不配置JIT
  4. 創建LinearAlloc
  5. 創建JavaVMExt
  6. 創建一個線程,同時attach線程(attach的過程實際就是創建Thread對象并初始化Thread對象的過程)
  7. 創建ClassLinker,如果有BootImageSpace則調用ClassLinker::InitFromBootImage完成ClassLinker的初始化;如果沒有BootImageSpace,則調用ClassLinker::InitWithoutImage來完成初始化
  8. 提前分配一個OutOfMemoryErrorNoClassDefFoundError

Heap的創建過程比較復雜,個人覺得需要單獨整理一個篇幅來學習, OatFileManagerLinearAlloc的構造函數都很簡單, 另外ClassLinker的初始化過程也較為繁瑣,加上ClassLinker類比較重要,同樣需要單獨的篇幅來學習

2.1.2 JavaVMExt::JavaVMExt

JavaVMExt的源文件是/art/runtime/java_vm_ext.cc,JavaVMExt繼承自JavaVM:

class JavaVMExt : public JavaVM {
  ...
};

JavaVM定義在/libnativehelper/include/nativehelper/jni.h

JavaVMExt::JavaVMExt(Runtime* runtime, const RuntimeArgumentMap& runtime_options)
    : runtime_(runtime),
      check_jni_abort_hook_(nullptr),
      check_jni_abort_hook_data_(nullptr),
      check_jni_(false),  // Initialized properly in the constructor body below.
      force_copy_(runtime_options.Exists(RuntimeArgumentMap::JniOptsForceCopy)),
      tracing_enabled_(runtime_options.Exists(RuntimeArgumentMap::JniTrace)
                       || VLOG_IS_ON(third_party_jni)),
      trace_(runtime_options.GetOrDefault(RuntimeArgumentMap::JniTrace)),
      globals_lock_("JNI global reference table lock"),
      globals_(gGlobalsInitial, gGlobalsMax, kGlobal),
      libraries_(new Libraries),
      unchecked_functions_(&gJniInvokeInterface),
      weak_globals_lock_("JNI weak global reference table lock", kJniWeakGlobalsLock),
      weak_globals_(kWeakGlobalsInitial, kWeakGlobalsMax, kWeakGlobal),
      allow_accessing_weak_globals_(true),
      weak_globals_add_condition_("weak globals add condition", weak_globals_lock_) {
  functions = unchecked_functions_;
  SetCheckJniEnabled(runtime_options.Exists(RuntimeArgumentMap::CheckJni));
}

可以看到,JavaVMExt的構造函數存儲了Runtme指針,之后初始化了自身變量

2.1.3 Thread::Startup

void Thread::Startup() {
  ...
  //調用pthread_key_create來創建線程私有數據TLS
  CHECK_PTHREAD_CALL(pthread_key_create, (&Thread::pthread_key_self_, Thread::ThreadExitCallback),
                     "self key");
  ...
}

2.1.4 Thread::Attach

Thread* Thread::Attach(const char* thread_name, bool as_daemon, jobject thread_group,
                       bool create_peer) {
  Runtime* runtime = Runtime::Current();
  ...
  Thread* self;
  {
    MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
    if (runtime->IsShuttingDownLocked()) {
      ...
      return nullptr;
    } else {
      Runtime::Current()->StartThreadBirth();
      //創建Thread對象
      self = new Thread(as_daemon);
      //初始化Thread對象
      bool init_success = self->Init(runtime->GetThreadList(), runtime->GetJavaVM());
      Runtime::Current()->EndThreadBirth();
      if (!init_success) {
        delete self;
        return nullptr;
      }
    }
  }
  //設置創建String對象的entry point為StringFactory
  self->InitStringEntryPoints();  
  self->SetState(kNative);

  ... //傳入的create_peer為false

  {
    ScopedObjectAccess soa(self);
    Dbg::PostThreadStart(self);
  }

  return self;
}

2.2 Runtime::Start

bool Runtime::Start() {

  ..

  Thread* self = Thread::Current();
  self->TransitionFromRunnableToSuspended(kNative);
  started_ = true;

  // 創建JIT
  if (jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo()) {
    std::string error_msg;
    if (!IsZygote()) {
      // If we are the zygote then we need to wait until after forking to create the code cache
      // due to SELinux restrictions on r/w/x memory regions.
      CreateJit();
    } else if (jit_options_->UseJitCompilation()) {
      if (!jit::Jit::LoadCompilerLibrary(&error_msg)) {
        // Try to load compiler pre zygote to reduce PSS. b/27744947
        LOG(WARNING) << "Failed to load JIT compiler with error " << error_msg;
      }
    }
  }

  ...

  {
    ScopedTrace trace2("InitNativeMethods");
    //初始化JniConstants的常量,JniConstants定義在/libnativehelper/include/native/JniConstants.h
    //注冊runtime中的native method,主要對應于Java層的java.lang,dalvik.system這些包下的類
    InitNativeMethods();
  }
  //創建main_thread_group和system_thread_group
  InitThreadGroups(self);
  //創建一個java.lang.Thread對象,并將Thread.nativePeer變量設為ART中的Thread對象self
  Thread::FinishStartup();
  //調用ClassLoader.getSystemClassLoader創建系統ClassLoader
  system_class_loader_ = CreateSystemClassLoader(this);

  //如果當前處于Zygote模式, 利用unshare,以及mount的SLAVE模式創建外部存儲文件系統
  if (is_zygote_) {
    if (!InitZygote()) {
      return false;
    }
  } else {
    if (is_native_bridge_loaded_) {
      PreInitializeNativeBridge(".");
    }
    NativeBridgeAction action = force_native_bridge_
        ? NativeBridgeAction::kInitialize
        : NativeBridgeAction::kUnload;
    InitNonZygoteOrPostFork(self->GetJniEnv(),
                            /* is_system_server */ false,
                            action,
                            GetInstructionSetString(kRuntimeISA));
  }
  //啟動java.lang.Daemon中定義的后臺線程
  StartDaemonThreads();

  {
    ScopedObjectAccess soa(self);
    self->GetJniEnv()->locals.AssertEmpty();
  }
  finished_starting_ = true;

  //如果ProfilerOptions開啟且存在profile文件,打開profile文件
  if (profiler_options_.IsEnabled() && !profile_output_filename_.empty()) {
    int fd = open(profile_output_filename_.c_str(), O_RDWR|O_CREAT|O_EXCL, 0660);
    if (fd >= 0) {
      close(fd);
    } else if (errno != EEXIST) {
      LOG(WARNING) << "Failed to access the profile file. Profiler disabled.";
    }
  }

  ... //Trace相關

  return true;
}

Runtime::Start主要操作是:

  1. 如果當前不是Zygote,則創建JIT
  2. 初始化libnativehelper.so中定義的JniConstants,注冊java.lang,dalvik.system包下的本地方法
  3. 創建main_thread_group和system_thread_group
  4. 創建一個java.lang.Thread對象,并將Thread.nativePeer變量設為ART中的Thread對象self
  5. 調用ClassLoader.getSystemClassLoader創建系統ClassLoader
  6. 如果當前處于Zygote模式, 利用unshare,以及mount的SLAVE模式創建外部存儲文件系統;如果不是,則初始化native bridge
  7. 啟動java.lang.Daemon中定義的后臺線程
  8. 判斷ProfilerOptions是否開啟,如果開啟且profile文件不為空,則打開profile文件(Profile文件是在7.0中跟JIT一起加入的, 主要為了提升運行效率)
  9. 查看Trace相關配置,如果不為空,則開啟Trace

三.總結

Java虛擬機有三個標準接口,只要實現這三個接口,就可以實現一個自定義的虛擬機,這三個接口分別是:JNI_CreateJavaVM_, JNI_GetCreatedJavaVMs_, JNI_GetDefaultJavaVMInitArgs_,這三個接口的具體實現都位于libart.so動態庫中,Zygote進程是通過dlopen打開libart.so,之后通過dlsym分別導出這三個接口,并調用JNI_CreateJavaVM_創建虛擬機Runtime實例,并將Runtime實例保存在JavaVM結構,JavaVM代表的就是虛擬機執行環境(在libart.so中實際返回的是其子類JavaVMExt).

需要留意的是,源碼的注釋中寫的很清楚,每一個進程都必須有一個JavaVM,而每一個線程都有一個JNIEnv

JNI_CreateJavaVM_創建虛擬機Runtime的過程可以總結為:

  1. 解析傳入的參數,將參數以key-value的形式組合在一起
  2. 調用Runtime::Create創建Runtime實例,創建的過程中還會依次創建OatFileManager, Heap, LinearAlloc, JavaVMExt, Thread, ClassLinker,同時初始化線程和ClassLinker
  3. 調用Runtime::Start完成最后的初始化工作
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,885評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,312評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,993評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,410評論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,778評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,955評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,521評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,266評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,468評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,696評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,193評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,431評論 2 378

推薦閱讀更多精彩內容