环境: 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,不过有点艰深。