Flutter Engine
embedder_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 "fml/task_runner.h"
6 #define FML_USED_ON_EMBEDDER
7 
8 #include <string>
9 #include <vector>
10 
11 #include "embedder.h"
12 #include "embedder_engine.h"
13 #include "flutter/flow/raster_cache.h"
14 #include "flutter/fml/file.h"
15 #include "flutter/fml/make_copyable.h"
16 #include "flutter/fml/mapping.h"
17 #include "flutter/fml/message_loop.h"
18 #include "flutter/fml/paths.h"
19 #include "flutter/fml/synchronization/count_down_latch.h"
20 #include "flutter/fml/synchronization/waitable_event.h"
21 #include "flutter/fml/thread.h"
22 #include "flutter/runtime/dart_vm.h"
23 #include "flutter/shell/platform/embedder/tests/embedder_assertions.h"
24 #include "flutter/shell/platform/embedder/tests/embedder_config_builder.h"
25 #include "flutter/shell/platform/embedder/tests/embedder_test.h"
26 #include "flutter/shell/platform/embedder/tests/embedder_unittests_util.h"
27 #include "flutter/testing/assertions_skia.h"
28 #include "flutter/testing/testing.h"
29 #include "third_party/skia/include/core/SkSurface.h"
31 
32 namespace flutter {
33 namespace testing {
34 
36 
37 TEST(EmbedderTestNoFixture, MustNotRunWithInvalidArgs) {
39  EmbedderConfigBuilder builder(
41  auto engine = builder.LaunchEngine();
42  ASSERT_FALSE(engine.is_valid());
43 }
44 
45 TEST_F(EmbedderTest, CanLaunchAndShutdownWithValidProjectArgs) {
46  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
48  context.AddIsolateCreateCallback([&latch]() { latch.Signal(); });
49  EmbedderConfigBuilder builder(context);
50  builder.SetSoftwareRendererConfig();
51  auto engine = builder.LaunchEngine();
52  ASSERT_TRUE(engine.is_valid());
53  // Wait for the root isolate to launch.
54  latch.Wait();
55  engine.reset();
56 }
57 
58 // TODO(41999): Disabled because flaky.
59 TEST_F(EmbedderTest, DISABLED_CanLaunchAndShutdownMultipleTimes) {
60  EmbedderConfigBuilder builder(
61  GetEmbedderContext(EmbedderTestContextType::kSoftwareContext));
62  builder.SetSoftwareRendererConfig();
63  for (size_t i = 0; i < 3; ++i) {
64  auto engine = builder.LaunchEngine();
65  ASSERT_TRUE(engine.is_valid());
66  FML_LOG(INFO) << "Engine launch count: " << i + 1;
67  }
68 }
69 
70 TEST_F(EmbedderTest, CanInvokeCustomEntrypoint) {
71  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
72  static fml::AutoResetWaitableEvent latch;
73  Dart_NativeFunction entrypoint = [](Dart_NativeArguments args) {
74  latch.Signal();
75  };
76  context.AddNativeCallback("SayHiFromCustomEntrypoint", entrypoint);
77  EmbedderConfigBuilder builder(context);
78  builder.SetSoftwareRendererConfig();
79  builder.SetDartEntrypoint("customEntrypoint");
80  auto engine = builder.LaunchEngine();
81  latch.Wait();
82  ASSERT_TRUE(engine.is_valid());
83 }
84 
85 TEST_F(EmbedderTest, CanInvokeCustomEntrypointMacro) {
86  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
87 
91 
92  // Can be defined separately.
93  auto entry1 = [&latch1](Dart_NativeArguments args) {
94  FML_LOG(INFO) << "In Callback 1";
95  latch1.Signal();
96  };
97  auto native_entry1 = CREATE_NATIVE_ENTRY(entry1);
98  context.AddNativeCallback("SayHiFromCustomEntrypoint1", native_entry1);
99 
100  // Can be wrapped in in the args.
101  auto entry2 = [&latch2](Dart_NativeArguments args) {
102  FML_LOG(INFO) << "In Callback 2";
103  latch2.Signal();
104  };
105  context.AddNativeCallback("SayHiFromCustomEntrypoint2",
106  CREATE_NATIVE_ENTRY(entry2));
107 
108  // Everything can be inline.
109  context.AddNativeCallback(
110  "SayHiFromCustomEntrypoint3",
111  CREATE_NATIVE_ENTRY([&latch3](Dart_NativeArguments args) {
112  FML_LOG(INFO) << "In Callback 3";
113  latch3.Signal();
114  }));
115 
116  EmbedderConfigBuilder builder(context);
117  builder.SetSoftwareRendererConfig();
118  builder.SetDartEntrypoint("customEntrypoint1");
119  auto engine = builder.LaunchEngine();
120  latch1.Wait();
121  latch2.Wait();
122  latch3.Wait();
123  ASSERT_TRUE(engine.is_valid());
124 }
125 
126 TEST_F(EmbedderTest, CanTerminateCleanly) {
127  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
128  EmbedderConfigBuilder builder(context);
129  builder.SetSoftwareRendererConfig();
130  builder.SetDartEntrypoint("terminateExitCodeHandler");
131  auto engine = builder.LaunchEngine();
132  ASSERT_TRUE(engine.is_valid());
133 }
134 
135 std::atomic_size_t EmbedderTestTaskRunner::sEmbedderTaskRunnerIdentifiers = {};
136 
137 TEST_F(EmbedderTest, CanSpecifyCustomPlatformTaskRunner) {
138  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
140 
141  // Run the test on its own thread with a message loop so that it can safely
142  // pump its event loop while we wait for all the conditions to be checked.
143  auto platform_task_runner = CreateNewThread("test_platform_thread");
144  static std::mutex engine_mutex;
145  static bool signaled_once = false;
147 
148  EmbedderTestTaskRunner test_task_runner(
149  platform_task_runner, [&](FlutterTask task) {
150  std::scoped_lock lock(engine_mutex);
151  if (!engine.is_valid()) {
152  return;
153  }
154  // There may be multiple tasks posted but we only need to check
155  // assertions once.
156  if (signaled_once) {
157  FlutterEngineRunTask(engine.get(), &task);
158  return;
159  }
160 
161  signaled_once = true;
162  ASSERT_TRUE(engine.is_valid());
163  ASSERT_EQ(FlutterEngineRunTask(engine.get(), &task), kSuccess);
164  latch.Signal();
165  });
166 
167  platform_task_runner->PostTask([&]() {
168  EmbedderConfigBuilder builder(context);
169  const auto task_runner_description =
170  test_task_runner.GetFlutterTaskRunnerDescription();
171  builder.SetSoftwareRendererConfig();
172  builder.SetPlatformTaskRunner(&task_runner_description);
173  builder.SetDartEntrypoint("invokePlatformTaskRunner");
174  std::scoped_lock lock(engine_mutex);
175  engine = builder.LaunchEngine();
176  ASSERT_TRUE(engine.is_valid());
177  });
178 
179  // Signaled when all the assertions are checked.
180  latch.Wait();
181  ASSERT_TRUE(engine.is_valid());
182 
183  // Since the engine was started on its own thread, it must be killed there as
184  // well.
185  fml::AutoResetWaitableEvent kill_latch;
186  platform_task_runner->PostTask(fml::MakeCopyable([&]() mutable {
187  std::scoped_lock lock(engine_mutex);
188  engine.reset();
189 
190  // There may still be pending tasks on the platform thread that were queued
191  // by the test_task_runner. Signal the latch after these tasks have been
192  // consumed.
193  platform_task_runner->PostTask([&kill_latch] { kill_latch.Signal(); });
194  }));
195  kill_latch.Wait();
196 
197  ASSERT_TRUE(signaled_once);
198  signaled_once = false;
199 }
200 
201 TEST(EmbedderTestNoFixture, CanGetCurrentTimeInNanoseconds) {
202  auto point1 = fml::TimePoint::FromEpochDelta(
204  auto point2 = fml::TimePoint::Now();
205 
206  ASSERT_LT((point2 - point1), fml::TimeDelta::FromMilliseconds(1));
207 }
208 
209 TEST_F(EmbedderTest, CanReloadSystemFonts) {
210  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
211  EmbedderConfigBuilder builder(context);
212  builder.SetSoftwareRendererConfig();
213  auto engine = builder.LaunchEngine();
214  ASSERT_TRUE(engine.is_valid());
215 
217  ASSERT_EQ(result, kSuccess);
218 }
219 
220 TEST_F(EmbedderTest, IsolateServiceIdSent) {
221  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
223 
224  fml::Thread thread;
226  std::string isolate_message;
227 
228  thread.GetTaskRunner()->PostTask([&]() {
229  EmbedderConfigBuilder builder(context);
230  builder.SetSoftwareRendererConfig();
231  builder.SetDartEntrypoint("main");
233  [&](const FlutterPlatformMessage* message) {
234  if (strcmp(message->channel, "flutter/isolate") == 0) {
235  isolate_message = {reinterpret_cast<const char*>(message->message),
236  message->message_size};
237  latch.Signal();
238  }
239  });
240  engine = builder.LaunchEngine();
241  ASSERT_TRUE(engine.is_valid());
242  });
243 
244  // Wait for the isolate ID message and check its format.
245  latch.Wait();
246  ASSERT_EQ(isolate_message.find("isolates/"), 0ul);
247 
248  // Since the engine was started on its own thread, it must be killed there as
249  // well.
250  fml::AutoResetWaitableEvent kill_latch;
251  thread.GetTaskRunner()->PostTask(
252  fml::MakeCopyable([&engine, &kill_latch]() mutable {
253  engine.reset();
254  kill_latch.Signal();
255  }));
256  kill_latch.Wait();
257 }
258 
259 //------------------------------------------------------------------------------
260 /// Creates a platform message response callbacks, does NOT send them, and
261 /// immediately collects the same.
262 ///
263 TEST_F(EmbedderTest, CanCreateAndCollectCallbacks) {
264  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
265  EmbedderConfigBuilder builder(context);
266  builder.SetSoftwareRendererConfig();
267  builder.SetDartEntrypoint("platform_messages_response");
268  context.AddNativeCallback(
269  "SignalNativeTest",
270  CREATE_NATIVE_ENTRY([](Dart_NativeArguments args) {}));
271 
272  auto engine = builder.LaunchEngine();
273  ASSERT_TRUE(engine.is_valid());
274 
275  FlutterPlatformMessageResponseHandle* response_handle = nullptr;
276  auto callback = [](const uint8_t* data, size_t size,
277  void* user_data) -> void {};
279  engine.get(), callback, nullptr, &response_handle);
280  ASSERT_EQ(result, kSuccess);
281  ASSERT_NE(response_handle, nullptr);
282 
284  response_handle);
285  ASSERT_EQ(result, kSuccess);
286 }
287 
288 //------------------------------------------------------------------------------
289 /// Sends platform messages to Dart code than simply echoes the contents of the
290 /// message back to the embedder. The embedder registers a native callback to
291 /// intercept that message.
292 ///
293 TEST_F(EmbedderTest, PlatformMessagesCanReceiveResponse) {
294  struct Captures {
296  std::thread::id thread_id;
297  };
298  Captures captures;
299 
300  CreateNewThread()->PostTask([&]() {
301  captures.thread_id = std::this_thread::get_id();
302  auto& context =
303  GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
304  EmbedderConfigBuilder builder(context);
305  builder.SetSoftwareRendererConfig();
306  builder.SetDartEntrypoint("platform_messages_response");
307 
309  context.AddNativeCallback(
310  "SignalNativeTest",
312  [&ready](Dart_NativeArguments args) { ready.Signal(); }));
313 
314  auto engine = builder.LaunchEngine();
315  ASSERT_TRUE(engine.is_valid());
316 
317  static std::string kMessageData = "Hello from embedder.";
318 
319  FlutterPlatformMessageResponseHandle* response_handle = nullptr;
320  auto callback = [](const uint8_t* data, size_t size,
321  void* user_data) -> void {
322  ASSERT_EQ(size, kMessageData.size());
323  ASSERT_EQ(strncmp(reinterpret_cast<const char*>(kMessageData.data()),
324  reinterpret_cast<const char*>(data), size),
325  0);
326  auto captures = reinterpret_cast<Captures*>(user_data);
327  ASSERT_EQ(captures->thread_id, std::this_thread::get_id());
328  captures->latch.Signal();
329  };
331  engine.get(), callback, &captures, &response_handle);
332  ASSERT_EQ(result, kSuccess);
333 
334  FlutterPlatformMessage message = {};
335  message.struct_size = sizeof(FlutterPlatformMessage);
336  message.channel = "test_channel";
337  message.message = reinterpret_cast<const uint8_t*>(kMessageData.data());
338  message.message_size = kMessageData.size();
339  message.response_handle = response_handle;
340 
341  ready.Wait();
343  ASSERT_EQ(result, kSuccess);
344 
346  response_handle);
347  ASSERT_EQ(result, kSuccess);
348  });
349 
350  captures.latch.Wait();
351 }
352 
353 //------------------------------------------------------------------------------
354 /// Tests that a platform message can be sent with no response handle. Instead
355 /// of the platform message integrity checked via a response handle, a native
356 /// callback with the response is invoked to assert integrity.
357 ///
358 TEST_F(EmbedderTest, PlatformMessagesCanBeSentWithoutResponseHandles) {
359  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
360  EmbedderConfigBuilder builder(context);
361  builder.SetSoftwareRendererConfig();
362  builder.SetDartEntrypoint("platform_messages_no_response");
363 
364  const std::string message_data = "Hello but don't call me back.";
365 
366  fml::AutoResetWaitableEvent ready, message;
367  context.AddNativeCallback(
368  "SignalNativeTest",
370  [&ready](Dart_NativeArguments args) { ready.Signal(); }));
371  context.AddNativeCallback(
372  "SignalNativeMessage",
374  ([&message, &message_data](Dart_NativeArguments args) {
375  auto received_message = tonic::DartConverter<std::string>::FromDart(
376  Dart_GetNativeArgument(args, 0));
377  ASSERT_EQ(received_message, message_data);
378  message.Signal();
379  })));
380 
381  auto engine = builder.LaunchEngine();
382 
383  ASSERT_TRUE(engine.is_valid());
384  ready.Wait();
385 
386  FlutterPlatformMessage platform_message = {};
387  platform_message.struct_size = sizeof(FlutterPlatformMessage);
388  platform_message.channel = "test_channel";
389  platform_message.message =
390  reinterpret_cast<const uint8_t*>(message_data.data());
391  platform_message.message_size = message_data.size();
392  platform_message.response_handle = nullptr; // No response needed.
393 
394  auto result =
395  FlutterEngineSendPlatformMessage(engine.get(), &platform_message);
396  ASSERT_EQ(result, kSuccess);
397  message.Wait();
398 }
399 
400 //------------------------------------------------------------------------------
401 /// Tests that a null platform message can be sent.
402 ///
403 TEST_F(EmbedderTest, NullPlatformMessagesCanBeSent) {
404  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
405  EmbedderConfigBuilder builder(context);
406  builder.SetSoftwareRendererConfig();
407  builder.SetDartEntrypoint("null_platform_messages");
408 
409  fml::AutoResetWaitableEvent ready, message;
410  context.AddNativeCallback(
411  "SignalNativeTest",
413  [&ready](Dart_NativeArguments args) { ready.Signal(); }));
414  context.AddNativeCallback(
415  "SignalNativeMessage",
416  CREATE_NATIVE_ENTRY(([&message](Dart_NativeArguments args) {
417  auto received_message = tonic::DartConverter<std::string>::FromDart(
418  Dart_GetNativeArgument(args, 0));
419  ASSERT_EQ("true", received_message);
420  message.Signal();
421  })));
422 
423  auto engine = builder.LaunchEngine();
424 
425  ASSERT_TRUE(engine.is_valid());
426  ready.Wait();
427 
428  FlutterPlatformMessage platform_message = {};
429  platform_message.struct_size = sizeof(FlutterPlatformMessage);
430  platform_message.channel = "test_channel";
431  platform_message.message = nullptr;
432  platform_message.message_size = 0;
433  platform_message.response_handle = nullptr; // No response needed.
434 
435  auto result =
436  FlutterEngineSendPlatformMessage(engine.get(), &platform_message);
437  ASSERT_EQ(result, kSuccess);
438  message.Wait();
439 }
440 
441 //------------------------------------------------------------------------------
442 /// Tests that a null platform message cannot be send if the message_size
443 /// isn't equals to 0.
444 ///
445 TEST_F(EmbedderTest, InvalidPlatformMessages) {
446  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
447  EmbedderConfigBuilder builder(context);
448  builder.SetSoftwareRendererConfig();
449  auto engine = builder.LaunchEngine();
450 
451  ASSERT_TRUE(engine.is_valid());
452 
453  FlutterPlatformMessage platform_message = {};
454  platform_message.struct_size = sizeof(FlutterPlatformMessage);
455  platform_message.channel = "test_channel";
456  platform_message.message = nullptr;
457  platform_message.message_size = 1;
458  platform_message.response_handle = nullptr; // No response needed.
459 
460  auto result =
461  FlutterEngineSendPlatformMessage(engine.get(), &platform_message);
462  ASSERT_EQ(result, kInvalidArguments);
463 }
464 
465 //------------------------------------------------------------------------------
466 /// Tests that setting a custom log callback works as expected and defaults to
467 /// using tag "flutter".
468 TEST_F(EmbedderTest, CanSetCustomLogMessageCallback) {
469  fml::AutoResetWaitableEvent callback_latch;
470  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
471  EmbedderConfigBuilder builder(context);
472  builder.SetDartEntrypoint("custom_logger");
473  builder.SetSoftwareRendererConfig();
474  context.SetLogMessageCallback(
475  [&callback_latch](const char* tag, const char* message) {
476  EXPECT_EQ(std::string(tag), "flutter");
477  EXPECT_EQ(std::string(message), "hello world");
478  callback_latch.Signal();
479  });
480  auto engine = builder.LaunchEngine();
481  ASSERT_TRUE(engine.is_valid());
482  callback_latch.Wait();
483 }
484 
485 //------------------------------------------------------------------------------
486 /// Tests that setting a custom log tag works.
487 TEST_F(EmbedderTest, CanSetCustomLogTag) {
488  fml::AutoResetWaitableEvent callback_latch;
489  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
490  EmbedderConfigBuilder builder(context);
491  builder.SetDartEntrypoint("custom_logger");
492  builder.SetSoftwareRendererConfig();
493  builder.SetLogTag("butterfly");
494  context.SetLogMessageCallback(
495  [&callback_latch](const char* tag, const char* message) {
496  EXPECT_EQ(std::string(tag), "butterfly");
497  EXPECT_EQ(std::string(message), "hello world");
498  callback_latch.Signal();
499  });
500  auto engine = builder.LaunchEngine();
501  ASSERT_TRUE(engine.is_valid());
502  callback_latch.Wait();
503 }
504 
505 //------------------------------------------------------------------------------
506 /// Asserts behavior of FlutterProjectArgs::shutdown_dart_vm_when_done (which is
507 /// set to true by default in these unit-tests).
508 ///
509 TEST_F(EmbedderTest, VMShutsDownWhenNoEnginesInProcess) {
510  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
511  EmbedderConfigBuilder builder(context);
512  builder.SetSoftwareRendererConfig();
513  const auto launch_count = DartVM::GetVMLaunchCount();
514 
515  {
516  auto engine = builder.LaunchEngine();
517  ASSERT_EQ(launch_count + 1u, DartVM::GetVMLaunchCount());
518  }
519 
520  {
521  auto engine = builder.LaunchEngine();
522  ASSERT_EQ(launch_count + 2u, DartVM::GetVMLaunchCount());
523  }
524 }
525 
526 //------------------------------------------------------------------------------
527 ///
528 TEST_F(EmbedderTest, DartEntrypointArgs) {
529  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
530  EmbedderConfigBuilder builder(context);
531  builder.SetSoftwareRendererConfig();
532  builder.AddDartEntrypointArgument("foo");
533  builder.AddDartEntrypointArgument("bar");
534  builder.SetDartEntrypoint("dart_entrypoint_args");
535  fml::AutoResetWaitableEvent callback_latch;
536  std::vector<std::string> callback_args;
537  auto nativeArgumentsCallback = [&callback_args,
538  &callback_latch](Dart_NativeArguments args) {
539  Dart_Handle exception = nullptr;
540  callback_args =
542  args, 0, exception);
543  callback_latch.Signal();
544  };
545  context.AddNativeCallback("NativeArgumentsCallback",
546  CREATE_NATIVE_ENTRY(nativeArgumentsCallback));
547  auto engine = builder.LaunchEngine();
548  callback_latch.Wait();
549  ASSERT_EQ(callback_args[0], "foo");
550  ASSERT_EQ(callback_args[1], "bar");
551 }
552 
553 //------------------------------------------------------------------------------
554 /// These snapshots may be materialized from symbols and the size field may not
555 /// be relevant. Since this information is redundant, engine launch should not
556 /// be gated on a non-zero buffer size.
557 ///
558 TEST_F(EmbedderTest, VMAndIsolateSnapshotSizesAreRedundantInAOTMode) {
560  GTEST_SKIP();
561  return;
562  }
563  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
564  EmbedderConfigBuilder builder(context);
565  builder.SetSoftwareRendererConfig();
566 
567  // The fixture sets this up correctly. Intentionally mess up the args.
572 
573  auto engine = builder.LaunchEngine();
574  ASSERT_TRUE(engine.is_valid());
575 }
576 
577 //------------------------------------------------------------------------------
578 /// Test the layer structure and pixels rendered when using a custom software
579 /// compositor.
580 ///
582  CompositorMustBeAbleToRenderKnownSceneWithSoftwareCompositor) {
583  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
584 
585  EmbedderConfigBuilder builder(context);
586  builder.SetSoftwareRendererConfig(SkISize::Make(800, 600));
587  builder.SetCompositor();
588  builder.SetDartEntrypoint("can_composite_platform_views_with_known_scene");
589 
590  builder.SetRenderTargetType(
592 
593  fml::CountDownLatch latch(5);
594 
595  auto scene_image = context.GetNextSceneImage();
596 
597  context.GetCompositor().SetNextPresentCallback(
598  [&](const FlutterLayer** layers, size_t layers_count) {
599  ASSERT_EQ(layers_count, 5u);
600 
601  // Layer Root
602  {
603  FlutterBackingStore backing_store = *layers[0]->backing_store;
604  backing_store.type = kFlutterBackingStoreTypeSoftware;
605  backing_store.did_update = true;
606  backing_store.software.height = 600;
607 
608  FlutterLayer layer = {};
609  layer.struct_size = sizeof(layer);
611  layer.backing_store = &backing_store;
612  layer.size = FlutterSizeMake(800.0, 600.0);
613  layer.offset = FlutterPointMake(0.0, 0.0);
614 
615  ASSERT_EQ(*layers[0], layer);
616  }
617 
618  // Layer 1
619  {
621  platform_view.struct_size = sizeof(platform_view);
622  platform_view.identifier = 1;
623 
624  FlutterLayer layer = {};
625  layer.struct_size = sizeof(layer);
627  layer.platform_view = &platform_view;
628  layer.size = FlutterSizeMake(50.0, 150.0);
629  layer.offset = FlutterPointMake(20.0, 20.0);
630 
631  ASSERT_EQ(*layers[1], layer);
632  }
633 
634  // Layer 2
635  {
636  FlutterBackingStore backing_store = *layers[2]->backing_store;
637  backing_store.type = kFlutterBackingStoreTypeSoftware;
638  backing_store.did_update = true;
639  backing_store.software.height = 600;
640 
641  FlutterLayer layer = {};
642  layer.struct_size = sizeof(layer);
644  layer.backing_store = &backing_store;
645  layer.size = FlutterSizeMake(800.0, 600.0);
646  layer.offset = FlutterPointMake(0.0, 0.0);
647 
648  ASSERT_EQ(*layers[2], layer);
649  }
650 
651  // Layer 3
652  {
654  platform_view.struct_size = sizeof(platform_view);
655  platform_view.identifier = 2;
656 
657  FlutterLayer layer = {};
658  layer.struct_size = sizeof(layer);
660  layer.platform_view = &platform_view;
661  layer.size = FlutterSizeMake(50.0, 150.0);
662  layer.offset = FlutterPointMake(40.0, 40.0);
663 
664  ASSERT_EQ(*layers[3], layer);
665  }
666 
667  // Layer 4
668  {
669  FlutterBackingStore backing_store = *layers[4]->backing_store;
670  backing_store.type = kFlutterBackingStoreTypeSoftware;
671  backing_store.did_update = true;
672  backing_store.software.height = 600;
673 
674  FlutterLayer layer = {};
675  layer.struct_size = sizeof(layer);
677  layer.backing_store = &backing_store;
678  layer.size = FlutterSizeMake(800.0, 600.0);
679  layer.offset = FlutterPointMake(0.0, 0.0);
680 
681  ASSERT_EQ(*layers[4], layer);
682  }
683 
684  latch.CountDown();
685  });
686 
687  context.GetCompositor().SetPlatformViewRendererCallback(
688  [&](const FlutterLayer& layer, GrDirectContext*
689  /* don't use because software compositor */) -> sk_sp<SkImage> {
690  auto surface = CreateRenderSurface(
691  layer, nullptr /* null because software compositor */);
692  auto canvas = surface->getCanvas();
693  FML_CHECK(canvas != nullptr);
694 
695  switch (layer.platform_view->identifier) {
696  case 1: {
697  SkPaint paint;
698  // See dart test for total order.
699  paint.setColor(SK_ColorGREEN);
700  paint.setAlpha(127);
701  const auto& rect =
702  SkRect::MakeWH(layer.size.width, layer.size.height);
703  canvas->drawRect(rect, paint);
704  latch.CountDown();
705  } break;
706  case 2: {
707  SkPaint paint;
708  // See dart test for total order.
709  paint.setColor(SK_ColorMAGENTA);
710  paint.setAlpha(127);
711  const auto& rect =
712  SkRect::MakeWH(layer.size.width, layer.size.height);
713  canvas->drawRect(rect, paint);
714  latch.CountDown();
715  } break;
716  default:
717  // Asked to render an unknown platform view.
718  FML_CHECK(false)
719  << "Test was asked to composite an unknown platform view.";
720  }
721 
722  return surface->makeImageSnapshot();
723  });
724 
725  context.AddNativeCallback(
726  "SignalNativeTest",
728  [&latch](Dart_NativeArguments args) { latch.CountDown(); }));
729 
730  auto engine = builder.LaunchEngine();
731 
732  // Send a window metrics events so frames may be scheduled.
733  FlutterWindowMetricsEvent event = {};
734  event.struct_size = sizeof(event);
735  event.width = 800;
736  event.height = 600;
737  event.pixel_ratio = 1.0;
738  event.physical_view_inset_top = 0.0;
739  event.physical_view_inset_right = 0.0;
740  event.physical_view_inset_bottom = 0.0;
741  event.physical_view_inset_left = 0.0;
743  kSuccess);
744  ASSERT_TRUE(engine.is_valid());
745 
746  latch.Wait();
747 
748  ASSERT_TRUE(ImageMatchesFixture("compositor_software.png", scene_image));
749 
750  // There should no present calls on the root surface.
751  ASSERT_EQ(context.GetSurfacePresentCount(), 0u);
752 }
753 
754 //------------------------------------------------------------------------------
755 /// Test that an engine can be initialized but not run.
756 ///
757 TEST_F(EmbedderTest, CanCreateInitializedEngine) {
758  EmbedderConfigBuilder builder(
759  GetEmbedderContext(EmbedderTestContextType::kSoftwareContext));
760  builder.SetSoftwareRendererConfig();
761  auto engine = builder.InitializeEngine();
762  ASSERT_TRUE(engine.is_valid());
763  engine.reset();
764 }
765 
766 //------------------------------------------------------------------------------
767 /// Test that an initialized engine can be run exactly once.
768 ///
769 TEST_F(EmbedderTest, CanRunInitializedEngine) {
770  EmbedderConfigBuilder builder(
771  GetEmbedderContext(EmbedderTestContextType::kSoftwareContext));
772  builder.SetSoftwareRendererConfig();
773  auto engine = builder.InitializeEngine();
774  ASSERT_TRUE(engine.is_valid());
775  ASSERT_EQ(FlutterEngineRunInitialized(engine.get()), kSuccess);
776  // Cannot re-run an already running engine.
778  engine.reset();
779 }
780 
781 //------------------------------------------------------------------------------
782 /// Test that an engine can be deinitialized.
783 ///
784 TEST_F(EmbedderTest, CaDeinitializeAnEngine) {
785  EmbedderConfigBuilder builder(
786  GetEmbedderContext(EmbedderTestContextType::kSoftwareContext));
787  builder.SetSoftwareRendererConfig();
788  auto engine = builder.InitializeEngine();
789  ASSERT_TRUE(engine.is_valid());
790  ASSERT_EQ(FlutterEngineRunInitialized(engine.get()), kSuccess);
791  // Cannot re-run an already running engine.
793  ASSERT_EQ(FlutterEngineDeinitialize(engine.get()), kSuccess);
794  // It is ok to deinitialize an engine multiple times.
795  ASSERT_EQ(FlutterEngineDeinitialize(engine.get()), kSuccess);
796 
797  // Sending events to a deinitialized engine fails.
798  FlutterWindowMetricsEvent event = {};
799  event.struct_size = sizeof(event);
800  event.width = 800;
801  event.height = 600;
802  event.pixel_ratio = 1.0;
803  event.physical_view_inset_top = 0.0;
804  event.physical_view_inset_right = 0.0;
805  event.physical_view_inset_bottom = 0.0;
806  event.physical_view_inset_left = 0.0;
809  engine.reset();
810 }
811 
812 TEST_F(EmbedderTest, CanUpdateLocales) {
813  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
814  EmbedderConfigBuilder builder(context);
815  builder.SetSoftwareRendererConfig();
816  builder.SetDartEntrypoint("can_receive_locale_updates");
818  context.AddNativeCallback(
819  "SignalNativeTest",
821  [&latch](Dart_NativeArguments args) { latch.Signal(); }));
822 
823  fml::AutoResetWaitableEvent check_latch;
824  context.AddNativeCallback(
825  "SignalNativeCount",
826  CREATE_NATIVE_ENTRY([&check_latch](Dart_NativeArguments args) {
828  Dart_GetNativeArgument(args, 0)),
829  2);
830  check_latch.Signal();
831  }));
832 
833  auto engine = builder.LaunchEngine();
834  ASSERT_TRUE(engine.is_valid());
835 
836  // Wait for the application to attach the listener.
837  latch.Wait();
838 
839  FlutterLocale locale1 = {};
840  locale1.struct_size = sizeof(locale1);
841  locale1.language_code = ""; // invalid
842  locale1.country_code = "US";
843  locale1.script_code = "";
844  locale1.variant_code = nullptr;
845 
846  FlutterLocale locale2 = {};
847  locale2.struct_size = sizeof(locale2);
848  locale2.language_code = "zh";
849  locale2.country_code = "CN";
850  locale2.script_code = "Hans";
851  locale2.variant_code = nullptr;
852 
853  std::vector<const FlutterLocale*> locales;
854  locales.push_back(&locale1);
855  locales.push_back(&locale2);
856 
857  ASSERT_EQ(
858  FlutterEngineUpdateLocales(engine.get(), locales.data(), locales.size()),
860 
861  // Fix the invalid code.
862  locale1.language_code = "en";
863 
864  ASSERT_EQ(
865  FlutterEngineUpdateLocales(engine.get(), locales.data(), locales.size()),
866  kSuccess);
867 
868  check_latch.Wait();
869 }
870 
871 TEST_F(EmbedderTest, LocalizationCallbacksCalled) {
872  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
874  context.AddIsolateCreateCallback([&latch]() { latch.Signal(); });
875  EmbedderConfigBuilder builder(context);
876  builder.SetSoftwareRendererConfig();
877  auto engine = builder.LaunchEngine();
878  ASSERT_TRUE(engine.is_valid());
879  // Wait for the root isolate to launch.
880  latch.Wait();
881 
882  flutter::Shell& shell = ToEmbedderEngine(engine.get())->GetShell();
883  std::vector<std::string> supported_locales;
884  supported_locales.push_back("es");
885  supported_locales.push_back("MX");
886  supported_locales.push_back("");
887  auto result = shell.GetPlatformView()->ComputePlatformResolvedLocales(
888  supported_locales);
889 
890  ASSERT_EQ((*result).size(), supported_locales.size()); // 3
891  ASSERT_EQ((*result)[0], supported_locales[0]);
892  ASSERT_EQ((*result)[1], supported_locales[1]);
893  ASSERT_EQ((*result)[2], supported_locales[2]);
894 
895  engine.reset();
896 }
897 
898 TEST_F(EmbedderTest, CanQueryDartAOTMode) {
901 }
902 
903 TEST_F(EmbedderTest, VerifyB143464703WithSoftwareBackend) {
904  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
905 
906  EmbedderConfigBuilder builder(context);
907  builder.SetSoftwareRendererConfig(SkISize::Make(1024, 600));
908  builder.SetCompositor();
909  builder.SetDartEntrypoint("verify_b143464703");
910 
911  builder.SetRenderTargetType(
913 
914  fml::CountDownLatch latch(1);
915  context.GetCompositor().SetNextPresentCallback(
916  [&](const FlutterLayer** layers, size_t layers_count) {
917  ASSERT_EQ(layers_count, 3u);
918 
919  // Layer 0 (Root)
920  {
921  FlutterBackingStore backing_store = *layers[0]->backing_store;
922  backing_store.type = kFlutterBackingStoreTypeSoftware;
923  backing_store.did_update = true;
924 
925  FlutterLayer layer = {};
926  layer.struct_size = sizeof(layer);
928  layer.backing_store = &backing_store;
929  layer.size = FlutterSizeMake(1024.0, 600.0);
930  layer.offset = FlutterPointMake(0.0, 0.0);
931 
932  ASSERT_EQ(*layers[0], layer);
933  }
934 
935  // Layer 1
936  {
938  platform_view.struct_size = sizeof(platform_view);
939  platform_view.identifier = 42;
940 
941  FlutterLayer layer = {};
942  layer.struct_size = sizeof(layer);
944  layer.platform_view = &platform_view;
945  layer.size = FlutterSizeMake(1024.0, 540.0);
946  layer.offset = FlutterPointMake(135.0, 60.0);
947 
948  ASSERT_EQ(*layers[1], layer);
949  }
950 
951  // Layer 2
952  {
953  FlutterBackingStore backing_store = *layers[2]->backing_store;
954  backing_store.type = kFlutterBackingStoreTypeSoftware;
955  backing_store.did_update = true;
956 
957  FlutterLayer layer = {};
958  layer.struct_size = sizeof(layer);
960  layer.backing_store = &backing_store;
961  layer.size = FlutterSizeMake(1024.0, 600.0);
962  layer.offset = FlutterPointMake(0.0, 0.0);
963 
964  ASSERT_EQ(*layers[2], layer);
965  }
966 
967  latch.CountDown();
968  });
969 
970  context.GetCompositor().SetPlatformViewRendererCallback(
971  [](const FlutterLayer& layer,
972  GrDirectContext* context) -> sk_sp<SkImage> {
973  auto surface = CreateRenderSurface(
974  layer, nullptr /* null because software compositor */);
975  auto canvas = surface->getCanvas();
976  FML_CHECK(canvas != nullptr);
977 
978  switch (layer.platform_view->identifier) {
979  case 42: {
980  SkPaint paint;
981  // See dart test for total order.
982  paint.setColor(SK_ColorGREEN);
983  paint.setAlpha(127);
984  const auto& rect =
985  SkRect::MakeWH(layer.size.width, layer.size.height);
986  canvas->drawRect(rect, paint);
987  } break;
988  default:
989  // Asked to render an unknown platform view.
990  FML_CHECK(false)
991  << "Test was asked to composite an unknown platform view.";
992  }
993 
994  return surface->makeImageSnapshot();
995  });
996 
997  auto engine = builder.LaunchEngine();
998 
999  // Send a window metrics events so frames may be scheduled.
1000  FlutterWindowMetricsEvent event = {};
1001  event.struct_size = sizeof(event);
1002  event.width = 1024;
1003  event.height = 600;
1004  event.pixel_ratio = 1.0;
1005  event.physical_view_inset_top = 0.0;
1006  event.physical_view_inset_right = 0.0;
1007  event.physical_view_inset_bottom = 0.0;
1008  event.physical_view_inset_left = 0.0;
1010  kSuccess);
1011  ASSERT_TRUE(engine.is_valid());
1012 
1013  auto rendered_scene = context.GetNextSceneImage();
1014 
1015  latch.Wait();
1016 
1017  // TODO(https://github.com/flutter/flutter/issues/53784): enable this on all
1018  // platforms.
1019 #if !defined(OS_LINUX)
1020  GTEST_SKIP() << "Skipping golden tests on non-Linux OSes";
1021 #endif // OS_LINUX
1022  ASSERT_TRUE(
1023  ImageMatchesFixture("verifyb143464703_soft_noxform.png", rendered_scene));
1024 }
1025 
1026 TEST_F(EmbedderTest, CanSendLowMemoryNotification) {
1027  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
1028 
1029  EmbedderConfigBuilder builder(context);
1030  builder.SetSoftwareRendererConfig();
1031 
1032  auto engine = builder.LaunchEngine();
1033 
1034  ASSERT_TRUE(engine.is_valid());
1035 
1036  // TODO(chinmaygarde): The shell ought to have a mechanism for notification
1037  // dispatch that engine subsystems can register handlers to. This would allow
1038  // the raster cache and the secondary context caches to respond to
1039  // notifications. Once that is in place, this test can be updated to actually
1040  // ensure that the dispatched message is visible to engine subsystems.
1042 }
1043 
1044 TEST_F(EmbedderTest, CanPostTaskToAllNativeThreads) {
1046  size_t worker_count = 0;
1047  fml::AutoResetWaitableEvent sync_latch;
1048 
1049  // One of the threads that the callback will be posted to is the platform
1050  // thread. So we cannot wait for assertions to complete on the platform
1051  // thread. Create a new thread to manage the engine instance and wait for
1052  // assertions on the test thread.
1053  auto platform_task_runner = CreateNewThread("platform_thread");
1054 
1055  platform_task_runner->PostTask([&]() {
1056  auto& context =
1057  GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
1058 
1059  EmbedderConfigBuilder builder(context);
1060  builder.SetSoftwareRendererConfig();
1061 
1062  engine = builder.LaunchEngine();
1063 
1064  ASSERT_TRUE(engine.is_valid());
1065 
1066  worker_count = ToEmbedderEngine(engine.get())
1067  ->GetShell()
1068  .GetDartVM()
1069  ->GetConcurrentMessageLoop()
1070  ->GetWorkerCount();
1071 
1072  sync_latch.Signal();
1073  });
1074 
1075  sync_latch.Wait();
1076 
1077  const auto engine_threads_count = worker_count + 4u;
1078 
1079  struct Captures {
1080  // Waits the adequate number of callbacks to fire.
1081  fml::CountDownLatch latch;
1082 
1083  // This class will be accessed from multiple threads concurrently to track
1084  // thread specific information that is later checked. All updates to fields
1085  // in this struct must be made with this mutex acquired.
1086 
1087  std::mutex captures_mutex;
1088  // Ensures that the expect number of distinct threads were serviced.
1089  std::set<std::thread::id> thread_ids;
1090 
1091  size_t platform_threads_count = 0;
1092  size_t render_threads_count = 0;
1093  size_t ui_threads_count = 0;
1094  size_t worker_threads_count = 0;
1095 
1096  Captures(size_t count) : latch(count) {}
1097  };
1098 
1099  Captures captures(engine_threads_count);
1100 
1101  platform_task_runner->PostTask([&]() {
1103  engine.get(),
1104  [](FlutterNativeThreadType type, void* baton) {
1105  auto captures = reinterpret_cast<Captures*>(baton);
1106  {
1107  std::scoped_lock lock(captures->captures_mutex);
1108  switch (type) {
1110  captures->render_threads_count++;
1111  break;
1113  captures->worker_threads_count++;
1114  break;
1116  captures->ui_threads_count++;
1117  break;
1119  captures->platform_threads_count++;
1120  break;
1121  }
1122  captures->thread_ids.insert(std::this_thread::get_id());
1123  }
1124  captures->latch.CountDown();
1125  },
1126  &captures),
1127  kSuccess);
1128  });
1129 
1130  captures.latch.Wait();
1131  ASSERT_EQ(captures.thread_ids.size(), engine_threads_count);
1132  ASSERT_EQ(captures.platform_threads_count, 1u);
1133  ASSERT_EQ(captures.render_threads_count, 1u);
1134  ASSERT_EQ(captures.ui_threads_count, 1u);
1135  ASSERT_EQ(captures.worker_threads_count, worker_count + 1u /* for IO */);
1136 
1137  platform_task_runner->PostTask([&]() {
1138  engine.reset();
1139  sync_latch.Signal();
1140  });
1141  sync_latch.Wait();
1142 
1143  // The engine should have already been destroyed on the platform task runner.
1144  ASSERT_FALSE(engine.is_valid());
1145 }
1146 
1147 TEST_F(EmbedderTest, InvalidAOTDataSourcesMustReturnError) {
1149  GTEST_SKIP();
1150  return;
1151  }
1152  FlutterEngineAOTDataSource data_in = {};
1153  FlutterEngineAOTData data_out = nullptr;
1154 
1155  // Null source specified.
1156  ASSERT_EQ(FlutterEngineCreateAOTData(nullptr, &data_out), kInvalidArguments);
1157  ASSERT_EQ(data_out, nullptr);
1158 
1159  // Null data_out specified.
1160  ASSERT_EQ(FlutterEngineCreateAOTData(&data_in, nullptr), kInvalidArguments);
1161 
1162  // Invalid FlutterEngineAOTDataSourceType type specified.
1163  data_in.type = FlutterEngineAOTDataSourceType(-1);
1164  ASSERT_EQ(FlutterEngineCreateAOTData(&data_in, &data_out), kInvalidArguments);
1165  ASSERT_EQ(data_out, nullptr);
1166 
1167  // Invalid ELF path specified.
1169  data_in.elf_path = nullptr;
1170  ASSERT_EQ(FlutterEngineCreateAOTData(&data_in, &data_out), kInvalidArguments);
1171  ASSERT_EQ(data_in.type, kFlutterEngineAOTDataSourceTypeElfPath);
1172  ASSERT_EQ(data_in.elf_path, nullptr);
1173  ASSERT_EQ(data_out, nullptr);
1174 
1175  // Invalid ELF path specified.
1176  data_in.elf_path = "";
1177  ASSERT_EQ(FlutterEngineCreateAOTData(&data_in, &data_out), kInvalidArguments);
1178  ASSERT_EQ(data_in.type, kFlutterEngineAOTDataSourceTypeElfPath);
1179  ASSERT_EQ(data_in.elf_path, "");
1180  ASSERT_EQ(data_out, nullptr);
1181 
1182  // Could not find VM snapshot data.
1183  data_in.elf_path = "/bin/true";
1184  ASSERT_EQ(FlutterEngineCreateAOTData(&data_in, &data_out), kInvalidArguments);
1185  ASSERT_EQ(data_in.type, kFlutterEngineAOTDataSourceTypeElfPath);
1186  ASSERT_EQ(data_in.elf_path, "/bin/true");
1187  ASSERT_EQ(data_out, nullptr);
1188 }
1189 
1190 TEST_F(EmbedderTest, MustNotRunWithMultipleAOTSources) {
1192  GTEST_SKIP();
1193  return;
1194  }
1195  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
1196 
1197  EmbedderConfigBuilder builder(
1198  context,
1200 
1201  builder.SetSoftwareRendererConfig();
1202 
1203  auto engine = builder.LaunchEngine();
1204  ASSERT_FALSE(engine.is_valid());
1205 }
1206 
1207 TEST_F(EmbedderTest, CanCreateAndCollectAValidElfSource) {
1209  GTEST_SKIP();
1210  return;
1211  }
1212  FlutterEngineAOTDataSource data_in = {};
1213  FlutterEngineAOTData data_out = nullptr;
1214 
1215  // Collecting a null object should be allowed
1216  ASSERT_EQ(FlutterEngineCollectAOTData(data_out), kSuccess);
1217 
1218  const auto elf_path =
1220 
1222  data_in.elf_path = elf_path.c_str();
1223 
1224  ASSERT_EQ(FlutterEngineCreateAOTData(&data_in, &data_out), kSuccess);
1225  ASSERT_EQ(data_in.type, kFlutterEngineAOTDataSourceTypeElfPath);
1226  ASSERT_EQ(data_in.elf_path, elf_path.c_str());
1227  ASSERT_NE(data_out, nullptr);
1228 
1229  ASSERT_EQ(FlutterEngineCollectAOTData(data_out), kSuccess);
1230 }
1231 
1232 TEST_F(EmbedderTest, CanLaunchAndShutdownWithAValidElfSource) {
1234  GTEST_SKIP();
1235  return;
1236  }
1237  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
1238 
1240  context.AddIsolateCreateCallback([&latch]() { latch.Signal(); });
1241 
1242  EmbedderConfigBuilder builder(
1243  context,
1245 
1246  builder.SetSoftwareRendererConfig();
1247 
1248  auto engine = builder.LaunchEngine();
1249  ASSERT_TRUE(engine.is_valid());
1250 
1251  // Wait for the root isolate to launch.
1252  latch.Wait();
1253  engine.reset();
1254 }
1255 
1256 TEST_F(EmbedderTest, InvalidFlutterWindowMetricsEvent) {
1257  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
1258  EmbedderConfigBuilder builder(context);
1259  builder.SetSoftwareRendererConfig();
1260  auto engine = builder.LaunchEngine();
1261 
1262  ASSERT_TRUE(engine.is_valid());
1263 
1264  FlutterWindowMetricsEvent event = {};
1265  event.struct_size = sizeof(event);
1266  event.width = 800;
1267  event.height = 600;
1268  event.pixel_ratio = 0.0;
1269  event.physical_view_inset_top = 0.0;
1270  event.physical_view_inset_right = 0.0;
1271  event.physical_view_inset_bottom = 0.0;
1272  event.physical_view_inset_left = 0.0;
1273 
1274  // Pixel ratio must be positive.
1277 
1278  event.pixel_ratio = 1.0;
1279  event.physical_view_inset_top = -1.0;
1280  event.physical_view_inset_right = -1.0;
1281  event.physical_view_inset_bottom = -1.0;
1282  event.physical_view_inset_left = -1.0;
1283 
1284  // Physical view insets must be non-negative.
1287 
1288  event.physical_view_inset_top = 700;
1289  event.physical_view_inset_right = 900;
1290  event.physical_view_inset_bottom = 700;
1291  event.physical_view_inset_left = 900;
1292 
1293  // Top/bottom insets cannot be greater than height.
1294  // Left/right insets cannot be greater than width.
1297 }
1298 
1299 //------------------------------------------------------------------------------
1300 // Key Data
1301 //------------------------------------------------------------------------------
1302 
1303 typedef struct {
1304  std::shared_ptr<fml::AutoResetWaitableEvent> latch;
1305  bool returned;
1307 
1308 // Convert `kind` in integer form to its enum form.
1309 //
1310 // It performs a revesed mapping from `_serializeKeyEventType`
1311 // in shell/platform/embedder/fixtures/main.dart.
1313  switch (kind) {
1314  case 1:
1315  return kFlutterKeyEventTypeUp;
1316  case 2:
1317  return kFlutterKeyEventTypeDown;
1318  case 3:
1320  default:
1321  FML_UNREACHABLE();
1322  return kFlutterKeyEventTypeUp;
1323  }
1324 }
1325 
1326 // Checks the equality of two `FlutterKeyEvent` by each of their members except
1327 // for `character`. The `character` must be checked separately.
1328 void ExpectKeyEventEq(const FlutterKeyEvent& subject,
1329  const FlutterKeyEvent& baseline) {
1330  EXPECT_EQ(subject.timestamp, baseline.timestamp);
1331  EXPECT_EQ(subject.type, baseline.type);
1332  EXPECT_EQ(subject.physical, baseline.physical);
1333  EXPECT_EQ(subject.logical, baseline.logical);
1334  EXPECT_EQ(subject.synthesized, baseline.synthesized);
1335 }
1336 
1337 TEST_F(EmbedderTest, KeyDataIsCorrectlySerialized) {
1338  auto message_latch = std::make_shared<fml::AutoResetWaitableEvent>();
1339  uint64_t echoed_char;
1340  FlutterKeyEvent echoed_event;
1341 
1342  auto native_echo_event = [&](Dart_NativeArguments args) {
1343  echoed_event.type =
1345  Dart_GetNativeArgument(args, 0)));
1347  Dart_GetNativeArgument(args, 1));
1349  Dart_GetNativeArgument(args, 2));
1351  Dart_GetNativeArgument(args, 3));
1353  Dart_GetNativeArgument(args, 4));
1354  echoed_event.synthesized =
1355  tonic::DartConverter<bool>::FromDart(Dart_GetNativeArgument(args, 5));
1356 
1357  message_latch->Signal();
1358  };
1359 
1360  auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
1361  EmbedderConfigBuilder builder(context);
1362  builder.SetSoftwareRendererConfig();
1363  builder.SetDartEntrypoint("key_data_echo");
1365  context.AddNativeCallback(
1366  "SignalNativeTest",
1368  [&ready](Dart_NativeArguments args) { ready.Signal(); }));
1369 
1370  context.AddNativeCallback("EchoKeyEvent",
1371  CREATE_NATIVE_ENTRY(native_echo_event));
1372 
1373  auto engine = builder.LaunchEngine();
1374  ASSERT_TRUE(engine.is_valid());
1375  ready.Wait();
1376 
1377  // A normal down event
1378  const FlutterKeyEvent down_event_upper_a{
1379  .struct_size = sizeof(FlutterKeyEvent),
1380  .timestamp = 1,
1382  .physical = 0x00070004,
1383  .logical = 0x00000000061,
1384  .character = "A",
1385  .synthesized = false,
1386  };
1388  engine.get(), &down_event_upper_a, [](bool handled, void* user_data) {},
1389  nullptr);
1390  message_latch->Wait();
1391 
1392  ExpectKeyEventEq(echoed_event, down_event_upper_a);
1393  EXPECT_EQ(echoed_char, 0x41llu);
1394 
1395  // A repeat event with multi-byte character
1396  const FlutterKeyEvent repeat_event_wide_char{
1397  .struct_size = sizeof(FlutterKeyEvent),
1398  .timestamp = 1000,
1400  .physical = 0x00070005,
1401  .logical = 0x00000000062,
1402  .character = "∆",
1403  .synthesized = false,
1404  };
1406  engine.get(), &repeat_event_wide_char,
1407  [](bool handled, void* user_data) {}, nullptr);
1408  message_latch->Wait();
1409 
1410  ExpectKeyEventEq(echoed_event, repeat_event_wide_char);
1411  EXPECT_EQ(echoed_char, 0x2206llu);
1412 
1413  // An up event with no character, synthesized
1414  const FlutterKeyEvent up_event{
1415  .struct_size = sizeof(FlutterKeyEvent),
1416  .timestamp = 1000000,
1418  .physical = 0x00070006,
1419  .logical = 0x00000000063,
1420  .character = nullptr,
1421  .synthesized = true,
1422  };
1424  engine.get(), &up_event, [](bool handled, void* user_data) {}, nullptr);
1425  message_latch->Wait();
1426 
1427  ExpectKeyEventEq(echoed_event, up_event);
1428  EXPECT_EQ(echoed_char, 0llu);
1429 }
1430 
1431 TEST_F(EmbedderTest, KeyDataResponseIsCorrectlyInvoked) {
1433  fml::AutoResetWaitableEvent sync_latch;
1435 
1436  // One of the threads that the key data callback will be posted to is the
1437  // platform thread. So we cannot wait for assertions to complete on the
1438  // platform thread. Create a new thread to manage the engine instance and wait
1439  // for assertions on the test thread.
1440  auto platform_task_runner = CreateNewThread("platform_thread");
1441 
1442  platform_task_runner->PostTask([&]() {
1443  auto& context =
1444  GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
1445  EmbedderConfigBuilder builder(context);
1446  builder.SetSoftwareRendererConfig();
1447  builder.SetDartEntrypoint("key_data_echo");
1448  context.AddNativeCallback(
1449  "SignalNativeTest",
1451  [&ready](Dart_NativeArguments args) { ready.Signal(); }));
1452  context.AddNativeCallback(
1453  "EchoKeyEvent", CREATE_NATIVE_ENTRY([](Dart_NativeArguments args) {}));
1454 
1455  engine = builder.LaunchEngine();
1456  ASSERT_TRUE(engine.is_valid());
1457 
1458  sync_latch.Signal();
1459  });
1460  sync_latch.Wait();
1461  ready.Wait();
1462 
1463  // Dispatch a single event
1464  FlutterKeyEvent event{
1465  .struct_size = sizeof(FlutterKeyEvent),
1466  .timestamp = 1000,
1468  .physical = 0x00070005,
1469  .logical = 0x00000000062,
1470  .character = nullptr,
1471  };
1472 
1473  KeyEventUserData user_data1{
1474  .latch = std::make_shared<fml::AutoResetWaitableEvent>(),
1475  };
1476  // Entrypoint `key_data_echo` returns `event.synthesized` as `handled`.
1477  event.synthesized = true;
1478  platform_task_runner->PostTask([&]() {
1480  engine.get(), &event,
1481  [](bool handled, void* untyped_user_data) {
1483  reinterpret_cast<KeyEventUserData*>(untyped_user_data);
1484  EXPECT_EQ(handled, true);
1485  user_data->latch->Signal();
1486  },
1487  &user_data1);
1488  });
1489  user_data1.latch->Wait();
1490  fml::AutoResetWaitableEvent shutdown_latch;
1491  platform_task_runner->PostTask([&]() {
1492  engine.reset();
1493  shutdown_latch.Signal();
1494  });
1495  shutdown_latch.Wait();
1496 }
1497 
1498 TEST_F(EmbedderTest, BackToBackKeyEventResponsesCorrectlyInvoked) {
1500  fml::AutoResetWaitableEvent sync_latch;
1502 
1503  // One of the threads that the callback will be posted to is the platform
1504  // thread. So we cannot wait for assertions to complete on the platform
1505  // thread. Create a new thread to manage the engine instance and wait for
1506  // assertions on the test thread.
1507  auto platform_task_runner = CreateNewThread("platform_thread");
1508 
1509  platform_task_runner->PostTask([&]() {
1510  auto& context =
1511  GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
1512 
1513  EmbedderConfigBuilder builder(context);
1514  builder.SetSoftwareRendererConfig();
1515  builder.SetDartEntrypoint("key_data_echo");
1516  context.AddNativeCallback(
1517  "SignalNativeTest",
1519  [&ready](Dart_NativeArguments args) { ready.Signal(); }));
1520 
1521  context.AddNativeCallback(
1522  "EchoKeyEvent", CREATE_NATIVE_ENTRY([](Dart_NativeArguments args) {}));
1523 
1524  engine = builder.LaunchEngine();
1525  ASSERT_TRUE(engine.is_valid());
1526 
1527  sync_latch.Signal();
1528  });
1529  sync_latch.Wait();
1530  ready.Wait();
1531 
1532  // Dispatch a single event
1533  FlutterKeyEvent event{
1534  .struct_size = sizeof(FlutterKeyEvent),
1535  .timestamp = 1000,
1537  .physical = 0x00070005,
1538  .logical = 0x00000000062,
1539  .character = nullptr,
1540  .synthesized = false,
1541  };
1542 
1543  // Dispatch two events back to back, using the same callback on different
1544  // user_data
1545  KeyEventUserData user_data2{
1546  .latch = std::make_shared<fml::AutoResetWaitableEvent>(),
1547  .returned = false,
1548  };
1549  KeyEventUserData user_data3{
1550  .latch = std::make_shared<fml::AutoResetWaitableEvent>(),
1551  .returned = false,
1552  };
1553  auto callback23 = [](bool handled, void* untyped_user_data) {
1555  reinterpret_cast<KeyEventUserData*>(untyped_user_data);
1556  EXPECT_EQ(handled, false);
1557  user_data->returned = true;
1558  user_data->latch->Signal();
1559  };
1560  platform_task_runner->PostTask([&]() {
1561  FlutterEngineSendKeyEvent(engine.get(), &event, callback23, &user_data2);
1562  FlutterEngineSendKeyEvent(engine.get(), &event, callback23, &user_data3);
1563  });
1564  user_data2.latch->Wait();
1565  user_data3.latch->Wait();
1566 
1567  EXPECT_TRUE(user_data2.returned);
1568  EXPECT_TRUE(user_data3.returned);
1569 
1570  fml::AutoResetWaitableEvent shutdown_latch;
1571  platform_task_runner->PostTask([&]() {
1572  engine.reset();
1573  shutdown_latch.Signal();
1574  });
1575  shutdown_latch.Wait();
1576 }
1577 
1578 } // namespace testing
1579 } // namespace flutter
size_t struct_size
This size of this struct. Must be sizeof(FlutterLocale).
Definition: embedder.h:1152
G_BEGIN_DECLS FlValue * args
KeyCallType type
Specified an software allocation for Flutter to render into using the CPU.
Definition: embedder.h:1048
const char * channel
Definition: embedder.h:758
FLUTTER_EXPORT FlutterEngineResult FlutterEngineDeinitialize(FLUTTER_API_SYMBOL(FlutterEngine) engine)
Stops running the Flutter engine instance. After this call, the embedder is also guaranteed that no m...
Definition: embedder.cc:1365
FlutterEngineResult FlutterPlatformMessageReleaseResponseHandle(FLUTTER_API_SYMBOL(FlutterEngine) engine, FlutterPlatformMessageResponseHandle *response)
Collects the handle created using FlutterPlatformMessageCreateResponseHandle.
Definition: embedder.cc:1722
static constexpr TimeDelta FromNanoseconds(int64_t nanos)
Definition: time_delta.h:40
FlutterEngineResult FlutterEngineRunTask(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterTask *task)
Inform the engine to run the specified task. This task has been given to the engine via the FlutterTa...
Definition: embedder.cc:1956
std::unique_ptr< flutter::PlatformViewIOS > platform_view
FlutterKeyEventType
Definition: embedder.h:677
FlutterEngineAOTDataSourceType
AOT data source type.
Definition: embedder.h:1319
const FlutterBackingStore * backing_store
Definition: embedder.h:1099
const FlutterPlatformMessageResponseHandle * response_handle
Definition: embedder.h:767
size_t vm_snapshot_instructions_size
Definition: embedder.h:1418
FlutterPlatformViewIdentifier identifier
Definition: embedder.h:1024
FlutterSize size
The size of the layer (in physical pixels).
Definition: embedder.h:1108
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
Definition: thread.cc:45
void reset(const T &value=Traits::InvalidValue())
Definition: unique_object.h:62
FlutterKeyEventType UnserializeKeyEventKind(uint64_t kind)
void * user_data
sk_sp< SkSurface > CreateRenderSurface(const FlutterLayer &layer, GrDirectContext *context)
FlutterSize FlutterSizeMake(double width, double height)
char32_t character
const char * variant_code
Definition: embedder.h:1171
GAsyncResult * result
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
void SetCompositor(bool avoid_backing_store_cache=false)
A task runner that we expect the embedder to provide but whose implementation is a real FML task runn...
#define FML_LOG(severity)
Definition: logging.h:65
static constexpr TimePoint FromEpochDelta(TimeDelta ticks)
Definition: time_point.h:38
FlutterPoint offset
Definition: embedder.h:1106
void SetPlatformMessageCallback(const std::function< void(const FlutterPlatformMessage *)> &callback)
const T & get() const
Definition: unique_object.h:87
FlutterEngineResult FlutterEngineNotifyLowMemoryWarning(FLUTTER_API_SYMBOL(FlutterEngine) raw_engine)
Posts a low memory notification to a running engine instance. The engine will do its best to release ...
Definition: embedder.cc:2189
FlKeyEvent FlKeyResponderAsyncCallback callback
bool is_valid() const
Definition: unique_object.h:89
uint64_t logical
Definition: embedder.h:729
FlKeyEvent * event
const char * script_code
Definition: embedder.h:1166
const char * country_code
Definition: embedder.h:1161
uint64_t physical
Definition: embedder.h:721
FlutterEngineResult FlutterEngineReloadSystemFonts(FLUTTER_API_SYMBOL(FlutterEngine) engine)
Reloads the system fonts in engine.
Definition: embedder.cc:1901
size_t struct_size
The size of this struct. Must be sizeof(FlutterKeyEvent).
Definition: embedder.h:707
internal::CopyableLambda< T > MakeCopyable(T lambda)
Definition: make_copyable.h:57
std::string JoinPaths(std::initializer_list< std::string > components)
Definition: paths.cc:14
Indicates that the contents of this layer are determined by the embedder.
Definition: embedder.h:1087
bool synthesized
Definition: embedder.h:745
FlutterSoftwareBackingStore software
The description of the software backing store.
Definition: embedder.h:1069
FlutterEngineResult FlutterEngineCollectAOTData(FlutterEngineAOTData data)
Collects the AOT data.
Definition: embedder.cc:802
const uint8_t * message
Definition: embedder.h:759
FlutterPoint FlutterPointMake(double x, double y)
#define CREATE_NATIVE_ENTRY(native_entry)
void ExpectKeyEventEq(const FlutterKeyEvent &subject, const FlutterKeyEvent &baseline)
FlutterKeyEventType type
The event kind.
Definition: embedder.h:713
const FlutterPlatformView * platform_view
Definition: embedder.h:1102
FlutterEngineResult FlutterEngineUpdateLocales(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterLocale **locales, size_t locales_count)
Notify a running engine instance that the locale has been updated. The preferred locale must be the f...
Definition: embedder.cc:2001
FlutterLayerContentType type
Definition: embedder.h:1095
const char * GetFixturesPath()
Returns the directory containing the test fixture for the target if this target has fixtures configur...
void SetPlatformTaskRunner(const FlutterTaskRunnerDescription *runner)
static bool IsRunningPrecompiledCode()
Checks if VM instances in the process can run precompiled code. This call can be made at any time and...
Definition: dart_vm.cc:202
double width
Definition: embedder.h:320
flutter::EmbedderEngine * ToEmbedderEngine(const FlutterEngine &engine)
FlutterEngineResult FlutterEngineSendKeyEvent(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterKeyEvent *event, FlutterKeyEventCallback callback, void *user_data)
Sends a key event to the engine. The framework will decide whether to handle this event in a synchron...
Definition: embedder.cc:1596
testing::EmbedderTest EmbedderTest
TEST_F(BackdropFilterLayerTest, PaintingEmptyLayerDies)
constexpr const char * kDefaultAOTAppELFFileName
Definition: elf_loader.h:17
size_t struct_size
The size of this struct. Must be sizeof(FlutterWindowMetricsEvent).
Definition: embedder.h:565
FlutterEngineResult FlutterEnginePostCallbackOnAllNativeThreads(FLUTTER_API_SYMBOL(FlutterEngine) engine, FlutterNativeThreadCallback callback, void *user_data)
Schedule a callback to be run on all engine managed threads. The engine will attempt to service this ...
Definition: embedder.cc:2212
size_t height
The number of rows in the allocation.
Definition: embedder.h:971
fml::WeakPtr< PlatformView > GetPlatformView()
Platform views may only be accessed on the platform task runner.
Definition: shell.cc:693
std::shared_ptr< fml::AutoResetWaitableEvent > latch
size_t isolate_snapshot_instructions_size
Definition: embedder.h:1434
FlutterBackingStoreType type
Specifies the type of backing store.
Definition: embedder.h:1061
static size_t GetVMLaunchCount()
The number of times the VM has been launched in the process. This call is inherently racy because the...
Definition: dart_vm.cc:264
#define FML_CHECK(condition)
Definition: logging.h:68
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition: time_delta.h:46
double height
Definition: embedder.h:321
FlutterNativeThreadType
Definition: embedder.h:1296
FlutterEngineAOTDataSourceType type
Definition: embedder.h:1326
double timestamp
Definition: embedder.h:711
size_t isolate_snapshot_data_size
Definition: embedder.h:1426
int32_t id
size_t struct_size
The size of this struct. Must be sizeof(FlutterPlatformView).
Definition: embedder.h:1020
bool ImageMatchesFixture(const std::string &fixture_file_name, sk_sp< SkImage > scene_image)
#define FML_UNREACHABLE()
Definition: logging.h:92
size_t struct_size
The size of this struct. Must be sizeof(FlutterPlatformMessage).
Definition: embedder.h:757
FlutterEngineResult FlutterEngineSendWindowMetricsEvent(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterWindowMetricsEvent *flutter_metrics)
Definition: embedder.cc:1388
const char * language_code
Definition: embedder.h:1156
virtual void PostTask(const fml::closure &task) override
Definition: task_runner.cc:24
FlutterEngineResult FlutterEngineRunInitialized(FLUTTER_API_SYMBOL(FlutterEngine) engine)
Runs an initialized engine instance. An engine can be initialized via FlutterEngineInitialize. An initialized instance can only be run once. During and after this call, custom task runners supplied by the embedder are expected to start servicing tasks.
Definition: embedder.cc:1326
bool FlutterEngineRunsAOTCompiledDartCode(void)
Returns if the Flutter engine instance will run AOT compiled Dart code. This call has no threading re...
Definition: embedder.cc:2061
size_t vm_snapshot_data_size
Definition: embedder.h:1410
const char * elf_path
Absolute path to an ELF library file.
Definition: embedder.h:1329
uint64_t FlutterEngineGetCurrentTime()
Get the current time in nanoseconds from the clock used by the flutter engine. This is the system mon...
Definition: embedder.cc:1952
size_t struct_size
This size of this struct. Must be sizeof(FlutterLayer).
Definition: embedder.h:1092
static TimePoint Now()
Definition: time_point.cc:39
FlutterEngineResult FlutterEngineSendPlatformMessage(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterPlatformMessage *flutter_message)
Definition: embedder.cc:1636
void SetRenderTargetType(EmbedderTestBackingStoreProducer::RenderTargetType type)
FlutterEngineResult FlutterPlatformMessageCreateResponseHandle(FLUTTER_API_SYMBOL(FlutterEngine) engine, FlutterDataCallback data_callback, void *user_data, FlutterPlatformMessageResponseHandle **response_out)
Creates a platform message response handle that allows the embedder to set a native callback for a re...
Definition: embedder.cc:1687
void SetSoftwareRendererConfig(SkISize surface_size=SkISize::Make(1, 1))
TEST(DisplayListCanvas, DrawPaint)
FlutterEngineResult FlutterEngineCreateAOTData(const FlutterEngineAOTDataSource *source, FlutterEngineAOTData *data_out)
Creates the necessary data structures to launch a Flutter Dart application in AOT mode...
Definition: embedder.cc:748