1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #define FML_USED_ON_EMBEDDER
6
7 #include "flutter/shell/common/shell_test.h"
8
9 #include "flutter/flow/layers/layer_tree.h"
10 #include "flutter/flow/layers/transform_layer.h"
11 #include "flutter/fml/make_copyable.h"
12 #include "flutter/fml/mapping.h"
13 #include "flutter/runtime/dart_vm.h"
14 #include "flutter/shell/gpu/gpu_surface_gl.h"
15 #include "flutter/testing/testing.h"
16
17 namespace flutter {
18 namespace testing {
19
ShellTest()20 ShellTest::ShellTest()
21 : native_resolver_(std::make_shared<TestDartNativeResolver>()) {}
22
23 ShellTest::~ShellTest() = default;
24
SendEnginePlatformMessage(Shell * shell,fml::RefPtr<PlatformMessage> message)25 void ShellTest::SendEnginePlatformMessage(
26 Shell* shell,
27 fml::RefPtr<PlatformMessage> message) {
28 fml::AutoResetWaitableEvent latch;
29 fml::TaskRunner::RunNowOrPostTask(
30 shell->GetTaskRunners().GetPlatformTaskRunner(),
31 [shell, &latch, message = std::move(message)]() {
32 if (auto engine = shell->weak_engine_) {
33 engine->HandlePlatformMessage(std::move(message));
34 }
35 latch.Signal();
36 });
37 latch.Wait();
38 }
39
SetSnapshotsAndAssets(Settings & settings)40 void ShellTest::SetSnapshotsAndAssets(Settings& settings) {
41 if (!assets_dir_.is_valid()) {
42 return;
43 }
44
45 settings.assets_dir = assets_dir_.get();
46
47 // In JIT execution, all snapshots are present within the binary itself and
48 // don't need to be explicitly suppiled by the embedder.
49 if (DartVM::IsRunningPrecompiledCode()) {
50 settings.vm_snapshot_data = [this]() {
51 return fml::FileMapping::CreateReadOnly(assets_dir_, "vm_snapshot_data");
52 };
53
54 settings.isolate_snapshot_data = [this]() {
55 return fml::FileMapping::CreateReadOnly(assets_dir_,
56 "isolate_snapshot_data");
57 };
58
59 if (DartVM::IsRunningPrecompiledCode()) {
60 settings.vm_snapshot_instr = [this]() {
61 return fml::FileMapping::CreateReadExecute(assets_dir_,
62 "vm_snapshot_instr");
63 };
64
65 settings.isolate_snapshot_instr = [this]() {
66 return fml::FileMapping::CreateReadExecute(assets_dir_,
67 "isolate_snapshot_instr");
68 };
69 }
70 } else {
71 settings.application_kernels = [this]() {
72 std::vector<std::unique_ptr<const fml::Mapping>> kernel_mappings;
73 kernel_mappings.emplace_back(
74 fml::FileMapping::CreateReadOnly(assets_dir_, "kernel_blob.bin"));
75 return kernel_mappings;
76 };
77 }
78 }
79
PlatformViewNotifyCreated(Shell * shell)80 void ShellTest::PlatformViewNotifyCreated(Shell* shell) {
81 fml::AutoResetWaitableEvent latch;
82 fml::TaskRunner::RunNowOrPostTask(
83 shell->GetTaskRunners().GetPlatformTaskRunner(), [shell, &latch]() {
84 shell->GetPlatformView()->NotifyCreated();
85 latch.Signal();
86 });
87 latch.Wait();
88 }
89
RunEngine(Shell * shell,RunConfiguration configuration)90 void ShellTest::RunEngine(Shell* shell, RunConfiguration configuration) {
91 fml::AutoResetWaitableEvent latch;
92 fml::TaskRunner::RunNowOrPostTask(
93 shell->GetTaskRunners().GetPlatformTaskRunner(),
94 [shell, &latch, &configuration]() {
95 shell->RunEngine(std::move(configuration),
96 [&latch](Engine::RunStatus run_status) {
97 ASSERT_EQ(run_status, Engine::RunStatus::Success);
98 latch.Signal();
99 });
100 });
101 latch.Wait();
102 }
103
PumpOneFrame(Shell * shell)104 void ShellTest::PumpOneFrame(Shell* shell) {
105 // Set viewport to nonempty, and call Animator::BeginFrame to make the layer
106 // tree pipeline nonempty. Without either of this, the layer tree below
107 // won't be rasterized.
108 fml::AutoResetWaitableEvent latch;
109 shell->GetTaskRunners().GetUITaskRunner()->PostTask(
110 [&latch, engine = shell->weak_engine_]() {
111 engine->SetViewportMetrics(
112 {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
113 engine->animator_->BeginFrame(fml::TimePoint::Now(),
114 fml::TimePoint::Now());
115 latch.Signal();
116 });
117 latch.Wait();
118
119 latch.Reset();
120 // Call |Render| to rasterize a layer tree and trigger |OnFrameRasterized|
121 fml::WeakPtr<RuntimeDelegate> runtime_delegate = shell->weak_engine_;
122 shell->GetTaskRunners().GetUITaskRunner()->PostTask(
123 [&latch, runtime_delegate]() {
124 auto layer_tree = std::make_unique<LayerTree>();
125 SkMatrix identity;
126 identity.setIdentity();
127 auto root_layer = std::make_shared<TransformLayer>(identity);
128 layer_tree->set_root_layer(root_layer);
129 runtime_delegate->Render(std::move(layer_tree));
130 latch.Signal();
131 });
132 latch.Wait();
133 }
134
UnreportedTimingsCount(Shell * shell)135 int ShellTest::UnreportedTimingsCount(Shell* shell) {
136 return shell->unreported_timings_.size();
137 }
138
SetNeedsReportTimings(Shell * shell,bool value)139 void ShellTest::SetNeedsReportTimings(Shell* shell, bool value) {
140 shell->SetNeedsReportTimings(value);
141 }
142
GetNeedsReportTimings(Shell * shell)143 bool ShellTest::GetNeedsReportTimings(Shell* shell) {
144 return shell->needs_report_timings_;
145 }
146
CreateSettingsForFixture()147 Settings ShellTest::CreateSettingsForFixture() {
148 Settings settings;
149 settings.leak_vm = false;
150 settings.task_observer_add = [](intptr_t key, fml::closure handler) {
151 fml::MessageLoop::GetCurrent().AddTaskObserver(key, handler);
152 };
153 settings.task_observer_remove = [](intptr_t key) {
154 fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
155 };
156 settings.isolate_create_callback = [this]() {
157 native_resolver_->SetNativeResolverForIsolate();
158 };
159 SetSnapshotsAndAssets(settings);
160 return settings;
161 }
162
GetTaskRunnersForFixture()163 TaskRunners ShellTest::GetTaskRunnersForFixture() {
164 return {
165 "test",
166 thread_host_->platform_thread->GetTaskRunner(), // platform
167 thread_host_->gpu_thread->GetTaskRunner(), // gpu
168 thread_host_->ui_thread->GetTaskRunner(), // ui
169 thread_host_->io_thread->GetTaskRunner() // io
170 };
171 }
172
CreateShell(Settings settings)173 std::unique_ptr<Shell> ShellTest::CreateShell(Settings settings) {
174 return CreateShell(std::move(settings), GetTaskRunnersForFixture());
175 }
176
CreateShell(Settings settings,TaskRunners task_runners)177 std::unique_ptr<Shell> ShellTest::CreateShell(Settings settings,
178 TaskRunners task_runners) {
179 return Shell::Create(
180 task_runners, settings,
181 [](Shell& shell) {
182 return std::make_unique<ShellTestPlatformView>(shell,
183 shell.GetTaskRunners());
184 },
185 [](Shell& shell) {
186 return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
187 });
188 }
189
190 // |testing::ThreadTest|
SetUp()191 void ShellTest::SetUp() {
192 ThreadTest::SetUp();
193 assets_dir_ =
194 fml::OpenDirectory(GetFixturesPath(), false, fml::FilePermission::kRead);
195 thread_host_ = std::make_unique<ThreadHost>(
196 "io.flutter.test." + GetCurrentTestName() + ".",
197 ThreadHost::Type::Platform | ThreadHost::Type::IO | ThreadHost::Type::UI |
198 ThreadHost::Type::GPU);
199 }
200
201 // |testing::ThreadTest|
TearDown()202 void ShellTest::TearDown() {
203 ThreadTest::TearDown();
204 assets_dir_.reset();
205 thread_host_.reset();
206 }
207
AddNativeCallback(std::string name,Dart_NativeFunction callback)208 void ShellTest::AddNativeCallback(std::string name,
209 Dart_NativeFunction callback) {
210 native_resolver_->AddNativeCallback(std::move(name), callback);
211 }
212
ShellTestPlatformView(PlatformView::Delegate & delegate,TaskRunners task_runners)213 ShellTestPlatformView::ShellTestPlatformView(PlatformView::Delegate& delegate,
214 TaskRunners task_runners)
215 : PlatformView(delegate, std::move(task_runners)) {}
216
217 ShellTestPlatformView::~ShellTestPlatformView() = default;
218
219 // |PlatformView|
CreateRenderingSurface()220 std::unique_ptr<Surface> ShellTestPlatformView::CreateRenderingSurface() {
221 return std::make_unique<GPUSurfaceGL>(this, true);
222 }
223
224 // |GPUSurfaceGLDelegate|
GLContextMakeCurrent()225 bool ShellTestPlatformView::GLContextMakeCurrent() {
226 return gl_surface_.MakeCurrent();
227 }
228
229 // |GPUSurfaceGLDelegate|
GLContextClearCurrent()230 bool ShellTestPlatformView::GLContextClearCurrent() {
231 return gl_surface_.ClearCurrent();
232 }
233
234 // |GPUSurfaceGLDelegate|
GLContextPresent()235 bool ShellTestPlatformView::GLContextPresent() {
236 return gl_surface_.Present();
237 }
238
239 // |GPUSurfaceGLDelegate|
GLContextFBO() const240 intptr_t ShellTestPlatformView::GLContextFBO() const {
241 return gl_surface_.GetFramebuffer();
242 }
243
244 // |GPUSurfaceGLDelegate|
GetGLProcResolver() const245 GPUSurfaceGLDelegate::GLProcResolver ShellTestPlatformView::GetGLProcResolver()
246 const {
247 return [surface = &gl_surface_](const char* name) -> void* {
248 return surface->GetProcAddress(name);
249 };
250 }
251
252 // |GPUSurfaceGLDelegate|
GetExternalViewEmbedder()253 ExternalViewEmbedder* ShellTestPlatformView::GetExternalViewEmbedder() {
254 return nullptr;
255 }
256
257 } // namespace testing
258 } // namespace flutter
259