Flutter之Dart虚拟机启动

4,810 阅读8分钟

Flutter之Engine启动流程一文中叙述了Engine是如何创建并调用入口函数——main的。由于篇幅原因,在该文中并没有具体讲解Dart VM的创建。所以本文就来看看Dart VM是如何创建的。

1、Dart VM对象的创建

直接来看ShellCreate函数(关于是如何调用该函数的,可以去阅读Flutter之Engine启动流程一文),代码如下。

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函数。代码如下。

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的创建流程。

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对象,来看该对象的构造函数。

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对象的构造函数中主要做了以下几件事。

  1. EventHandler的创建。
  2. UI相关类的在Engine层的注册。
  3. Dart VM的初始化。

先来看EventHandler的创建。

2、EventHandler的创建

EventHandler是通过BootstrapDartIo函数来创建的,实现代码如下。

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

EventHandlerStart函数中,会创建一个全局socket(globalTcpListeningSocketRegistry)、一个Monitor对象及EventHandler对象。

EventHandler的具体实现因系统而异,这里以Android系统为例。EventHandlerdelegate_是一个EventHandlerImplementation对象,他的具体实现在eventhandler_android.cc中。

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。

3、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函数中注册的。

4、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函数调用过程分析