Flutter之Dart虛擬機啓動

Flutter之Engine啓動流程一文中敘述了Engine是如何建立並調用入口函數——main的。因爲篇幅緣由,在該文中並無具體講解Dart VM的建立。因此本文就來看看Dart VM是如何建立的。html

一、Dart VM對象的建立

直接來看ShellCreate函數(關因而如何調用該函數的,能夠去閱讀Flutter之Engine啓動流程一文),代碼以下。android

std::unique_ptr<Shell> Shell::Create(
    TaskRunners task_runners,
    const WindowData window_data,
    Settings settings,
    Shell::CreateCallback<PlatformView> on_create_platform_view,
    Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
  PerformInitializationTasks(settings);
  PersistentCache::SetCacheSkSL(settings.cache_sksl);
  
  //Dart VM的建立
  auto vm = DartVMRef::Create(settings);

  auto vm_data = vm->GetVMData();
  
  //繼續進行Shell對象的建立
  return Shell::Create(std::move(task_runners),        //
                       std::move(window_data),         //
                       std::move(settings),            //
                       vm_data->GetIsolateSnapshot(),  // isolate snapshot
                       on_create_platform_view,        //
                       on_create_rasterizer,           //
                       std::move(vm)                   //
  );
}
複製代碼

Create主要是進行Dart VM的建立,經過DartVMRef中的Create函數。代碼以下。c++

DartVMRef DartVMRef::Create(Settings settings,
                            fml::RefPtr<DartSnapshot> vm_snapshot,
                            fml::RefPtr<DartSnapshot> isolate_snapshot) {
  std::scoped_lock lifecycle_lock(gVMMutex);

  //若是進程中存在正在運行的Dart VM,那麼直接使用這個Dart VM。也就是在同一進程中,只會存在一個Dart VM
  if (auto vm = gVM.lock()) {
    //直接返回進程中已存在的Dart VM
    return DartVMRef{std::move(vm)};
  }

  std::scoped_lock dependents_lock(gVMDependentsMutex);

  gVMData.reset();
  gVMServiceProtocol.reset();
  gVMIsolateNameServer.reset();
  gVM.reset();

  //若是進程中沒有Dart VM,就建立並初始化一個Dart VM
  auto isolate_name_server = std::make_shared<IsolateNameServer>();
  auto vm = DartVM::Create(std::move(settings),          //
                           std::move(vm_snapshot),       //
                           std::move(isolate_snapshot),  //
                           isolate_name_server           //
  );

  if (!vm) {//建立DartVM實例失敗
    return {nullptr};
  }

  //將Dart VM的引用設爲全局引用,保證進程內惟一性。
  gVMData = vm->GetVMData();
  gVMServiceProtocol = vm->GetServiceProtocol();
  gVMIsolateNameServer = isolate_name_server;
  gVM = vm;

  if (settings.leak_vm) {
    gVMLeak = new std::shared_ptr<DartVM>(vm);
  }

  return DartVMRef{std::move(vm)};
}
複製代碼

DartVMRef中的Create函數中主要是返回一個Dart VM引用,這個Dart VM是進程內惟一的,也就是進程中若是不存在Dart VM,那麼就建立並初始化一個Dart VM,不然直接使用已存在的Dart VM。下面再來看Dart VM的建立流程。git

std::shared_ptr<DartVM> DartVM::Create(
    Settings settings,
    fml::RefPtr<DartSnapshot> vm_snapshot,
    fml::RefPtr<DartSnapshot> isolate_snapshot,
    std::shared_ptr<IsolateNameServer> isolate_name_server) {
  auto vm_data = DartVMData::Create(settings,                    //
                                    std::move(vm_snapshot),      //
                                    std::move(isolate_snapshot)  //
  );

  if (!vm_data) {
    return {};
  }

  //建立Dart VM
  return std::shared_ptr<DartVM>(
      new DartVM(std::move(vm_data), std::move(isolate_name_server)));
}
複製代碼

上面代碼就是簡單的建立一個DartVM對象,來看該對象的構造函數。bootstrap

DartVM::DartVM(std::shared_ptr<const DartVMData> vm_data,
               std::shared_ptr<IsolateNameServer> isolate_name_server)
    : settings_(vm_data->GetSettings()),
      concurrent_message_loop_(fml::ConcurrentMessageLoop::Create()),
      skia_concurrent_executor_(
          [runner = concurrent_message_loop_->GetTaskRunner()](
              fml::closure work) { runner->PostTask(work); }),
      vm_data_(vm_data),
      isolate_name_server_(std::move(isolate_name_server)),
      service_protocol_(std::make_shared<ServiceProtocol>()) {
  gVMLaunchCount++;

  //因爲Dart VM初始化是線程安全的,所以這裏的調用也是線程安全的
  SkExecutor::SetDefault(&skia_concurrent_executor_);

  {
    //EventHandler的建立
    dart::bin::BootstrapDartIo();

    if (!settings_.temp_directory_path.empty()) {
      dart::bin::SetSystemTempDirectory(settings_.temp_directory_path.c_str());
    }
  }

  ...
  
  //UI相關類的註冊,如Canvas、Picture、Window等。
  DartUI::InitForGlobal();

  {
    //Dart VM初始化參數
    Dart_InitializeParams params = {};
    params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
    params.vm_snapshot_data = vm_data_->GetVMSnapshot().GetDataMapping();
    params.vm_snapshot_instructions =
        vm_data_->GetVMSnapshot().GetInstructionsMapping();
    params.create_group = reinterpret_cast<decltype(params.create_group)>(
        DartIsolate::DartIsolateGroupCreateCallback);
    params.initialize_isolate =
        reinterpret_cast<decltype(params.initialize_isolate)>(
            DartIsolate::DartIsolateInitializeCallback);
    params.shutdown_isolate =
        reinterpret_cast<decltype(params.shutdown_isolate)>(
            DartIsolate::DartIsolateShutdownCallback);
    params.cleanup_isolate = reinterpret_cast<decltype(params.cleanup_isolate)>(
        DartIsolate::DartIsolateCleanupCallback);
    params.cleanup_group = reinterpret_cast<decltype(params.cleanup_group)>(
        DartIsolate::DartIsolateGroupCleanupCallback);
    params.thread_exit = ThreadExitCallback;
    params.get_service_assets = GetVMServiceAssetsArchiveCallback;
    params.entropy_source = dart::bin::GetEntropy;
    //Dart VM初始化
    char* init_error = Dart_Initialize(&params);
    
    ...
  }

  ...
}
複製代碼

DartVM對象的構造函數中主要作了如下幾件事。api

  1. EventHandler的建立。
  2. UI相關類的在Engine層的註冊。
  3. Dart VM的初始化。

先來看EventHandler的建立。安全

二、EventHandler的建立

EventHandler是經過BootstrapDartIo函數來建立的,實現代碼以下。app

void BootstrapDartIo() {
  // Bootstrap 'dart:io' event handler.
  TimerUtils::InitOnce();
  EventHandler::Start();
}
複製代碼

EventHandlerStart函數中,會建立一個全局socket(globalTcpListeningSocketRegistry)、一個Monitor對象及EventHandler對象。異步

EventHandler的具體實現因系統而已,這裏以Android系統爲例。EventHandlerdelegate_是一個EventHandlerImplementation對象,他的具體實如今eventhandler_android.cc中。socket

void EventHandler::Start() {
  //初始化一個全局socket(globalTcpListeningSocketRegistry)
  ListeningSocketRegistry::Initialize();

  shutdown_monitor = new Monitor();
  //建立EventHandler對象
  event_handler = new EventHandler();
  event_handler->delegate_.Start(event_handler);
  ...
}
複製代碼

delegate_的構造函數中,會建立一個epoll句柄,並註冊一個interrupt_fdepoll中。

再來看delegate_start函數,在該函數中會建立一個名爲dart:io EventHandler的新線程。Java中,建立一個新線程,都會傳遞一個回調方法。這裏也不例外。其對應的回調函數就是Poll函數,在該函數中會經過epoll來等待事件並執行。

經過epoll拿到執行完畢的任務後,直接調用HandleEvents函數來進一步處理,並經過isolateMessageHandler來執行對應的回調。

//建立epoll句柄
EventHandlerImplementation::EventHandlerImplementation()
    : socket_map_(&SimpleHashMap::SamePointerValue, 16) {
  intptr_t result;
  result = NO_RETRY_EXPECTED(pipe(interrupt_fds_));
  shutdown_ = false;
  //傳遞給epoll_create的初始大小,當Linux版本>=2.6.8時,該值將被忽略
  static const int kEpollInitialSize = 64;
  //建立epoll句柄
  epoll_fd_ = NO_RETRY_EXPECTED(epoll_create(kEpollInitialSize));
  //註冊interrupt_fd到epoll中。
  struct epoll_event event;
  event.events = EPOLLIN;
  event.data.ptr = NULL;
  int status = NO_RETRY_EXPECTED(
      epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupt_fds_[0], &event));
}

void EventHandlerImplementation::Start(EventHandler* handler) {
  //建立線程名爲dart:io EventHandler的新線程
  int result =
      Thread::Start("dart:io EventHandler", &EventHandlerImplementation::Poll,
                    reinterpret_cast<uword>(handler));
}

//新線程的具體執行函數
void EventHandlerImplementation::Poll(uword args) {
  ThreadSignalBlocker signal_blocker(SIGPROF);
  static const intptr_t kMaxEvents = 16;
  struct epoll_event events[kMaxEvents];
  EventHandler* handler = reinterpret_cast<EventHandler*>(args);
  EventHandlerImplementation* handler_impl = &handler->delegate_;

  while (!handler_impl->shutdown_) {
    int64_t millis = handler_impl->GetTimeout();
    if (millis > kMaxInt32) {
      millis = kMaxInt32;
    }
    //阻塞等待
    intptr_t result = TEMP_FAILURE_RETRY_NO_SIGNAL_BLOCKER(
        epoll_wait(handler_impl->epoll_fd_, events, kMaxEvents, millis));
    if (result == -1) {
      ...
    } else {
      handler_impl->HandleTimeout();
      //在子線程調用HandleEvents函數,會處理拿到的全部任務
      handler_impl->HandleEvents(events, result);
    }
  }
  handler->NotifyShutdownDone();
}
//處理拿到的全部事件
void EventHandlerImplementation::HandleEvents(struct epoll_event* events,
                                              int size) {
  bool interrupt_seen = false;
  for (int i = 0; i < size; i++) {
    if (events[i].data.ptr == NULL) {
      interrupt_seen = true;
    } else {
      DescriptorInfo* di =
          reinterpret_cast<DescriptorInfo*>(events[i].data.ptr);
      const intptr_t old_mask = di->Mask();
      const intptr_t event_mask = GetPollEvents(events[i].events, di);
      if ((event_mask & (1 << kErrorEvent)) != 0) {
        di->NotifyAllDartPorts(event_mask);
        UpdateEpollInstance(old_mask, di);
      } else if (event_mask != 0) {
        Dart_Port port = di->NextNotifyDartPort(event_mask);
        UpdateEpollInstance(old_mask, di);
        //發送消息給isolate中MessageHandler
        DartUtils::PostInt32(port, event_mask);
      }
    }
  }
  if (interrupt_seen) {
    // Handle after socket events, so we avoid closing a socket before we handle
    // the current events.
    HandleInterruptFd();
  }
}
複製代碼

EventHandler的建立中,主要是建立新線程及epoll的使用。在上層使用中,socketTimer定時任務的執行就是經過EventHandler來實現的。

IOS中,則是採用的kqueue來實現異步IO。

三、DartUI相關的初始化

EventHandler建立成功後,還會進行UI相關類在C/C++層的註冊,從而使framework層能順利的調用native方法。在Java中,若是想要調用native方法,也會進行相似的註冊。

void DartUI::InitForGlobal() {
  if (!g_natives) {
    g_natives = new tonic::DartLibraryNatives();
    Canvas::RegisterNatives(g_natives);
    CanvasGradient::RegisterNatives(g_natives);
    CanvasImage::RegisterNatives(g_natives);
    CanvasPath::RegisterNatives(g_natives);
    CanvasPathMeasure::RegisterNatives(g_natives);
    Codec::RegisterNatives(g_natives);
    ColorFilter::RegisterNatives(g_natives);
    DartRuntimeHooks::RegisterNatives(g_natives);
    EngineLayer::RegisterNatives(g_natives);
    FontCollection::RegisterNatives(g_natives);
    FrameInfo::RegisterNatives(g_natives);
    ImageFilter::RegisterNatives(g_natives);
    ImageShader::RegisterNatives(g_natives);
    IsolateNameServerNatives::RegisterNatives(g_natives);
    Paragraph::RegisterNatives(g_natives);
    ParagraphBuilder::RegisterNatives(g_natives);
    Picture::RegisterNatives(g_natives);
    PictureRecorder::RegisterNatives(g_natives);
    Scene::RegisterNatives(g_natives);
    SceneBuilder::RegisterNatives(g_natives);
    SemanticsUpdate::RegisterNatives(g_natives);
    SemanticsUpdateBuilder::RegisterNatives(g_natives);
    Vertices::RegisterNatives(g_natives);
    Window::RegisterNatives(g_natives);
#if defined(OS_FUCHSIA)
    SceneHost::RegisterNatives(g_natives);
#endif

    // Secondary isolates do not provide UI-related APIs.
    g_natives_secondary = new tonic::DartLibraryNatives();
    DartRuntimeHooks::RegisterNatives(g_natives_secondary);
    IsolateNameServerNatives::RegisterNatives(g_natives_secondary);
  }
}
複製代碼

能夠看到不少與UI相關的native方法都是在InitForGlobal函數中註冊的。

四、Dart VM的初始化

最後再來看Dart VM的初始化。

char* Dart::Init(const uint8_t* vm_isolate_snapshot,
                 const uint8_t* instructions_snapshot,
                 Dart_IsolateGroupCreateCallback create_group,
                 Dart_InitializeIsolateCallback initialize_isolate,
                 Dart_IsolateShutdownCallback shutdown,
                 Dart_IsolateCleanupCallback cleanup,
                 Dart_IsolateGroupCleanupCallback cleanup_group,
                 Dart_ThreadExitCallback thread_exit,
                 Dart_FileOpenCallback file_open,
                 Dart_FileReadCallback file_read,
                 Dart_FileWriteCallback file_write,
                 Dart_FileCloseCallback file_close,
                 Dart_EntropySource entropy_source,
                 Dart_GetVMServiceAssetsArchive get_service_assets,
                 bool start_kernel_isolate,
                 Dart_CodeObserver* observer) {
  ...
  //棧幀佈局的初始化
  FrameLayout::Init();
  
  set_thread_exit_callback(thread_exit);
  SetFileCallbacks(file_open, file_read, file_write, file_close);
  set_entropy_source_callback(entropy_source);
  //系統相關初始化,針對不一樣系統作的適配
  OS::Init();
  ...
  
  start_time_micros_ = OS::GetCurrentMonotonicMicros();
  //虛擬內存初始化,默認是獲取一頁的大小
  VirtualMemory::Init();
  //OSThread線程初始化,建立一個名爲Dart_Initialize的OSThread並將其設置爲TLS
  OSThread::Init();
  //zone初始化
  Zone::Init();
  ...
  
  //將isolate的一些回調重置爲null,如create_group_callback_、initialize_callback_等
  Isolate::InitVM();
  //IsolateGroup初始化
  IsolateGroup::Init();
  //PortMap初始化,建立一個初始化容量爲8的map
  PortMap::Init();
  //FreeListElement初始化,主要是作一些assert判斷
  FreeListElement::Init();
  //ForwardingCorpse初始化,主要是作一些assert判斷
  ForwardingCorpse::Init();
  //Api初始化
  Api::Init();
  //與具體操做系統相關,目前都是空實現
  NativeSymbolResolver::Init();
  //SemiSpace初始化,SemiSpace主要是用於對內存的管理,新生代就由兩個SemiSpace組成
  SemiSpace::Init();
  NOT_IN_PRODUCT(Metric::Init());
  StoreBuffer::Init();
  MarkingStack::Init();

  ...
  // Create the read-only handles area.
  predefined_handles_ = new ReadOnlyHandles();
  // Create the VM isolate and finish the VM initialization.
  //建立一個線程池
  thread_pool_ = new ThreadPool();
  { 
    //即將建立的isolate是vm isolate
    const bool is_vm_isolate = true;

    // Cache value of "non-nullable" experimental flag.
    set_non_nullable_flag(KernelIsolate::GetExperimentalFlag("non-nullable"));

    // Setup default flags for the VM isolate.
    Dart_IsolateFlags api_flags;
    Isolate::FlagsInitialize(&api_flags);

    //這裏建立一個僞IsolateGroupSource對象,由於即將建立的vm-isolate不是一個真正的isolate對象。它更多充當的是一個包含VM全局對象的容器。
    std::unique_ptr<IsolateGroupSource> source(
        new IsolateGroupSource(nullptr, kVmIsolateName, vm_isolate_snapshot,
                               instructions_snapshot, nullptr, -1, api_flags));
    auto group = new IsolateGroup(std::move(source), /*embedder_data=*/nullptr);
    IsolateGroup::RegisterIsolateGroup(group);
    //建立一個名爲vm-isolate的isolate對象
    vm_isolate_ =
        Isolate::InitIsolate(kVmIsolateName, group, api_flags, is_vm_isolate);
    group->set_initial_spawn_successful();


    Thread* T = Thread::Current();
    StackZone zone(T);
    HandleScope handle_scope(T);
    //建立null對象,null是Dart VM建立的第一個對象
    Object::InitNull(vm_isolate_);
    //建立一個ObjectStore對象,該對象主要是來存儲每一個isolate對於Dart VM中對象的引用
    ObjectStore::Init(vm_isolate_);
    //初始化CPU相關信息
    TargetCPUFeatures::Init();
    //初始化對象。
    Object::Init(vm_isolate_);
    ArgumentsDescriptor::Init();
    ICData::Init();
    SubtypeTestCache::Init();
    
    if (vm_isolate_snapshot != NULL) {...} else {...}
    
    //因爲bootstrapping問題,這裏須要在vm isolate所在線程來初始化常量
    T->InitVMConstants();
    {
      Object::FinalizeVMIsolate(vm_isolate_);
    }
  }
  Api::InitHandles();

  //取消註冊該線程中的VM isolate
  Thread::ExitIsolate();
  Isolate::SetCreateGroupCallback(create_group);
  Isolate::SetInitializeCallback_(initialize_isolate);
  Isolate::SetShutdownCallback(shutdown);
  Isolate::SetCleanupCallback(cleanup);
  Isolate::SetGroupCleanupCallback(cleanup_group);
  
  ...

  return NULL;
}
複製代碼

上面代碼中作了詳細的註釋。能夠發如今Dart VM初始化時,須要作的操做仍是蠻多的,好比棧幀佈局的初始化、虛擬內存初始化、OSThread初始化、null對象及其餘共享對象的初始化、PortMap的初始化、線程池的建立、名爲vm-isolateisolate對象建立等。

這裏重點來看vm-isolate,它是一個isolate,但與普通isolate有很大的區別,因此不是一個真正的isolate,是一個僞isolate。主要區別以下:

  1. 通常isolate堆中都會分爲新生代與老年代,而且新生代中fromto的比例是1:1,新建立的對象也基本上都會分配在to中。而vm-isolate的堆中,新生代的空間大小爲0,也就是不存在新生代。也所以,全部對象都直接分配在老年代中。
  2. isolate相似進程,之間的對象是沒法相互引用的。但對於vm-isolate倒是例外,它的堆中包含一些不可變對象,如null,true,false,而且其餘isolate能夠引用vm-isolate中堆的對象。

關於vm-isolate的具體建立能夠參考深刻理解Isolate原理這篇文章。

Dart VM啓動流程圖以下,是從Flutter之引擎啓動流程的基礎上開始的

Dart VM初始化成功後,也就意味着在同一進程中,Dart虛擬機已經啓動成功並使用它了。不管engine建立多少次,在同一進程中,Dart VM僅會建立一次。

【參考資料】

Introduction to Dart VM

深刻理解Dart虛擬機啓動

Flutter: Don’t Fear the Garbage Collector

ARM函數調用過程分析

相關文章
相關標籤/搜索