Android ART 的初始化和啓動

新書上市《深入解析Android 5.0系統》

 以下內容節選自本書


ART的初始化
 下面我們從JNI_GetDefaultJavaVMInitArgs(),JNI_CreateJavaVM()和JNI_GetCreatedJavaVMs()三個函數入手來了解ART的初始化過程。這三個函數的代碼位於jni_internal.cc中。
 JNI_GetDefaultJavaVMInitArgs()函數在ART中沒有作爲,只是返回JNI_ERR。如下所示:
 extern "C" jintJNI_GetDefaultJavaVMInitArgs(void* ) {
   return JNI_ERR;
 }
 JNI_GetCreatedJavaVMs()函數用來返回在Runtime中保存的JavaVMExt的指針,函數代碼如下所示:
 extern "C" jint JNI_GetCreatedJavaVMs(JavaVM**vms, jsize, jsize* vm_count) {
   Runtime* runtime =Runtime::Current();
   if (runtime == NULL) {
    *vm_count = 0;
   } else {
    *vm_count = 1;
    vms[0] = runtime->GetJavaVM();
   }
   return JNI_OK;
 }
 Runtime的GetJavaVM()函數只是返回了Runtime類的成員變量java_vm_,如下所示。
 JavaVMExt* GetJavaVM() const {
    return java_vm_;
 }
java_vm_是JavaVMExt類型的指針,定義如下:
  JavaVMExt* java_vm_;


 理解了兩個簡單的函數後,我們再來分析JNI_CreateJavaVM()函數,代碼如下:
 extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm,JNIEnv** p_env, void* vm_args) {
   const JavaVMInitArgs* args =static_cast(vm_args);
   // 檢查JNI的版本
   if(IsBadJniVersion(args->version)) {
    LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: "<< args->version;
    return JNI_EVERSION;
   }
   // 保存啓動參數到options中。
   Runtime::Optionsoptions;
   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;
   }
   Runtime* runtime =Runtime::Current();
   bool started =runtime->Start();      //啓動虛擬機
   if (!started) {
    delete Thread::Current()->GetJniEnv();
    delete runtime->GetJavaVM();
    return JNI_ERR; // 啓動失敗,方法
   }
   *p_env =Thread::Current()->GetJniEnv();
   *p_vm =runtime->GetJavaVM();
   return JNI_OK;
 }
 JNI_CreateJavaVM()函數中調用Runtime的Create()函數來創建虛擬機,然後調用start()函數來啓動它。在ART中,Runtime對象的地位和Dalvik中的DvmGlobals對象gDVm類似,包含了所有重要的變量。
下面我們繼續分析Create()函數:
 bool Runtime::Create(const Options& options,bool ignore_unrecognized) {
   if (Runtime::instance_ !=NULL) {
    return false;  //只能創建一個Runtime實例
   }
  InitLogging(NULL);  // Calls Locks::Init() as aside effect.
   instance_ = newRuntime;  // 創建了Runtime類的實例
   if(!instance_->Init(options, ignore_unrecognized)){ // 初始化Runtime對象
    delete instance_;
    instance_ = NULL;
    return false;
   }
   return true;
 }
 Runtime的Create()函數中創建了Runtime對象,並調用它的Init()函數進行初始化。函數代碼如下:
 bool Runtime::Init(const Options&raw_options, bool ignore_unrecognized) {
   UniquePtroptions(ParsedOptions::Create(raw_options,
 ignore_unrecognized));
   ......
   QuasiAtomic::Startup();
  Monitor::Init(options->lock_profiling_threshold_,
 options->hook_is_sensitive_thread_);
   host_prefix_ =options->host_prefix_;
   boot_class_path_string_ =options->boot_class_path_string_;
   ... // 更多的賦值語句
   monitor_list_ = newMonitorList;
   thread_list_ = newThreadList;
   intern_table_ = newInternTable;
   if(options->interpreter_only_) {
    GetInstrumentation()->ForceInterpretOnly();
   }
   // 創建堆(Heap)對象
   heap_ = newgc::Heap(options->heap_initial_size_,
                       options->heap_growth_limit_,
                       ......);
   BlockSignals();
  InitPlatformSignalHandlers();
   // 創建JavaVMExt對象
   java_vm_ = new JavaVMExt(this,options.get());
  // 將當前的主線程變成一個“Java” 線程
  Thread::Startup(); 
   Thread* self =Thread::Attach("main", false, NULL, false); 
  self->TransitionFromSuspendedToRunnable();
  GetHeap()->EnableObjectValidation();
   if(GetHeap()->GetContinuousSpaces()[0]->IsImageSpace()) {
    class_linker_ = ClassLinker::CreateFromImage(intern_table_);
   } else {
    class_linker_ =ClassLinker::CreateFromCompiler(*options->boot_class_path_, intern_table_);
   }
   ......
   return true;
 }
 Init()函數最重要的工作是創建了Heap對象和ClassLinker對象。我們只要將ART和Dalvik對比一下就可以理解,因爲ART模式下並不需要去解析和執行字節碼,所以它的工作比Dalivk要少很多。即使應用已經編譯成了可執行代碼,但是同樣也要支持垃圾回收功能,所以Heap模塊還是必不可少的。Art的Heap模塊的功能幾乎和Dalvik中的相同,垃圾回收的算法也是標誌並清除法,不過代碼的實現更加晦澀,所以本書不打算再分析一遍Art的Heap算法了。
 ART雖然不用去裝載和執行字節碼,但是還是要保留所有Java類的信息,Java程序和C++程序除了內存管理方式不同外,最大的區別是Java程序能夠動態的獲取各種類的信息,包括方法,變量等。所以ART中同樣也要提供這些功能,否則編譯出來的程序也無法使用。ClassLinker類的作用就是在ART內部提供各種Java類的解析功能。

ART開始運行
 初始化完成之後,接下來是調用Runtime的start()函數開始運行,函數代碼如下:
 bool Runtime::Start() {
   VLOG(startup) <<"Runtime::Start entering";
   Thread* self =Thread::Current();
  self->TransitionFromRunnableToSuspended(kNative);
   started_ = true;
  InitNativeMethods()   //初始化本地的JNI方法
   InitThreadGroups(self);
   Thread::FinishStartup();
   if (is_zygote_) {
      if (!InitZygote()) {
          return false;
      }
   } else {
      DidForkFromZygote();
   }
  StartDaemonThreads();  //調用java.lang.Daemons的start方法
   system_class_loader_ =CreateSystemClassLoader(); //創建一個ClassLoader對象
  self->GetJniEnv()->locals.AssertEmpty();
   VLOG(startup) <<"Runtime::Start exiting";
   finished_starting_ =true;
   return true;
 }
 Start()方法中會調用InitNativeMethods()來初始化本地的JNI方法,ART中也同樣支持JNI函數,不過ART中對部分系統的JNI函數進行了重寫,但是實現原理和Dalvik中的沒有太大區別,而大部分其他模塊的JNI函數還是保持不變。調用InitNativeMethods()方法後這些JNI函數就可以使用了。
接下來如果是在Zygote進程中,則會調用InitZygote()函數來進行初始化,這個函數的實現和Dalvik中的幾乎一樣,主要工作是設置進程的groupid,以及mountrootfs文件系統到根目錄。如果不是Zygote進程,則調用DidForkFromZygote()函數,這個函數主要工作是調用Heap對象的CreateThreadPool()函數來創建線程池。
最後Start()函數中調用了StartDaemonThreads()函數,這個函數的工作是調用Java類Daemons的start()方法來啓動一些Deamon線程,這些Deamon前面我們已經分析過了。這個過程實際上和Dalvik啓動時完成的最後一項工作相同。
對比Dalivk啓動時需要完成的工作,ART是相當的簡單了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章