Flutter Engine
engine_unittests.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 #include "flutter/shell/common/engine.h"
6 
7 #include <cstring>
8 
9 #include "flutter/runtime/dart_vm_lifecycle.h"
10 #include "flutter/shell/common/thread_host.h"
11 #include "flutter/testing/fixture_test.h"
12 #include "flutter/testing/testing.h"
13 #include "gmock/gmock.h"
14 #include "rapidjson/document.h"
15 #include "rapidjson/stringbuffer.h"
16 #include "rapidjson/writer.h"
17 
18 ///\note Deprecated MOCK_METHOD macros used until this issue is resolved:
19 // https://github.com/google/googletest/issues/2490
20 
21 namespace flutter {
22 
23 namespace {
24 class MockDelegate : public Engine::Delegate {
25  public:
26  MOCK_METHOD2(OnEngineUpdateSemantics,
28  MOCK_METHOD1(OnEngineHandlePlatformMessage,
29  void(std::unique_ptr<PlatformMessage>));
30  MOCK_METHOD0(OnPreEngineRestart, void());
31  MOCK_METHOD0(OnRootIsolateCreated, void());
32  MOCK_METHOD2(UpdateIsolateDescription, void(const std::string, int64_t));
33  MOCK_METHOD1(SetNeedsReportTimings, void(bool));
34  MOCK_METHOD1(ComputePlatformResolvedLocale,
35  std::unique_ptr<std::vector<std::string>>(
36  const std::vector<std::string>&));
37  MOCK_METHOD1(RequestDartDeferredLibrary, void(intptr_t));
38  MOCK_METHOD0(GetCurrentTimePoint, fml::TimePoint());
39 };
40 
41 class MockResponse : public PlatformMessageResponse {
42  public:
43  MOCK_METHOD1(Complete, void(std::unique_ptr<fml::Mapping> data));
44  MOCK_METHOD0(CompleteEmpty, void());
45 };
46 
47 class MockRuntimeDelegate : public RuntimeDelegate {
48  public:
49  MOCK_METHOD0(DefaultRouteName, std::string());
50  MOCK_METHOD1(ScheduleFrame, void(bool));
51  MOCK_METHOD1(Render, void(std::unique_ptr<flutter::LayerTree>));
52  MOCK_METHOD2(UpdateSemantics,
54  MOCK_METHOD1(HandlePlatformMessage, void(std::unique_ptr<PlatformMessage>));
55  MOCK_METHOD0(GetFontCollection, FontCollection&());
56  MOCK_METHOD0(OnRootIsolateCreated, void());
57  MOCK_METHOD2(UpdateIsolateDescription, void(const std::string, int64_t));
58  MOCK_METHOD1(SetNeedsReportTimings, void(bool));
59  MOCK_METHOD1(ComputePlatformResolvedLocale,
60  std::unique_ptr<std::vector<std::string>>(
61  const std::vector<std::string>&));
62  MOCK_METHOD1(RequestDartDeferredLibrary, void(intptr_t));
63 };
64 
65 class MockRuntimeController : public RuntimeController {
66  public:
67  MockRuntimeController(RuntimeDelegate& client, TaskRunners p_task_runners)
68  : RuntimeController(client, p_task_runners) {}
69  MOCK_METHOD0(IsRootIsolateRunning, bool());
70  MOCK_METHOD1(DispatchPlatformMessage, bool(std::unique_ptr<PlatformMessage>));
71  MOCK_METHOD3(LoadDartDeferredLibraryError,
72  void(intptr_t, const std::string, bool));
73  MOCK_CONST_METHOD0(GetDartVM, DartVM*());
74  MOCK_METHOD1(NotifyIdle, bool(fml::TimePoint));
75 };
76 
77 std::unique_ptr<PlatformMessage> MakePlatformMessage(
78  const std::string& channel,
79  const std::map<std::string, std::string>& values,
81  rapidjson::Document document;
82  auto& allocator = document.GetAllocator();
83  document.SetObject();
84 
85  for (const auto& pair : values) {
86  rapidjson::Value key(pair.first.c_str(), strlen(pair.first.c_str()),
87  allocator);
88  rapidjson::Value value(pair.second.c_str(), strlen(pair.second.c_str()),
89  allocator);
90  document.AddMember(key, value, allocator);
91  }
92 
93  rapidjson::StringBuffer buffer;
94  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
95  document.Accept(writer);
96  const uint8_t* data = reinterpret_cast<const uint8_t*>(buffer.GetString());
97 
98  std::unique_ptr<PlatformMessage> message = std::make_unique<PlatformMessage>(
99  channel, fml::MallocMapping::Copy(data, buffer.GetSize()), response);
100  return message;
101 }
102 
103 class EngineTest : public testing::FixtureTest {
104  public:
105  EngineTest()
106  : thread_host_("EngineTest",
107  ThreadHost::Type::Platform | ThreadHost::Type::IO |
108  ThreadHost::Type::UI | ThreadHost::Type::RASTER),
109  task_runners_({
110  "EngineTest",
111  thread_host_.platform_thread->GetTaskRunner(), // platform
112  thread_host_.raster_thread->GetTaskRunner(), // raster
113  thread_host_.ui_thread->GetTaskRunner(), // ui
114  thread_host_.io_thread->GetTaskRunner() // io
115  }) {}
116 
117  void PostUITaskSync(const std::function<void()>& function) {
119  task_runners_.GetUITaskRunner()->PostTask([&] {
120  function();
121  latch.Signal();
122  });
123  latch.Wait();
124  }
125 
126  protected:
127  void SetUp() override {
128  settings_ = CreateSettingsForFixture();
129  dispatcher_maker_ = [](PointerDataDispatcher::Delegate&) {
130  return nullptr;
131  };
132  }
133 
134  MockDelegate delegate_;
136  ThreadHost thread_host_;
137  TaskRunners task_runners_;
138  Settings settings_;
139  std::unique_ptr<Animator> animator_;
141  std::unique_ptr<RuntimeController> runtime_controller_;
142  std::shared_ptr<fml::ConcurrentTaskRunner> image_decoder_task_runner_;
143 };
144 } // namespace
145 
146 TEST_F(EngineTest, Create) {
147  PostUITaskSync([this] {
148  auto engine = std::make_unique<Engine>(
149  /*delegate=*/delegate_,
150  /*dispatcher_maker=*/dispatcher_maker_,
151  /*image_decoder_task_runner=*/image_decoder_task_runner_,
152  /*task_runners=*/task_runners_,
153  /*settings=*/settings_,
154  /*animator=*/std::move(animator_),
155  /*io_manager=*/io_manager_,
156  /*font_collection=*/std::make_shared<FontCollection>(),
157  /*runtime_controller=*/std::move(runtime_controller_));
158  EXPECT_TRUE(engine);
159  });
160 }
161 
162 TEST_F(EngineTest, DispatchPlatformMessageUnknown) {
163  PostUITaskSync([this] {
164  MockRuntimeDelegate client;
165  auto mock_runtime_controller =
166  std::make_unique<MockRuntimeController>(client, task_runners_);
167  EXPECT_CALL(*mock_runtime_controller, IsRootIsolateRunning())
168  .WillRepeatedly(::testing::Return(false));
169  auto engine = std::make_unique<Engine>(
170  /*delegate=*/delegate_,
171  /*dispatcher_maker=*/dispatcher_maker_,
172  /*image_decoder_task_runner=*/image_decoder_task_runner_,
173  /*task_runners=*/task_runners_,
174  /*settings=*/settings_,
175  /*animator=*/std::move(animator_),
176  /*io_manager=*/io_manager_,
177  /*font_collection=*/std::make_shared<FontCollection>(),
178  /*runtime_controller=*/std::move(mock_runtime_controller));
179 
181  fml::MakeRefCounted<MockResponse>();
182  std::unique_ptr<PlatformMessage> message =
183  std::make_unique<PlatformMessage>("foo", response);
184  engine->DispatchPlatformMessage(std::move(message));
185  });
186 }
187 
188 TEST_F(EngineTest, DispatchPlatformMessageInitialRoute) {
189  PostUITaskSync([this] {
190  MockRuntimeDelegate client;
191  auto mock_runtime_controller =
192  std::make_unique<MockRuntimeController>(client, task_runners_);
193  EXPECT_CALL(*mock_runtime_controller, IsRootIsolateRunning())
194  .WillRepeatedly(::testing::Return(false));
195  auto engine = std::make_unique<Engine>(
196  /*delegate=*/delegate_,
197  /*dispatcher_maker=*/dispatcher_maker_,
198  /*image_decoder_task_runner=*/image_decoder_task_runner_,
199  /*task_runners=*/task_runners_,
200  /*settings=*/settings_,
201  /*animator=*/std::move(animator_),
202  /*io_manager=*/io_manager_,
203  /*font_collection=*/std::make_shared<FontCollection>(),
204  /*runtime_controller=*/std::move(mock_runtime_controller));
205 
207  fml::MakeRefCounted<MockResponse>();
208  std::map<std::string, std::string> values{
209  {"method", "setInitialRoute"},
210  {"args", "test_initial_route"},
211  };
212  std::unique_ptr<PlatformMessage> message =
213  MakePlatformMessage("flutter/navigation", values, response);
214  engine->DispatchPlatformMessage(std::move(message));
215  EXPECT_EQ(engine->InitialRoute(), "test_initial_route");
216  });
217 }
218 
219 TEST_F(EngineTest, DispatchPlatformMessageInitialRouteIgnored) {
220  PostUITaskSync([this] {
221  MockRuntimeDelegate client;
222  auto mock_runtime_controller =
223  std::make_unique<MockRuntimeController>(client, task_runners_);
224  EXPECT_CALL(*mock_runtime_controller, IsRootIsolateRunning())
225  .WillRepeatedly(::testing::Return(true));
226  EXPECT_CALL(*mock_runtime_controller, DispatchPlatformMessage(::testing::_))
227  .WillRepeatedly(::testing::Return(true));
228  auto engine = std::make_unique<Engine>(
229  /*delegate=*/delegate_,
230  /*dispatcher_maker=*/dispatcher_maker_,
231  /*image_decoder_task_runner=*/image_decoder_task_runner_,
232  /*task_runners=*/task_runners_,
233  /*settings=*/settings_,
234  /*animator=*/std::move(animator_),
235  /*io_manager=*/io_manager_,
236  /*font_collection=*/std::make_shared<FontCollection>(),
237  /*runtime_controller=*/std::move(mock_runtime_controller));
238 
240  fml::MakeRefCounted<MockResponse>();
241  std::map<std::string, std::string> values{
242  {"method", "setInitialRoute"},
243  {"args", "test_initial_route"},
244  };
245  std::unique_ptr<PlatformMessage> message =
246  MakePlatformMessage("flutter/navigation", values, response);
247  engine->DispatchPlatformMessage(std::move(message));
248  EXPECT_EQ(engine->InitialRoute(), "");
249  });
250 }
251 
252 TEST_F(EngineTest, SpawnSharesFontLibrary) {
253  PostUITaskSync([this] {
254  MockRuntimeDelegate client;
255  auto mock_runtime_controller =
256  std::make_unique<MockRuntimeController>(client, task_runners_);
257  auto vm_ref = DartVMRef::Create(settings_);
258  EXPECT_CALL(*mock_runtime_controller, GetDartVM())
259  .WillRepeatedly(::testing::Return(vm_ref.get()));
260  auto engine = std::make_unique<Engine>(
261  /*delegate=*/delegate_,
262  /*dispatcher_maker=*/dispatcher_maker_,
263  /*image_decoder_task_runner=*/image_decoder_task_runner_,
264  /*task_runners=*/task_runners_,
265  /*settings=*/settings_,
266  /*animator=*/std::move(animator_),
267  /*io_manager=*/io_manager_,
268  /*font_collection=*/std::make_shared<FontCollection>(),
269  /*runtime_controller=*/std::move(mock_runtime_controller));
270 
271  auto spawn = engine->Spawn(delegate_, dispatcher_maker_, settings_, nullptr,
272  std::string(), io_manager_);
273  EXPECT_TRUE(spawn != nullptr);
274  EXPECT_EQ(&engine->GetFontCollection(), &spawn->GetFontCollection());
275  });
276 }
277 
278 TEST_F(EngineTest, SpawnWithCustomInitialRoute) {
279  PostUITaskSync([this] {
280  MockRuntimeDelegate client;
281  auto mock_runtime_controller =
282  std::make_unique<MockRuntimeController>(client, task_runners_);
283  auto vm_ref = DartVMRef::Create(settings_);
284  EXPECT_CALL(*mock_runtime_controller, GetDartVM())
285  .WillRepeatedly(::testing::Return(vm_ref.get()));
286  auto engine = std::make_unique<Engine>(
287  /*delegate=*/delegate_,
288  /*dispatcher_maker=*/dispatcher_maker_,
289  /*image_decoder_task_runner=*/image_decoder_task_runner_,
290  /*task_runners=*/task_runners_,
291  /*settings=*/settings_,
292  /*animator=*/std::move(animator_),
293  /*io_manager=*/io_manager_,
294  /*font_collection=*/std::make_shared<FontCollection>(),
295  /*runtime_controller=*/std::move(mock_runtime_controller));
296 
297  auto spawn = engine->Spawn(delegate_, dispatcher_maker_, settings_, nullptr,
298  "/foo", io_manager_);
299  EXPECT_TRUE(spawn != nullptr);
300  ASSERT_EQ("/foo", spawn->InitialRoute());
301  });
302 }
303 
304 TEST_F(EngineTest, SpawnResetsViewportMetrics) {
305  PostUITaskSync([this] {
306  MockRuntimeDelegate client;
307  auto mock_runtime_controller =
308  std::make_unique<MockRuntimeController>(client, task_runners_);
309  auto vm_ref = DartVMRef::Create(settings_);
310  EXPECT_CALL(*mock_runtime_controller, GetDartVM())
311  .WillRepeatedly(::testing::Return(vm_ref.get()));
312  ViewportMetrics old_viewport_metrics = ViewportMetrics();
313  const double kViewWidth = 768;
314  const double kViewHeight = 1024;
315  old_viewport_metrics.physical_width = kViewWidth;
316  old_viewport_metrics.physical_height = kViewHeight;
317  mock_runtime_controller->SetViewportMetrics(old_viewport_metrics);
318  auto engine = std::make_unique<Engine>(
319  /*delegate=*/delegate_,
320  /*dispatcher_maker=*/dispatcher_maker_,
321  /*image_decoder_task_runner=*/image_decoder_task_runner_,
322  /*task_runners=*/task_runners_,
323  /*settings=*/settings_,
324  /*animator=*/std::move(animator_),
325  /*io_manager=*/io_manager_,
326  /*font_collection=*/std::make_shared<FontCollection>(),
327  /*runtime_controller=*/std::move(mock_runtime_controller));
328 
329  auto& old_platform_data = engine->GetRuntimeController()->GetPlatformData();
330  EXPECT_EQ(old_platform_data.viewport_metrics.physical_width, kViewWidth);
331  EXPECT_EQ(old_platform_data.viewport_metrics.physical_height, kViewHeight);
332 
333  auto spawn = engine->Spawn(delegate_, dispatcher_maker_, settings_, nullptr,
334  std::string(), io_manager_);
335  EXPECT_TRUE(spawn != nullptr);
336  auto& new_viewport_metrics =
337  spawn->GetRuntimeController()->GetPlatformData().viewport_metrics;
338  EXPECT_EQ(new_viewport_metrics.physical_width, 0);
339  EXPECT_EQ(new_viewport_metrics.physical_height, 0);
340  });
341 }
342 
343 TEST_F(EngineTest, SpawnWithCustomSettings) {
344  PostUITaskSync([this] {
345  MockRuntimeDelegate client;
346  auto mock_runtime_controller =
347  std::make_unique<MockRuntimeController>(client, task_runners_);
348  auto vm_ref = DartVMRef::Create(settings_);
349  EXPECT_CALL(*mock_runtime_controller, GetDartVM())
350  .WillRepeatedly(::testing::Return(vm_ref.get()));
351  auto engine = std::make_unique<Engine>(
352  /*delegate=*/delegate_,
353  /*dispatcher_maker=*/dispatcher_maker_,
354  /*image_decoder_task_runner=*/image_decoder_task_runner_,
355  /*task_runners=*/task_runners_,
356  /*settings=*/settings_,
357  /*animator=*/std::move(animator_),
358  /*io_manager=*/io_manager_,
359  /*font_collection=*/std::make_shared<FontCollection>(),
360  /*runtime_controller=*/std::move(mock_runtime_controller));
361 
362  Settings custom_settings = settings_;
363  custom_settings.persistent_isolate_data =
364  std::make_shared<fml::DataMapping>("foo");
365  auto spawn = engine->Spawn(delegate_, dispatcher_maker_, custom_settings,
366  nullptr, std::string(), io_manager_);
367  EXPECT_TRUE(spawn != nullptr);
368  auto new_persistent_isolate_data =
369  const_cast<RuntimeController*>(spawn->GetRuntimeController())
370  ->GetPersistentIsolateData();
371  EXPECT_EQ(custom_settings.persistent_isolate_data->GetMapping(),
372  new_persistent_isolate_data->GetMapping());
373  EXPECT_EQ(custom_settings.persistent_isolate_data->GetSize(),
374  new_persistent_isolate_data->GetSize());
375  });
376 }
377 
378 TEST_F(EngineTest, PassesLoadDartDeferredLibraryErrorToRuntime) {
379  PostUITaskSync([this] {
380  intptr_t error_id = 123;
381  const std::string error_message = "error message";
382  MockRuntimeDelegate client;
383  auto mock_runtime_controller =
384  std::make_unique<MockRuntimeController>(client, task_runners_);
385  EXPECT_CALL(*mock_runtime_controller, IsRootIsolateRunning())
386  .WillRepeatedly(::testing::Return(true));
387  EXPECT_CALL(*mock_runtime_controller,
388  LoadDartDeferredLibraryError(error_id, error_message, true))
389  .Times(1);
390  auto engine = std::make_unique<Engine>(
391  /*delegate=*/delegate_,
392  /*dispatcher_maker=*/dispatcher_maker_,
393  /*image_decoder_task_runner=*/image_decoder_task_runner_,
394  /*task_runners=*/task_runners_,
395  /*settings=*/settings_,
396  /*animator=*/std::move(animator_),
397  /*io_manager=*/io_manager_,
398  /*font_collection=*/std::make_shared<FontCollection>(),
399  /*runtime_controller=*/std::move(mock_runtime_controller));
400 
401  engine->LoadDartDeferredLibraryError(error_id, error_message, true);
402  });
403 }
404 
405 } // namespace flutter
fml::WeakPtr< IOManager > io_manager_
MockDelegate delegate_
std::shared_ptr< fml::ConcurrentTaskRunner > image_decoder_task_runner_
Dart_NativeFunction function
Definition: fuchsia.cc:51
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
ThreadHost thread_host_
std::function< std::unique_ptr< PointerDataDispatcher >(PointerDataDispatcher::Delegate &)> PointerDataDispatcherMaker
Signature for constructing PointerDataDispatcher.
std::unique_ptr< RuntimeController > runtime_controller_
static DartVMRef Create(Settings settings, fml::RefPtr< const DartSnapshot > vm_snapshot=nullptr, fml::RefPtr< const DartSnapshot > isolate_snapshot=nullptr)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition: switches.h:41
uint8_t value
TEST_F(EngineTest, Create)
Dart_Handle ComputePlatformResolvedLocale(Dart_Handle supportedLocalesHandle)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data observatory The hostname IP address on which the Dart Observatory should be served If not defaults to or::depending on whether ipv6 is specified disable Disable the Dart Observatory The observatory is never available in release mode Bind to the IPv6 localhost address for the Dart Observatory Ignored if observatory host is set endless trace buffer
Definition: switches.h:98
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data observatory The hostname IP address on which the Dart Observatory should be served If not defaults to or::depending on whether ipv6 is specified disable Disable the Dart Observatory The observatory is never available in release mode Bind to the IPv6 localhost address for the Dart Observatory Ignored if observatory host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however skia deterministic Skips the call to thus avoiding swapping out some Skia function pointers based on available CPU features This is used to obtain deterministic behavior in Skia rendering disable service auth Disable the requirement for authentication codes for communicating with the VM service start Start the application paused in the Dart debugger trace Trace Skia calls This is useful when debugging the GPU threed By Skia tracing is not enabled to reduce the number of traced events trace Filters out all trace events except those that are specified in this comma separated list of allowed prefixes cache Only cache the shader in SkSL instead of binary or GLSL This should only be used during development phases The generated SkSLs can later be used in the release build for shader precompilation at launch in order to eliminate the shader compile jank trace Trace to the system use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed disallow insecure By all insecure connections are rejected force Uses separate threads for the UI
Definition: switches.h:207
static void DispatchPlatformMessage(JNIEnv *env, jobject jcaller, jlong shell_holder, jstring channel, jobject message, jint position, jint responseId)
static MallocMapping Copy(const T *begin, const T *end)
Definition: mapping.h:162
TaskRunners task_runners_
std::unique_ptr< Animator > animator_
std::unordered_map< int32_t, CustomAccessibilityAction > CustomAccessibilityActionUpdates
Settings settings_
PointerDataDispatcherMaker dispatcher_maker_