在Flutter之Engine啟動流程一文中敘述了Engine
是如何建立並呼叫入口函式——main
的。由於篇幅原因,在該文中並沒有具體講解Dart VM的建立。所以本文就來看看Dart VM是如何建立的。
1、Dart VM物件的建立
直接來看Shell
的Create
函式(關於是如何呼叫該函式的,可以去閱讀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(¶ms);
...
}
...
}
複製程式碼
在DartVM
物件的建構函式中主要做了以下幾件事。
EventHandler
的建立。- UI相關類的在
Engine
層的註冊。 - Dart VM的初始化。
先來看EventHandler
的建立。
2、EventHandler的建立
EventHandler
是通過BootstrapDartIo
函式來建立的,實現程式碼如下。
void BootstrapDartIo() {
// Bootstrap 'dart:io' event handler.
TimerUtils::InitOnce();
EventHandler::Start();
}
複製程式碼
在EventHandler
的Start
函式中,會建立一個全域性socket(globalTcpListeningSocketRegistry
)、一個Monitor
物件及EventHandler
物件。
EventHandler
的具體實現因系統而已,這裡以Android
系統為例。EventHandler
的delegate_
是一個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_fd
到epoll
中。
再來看delegate_
的start
函式,在該函式中會建立一個名為dart:io EventHandler
的新執行緒。Java中,建立一個新執行緒,都會傳遞一個回撥方法。這裡也不例外。其對應的回撥函式就是Poll
函式,在該函式中會通過epoll
來等待事件並執行。
通過epoll
拿到執行完畢的任務後,直接呼叫HandleEvents
函式來進一步處理,並通過isolate
的MessageHandler
來執行對應的回撥。
//建立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
的使用。在上層使用中,socket
及Timer
定時任務的執行就是通過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-isolate
的isolate
物件建立等。
這裡重點來看vm-isolate
,它是一個isolate
,但與普通isolate
有很大的區別,所以不是一個真正的isolate
,是一個偽isolate
。主要區別如下:
- 一般
isolate
堆中都會分為新生代與老年代,並且新生代中from
與to
的比例是1:1,新建立的物件也基本上都會分配在to
中。而vm-isolate
的堆中,新生代的空間大小為0,也就是不存在新生代。也因此,所有物件都直接分配在老年代中。 isolate
類似程式,之間的物件是無法相互引用的。但對於vm-isolate
卻是例外,它的堆中包含一些不可變物件,如null,true,false,並且其他isolate
可以引用vm-isolate
中堆的物件。
關於vm-isolate
的具體建立可以參考深入理解Isolate原理這篇文章。
Dart VM啟動流程圖如下,是從Flutter之引擎啟動流程的基礎上開始的
Dart VM初始化成功後,也就意味著在同一程式中,Dart虛擬機器已經啟動成功並使用它了。無論engine
建立多少次,在同一程式中,Dart VM僅會建立一次。
【參考資料】