Flutter Engine
dart_isolate_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/runtime/dart_isolate.h"
6 
7 #include "flutter/fml/mapping.h"
8 #include "flutter/fml/synchronization/count_down_latch.h"
9 #include "flutter/fml/synchronization/waitable_event.h"
10 #include "flutter/fml/thread.h"
11 #include "flutter/runtime/dart_vm.h"
12 #include "flutter/runtime/dart_vm_lifecycle.h"
13 #include "flutter/runtime/isolate_configuration.h"
14 #include "flutter/testing/dart_isolate_runner.h"
15 #include "flutter/testing/fixture_test.h"
16 #include "flutter/testing/testing.h"
19 
20 namespace flutter {
21 namespace testing {
22 
23 class DartIsolateTest : public FixtureTest {
24  public:
26 
27  void Wait() { latch_.Wait(); }
28 
29  void Signal() { latch_.Signal(); }
30 
31  private:
33 
34  FML_DISALLOW_COPY_AND_ASSIGN(DartIsolateTest);
35 };
36 
37 TEST_F(DartIsolateTest, RootIsolateCreationAndShutdown) {
38  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
39  auto settings = CreateSettingsForFixture();
40  auto vm_ref = DartVMRef::Create(settings);
41  ASSERT_TRUE(vm_ref);
42  auto vm_data = vm_ref.GetVMData();
43  ASSERT_TRUE(vm_data);
44  TaskRunners task_runners(GetCurrentTestName(), //
49  );
50 
51  auto isolate_configuration =
53 
54  auto weak_isolate = DartIsolate::CreateRunningRootIsolate(
55  vm_data->GetSettings(), // settings
56  vm_data->GetIsolateSnapshot(), // isolate snapshot
57  std::move(task_runners), // task runners
58  nullptr, // window
59  {}, // snapshot delegate
60  {}, // hint freed delegate
61  {}, // io manager
62  {}, // unref queue
63  {}, // image decoder
64  "main.dart", // advisory uri
65  "main", // advisory entrypoint,
66  DartIsolate::Flags{}, // flags
67  settings.isolate_create_callback, // isolate create callback
68  settings.isolate_shutdown_callback, // isolate shutdown callback
69  "main", // dart entrypoint
70  std::nullopt, // dart entrypoint library
71  std::move(isolate_configuration) // isolate configuration
72  );
73  auto root_isolate = weak_isolate.lock();
74  ASSERT_TRUE(root_isolate);
75  ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::Running);
76  ASSERT_TRUE(root_isolate->Shutdown());
77 }
78 
79 TEST_F(DartIsolateTest, IsolateShutdownCallbackIsInIsolateScope) {
80  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
81  auto settings = CreateSettingsForFixture();
82  auto vm_ref = DartVMRef::Create(settings);
83  ASSERT_TRUE(vm_ref);
84  auto vm_data = vm_ref.GetVMData();
85  ASSERT_TRUE(vm_data);
86  TaskRunners task_runners(GetCurrentTestName(), //
91  );
92  auto isolate_configuration =
94  auto weak_isolate = DartIsolate::CreateRunningRootIsolate(
95  vm_data->GetSettings(), // settings
96  vm_data->GetIsolateSnapshot(), // isolate snapshot
97  std::move(task_runners), // task runners
98  nullptr, // window
99  {}, // snapshot delegate
100  {}, // hint freed delegate
101  {}, // io manager
102  {}, // unref queue
103  {}, // image decoder
104  "main.dart", // advisory uri
105  "main", // advisory entrypoint
106  DartIsolate::Flags{}, // flags
107  settings.isolate_create_callback, // isolate create callback
108  settings.isolate_shutdown_callback, // isolate shutdown callback
109  "main", // dart entrypoint
110  std::nullopt, // dart entrypoint library
111  std::move(isolate_configuration) // isolate configuration
112  );
113  auto root_isolate = weak_isolate.lock();
114  ASSERT_TRUE(root_isolate);
115  ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::Running);
116  size_t destruction_callback_count = 0;
117  root_isolate->AddIsolateShutdownCallback([&destruction_callback_count]() {
118  ASSERT_NE(Dart_CurrentIsolate(), nullptr);
119  destruction_callback_count++;
120  });
121  ASSERT_TRUE(root_isolate->Shutdown());
122  ASSERT_EQ(destruction_callback_count, 1u);
123 }
124 
125 TEST_F(DartIsolateTest, IsolateCanLoadAndRunDartCode) {
126  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
127  const auto settings = CreateSettingsForFixture();
128  auto vm_ref = DartVMRef::Create(settings);
129  TaskRunners task_runners(GetCurrentTestName(), //
134  );
135  auto isolate = RunDartCodeInIsolate(vm_ref, settings, task_runners, "main",
136  {}, GetFixturesPath());
137  ASSERT_TRUE(isolate);
138  ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
139 }
140 
141 TEST_F(DartIsolateTest, IsolateCannotLoadAndRunUnknownDartEntrypoint) {
142  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
143  const auto settings = CreateSettingsForFixture();
144  auto vm_ref = DartVMRef::Create(settings);
145  TaskRunners task_runners(GetCurrentTestName(), //
150  );
151  auto isolate =
152  RunDartCodeInIsolate(vm_ref, settings, task_runners, "thisShouldNotExist",
153  {}, GetFixturesPath());
154  ASSERT_FALSE(isolate);
155 }
156 
157 TEST_F(DartIsolateTest, CanRunDartCodeCodeSynchronously) {
158  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
159  const auto settings = CreateSettingsForFixture();
160  auto vm_ref = DartVMRef::Create(settings);
161  TaskRunners task_runners(GetCurrentTestName(), //
166  );
167  auto isolate = RunDartCodeInIsolate(vm_ref, settings, task_runners, "main",
168  {}, GetFixturesPath());
169 
170  ASSERT_TRUE(isolate);
171  ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
172  ASSERT_TRUE(isolate->RunInIsolateScope([]() -> bool {
173  if (tonic::LogIfError(::Dart_Invoke(Dart_RootLibrary(),
174  tonic::ToDart("sayHi"), 0, nullptr))) {
175  return false;
176  }
177  return true;
178  }));
179 }
180 
181 TEST_F(DartIsolateTest, CanRegisterNativeCallback) {
182  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
183  AddNativeCallback("NotifyNative",
184  CREATE_NATIVE_ENTRY(([this](Dart_NativeArguments args) {
185  FML_LOG(ERROR) << "Hello from Dart!";
186  Signal();
187  })));
188  const auto settings = CreateSettingsForFixture();
189  auto vm_ref = DartVMRef::Create(settings);
190  auto thread = CreateNewThread();
191  TaskRunners task_runners(GetCurrentTestName(), //
192  thread, //
193  thread, //
194  thread, //
195  thread //
196  );
197  auto isolate =
198  RunDartCodeInIsolate(vm_ref, settings, task_runners,
199  "canRegisterNativeCallback", {}, GetFixturesPath());
200  ASSERT_TRUE(isolate);
201  ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
202  Wait();
203 }
204 
205 TEST_F(DartIsolateTest, CanSaveCompilationTrace) {
207  // Can only save compilation traces in JIT modes.
208  GTEST_SKIP();
209  return;
210  }
211  AddNativeCallback("NotifyNative",
212  CREATE_NATIVE_ENTRY(([this](Dart_NativeArguments args) {
214  Dart_GetNativeArgument(args, 0)));
215  Signal();
216  })));
217 
218  const auto settings = CreateSettingsForFixture();
219  auto vm_ref = DartVMRef::Create(settings);
220  auto thread = CreateNewThread();
221  TaskRunners task_runners(GetCurrentTestName(), //
222  thread, //
223  thread, //
224  thread, //
225  thread //
226  );
227  auto isolate = RunDartCodeInIsolate(vm_ref, settings, task_runners,
228  "testCanSaveCompilationTrace", {},
229  GetFixturesPath());
230  ASSERT_TRUE(isolate);
231  ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
232 
233  Wait();
234 }
235 
237  public:
238  DartSecondaryIsolateTest() : latch_(3) {}
239 
240  void LatchCountDown() { latch_.CountDown(); }
241 
242  void LatchWait() { latch_.Wait(); }
243 
244  void ChildShutdownSignal() { child_shutdown_latch_.Signal(); }
245 
246  void ChildShutdownWait() { child_shutdown_latch_.Wait(); }
247 
248  void RootIsolateShutdownSignal() { root_isolate_shutdown_latch_.Signal(); }
249 
251  return root_isolate_shutdown_latch_.IsSignaledForTest();
252  }
253 
254  private:
255  fml::CountDownLatch latch_;
256  fml::AutoResetWaitableEvent child_shutdown_latch_;
257  fml::AutoResetWaitableEvent root_isolate_shutdown_latch_;
258 
260 };
261 
262 TEST_F(DartSecondaryIsolateTest, CanLaunchSecondaryIsolates) {
263  AddNativeCallback("NotifyNative",
264  CREATE_NATIVE_ENTRY(([this](Dart_NativeArguments args) {
265  LatchCountDown();
266  })));
268  "PassMessage", CREATE_NATIVE_ENTRY(([this](Dart_NativeArguments args) {
270  Dart_GetNativeArgument(args, 0));
271  ASSERT_EQ("Hello from code is secondary isolate.", message);
272  LatchCountDown();
273  })));
274  auto settings = CreateSettingsForFixture();
275  settings.root_isolate_shutdown_callback = [this]() {
276  RootIsolateShutdownSignal();
277  };
278  settings.isolate_shutdown_callback = [this]() { ChildShutdownSignal(); };
279  auto vm_ref = DartVMRef::Create(settings);
280  auto thread = CreateNewThread();
281  TaskRunners task_runners(GetCurrentTestName(), //
282  thread, //
283  thread, //
284  thread, //
285  thread //
286  );
287  auto isolate = RunDartCodeInIsolate(vm_ref, settings, task_runners,
288  "testCanLaunchSecondaryIsolate", {},
289  GetFixturesPath());
290  ASSERT_TRUE(isolate);
291  ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
292  ChildShutdownWait(); // wait for child isolate to shutdown first
293  ASSERT_FALSE(RootIsolateIsSignaled());
294  LatchWait(); // wait for last NotifyNative called by main isolate
295  // root isolate will be auto-shutdown
296 }
297 
298 TEST_F(DartIsolateTest, CanRecieveArguments) {
299  AddNativeCallback("NotifyNative",
300  CREATE_NATIVE_ENTRY(([this](Dart_NativeArguments args) {
302  Dart_GetNativeArgument(args, 0)));
303  Signal();
304  })));
305 
306  const auto settings = CreateSettingsForFixture();
307  auto vm_ref = DartVMRef::Create(settings);
308  auto thread = CreateNewThread();
309  TaskRunners task_runners(GetCurrentTestName(), //
310  thread, //
311  thread, //
312  thread, //
313  thread //
314  );
315  auto isolate = RunDartCodeInIsolate(vm_ref, settings, task_runners,
316  "testCanRecieveArguments", {"arg1"},
317  GetFixturesPath());
318  ASSERT_TRUE(isolate);
319  ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
320 
321  Wait();
322 }
323 
324 TEST_F(DartIsolateTest, CanCreateServiceIsolate) {
325 #if (FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_DEBUG) && \
326  (FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_PROFILE)
327  GTEST_SKIP();
328 #endif
329  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
330  fml::AutoResetWaitableEvent service_isolate_latch;
331  auto settings = CreateSettingsForFixture();
332  settings.enable_observatory = true;
333  settings.observatory_port = 0;
334  settings.observatory_host = "127.0.0.1";
335  settings.enable_service_port_fallback = true;
336  settings.service_isolate_create_callback = [&service_isolate_latch]() {
337  service_isolate_latch.Signal();
338  };
339  auto vm_ref = DartVMRef::Create(settings);
340  ASSERT_TRUE(vm_ref);
341  auto vm_data = vm_ref.GetVMData();
342  ASSERT_TRUE(vm_data);
343  TaskRunners task_runners(GetCurrentTestName(), //
348  );
349 
350  auto isolate_configuration =
352  auto weak_isolate = DartIsolate::CreateRunningRootIsolate(
353  vm_data->GetSettings(), // settings
354  vm_data->GetIsolateSnapshot(), // isolate snapshot
355  std::move(task_runners), // task runners
356  nullptr, // window
357  {}, // snapshot delegate
358  {}, // hint freed delegate
359  {}, // io manager
360  {}, // unref queue
361  {}, // image decoder
362  "main.dart", // advisory uri
363  "main", // advisory entrypoint,
364  DartIsolate::Flags{}, // flags
365  settings.isolate_create_callback, // isolate create callback
366  settings.isolate_shutdown_callback, // isolate shutdown callback
367  "main", // dart entrypoint
368  std::nullopt, // dart entrypoint library
369  std::move(isolate_configuration) // isolate configuration
370  );
371  auto root_isolate = weak_isolate.lock();
372  ASSERT_TRUE(root_isolate);
373  ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::Running);
374  service_isolate_latch.Wait();
375  ASSERT_TRUE(root_isolate->Shutdown());
376 }
377 
379  RootIsolateCreateCallbackIsMadeOnceAndBeforeIsolateRunning) {
380  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
381  auto settings = CreateSettingsForFixture();
382  size_t create_callback_count = 0u;
383  settings.root_isolate_create_callback =
384  [&create_callback_count](const auto& isolate) {
385  ASSERT_EQ(isolate.GetPhase(), DartIsolate::Phase::Ready);
386  create_callback_count++;
387  ASSERT_NE(::Dart_CurrentIsolate(), nullptr);
388  };
389  auto vm_ref = DartVMRef::Create(settings);
390  TaskRunners task_runners(GetCurrentTestName(), //
395  );
396  {
397  auto isolate = RunDartCodeInIsolate(vm_ref, settings, task_runners, "main",
398  {}, GetFixturesPath());
399  ASSERT_TRUE(isolate);
400  ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
401  }
402  ASSERT_EQ(create_callback_count, 1u);
403 }
404 
406  IsolateCreateCallbacksTakeInstanceSettingsInsteadOfVMSettings) {
407  ASSERT_FALSE(DartVMRef::IsInstanceRunning());
408  auto vm_settings = CreateSettingsForFixture();
409  auto vm_ref = DartVMRef::Create(vm_settings);
410  auto instance_settings = vm_settings;
411  size_t create_callback_count = 0u;
412  instance_settings.root_isolate_create_callback =
413  [&create_callback_count](const auto& isolate) {
414  ASSERT_EQ(isolate.GetPhase(), DartIsolate::Phase::Ready);
415  create_callback_count++;
416  ASSERT_NE(::Dart_CurrentIsolate(), nullptr);
417  };
418  TaskRunners task_runners(GetCurrentTestName(), //
423  );
424  {
425  auto isolate = RunDartCodeInIsolate(vm_ref, instance_settings, task_runners,
426  "main", {}, GetFixturesPath());
427  ASSERT_TRUE(isolate);
428  ASSERT_EQ(isolate->get()->GetPhase(), DartIsolate::Phase::Running);
429  }
430  ASSERT_EQ(create_callback_count, 1u);
431 }
432 
433 } // namespace testing
434 } // namespace flutter
fml::RefPtr< fml::TaskRunner > GetCurrentTaskRunner()
Get the task runner for the thread that the current unit-test is running on. This creates a message l...
Definition: thread_test.cc:22
fml::RefPtr< fml::TaskRunner > CreateNewThread(std::string name="")
Creates a new thread, initializes a message loop on it, and, returns its task runner to the unit-test...
Definition: thread_test.cc:26
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:12
static std::weak_ptr< DartIsolate > CreateRunningRootIsolate(const Settings &settings, fml::RefPtr< const DartSnapshot > isolate_snapshot, TaskRunners task_runners, std::unique_ptr< PlatformConfiguration > platform_configuration, fml::WeakPtr< SnapshotDelegate > snapshot_delegate, fml::WeakPtr< HintFreedDelegate > hint_freed_delegate, fml::WeakPtr< IOManager > io_manager, fml::RefPtr< SkiaUnrefQueue > skia_unref_queue, fml::WeakPtr< ImageDecoder > image_decoder, std::string advisory_script_uri, std::string advisory_script_entrypoint, Flags flags, const fml::closure &isolate_create_callback, const fml::closure &isolate_shutdown_callback, std::optional< std::string > dart_entrypoint, std::optional< std::string > dart_entrypoint_library, std::unique_ptr< IsolateConfiguration > isolate_configration)
Creates an instance of a root isolate and returns a weak pointer to the same. The isolate instance ma...
Definition: dart_isolate.cc:76
#define FML_LOG(severity)
Definition: logging.h:65
static bool IsInstanceRunning()
static DartVMRef Create(Settings settings, fml::RefPtr< DartSnapshot > vm_snapshot=nullptr, fml::RefPtr< DartSnapshot > isolate_snapshot=nullptr)
virtual Settings CreateSettingsForFixture()
Definition: fixture_test.cc:17
static std::unique_ptr< IsolateConfiguration > InferFromSettings(const Settings &settings, std::shared_ptr< AssetManager > asset_manager=nullptr, fml::RefPtr< fml::TaskRunner > io_worker=nullptr)
Attempts to infer the isolate configuration from the Settings object. If the VM is configured for AOT...
#define CREATE_NATIVE_ENTRY(native_entry)
const char * GetFixturesPath()
Returns the directory containing the test fixture for the target if this target has fixtures configur...
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:199
TEST_F(BackdropFilterLayerTest, PaintingEmptyLayerDies)
void AddNativeCallback(std::string name, Dart_NativeFunction callback)
Definition: fixture_test.cc:58
std::unique_ptr< AutoIsolateShutdown > RunDartCodeInIsolate(DartVMRef &vm_ref, const Settings &settings, const TaskRunners &task_runners, std::string entrypoint, const std::vector< std::string > &args, const std::string &fixtures_path, fml::WeakPtr< IOManager > io_manager)
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: macros.h:27