Flutter Engine
 
Loading...
Searching...
No Matches
shell_test.cc
Go to the documentation of this file.
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
8
14#include "flutter/fml/mapping.h"
19
20namespace flutter {
21namespace testing {
22
23constexpr int64_t kImplicitViewId = 0;
24
26 return std::map<int64_t, ViewContent>();
27}
28
30 FrameContent result;
32 .viewport_metrics = {1.0, width, height, 22, 0},
33 .builder = {},
34 };
35 return result;
36}
37
39 FrameContent result;
42 .builder = {},
43 };
44 return result;
45}
46
48 double height,
49 LayerTreeBuilder builder) {
50 FrameContent result;
52 .viewport_metrics = {1.0, width, height, 22, 0},
53 .builder = std::move(builder),
54 };
55 return result;
56}
57
59 : thread_host_("io.flutter.test." + GetCurrentTestName() + ".",
60 ThreadHost::Type::kPlatform | ThreadHost::Type::kIo |
61 ThreadHost::Type::kUi | ThreadHost::Type::kRaster) {}
62
64 std::unique_ptr<PlatformMessage> message) {
65 shell->OnPlatformViewDispatchPlatformMessage(std::move(message));
66}
67
69 int64_t view_id,
70 int32_t node_id,
73 shell->OnPlatformViewDispatchSemanticsAction(view_id, node_id, action,
74 std::move(args));
75}
76
78 Shell* shell,
79 std::unique_ptr<PlatformMessage> message) {
84 [shell, &latch, message = std::move(message)]() mutable {
85 if (auto engine = shell->weak_engine_) {
86 engine->HandlePlatformMessage(std::move(message));
87 }
88 latch.Signal();
89 }));
90 latch.Wait();
91}
92
93void ShellTest::PlatformViewNotifyCreated(Shell* shell) {
96 shell->GetTaskRunners().GetPlatformTaskRunner(), [shell, &latch]() {
97 shell->GetPlatformView()->NotifyCreated();
98 latch.Signal();
99 });
100 latch.Wait();
101}
102
103void ShellTest::PlatformViewNotifyDestroyed(Shell* shell) {
106 shell->GetTaskRunners().GetPlatformTaskRunner(), [shell, &latch]() {
107 shell->GetPlatformView()->NotifyDestroyed();
108 latch.Signal();
109 });
110 latch.Wait();
111}
112
113void ShellTest::RunEngine(Shell* shell, RunConfiguration configuration) {
117 [shell, &latch, &configuration]() {
118 shell->RunEngine(std::move(configuration),
119 [&latch](Engine::RunStatus run_status) {
120 ASSERT_EQ(run_status, Engine::RunStatus::Success);
121 latch.Signal();
122 });
123 });
124 latch.Wait();
125}
126
127void ShellTest::RestartEngine(Shell* shell, RunConfiguration configuration) {
128 std::promise<bool> restarted;
131 [shell, &restarted, &configuration]() {
132 restarted.set_value(shell->engine_->Restart(std::move(configuration)));
133 });
134 ASSERT_TRUE(restarted.get_future().get());
135}
136
137void ShellTest::VSyncFlush(Shell* shell, bool* will_draw_new_frame) {
141 [shell, will_draw_new_frame, &latch] {
142 // The following UI task ensures that all previous UI tasks are flushed.
143 fml::AutoResetWaitableEvent ui_latch;
144 shell->GetTaskRunners().GetUITaskRunner()->PostTask(
145 [&ui_latch, will_draw_new_frame]() {
146 if (will_draw_new_frame != nullptr) {
147 *will_draw_new_frame = true;
148 }
149 ui_latch.Signal();
150 });
151
152 ShellTestPlatformView* test_platform_view =
153 static_cast<ShellTestPlatformView*>(shell->GetPlatformView().get());
154 do {
155 test_platform_view->SimulateVSync();
156 } while (ui_latch.WaitWithTimeout(fml::TimeDelta::FromMilliseconds(1)));
157
158 latch.Signal();
159 });
160 latch.Wait();
161}
162
163void ShellTest::SetViewportMetrics(Shell* shell, double width, double height) {
164 flutter::ViewportMetrics viewport_metrics = {
165 1, // device pixel ratio
166 width, // physical width
167 height, // physical height
168 0, // min width constraint
169 0, // max width constraint
170 0, // min height constraint
171 0, // max height constraint
172 0, // padding top
173 0, // padding right
174 0, // padding bottom
175 0, // padding left
176 0, // view inset top
177 0, // view inset right
178 0, // view inset bottom
179 0, // view inset left
180 0, // gesture inset top
181 0, // gesture inset right
182 0, // gesture inset bottom
183 0, // gesture inset left
184 22, // physical touch slop
185 std::vector<double>(), // display features bounds
186 std::vector<int>(), // display features type
187 std::vector<int>(), // display features state
188 0 // Display ID
189 };
190 // Set viewport to nonempty, and call Animator::BeginFrame to make the layer
191 // tree pipeline nonempty. Without either of this, the layer tree below
192 // won't be rasterized.
195 [&latch, engine = shell->weak_engine_, viewport_metrics]() {
196 if (engine) {
197 engine->SetViewportMetrics(kImplicitViewId, viewport_metrics);
198 const auto frame_begin_time = fml::TimePoint::Now();
199 const auto frame_end_time =
200 frame_begin_time + fml::TimeDelta::FromSecondsF(1.0 / 60.0);
201 std::unique_ptr<FrameTimingsRecorder> recorder =
202 std::make_unique<FrameTimingsRecorder>();
203 recorder->RecordVsync(frame_begin_time, frame_end_time);
204 engine->animator_->BeginFrame(std::move(recorder));
205 engine->animator_->EndFrame();
206 }
207 latch.Signal();
208 });
209 latch.Wait();
210}
211
212void ShellTest::NotifyIdle(Shell* shell, fml::TimeDelta deadline) {
215 [&latch, engine = shell->weak_engine_, deadline]() {
216 if (engine) {
217 engine->NotifyIdle(deadline);
218 }
219 latch.Signal();
220 });
221 latch.Wait();
222}
223
224void ShellTest::PumpOneFrame(Shell* shell) {
225 PumpOneFrame(shell, ViewContent::DummyView());
226}
227
228void ShellTest::PumpOneFrame(Shell* shell, FrameContent frame_content) {
229 // Set viewport to nonempty, and call Animator::BeginFrame to make the layer
230 // tree pipeline nonempty. Without either of this, the layer tree below
231 // won't be rasterized.
234 shell->weak_engine_;
236 [&latch, engine = shell->weak_engine_, &frame_content,
237 runtime_delegate]() {
238 for (auto& [view_id, view_content] : frame_content) {
239 engine->SetViewportMetrics(view_id, view_content.viewport_metrics);
240 }
241 const auto frame_begin_time = fml::TimePoint::Now();
242 const auto frame_end_time =
243 frame_begin_time + fml::TimeDelta::FromSecondsF(1.0 / 60.0);
244 std::unique_ptr<FrameTimingsRecorder> recorder =
245 std::make_unique<FrameTimingsRecorder>();
246 recorder->RecordVsync(frame_begin_time, frame_end_time);
247 engine->animator_->BeginFrame(std::move(recorder));
248
249 // The BeginFrame phase and the EndFrame phase must be performed in a
250 // single task, otherwise a normal vsync might be inserted in between,
251 // causing flaky assertion errors.
252
253 for (auto& [view_id, view_content] : frame_content) {
254 auto root_layer = std::make_shared<TransformLayer>(DlMatrix());
255 auto layer_tree = std::make_unique<LayerTree>(
256 root_layer,
257 DlISize(view_content.viewport_metrics.physical_width,
258 view_content.viewport_metrics.physical_height));
259 float device_pixel_ratio = static_cast<float>(
260 view_content.viewport_metrics.device_pixel_ratio);
261 if (view_content.builder) {
262 view_content.builder(root_layer);
263 }
264 runtime_delegate->Render(view_id, std::move(layer_tree),
265 device_pixel_ratio);
266 }
267 engine->animator_->EndFrame();
268 latch.Signal();
269 });
270 latch.Wait();
271}
272
273void ShellTest::DispatchFakePointerData(Shell* shell, double x) {
274 auto packet = std::make_unique<PointerDataPacket>(1);
275 packet->SetPointerData(0, PointerData{
276 .change = PointerData::Change::kHover,
277 .physical_x = x,
278 });
279 DispatchPointerData(shell, std::move(packet));
280}
281
282void ShellTest::DispatchPointerData(Shell* shell,
283 std::unique_ptr<PointerDataPacket> packet) {
286 [&latch, shell, &packet]() {
287 // Goes through PlatformView to ensure packet is corrected converted.
288 shell->GetPlatformView()->DispatchPointerDataPacket(std::move(packet));
289 latch.Signal();
290 });
291 latch.Wait();
292}
293
294int ShellTest::UnreportedTimingsCount(Shell* shell) {
295 return shell->unreported_timings_.size();
296}
297
298void ShellTest::SetNeedsReportTimings(Shell* shell, bool value) {
299 shell->SetNeedsReportTimings(value);
300}
301
302bool ShellTest::GetNeedsReportTimings(Shell* shell) {
303 return shell->needs_report_timings_;
304}
305
306void ShellTest::StorePersistentCache(PersistentCache* cache,
307 const SkData& key,
308 const SkData& value) {
309 cache->store(key, value);
310}
311
312void ShellTest::OnServiceProtocol(
313 Shell* shell,
314 ServiceProtocolEnum some_protocol,
315 const fml::RefPtr<fml::TaskRunner>& task_runner,
317 rapidjson::Document* response) {
318 std::promise<bool> finished;
320 task_runner, [shell, some_protocol, params, response, &finished]() {
321 switch (some_protocol) {
322 case ServiceProtocolEnum::kGetSkSLs:
323 shell->OnServiceProtocolGetSkSLs(params, response);
324 break;
325 case ServiceProtocolEnum::kEstimateRasterCacheMemory:
326 shell->OnServiceProtocolEstimateRasterCacheMemory(params, response);
327 break;
328 case ServiceProtocolEnum::kSetAssetBundlePath:
329 shell->OnServiceProtocolSetAssetBundlePath(params, response);
330 break;
331 case ServiceProtocolEnum::kRunInView:
332 shell->OnServiceProtocolRunInView(params, response);
333 break;
334 }
335 finished.set_value(true);
336 });
337 finished.get_future().wait();
338}
339
340std::shared_ptr<txt::FontCollection> ShellTest::GetFontCollection(
341 Shell* shell) {
342 return shell->weak_engine_->GetFontCollection().GetFontCollection();
343}
344
345Settings ShellTest::CreateSettingsForFixture() {
346 Settings settings;
347 settings.leak_vm = false;
348 settings.task_observer_add = [](intptr_t key, const fml::closure& handler) {
351 handler);
352 return queue_id;
353 };
354 settings.task_observer_remove = [](fml::TaskQueueId queue_id, intptr_t key) {
356 key);
357 };
358 settings.isolate_create_callback = [this]() {
359 native_resolver_->SetNativeResolverForIsolate();
360 };
361#if OS_FUCHSIA
362 settings.verbose_logging = true;
363#endif
364 SetSnapshotsAndAssets(settings);
365 return settings;
366}
367
368TaskRunners ShellTest::GetTaskRunnersForFixture() {
369 return {
370 "test",
371 thread_host_.platform_thread->GetTaskRunner(), // platform
372 thread_host_.raster_thread->GetTaskRunner(), // raster
373 thread_host_.ui_thread->GetTaskRunner(), // ui
374 thread_host_.io_thread->GetTaskRunner() // io
375 };
376}
377
378fml::TimePoint ShellTest::GetLatestFrameTargetTime(Shell* shell) const {
379 return shell->GetLatestFrameTargetTime();
380}
381
382std::unique_ptr<Shell> ShellTest::CreateShell(
383 const Settings& settings,
384 std::optional<TaskRunners> task_runners) {
385 return CreateShell({
386 .settings = settings,
387 .task_runners = std::move(task_runners),
388 });
389}
390
391std::unique_ptr<Shell> ShellTest::CreateShell(const Config& config) {
392 TaskRunners task_runners = config.task_runners.has_value()
393 ? config.task_runners.value()
395 Shell::CreateCallback<PlatformView> platform_view_create_callback =
397 if (!platform_view_create_callback) {
398 platform_view_create_callback = ShellTestPlatformViewBuilder({});
399 }
400
401 Shell::CreateCallback<Rasterizer> rasterizer_create_callback =
402 [](Shell& shell) { return std::make_unique<Rasterizer>(shell); };
403
404 return Shell::Create(flutter::PlatformData(), //
405 task_runners, //
406 config.settings, //
407 platform_view_create_callback, //
408 rasterizer_create_callback, //
409 config.is_gpu_disabled //
410 );
411}
412
413void ShellTest::DestroyShell(std::unique_ptr<Shell> shell) {
414 DestroyShell(std::move(shell), GetTaskRunnersForFixture());
415}
416
417void ShellTest::DestroyShell(std::unique_ptr<Shell> shell,
418 const TaskRunners& task_runners) {
421 [&shell, &latch]() mutable {
422 shell.reset();
423 latch.Signal();
424 });
425 latch.Wait();
426}
427
428void ShellTest::TurnOffGPU(Shell* shell, bool value) {
429 shell->is_gpu_disabled_sync_switch_->SetSwitch(value);
430}
431
432bool ShellTest::ShouldDiscardLayerTree(Shell* shell,
433 int64_t view_id,
434 const flutter::LayerTree& tree) {
435 return shell->ShouldDiscardLayerTree(view_id, tree);
436}
437
438} // namespace testing
439} // namespace flutter
Specifies all the configuration required by the runtime library to launch the root isolate....
std::map< std::string_view, std::string_view > ServiceProtocolMap
const TaskRunners & GetTaskRunners() const override
If callers wish to interact directly with any shell subcomponents, they must (on the platform thread)...
Definition shell.cc:911
std::function< std::unique_ptr< T >(Shell &)> CreateCallback
Definition shell.h:121
fml::WeakPtr< PlatformView > GetPlatformView()
Platform views may only be accessed on the platform task runner.
Definition shell.cc:930
fml::RefPtr< fml::TaskRunner > GetUITaskRunner() const
fml::RefPtr< fml::TaskRunner > GetPlatformTaskRunner() const
void SendPlatformMessage(Shell *shell, std::unique_ptr< PlatformMessage > message)
Definition shell_test.cc:63
void SendEnginePlatformMessage(Shell *shell, std::unique_ptr< PlatformMessage > message)
Definition shell_test.cc:77
void SendSemanticsAction(Shell *shell, int64_t view_id, int32_t node_id, SemanticsAction action, fml::MallocMapping args)
Definition shell_test.cc:68
A Mapping like NonOwnedMapping, but uses Free as its release proc.
Definition mapping.h:144
static TaskQueueId GetCurrentTaskQueueId()
static MessageLoopTaskQueues * GetInstance()
void AddTaskObserver(TaskQueueId queue_id, intptr_t key, const fml::closure &callback)
void RemoveTaskObserver(TaskQueueId queue_id, intptr_t key)
static void RunNowOrPostTask(const fml::RefPtr< fml::TaskRunner > &runner, const fml::closure &task)
virtual void PostTask(const fml::closure &task) override
static constexpr TimeDelta FromSecondsF(double seconds)
Definition time_delta.h:53
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition time_delta.h:46
static TimePoint Now()
Definition time_point.cc:49
int32_t value
int32_t x
@ kRaster
Suitable for thread which raster data.
Definition embedder.h:377
const EmbeddedViewParams * params
ThreadHost thread_host_
FlutterEngine engine
Definition main.cc:84
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const gchar FlBinaryMessengerMessageHandler handler
G_BEGIN_DECLS GBytes * message
G_BEGIN_DECLS FlutterViewId view_id
std::string GetCurrentTestName()
Gets the name of the currently running test. This is useful in generating logs or assets based on tes...
Definition testing.cc:14
std::function< void(std::shared_ptr< ContainerLayer > root)> LayerTreeBuilder
Definition shell_test.h:33
std::map< int64_t, ViewContent > FrameContent
Definition shell_test.h:36
constexpr int64_t kImplicitViewId
internal::CopyableLambda< T > MakeCopyable(T lambda)
std::function< void()> closure
Definition closure.h:14
int32_t height
int32_t width
TaskObserverRemove task_observer_remove
Definition settings.h:282
TaskObserverAdd task_observer_add
Definition settings.h:281
fml::closure isolate_create_callback
Definition settings.h:288
The collection of all the threads used by the engine.
Definition thread_host.h:21
Shell::CreateCallback< PlatformView > platform_view_create_callback
Definition shell_test.h:73
std::optional< TaskRunners > task_runners
Definition shell_test.h:69
static FrameContent ImplicitView(double width, double height, LayerTreeBuilder builder)
Definition shell_test.cc:47
static FrameContent DummyView(double width=1, double height=1)
Definition shell_test.cc:29
flutter::ViewportMetrics viewport_metrics
Definition shell_test.h:39
static FrameContent NoViews()
Definition shell_test.cc:25
A 4x4 matrix using column-major storage.
Definition matrix.h:37