0%

FlutterEngine初始化源码分析以及优化(官方PR)

核心点

主要分为3个部分

  • 启动Engine前的准备(Platform端Android)
  • Engine的启动(创建DartVM、相关线程、初始化相关配置)
  • Engine加载Dart产物,直到执行main.dart中的main方法

给官方提交了相关PR给官方,支持engine异步初始化

Engine创建流程不是很合理,底层在做异步任务的时候,主线程会wait阻塞,非常影响体验。

flutter版本:1.12

启动流程

1
2
3
4
5

//初始化engine
FlutterEngien engine = new FlutterEngine(...);
//加载dart代码
engine.getDartExecutor().executeDartEntrypoint(...);

分为2部分

  • 初始化engine
  • 加载、执行Dart代码

整体流程图如下

初始化的对象大概如下

初始化engine

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/** Fully configurable {@code FlutterEngine} constructor. */

public FlutterEngine(..) {

//第一步: 加载flutter.so、assest下的资源(字体、debug模式的snapshot文件)
flutterLoader.startInitialization(context.getApplicationContext());
flutterLoader.ensureInitializationComplete(context, dartVmArgs);

//第二步: 核心初始化函数,在native创建dartVM、相关线程
attachToJni();

this.dartExecutor = new DartExecutor(flutterJNI, context.getAssets());
this.dartExecutor.onAttachedToJNI();

//第3步:创建renderer,管理flutter到surface/texuteview 的纹理显示数据,在启动activity后,会和acitvity上的view关联
this.renderer = new FlutterRenderer(flutterJNI);

//注册各种channnel(键盘、系统事件监听)
xxxChannel = new xxxChannel();

this.platformViewsController.onAttachedToJNI();

if (automaticallyRegisterPlugins) {
//第5步:注册 pubspect.ymal 中依赖的plugin
registerPlugins();
}
}

1、启动Engine前的准备

  • 初始化vsync
  • 将assest下flutter的资源copy到私有目录中
  • load flutter.so
  • 主线程wait等待结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//FlutterLoader.java
startInitialization(){
//初始化vsync
VsyncWaiter
.getInstance((WindowManager)appContext.getSystemService(Context.WINDOW_SERVICE))
.init();

Callable<InitResult> initTask = new Callable<InitResult>() {
//会启动一个asynctask,将assest目录下的flutter资源copy到私有目录
ResourceExtractor resourceExtractor = initResources(appContext);

System.loadLibrary("flutter");

//等待资源copy完毕
if (resourceExtractor != null) {
resourceExtractor.waitForCompletion();
}
};
initResultFuture = Executors.newSingleThreadExecutor().submit(initTask);
}

主线程wait, 等待整个流程执行完成

1
2
flutterLoader.ensureInitializationComplete(...);

2、启动engine

核心函数attachToJni(),辗转调用到AndroidShellHolder的构造函数中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
AndroidShellHolder::AndroidShellHolder(...) {
//创建3个线程:UI、GPU、IO
thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU |
ThreadHost::Type::IO};
//创建callback: platform_view_android
Shell::CreateCallback<PlatformView> on_create_platform_view = [](..) {
platform_view_android = std::make_unique<PlatformViewAndroid>(...);
);


//创建callback: Rasterizer
Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
};

//创建callback: IOManager
fml::TaskRunner::RunNowOrPostTask(io_task_runner,[]() {
auto io_manager = std::make_unique<ShellIOManager>(...);
io_manager_promise.set_value(std::move(io_manager));
});

//创建engine(内部创建dart、skia环境)
shell_ =
Shell::Create(task_runners, // task runners
GetDefaultWindowData(), // window data
settings_, // settings
on_create_platform_view, // platform view create callback
on_create_rasterizer // rasterizer create callback
);

is_valid_ = shell_ != nullptr;
}

主要是在初始化flutterengine运行的环境

  • 3个线程(UI、GPU、IO)
  • 创建3个callback: 用于初始化platform_view_android、Rasterizer、IOManager
  • 创建engine

继续往下看

1
2
3
4
5
6
7
//shell.cc
std::unique_ptr<Shell> Shell::Create(){
//创建DartVm
auto vm = DartVMRef::Create(settings);
//创建engine
return Shell::Create(... , std::move(vm));
}

首先,会创建一个DartVM,然后调用Shell::Create,内部会调用到函数CreateShellOnPlatformThread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(...) {
//创建shell对象,但是还未初始化完成
auto shell = std::unique_ptr<Shell>(new Shell(std::move(vm), task_runners, settings));

//在gpu线程中创建rasterizer,用于将渲染结果,纹理化
fml::TaskRunner::RunNowOrPostTask(RasterTaskRunner, [..]() {
std::unique_ptr<Rasterizer> rasterizer(on_create_rasterizer(*shell));
rasterizer_promise.set_value(std::move(rasterizer));
});

//创建platformview对象
auto platform_view = on_create_platform_view(*shell.get());
if (!platform_view || !platform_view->GetWeakPtr()) {
return nullptr;
}
//在io线程中创建IOManager,一般是用于图片纹理上传
fml::TaskRunner::RunNowOrPostTask(io_task_runner,[]() {
auto io_manager = std::make_unique<ShellIOManager>(...);
io_manager_promise.set_value(std::move(io_manager));
});

std::promise<std::unique_ptr<Engine>> engine_promise;
auto engine_future = engine_promise.get_future();

//创建native的engine对象
fml::TaskRunner::RunNowOrPostTask(UITaskRunner(),[...]() mutable {
//创建animator
auto animator = std::make_unique<Animator>(*shell, ...));
//创建engine
engine_promise.set_value(
std::make_unique<Engine>(weak_io_future.get(),...)
)
);

//主线程等待io、gpu、io线程的任务都执行完,完成对shell的初始化
if (!shell->Setup(std::move(platform_view), //
engine_future.get(), //
rasterizer_future.get(), //
io_manager_future.get()) //
) {
return nullptr;
}
return shell;
}

分为3个部分

  • 使用上一步的callback,创建相应的对象
    • 在gpu线程中创建rasterizer
    • 在platform线程中创建platform_view
    • 在io线程中创建IOManager
  • UI线程等待其它线程task执行完,开始创建engine
  • platform线程wait(future.get),等待其它线程都执行完,最后执行shell->Setup完成shell的初始化

这里其实设计的不是很好,在Android和iOS上阻塞主线程的代价是非常大的,测试低端机这里大概会有200ms左右的阻塞,已经给官方提了PR改成异步模式

我们接着看Engine的初始化

1
2
3
4
5
6
7
class Engine{
FontCollection font_collection_;
}

Engine::Engine(...) {
runtime_controller_ = std::make_unique<RuntimeController>(...);
}
  • 先初始化engine上的成员FontCollection,这里也是一个比较耗时的地方
  • engine的构造函数中,会去创建RuntimeController
1
2
3
4
5
6
RuntimeController::RuntimeController(...){

auto strong_root_isolate = DartIsolate::CreateRootIsolate(...).lock();

window->DidCreateIsolate();
}

RuntimeController中会创建一个DartIsolate

DartIsolate图.jpg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
std::weak_ptr<DartIsolate> DartIsolate::CreateRootIsolate(...) {

auto isolate_group_data = std::make_unique<std::shared_ptr<DartIsolateGroupData>>(
std::shared_ptr<DartIsolateGroupData>(new DartIsolateGroupData(...))
);

auto isolate_data = std::make_unique<std::shared_ptr<DartIsolate>>(
std::shared_ptr<DartIsolate>(new DartIsolate(...))
);

Dart_Isolate vm_isolate = CreateDartIsolateGroup(...);

std::shared_ptr<DartIsolate>* root_isolate_data =
static_cast<std::shared_ptr<DartIsolate>*>(Dart_IsolateData(vm_isolate));

(*root_isolate_data)->SetWindow(std::move(window));

return (*root_isolate_data)->GetWeakIsolatePtr();
}

在执行完后,shel->DartVM->engine->runtimecontroller->DartIsolate的创建。回到CreateShellOnPlatformThread方法中

1
2
3
4
5
6
7
8
9
10
fml::TaskRunner::RunNowOrPostTask(UITaskRunner(),[...]() mutable {
//创建完shell后,通知platfrom线程
engine_promise.set_value(
std::make_unique<Engine>(weak_io_future.get(),...)
)
);

//platfrom线程线程等待io、gpu、io线程的任务都执行完,完成对shell的初始化
shell->Setup( ... , engine_future.get())

shell->Setup其实就是将上述执创建的engine、platform_view、rasterizer、io_manager等等挂到shell的成员变量上.

至此,native环境创建完毕,回到创建AndroidShellHolder的JNI函数attachjni入口

1
2
3
4
5
6
7
8
9
10
11
12
//platform_view_android_jni.cc
static jlong AttachJNI(...) {
auto shell_holder = std::make_unique<AndroidShellHolder>(...);
//返回AndroidShellHolder的指针
return reinterpret_cast<jlong>(shell_holder.release());
}

//FlutterJNI.java
public void attachToNative(boolean isBackgroundView) {
//持有AndroidShellHolder的指针
nativePlatformViewId = nativeAttach(this, isBackgroundView);
}

FlutterJNI持有了AndroidshellHolder的指针,AndroidShellHolder持有了底层整个环境的变量(engine、shell、DartVm、DartIsolaate)

3、初始化变量

attachToJni执行完后,会在平台层(Android)继续初始化上层需要的变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//FlutterEngine.java
attachToJni()

//初始化DartExecutor,用于后面加载、执行dart产物
this.dartExecutor = new DartExecutor(flutterJNI, context.getAssets());
this.dartExecutor.onAttachedToJNI();

//创建renderer,管理flutter到surface/texuteview 的纹理显示数据,在启动activity后,会和acitvity上的view关联
this.renderer = new FlutterRenderer(flutterJNI);

//注册各种channnel(键盘、系统事件监听)
xxxChannel = new xxxChannel();

//注册 pubspect.ymal 中依赖的plugin
if (automaticallyRegisterPlugins) {
registerPlugins();
}

这里主要是在初始化上层的一些环境

  • DartExecutor:用于后面加载、执行dart产物
  • FlutterRenderer:管理flutter到surface/texuteview 的纹理显示数据,在启动activity后,会和acitvity上的view关联
  • xxxChannel:各种flutter和native通信能力,比如监听系统事件的、activity切换声明周期等等
  • registerPlugins: 注册注册pubspect.ymal中依赖的plugin
1
2
3
4
5
6
7
private void registerPlugins() {
Class<?> generatedPluginRegistrant =
Class.forName("io.flutter.plugins.GeneratedPluginRegistrant");
Method registrationMethod =
generatedPluginRegistrant.getDeclaredMethod("registerWith", FlutterEngine.class);
registrationMethod.invoke(null, this);
}

反射调用GeneratedPluginRegistrant类,注册pubspect.ymal中声明的插件

加载执行Dart代码

接着看engine初始化完后,加载执行dart代码的流程

1
2
3
4
5
6
engine.getDartExecutor().executeDartEntrypoint(...);

//DartExecutor.java
executeEntryPoint(...){
flutterJNI.runBundleAndSnapshotFromLibrary(...);
}

经过一系列跳转,最终会执行到DartIsolateRun 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

bool DartIsolate::Run(const std::string& entrypoint_name,
const std::vector<std::string>& args,
const fml::closure& on_run) {

//entrypoint_name为"main",指Dart代码的入口函数
//在dart产物上,寻找key为"main"(entrypoint_name)的入口函数
auto user_entrypoint_function =
Dart_GetField(Dart_RootLibrary(), tonic::ToDart(entrypoint_name.c_str()));

auto entrypoint_args = tonic::ToDart(args);

//执行main.dart函数中的main()方法
if (!InvokeMainEntrypoint(user_entrypoint_function, entrypoint_args)) {
return false;
}
return true;
}

最后

至此,flutter初始化完毕

  • 可以正常执行dart代码
  • 进行渲染(startActivity后)