環境: flutter sdk v1.7.8+hotfix.3@stablehtml
對應 flutter engine: 54ad777fd29b031b87c7a68a6637fb48c0932862java
在創建異步線程與消息循環以後,天然就是運行應用腳本,也就是dart文件。這一部分感受很龐大並且千頭萬緒:對dart不一樣模式的編譯,不一樣參數的配置,從代碼看還有熱加載(hot reload)的機制,從裏到外都是一團亂麻;有這種感受只是由於不熟悉,剛剛接觸陌生環境產生的畏懼,只要熟悉啥都不是事。因此先不貿然進入熱加載之類的細節,以目前瞭解的通訊與異步爲基礎,漸次深刻對象關聯關係爲上。android
在FlutterActivityDelegate.onCreate
的最後容易發現一個比較重要的調用runBundle
,深刻的調用序列以下:git
FlutterActivity.onCreate
FlutterActivityDelegate.onCreate
FlutterActivityDelegate.runBundle
FlutterView.runFromBundle
FlutterView.preRun
FlutterNativeView.runFromBundle
FlutterNativeView.runFromBundleInternal
FlutterJNI.runBundleAndSnapshotFromLibrary
FlutterJNI.nativeRunBundleAndSnapshotFromLibrary
FlutterView.postRun
複製代碼
與C++層的調用序列分開:github
::RunBundleAndSnapshotFromLibrary
AndroidShellHolder::Launch
...[async:ui_thread]Engine::Run
Engine::PrepareAndLaunchIsolate
RuntimeController::GetRootIsolate
IsolateConfiguration::PrepareIsolate
IsolateConfiguration::DoPrepareIsolate => AppSnapshotIsolateConfiguration::DoPrepareIsolate
DartIsolate::PrepareForRunningFromPrecompiledCode
DartIsolate::Run
DartIsolate::InvokeMainEntrypoint
複製代碼
這裏已經有點暈了,各類名稱堆砌在一塊兒:DartIsolate
, Dart_Isolate
, RootDartIsolate
; RunConfiguration
, IsolateConfiguration
AppSnapshotIsolateConfiguration
; 撇開這些名稱至少咱們知道:安全
AndroidShellHolder
異步調用了Engine
的Run
方法Engine
的Run
跑在flutter的ui線程中Engine
獲取成員RuntimeController
的一個叫RootIsolate
的對象並最終調用了其DartIsolate::Run
方法DartIsolate
進入到了主入口方法,在這裏就是lib/main.dart中的main()
方法(runFromBundle(bundlePath, defaultPath, "main", false);
FlutterView.java:611
)。顯然最終調的是dartSDK提供的各類方法,雖然咱們大概知道flutter的Engine不會具體作dart代碼的解釋與執行,但比較棘手的是咱們很難分清Engine與DartSDK的界限;DartSDK的接口方法散落在各處,他們的前後調用關係,對象依賴關係,內部狀態的變化與檢查,對於初學者都增長理解上的難度。因此最好是針對DartSDK再有一層封裝或者抽象,不只初始化與運行調用序列清晰,讓sdk可替換(若是之後有其它的dart實現呢?),也讓引擎真正成爲引擎。bash
因此這裏也能夠對引擎的含義作一個梳理:引擎天然是可插撥的一種形態,只要與引擎提供的接口一致能夠更換別的實現如同燈泡座與燈泡的關係,在這裏顯然沒法更換DartSDK, 因此Flutter的引擎是針對平臺的引擎,咱們能夠將應用移植到各類平臺或者操做系統。app
這時候死看代碼難有進展,咱們最好先了解DartSDK原本有什麼
。但發現居然很難找到一份針對DartSDK的使用教程與文檔(不是Dart語言使用文檔,是開發集成Dart虛擬機的C接口文檔),它的初始化,運行,集成像一個巨大的黑盒。由於最終運行的仍是Isolate
的Run
方法,核心仍是理解Dart的Isolate
。less
Engine-architecture裏的UI Task Runner
提到:異步
(root Dart isolate)runs the application's main Dart code. Bindings are set up on this isolate by the engine to schedule and submit frames.
Terminating the root isolate will also terminate all isolates spawned by that root isolate.
(root Dart isolate)also executes all responses for platform plugin messages, timers, microtasks and asynchronous I/O.
you cannot interact with the Flutter framework in any meaningful way on the secondary isolate. As non-root isolates are incapable of scheduling frames and do not have bindings that the Flutter framework depends on.
然而引用的dart isolate幾乎沒有用,咱們想要的是isolate
在flutter引擎中的表示,而不是isolate
概念及使用文檔。但以上描述與flutter中用ui thread來運行RootIsolate::Run
是一致的。
因此Isolate
能夠理解爲(至少在flutter的表示中)一種特殊的線程,這個線程有本身的堆和棧(和普通線程同樣),但不能共享狀態,也就是不能加鎖來進行同步!RootIsolate
又是一個特殊的Isolate
,它的一個重要功能是調度和準備渲染幀,而具體的渲染工做由RootIsolate
交給GPU線程(應該存在另外一個isolate實例)來作。 這個理解與在Engine::PrepareAndLaunchIsolate
中調用了DartIsolate::Run
是一致的,因而看RootIsolate建立流程:
RuntimeController::RuntimeController
DartIsolate::CreateRootIsolate
DartIsolate::DartIsolate
phase_ = Phase::Uninitialized;
DartIsolate::CreateDartVMAndEmbedderObjectPair
Dart_CreateIsolate
DartIsolate::Initialize
phase_ = Phase::Initialized;
DartIsolate::LoadLibraries
phase_ = Phase::LibrariesSetup;
複製代碼
在這裏標註了一下DartIsolate::phase_
的變化,以便能更好追蹤DartIsolate的狀態,一樣,結合以前的DartIsolate::Run
調用序列:
::RunBundleAndSnapshotFromLibrary
::CreateIsolateConfiguration
IsolateConfiguration::CreateForAppSnapshot
AndroidShellHolder::Launch
...[async:ui_thread]Engine::Run
Engine::PrepareAndLaunchIsolate
IsolateConfiguration::PrepareIsolate
IsolateConfiguration::DoPrepareIsolate => AppSnapshotIsolateConfiguration::DoPrepareIsolate
DartIsolate::PrepareForRunningFromPrecompiledCode
Dart_RootLibrary
MarkIsolateRunnable
phase_ = Phase::Ready;
DartIsolate::Run
Dart_RootLibrary(), "main"
DartIsolate::InvokeMainEntrypoint
"dart:isolate._getStartMainIsolateFunction"
"dart:ui._runMainZoned"
phase_ = Phase::Running;
複製代碼
可見對phase_
的檢查是符合預期的(phase_
被置成Phase::Ready
以前必須是Phase::LibrariesSetup
) 以Dart_
開頭的方法都是DartSDK的方法,分佈在各類對象的各類方法中,但大致上咱們知道了flutter中的DartIsolate
是SDK中Dart_Isolate
的封裝。 在調用入口方法以前(InvokeMainEntrypoint
),先獲取了入口方法自己(user_entrypoint_function
),從哪裏獲取的?Dart_RootLibrary()。咱們應該能猜出來這個RootLibrary應該就是咱們編寫的Dart應用(main.dart所在的lib/目錄下那一坨),因此另外追蹤一下如何設置RootLibrary的,Dart_SetRootLibrary流程:
Shell::Create
DartVMRef::Create
DartVM::Create
DartVM::DartVM
DartUI::InitForGlobal
Dart_Initialize
DartIsolate::DartIsolateCreateCallback
DartIsolate::DartCreateAndStartServiceIsolate
DartServiceIsolate::Startup
Dart_SetRootLibrary
複製代碼
原來是在建立Shell
前先建立了DartVM
,在DartVM
的構造函數時設置的,並且終於涉及到了那個一直被雪藏的類DartVM
!
DartVM
與DartVMRef
是什麼關係?按照字面及代碼註釋意思,是一個實例與強引用的關係,DartVM
只能經過DartVMRef::Create
來獲取實例
A reference to the VM may only be obtained via the |Create| method.
那麼能夠總結以下:
DartVMRef
屏蔽了DartVM
的建立DartVMRef
保證進程全局只有一個DartVM
實例及數據(DartVMData
)DartVMRef
線程安全的獲取DartVM
實例我以爲倒不如叫DartVMManager
來的簡單明白,DartVMRef
除了引用還幹了這麼多事...那個經過DartVMRef::Create
方法來獲取實例的操做看着也比較彆扭。
目前的階段無法深刻虛擬機實現原理,加載機制,只能通觀概覽的瞭解一下它的特性。目測DartVM
所作的工做其實並很少,主要是調用了DartSDK的各類API。
虛擬機先分爲系統虛擬機(system vm)和應用虛擬機(process vm), 應用虛擬機又可分爲字節碼虛擬機(bytecode vm)和源碼虛擬機(language vm),與JVM不一樣,DartVM是後面這種。
咱們知道Dart虛擬機能夠JIT(解釋執行)也能夠AOT(編譯運行),這是被選做flutter開發語言的緣由之一。能夠確定的是Dart虛擬機沒有基於字節碼,由於一旦用了字節碼指令,相關的複雜度實際上是膨脹的,解釋能夠參看這篇很是棒的爲何不用字節碼 ,這種源碼虛擬機(language vm)其實和JS引擎有點相似。
語言自己在建立之初的考慮就是避免這種鎖競爭的(Isolate
機制)。
Adding support for sharing memory across threads in our VM would be pointless since the one language we know our VM will run doesn’t use it.
總之不採用字節碼是一種折衷(tradeoff),歸根結底仍是爲了保持簡單! 另外還可經過這篇文章瞭解DartVM,不過有點艱深。