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

一. Zygote啟動(dòng)過程中的創(chuàng)建虛擬機(jī)過程

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方法中省略的代碼中主要在處理傳入的參數(shù), 從而確定當(dāng)前是否要執(zhí)行zygote的邏輯以及啟動(dòng)zygote時(shí)是否需要啟動(dòng)system_server, 這里主要兩個(gè)關(guān)鍵調(diào)用:

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

1.1 AndroidRuntime

AppRuntime的定義就在app_main.cpp中,其構(gòu)造函數(shù)為:

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

可以看到AppRuntime的構(gòu)造函數(shù)沒做任何事,主要就是調(diào)用父類AndroidRuntime的構(gòu)造函數(shù), AndroidRuntime定義在/framework/base/include/android_runtime/AndroidRuntime.h,對(duì)應(yīng)的源文件在/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)
{
    ... //設(shè)置ANDROID_ROOT


    /* 啟動(dòng)虛擬機(jī) */
    //[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相關(guān)的jni方法 */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    ... //調(diào)用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中有三個(gè)重要的變量:

  • JNI_CreateJavaVM_(創(chuàng)建虛擬機(jī)實(shí)例)
  • JNI_GetCreatedJavaVMs_(獲取創(chuàng)建的虛擬機(jī)實(shí)例)
  • JNI_GetDefaultJavaVMInitArgs_(獲取虛擬機(jī)的默認(rèn)初始化參數(shù))

這三個(gè)變量是標(biāo)準(zhǔn)的Java虛擬機(jī)的接口,也就是說實(shí)現(xiàn)了這個(gè)三個(gè)接口,就可以實(shí)現(xiàn)一個(gè)Java虛擬機(jī),具體可參考羅升陽的博客.
JniInvocation的構(gòu)造函數(shù)中初始化這三個(gè)變量為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,所以最后實(shí)際獲取到的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
  }
  //尋找并導(dǎo)出JNI_GetDefaultJavaVMInitArgs_
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
                  "JNI_GetDefaultJavaVMInitArgs")) {
    return false;
  }
  //尋找并導(dǎo)出JNI_CreateJavaVM_
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
                  "JNI_CreateJavaVM")) {
    return false;
  }
  //尋找并導(dǎo)出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函數(shù)打開libart.so,之后利用dlsym函數(shù)尋找并導(dǎo)出Java虛擬機(jī)的三個(gè)接口,這樣就可以通過這三個(gè)接口創(chuàng)建并訪問虛擬機(jī)

1.5 AndroidRuntime::startVm

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

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

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

    return 0;
}

Android::startVm主要做了兩項(xiàng)工作:

  1. 解析虛擬機(jī)啟動(dòng)參數(shù)
  2. 調(diào)用JNI_CreateJavaVM創(chuàng)建虛擬機(jī).源碼的注釋中清楚地說明了創(chuàng)建虛擬機(jī)后每一個(gè)進(jìn)程都應(yīng)該具有一個(gè)JavaVM指針,而每一個(gè)線程都具有一個(gè)JNIEnv指針.JNI_CreateJavaVM實(shí)現(xiàn)在/libnativehelper/JniInvocation.cpp中,其主要邏輯就是返回之前從libart.so中導(dǎo)出的JNI_CreateJavaVM_接口,即JNI_CreateJavaVM的真正實(shí)現(xiàn)是由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中導(dǎo)出的函數(shù)指針

1.6 AppRuntime::onVmCreated

AndroidRuntime::onVmCreated是一個(gè)虛方法,AndroidRuntime類并沒有實(shí)現(xiàn)這個(gè)方法,具體實(shí)現(xiàn)是由子類AppRuntime實(shí)現(xiàn)

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的啟動(dòng),則onVmCreated實(shí)際什么也沒有做

二. 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版本號(hào)
  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] 創(chuàng)建Runtime
  if (!Runtime::Create(options, ignore_unrecognized)) {
    return JNI_ERR;
  }

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

  Runtime* runtime = Runtime::Current();
  //[2.2] 啟動(dòng)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;
  //首先調(diào)用ParseOptions,之后再調(diào)用另一個(gè)重載版本的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;
  //調(diào)用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()最終會(huì)調(diào)用ParsedOptions::DoParse方法(/art/runtime/parsed_options.cc),主要就是用來解析傳入的啟動(dòng)參數(shù),這里暫時(shí)先不分析其主要邏輯.從代碼中可以看到Create函數(shù)主要操作視調(diào)用Runtime::Init函數(shù)

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

  //創(chuàng)建OatFileManager, OatFileManager主要用來加載oat文件
  oat_file_manager_ = new OatFileManager;

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

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

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

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

  //創(chuàng)建堆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

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

  //創(chuàng)建lamba_box_table, arena_pool_, jit_arena_pool_, 如果是64位架構(gòu)且當(dāng)前是dex2oat, 獲取low_4gb_arena_pool_
  ...
  //創(chuàng)建線性分配器linear_alloc_,LinearAlloc創(chuàng)建時(shí)會(huì)用到上面創(chuàng)建的low_4gb_arena_pool_(64位架構(gòu)且是dex2oat時(shí))或者arena_pool_
  linear_alloc_.reset(CreateLinearAlloc());

  BlockSignals();
  //初始化SIGSEGV信號(hào)處理函數(shù)為HandleUnexpectedSignal
  InitPlatformSignalHandlers();

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

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

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

  //創(chuàng)建線程TLS
  Thread::Startup();
  //attach線程, 創(chuàng)建Thread對(duì)象,初始化Thread對(duì)象
  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();

  // 驗(yàn)證heap
  GetHeap()->EnableObjectValidation();

  //創(chuàng)建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文件列表中進(jìn)行構(gòu)造,這里的dex文件列表是系統(tǒng)構(gòu)建時(shí)已經(jīng)創(chuàng)建好的眾多預(yù)加載的文件
      ...
    }
    // 在intern_table_中添加boot image space;將boo image space添加到當(dāng)前ClassLinker的ClassTable中
    ...
  } else {
    ....
    if (!class_linker_->InitWithoutImage(std::move(boot_class_path), &error_msg)) {
      return false;
    }
    ...
  }

  ... //MethodTrace, ProfilerOptions, Trace

  //提前分配一個(gè)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();

  //提前分配一個(gè)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();

  ... //從傳入的參數(shù)中獲取native_bridge_file_name

  return true;
}

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

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

Heap的創(chuàng)建過程比較復(fù)雜,個(gè)人覺得需要單獨(dú)整理一個(gè)篇幅來學(xué)習(xí), OatFileManagerLinearAlloc的構(gòu)造函數(shù)都很簡單, 另外ClassLinker的初始化過程也較為繁瑣,加上ClassLinker類比較重要,同樣需要單獨(dú)的篇幅來學(xué)習(xí)

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的構(gòu)造函數(shù)存儲(chǔ)了Runtme指針,之后初始化了自身變量

2.1.3 Thread::Startup

void Thread::Startup() {
  ...
  //調(diào)用pthread_key_create來創(chuàng)建線程私有數(shù)據(jù)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();
      //創(chuàng)建Thread對(duì)象
      self = new Thread(as_daemon);
      //初始化Thread對(duì)象
      bool init_success = self->Init(runtime->GetThreadList(), runtime->GetJavaVM());
      Runtime::Current()->EndThreadBirth();
      if (!init_success) {
        delete self;
        return nullptr;
      }
    }
  }
  //設(shè)置創(chuàng)建String對(duì)象的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;

  // 創(chuàng)建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,主要對(duì)應(yīng)于Java層的java.lang,dalvik.system這些包下的類
    InitNativeMethods();
  }
  //創(chuàng)建main_thread_group和system_thread_group
  InitThreadGroups(self);
  //創(chuàng)建一個(gè)java.lang.Thread對(duì)象,并將Thread.nativePeer變量設(shè)為ART中的Thread對(duì)象self
  Thread::FinishStartup();
  //調(diào)用ClassLoader.getSystemClassLoader創(chuàng)建系統(tǒng)ClassLoader
  system_class_loader_ = CreateSystemClassLoader(this);

  //如果當(dāng)前處于Zygote模式, 利用unshare,以及mount的SLAVE模式創(chuàng)建外部存儲(chǔ)文件系統(tǒng)
  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));
  }
  //啟動(dòng)java.lang.Daemon中定義的后臺(tái)線程
  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相關(guān)

  return true;
}

Runtime::Start主要操作是:

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

三.總結(jié)

Java虛擬機(jī)有三個(gè)標(biāo)準(zhǔn)接口,只要實(shí)現(xiàn)這三個(gè)接口,就可以實(shí)現(xiàn)一個(gè)自定義的虛擬機(jī),這三個(gè)接口分別是:JNI_CreateJavaVM_, JNI_GetCreatedJavaVMs_, JNI_GetDefaultJavaVMInitArgs_,這三個(gè)接口的具體實(shí)現(xiàn)都位于libart.so動(dòng)態(tài)庫中,Zygote進(jìn)程是通過dlopen打開libart.so,之后通過dlsym分別導(dǎo)出這三個(gè)接口,并調(diào)用JNI_CreateJavaVM_創(chuàng)建虛擬機(jī)Runtime實(shí)例,并將Runtime實(shí)例保存在JavaVM結(jié)構(gòu),JavaVM代表的就是虛擬機(jī)執(zhí)行環(huán)境(在libart.so中實(shí)際返回的是其子類JavaVMExt).

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

JNI_CreateJavaVM_創(chuàng)建虛擬機(jī)Runtime的過程可以總結(jié)為:

  1. 解析傳入的參數(shù),將參數(shù)以key-value的形式組合在一起
  2. 調(diào)用Runtime::Create創(chuàng)建Runtime實(shí)例,創(chuàng)建的過程中還會(huì)依次創(chuàng)建OatFileManager, Heap, LinearAlloc, JavaVMExt, Thread, ClassLinker,同時(shí)初始化線程和ClassLinker
  3. 調(diào)用Runtime::Start完成最后的初始化工作
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末旧找,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子臀防,更是在濱河造成了極大的恐慌滞欠,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哩陕,死亡現(xiàn)場離奇詭異躲查,居然都是意外死亡弟蚀,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門挑豌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來安券,“玉大人,你說我怎么就攤上這事氓英『蠲悖” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵铝阐,是天一觀的道長址貌。 經(jīng)常有香客問我,道長徘键,這世上最難降的妖魔是什么练对? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮吹害,結(jié)果婚禮上螟凭,老公的妹妹穿的比我還像新娘。我一直安慰自己赠制,他們只是感情好赂摆,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著钟些,像睡著了一般烟号。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上政恍,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天汪拥,我揣著相機(jī)與錄音,去河邊找鬼篙耗。 笑死迫筑,一個(gè)胖子當(dāng)著我的面吹牛宪赶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播脯燃,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼搂妻,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了辕棚?” 一聲冷哼從身側(cè)響起欲主,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎逝嚎,沒想到半個(gè)月后扁瓢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡补君,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年引几,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挽铁。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡伟桅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出屿储,到底是詐尸還是另有隱情贿讹,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布够掠,位于F島的核電站民褂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏疯潭。R本人自食惡果不足惜赊堪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望竖哩。 院中可真熱鬧哭廉,春花似錦、人聲如沸相叁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽增淹。三九已至椿访,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間虑润,已是汗流浹背成玫。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人哭当。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓猪腕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親钦勘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子陋葡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容