flutter: 加載與運行Dart

環境: 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; 撇開這些名稱至少咱們知道:安全

  1. AndroidShellHolder異步調用了EngineRun方法
  2. EngineRun跑在flutter的ui線程中
  3. Engine獲取成員RuntimeController的一個叫RootIsolate的對象並最終調用了其DartIsolate::Run方法
  4. 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接口文檔),它的初始化,運行,集成像一個巨大的黑盒。由於最終運行的仍是IsolateRun方法,核心仍是理解Dart的Isolateless

一些資料

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

DartVMDartVMRef是什麼關係?按照字面及代碼註釋意思,是一個實例與強引用的關係,DartVM只能經過DartVMRef::Create來獲取實例

A reference to the VM may only be obtained via the |Create| method.

那麼能夠總結以下:

  1. DartVMRef屏蔽了DartVM的建立
  2. DartVMRef保證進程全局只有一個DartVM實例及數據(DartVMData)
  3. DartVMRef線程安全的獲取DartVM實例

我以爲倒不如叫DartVMManager來的簡單明白,DartVMRef除了引用還幹了這麼多事...那個經過DartVMRef::Create方法來獲取實例的操做看着也比較彆扭。

Dart虛擬機

目前的階段無法深刻虛擬機實現原理,加載機制,只能通觀概覽的瞭解一下它的特性。目測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,不過有點艱深。

另:flutter編譯模式

相關文章
相關標籤/搜索