Flutter Engine
dart_isolate.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 <cstdlib>
8 #include <tuple>
9 
10 #include "flutter/fml/paths.h"
11 #include "flutter/fml/posix_wrappers.h"
12 #include "flutter/fml/trace_event.h"
13 #include "flutter/lib/io/dart_io.h"
14 #include "flutter/lib/ui/dart_runtime_hooks.h"
15 #include "flutter/lib/ui/dart_ui.h"
16 #include "flutter/runtime/dart_isolate_group_data.h"
17 #include "flutter/runtime/dart_service_isolate.h"
18 #include "flutter/runtime/dart_vm.h"
19 #include "flutter/runtime/dart_vm_lifecycle.h"
20 #include "flutter/runtime/isolate_configuration.h"
21 #include "third_party/dart/runtime/include/dart_api.h"
22 #include "third_party/dart/runtime/include/dart_tools_api.h"
32 
33 namespace flutter {
34 
35 namespace {
36 
37 class DartErrorString {
38  public:
39  DartErrorString() : str_(nullptr) {}
40  ~DartErrorString() {
41  if (str_) {
42  ::free(str_);
43  }
44  }
45  char** error() { return &str_; }
46  const char* str() const { return str_; }
47  explicit operator bool() const { return str_ != nullptr; }
48 
49  private:
50  FML_DISALLOW_COPY_AND_ASSIGN(DartErrorString);
51  char* str_;
52 };
53 
54 } // anonymous namespace
55 
57 
58 DartIsolate::Flags::Flags(const Dart_IsolateFlags* flags) {
59  if (flags) {
60  flags_ = *flags;
61  } else {
62  ::Dart_IsolateFlagsInitialize(&flags_);
63  }
64 }
65 
66 DartIsolate::Flags::~Flags() = default;
67 
69  flags_.null_safety = enabled;
70 }
71 
72 Dart_IsolateFlags DartIsolate::Flags::Get() const {
73  return flags_;
74 }
75 
76 std::weak_ptr<DartIsolate> DartIsolate::CreateRunningRootIsolate(
77  const Settings& settings,
78  fml::RefPtr<const DartSnapshot> isolate_snapshot,
79  TaskRunners task_runners,
80  std::unique_ptr<PlatformConfiguration> platform_configuration,
81  fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
82  fml::WeakPtr<HintFreedDelegate> hint_freed_delegate,
83  fml::WeakPtr<IOManager> io_manager,
84  fml::RefPtr<SkiaUnrefQueue> skia_unref_queue,
85  fml::WeakPtr<ImageDecoder> image_decoder,
86  std::string advisory_script_uri,
87  std::string advisory_script_entrypoint,
88  Flags isolate_flags,
89  const fml::closure& isolate_create_callback,
90  const fml::closure& isolate_shutdown_callback,
91  std::optional<std::string> dart_entrypoint,
92  std::optional<std::string> dart_entrypoint_library,
93  std::unique_ptr<IsolateConfiguration> isolate_configration) {
94  if (!isolate_snapshot) {
95  FML_LOG(ERROR) << "Invalid isolate snapshot.";
96  return {};
97  }
98 
99  if (!isolate_configration) {
100  FML_LOG(ERROR) << "Invalid isolate configuration.";
101  return {};
102  }
103 
104  isolate_flags.SetNullSafetyEnabled(
105  isolate_configration->IsNullSafetyEnabled(*isolate_snapshot));
106 
107  auto isolate = CreateRootIsolate(settings, //
108  isolate_snapshot, //
109  task_runners, //
110  std::move(platform_configuration), //
111  snapshot_delegate, //
112  hint_freed_delegate, //
113  io_manager, //
114  skia_unref_queue, //
115  image_decoder, //
116  advisory_script_uri, //
117  advisory_script_entrypoint, //
118  isolate_flags, //
119  isolate_create_callback, //
120  isolate_shutdown_callback //
121  )
122  .lock();
123 
124  if (!isolate) {
125  FML_LOG(ERROR) << "Could not create root isolate.";
126  return {};
127  }
128 
129  fml::ScopedCleanupClosure shutdown_on_error([isolate]() {
130  if (!isolate->Shutdown()) {
131  FML_DLOG(ERROR) << "Could not shutdown transient isolate.";
132  }
133  });
134 
135  if (isolate->GetPhase() != DartIsolate::Phase::LibrariesSetup) {
136  FML_LOG(ERROR) << "Root isolate was created in an incorrect phase.";
137  return {};
138  }
139 
140  if (!isolate_configration->PrepareIsolate(*isolate.get())) {
141  FML_LOG(ERROR) << "Could not prepare isolate.";
142  return {};
143  }
144 
145  if (isolate->GetPhase() != DartIsolate::Phase::Ready) {
146  FML_LOG(ERROR) << "Root isolate not in the ready phase for Dart entrypoint "
147  "invocation.";
148  return {};
149  }
150 
151  if (settings.root_isolate_create_callback) {
152  // Isolate callbacks always occur in isolate scope and before user code has
153  // had a chance to run.
154  tonic::DartState::Scope scope(isolate.get());
155  settings.root_isolate_create_callback(*isolate.get());
156  }
157 
158  if (!isolate->RunFromLibrary(dart_entrypoint_library, //
159  dart_entrypoint, //
160  settings.dart_entrypoint_args //
161  )) {
162  FML_LOG(ERROR) << "Could not run the run main Dart entrypoint.";
163  return {};
164  }
165 
166  if (settings.root_isolate_shutdown_callback) {
167  isolate->AddIsolateShutdownCallback(
169  }
170 
171  shutdown_on_error.Release();
172 
173  return isolate;
174 }
175 
176 std::weak_ptr<DartIsolate> DartIsolate::CreateRootIsolate(
177  const Settings& settings,
178  fml::RefPtr<const DartSnapshot> isolate_snapshot,
179  TaskRunners task_runners,
180  std::unique_ptr<PlatformConfiguration> platform_configuration,
181  fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
182  fml::WeakPtr<HintFreedDelegate> hint_freed_delegate,
183  fml::WeakPtr<IOManager> io_manager,
184  fml::RefPtr<SkiaUnrefQueue> unref_queue,
185  fml::WeakPtr<ImageDecoder> image_decoder,
186  std::string advisory_script_uri,
187  std::string advisory_script_entrypoint,
188  Flags flags,
189  const fml::closure& isolate_create_callback,
190  const fml::closure& isolate_shutdown_callback) {
191  TRACE_EVENT0("flutter", "DartIsolate::CreateRootIsolate");
192 
193  // The child isolate preparer is null but will be set when the isolate is
194  // being prepared to run.
195  auto isolate_group_data =
196  std::make_unique<std::shared_ptr<DartIsolateGroupData>>(
197  std::shared_ptr<DartIsolateGroupData>(new DartIsolateGroupData(
198  settings, // settings
199  std::move(isolate_snapshot), // isolate snapshot
200  advisory_script_uri, // advisory URI
201  advisory_script_entrypoint, // advisory entrypoint
202  nullptr, // child isolate preparer
203  isolate_create_callback, // isolate create callback
204  isolate_shutdown_callback // isolate shutdown callback
205  )));
206 
207  auto isolate_data = std::make_unique<std::shared_ptr<DartIsolate>>(
208  std::shared_ptr<DartIsolate>(new DartIsolate(
209  settings, // settings
210  task_runners, // task runners
211  std::move(snapshot_delegate), // snapshot delegate
212  std::move(hint_freed_delegate), // hint freed delegate
213  std::move(io_manager), // IO manager
214  std::move(unref_queue), // Skia unref queue
215  std::move(image_decoder), // Image Decoder
216  advisory_script_uri, // advisory URI
217  advisory_script_entrypoint, // advisory entrypoint
218  true // is_root_isolate
219  )));
220 
221  DartErrorString error;
222  auto isolate_flags = flags.Get();
223  Dart_Isolate vm_isolate = CreateDartIsolateGroup(
224  std::move(isolate_group_data), std::move(isolate_data), &isolate_flags,
225  error.error());
226 
227  if (error) {
228  FML_LOG(ERROR) << "CreateDartIsolateGroup failed: " << error.str();
229  }
230 
231  if (vm_isolate == nullptr) {
232  return {};
233  }
234 
235  std::shared_ptr<DartIsolate>* root_isolate_data =
236  static_cast<std::shared_ptr<DartIsolate>*>(Dart_IsolateData(vm_isolate));
237 
238  (*root_isolate_data)
239  ->SetPlatformConfiguration(std::move(platform_configuration));
240 
241  return (*root_isolate_data)->GetWeakIsolatePtr();
242 }
243 
244 DartIsolate::DartIsolate(const Settings& settings,
245  TaskRunners task_runners,
246  fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
247  fml::WeakPtr<HintFreedDelegate> hint_freed_delegate,
248  fml::WeakPtr<IOManager> io_manager,
249  fml::RefPtr<SkiaUnrefQueue> unref_queue,
250  fml::WeakPtr<ImageDecoder> image_decoder,
251  std::string advisory_script_uri,
252  std::string advisory_script_entrypoint,
253  bool is_root_isolate)
254  : UIDartState(std::move(task_runners),
255  settings.task_observer_add,
256  settings.task_observer_remove,
257  std::move(snapshot_delegate),
258  std::move(hint_freed_delegate),
259  std::move(io_manager),
260  std::move(unref_queue),
261  std::move(image_decoder),
262  advisory_script_uri,
263  advisory_script_entrypoint,
264  settings.log_tag,
267  is_root_isolate),
268  may_insecurely_connect_to_all_domains_(
270  domain_network_policy_(settings.domain_network_policy) {
271  phase_ = Phase::Uninitialized;
272 }
273 
276  FML_DCHECK(GetMessageHandlingTaskRunner()->RunsTasksOnCurrentThread());
277  }
278 }
279 
281  return phase_;
282 }
283 
285  const char* service_id_buf = Dart_IsolateServiceId(isolate());
286  std::string service_id(service_id_buf);
287  free(const_cast<char*>(service_id_buf));
288  return service_id;
289 }
290 
291 bool DartIsolate::Initialize(Dart_Isolate dart_isolate) {
292  TRACE_EVENT0("flutter", "DartIsolate::Initialize");
293  if (phase_ != Phase::Uninitialized) {
294  return false;
295  }
296 
297  if (dart_isolate == nullptr) {
298  return false;
299  }
300 
301  if (Dart_CurrentIsolate() != dart_isolate) {
302  return false;
303  }
304 
305  // After this point, isolate scopes can be safely used.
306  SetIsolate(dart_isolate);
307 
308  // We are entering a new scope (for the first time since initialization) and
309  // we want to restore the current scope to null when we exit out of this
310  // method. This balances the implicit Dart_EnterIsolate call made by
311  // Dart_CreateIsolateGroup (which calls the Initialize).
312  Dart_ExitIsolate();
313 
315 
316  SetMessageHandlingTaskRunner(GetTaskRunners().GetUITaskRunner());
317 
318  if (tonic::LogIfError(
319  Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))) {
320  return false;
321  }
322 
323  if (!UpdateThreadPoolNames()) {
324  return false;
325  }
326 
327  phase_ = Phase::Initialized;
328  return true;
329 }
330 
332  return message_handling_task_runner_;
333 }
334 
335 void DartIsolate::SetMessageHandlingTaskRunner(
337  if (!IsRootIsolate() || !runner) {
338  return;
339  }
340 
341  message_handling_task_runner_ = runner;
342 
344  [runner](std::function<void()> task) { runner->PostTask(task); });
345 }
346 
347 // Updating thread names here does not change the underlying OS thread names.
348 // Instead, this is just additional metadata for the Observatory to show the
349 // thread name of the isolate.
350 bool DartIsolate::UpdateThreadPoolNames() const {
351  // TODO(chinmaygarde): This implementation does not account for multiple
352  // shells sharing the same (or subset of) threads.
353  const auto& task_runners = GetTaskRunners();
354 
355  if (auto task_runner = task_runners.GetRasterTaskRunner()) {
356  task_runner->PostTask(
357  [label = task_runners.GetLabel() + std::string{".raster"}]() {
358  Dart_SetThreadName(label.c_str());
359  });
360  }
361 
362  if (auto task_runner = task_runners.GetUITaskRunner()) {
363  task_runner->PostTask(
364  [label = task_runners.GetLabel() + std::string{".ui"}]() {
365  Dart_SetThreadName(label.c_str());
366  });
367  }
368 
369  if (auto task_runner = task_runners.GetIOTaskRunner()) {
370  task_runner->PostTask(
371  [label = task_runners.GetLabel() + std::string{".io"}]() {
372  Dart_SetThreadName(label.c_str());
373  });
374  }
375 
376  if (auto task_runner = task_runners.GetPlatformTaskRunner()) {
377  task_runner->PostTask(
378  [label = task_runners.GetLabel() + std::string{".platform"}]() {
379  Dart_SetThreadName(label.c_str());
380  });
381  }
382 
383  return true;
384 }
385 
386 bool DartIsolate::LoadLibraries() {
387  TRACE_EVENT0("flutter", "DartIsolate::LoadLibraries");
388  if (phase_ != Phase::Initialized) {
389  return false;
390  }
391 
392  tonic::DartState::Scope scope(this);
393 
394  DartIO::InitForIsolate(may_insecurely_connect_to_all_domains_,
395  domain_network_policy_);
396 
398 
399  const bool is_service_isolate = Dart_IsServiceIsolate(isolate());
400 
401  DartRuntimeHooks::Install(IsRootIsolate() && !is_service_isolate,
403 
404  if (!is_service_isolate) {
406  "ui", std::make_unique<tonic::DartClassProvider>(this, "dart:ui"));
407  }
408 
409  phase_ = Phase::LibrariesSetup;
410  return true;
411 }
412 
414  TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromPrecompiledCode");
415  if (phase_ != Phase::LibrariesSetup) {
416  return false;
417  }
418 
419  tonic::DartState::Scope scope(this);
420 
421  if (Dart_IsNull(Dart_RootLibrary())) {
422  return false;
423  }
424 
425  if (!MarkIsolateRunnable()) {
426  return false;
427  }
428 
429  if (GetIsolateGroupData().GetChildIsolatePreparer() == nullptr) {
430  GetIsolateGroupData().SetChildIsolatePreparer([](DartIsolate* isolate) {
431  return isolate->PrepareForRunningFromPrecompiledCode();
432  });
433  }
434 
435  const fml::closure& isolate_create_callback =
436  GetIsolateGroupData().GetIsolateCreateCallback();
437  if (isolate_create_callback) {
438  isolate_create_callback();
439  }
440 
441  phase_ = Phase::Ready;
442  return true;
443 }
444 
445 bool DartIsolate::LoadKernel(std::shared_ptr<const fml::Mapping> mapping,
446  bool last_piece) {
447  if (!Dart_IsKernel(mapping->GetMapping(), mapping->GetSize())) {
448  return false;
449  }
450 
451  // Mapping must be retained until isolate shutdown.
452  kernel_buffers_.push_back(mapping);
453 
454  Dart_Handle library =
455  Dart_LoadLibraryFromKernel(mapping->GetMapping(), mapping->GetSize());
456  if (tonic::LogIfError(library)) {
457  return false;
458  }
459 
460  if (!last_piece) {
461  // More to come.
462  return true;
463  }
464 
465  Dart_SetRootLibrary(library);
466  if (tonic::LogIfError(Dart_FinalizeLoading(false))) {
467  return false;
468  }
469  return true;
470 }
471 
473  std::shared_ptr<const fml::Mapping> mapping,
474  bool last_piece) {
475  TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromKernel");
476  if (phase_ != Phase::LibrariesSetup) {
477  return false;
478  }
479 
481  return false;
482  }
483 
484  if (!mapping || mapping->GetSize() == 0) {
485  return false;
486  }
487 
488  tonic::DartState::Scope scope(this);
489 
490  // Use root library provided by kernel in favor of one provided by snapshot.
491  Dart_SetRootLibrary(Dart_Null());
492 
493  if (!LoadKernel(mapping, last_piece)) {
494  return false;
495  }
496 
497  if (!last_piece) {
498  // More to come.
499  return true;
500  }
501 
502  if (Dart_IsNull(Dart_RootLibrary())) {
503  return false;
504  }
505 
506  if (!MarkIsolateRunnable()) {
507  return false;
508  }
509 
510  // Child isolate shares root isolate embedder_isolate (lines 691 and 693
511  // below). Re-initializing child_isolate_preparer_ lambda while it is being
512  // executed leads to crashes.
513  if (GetIsolateGroupData().GetChildIsolatePreparer() == nullptr) {
514  GetIsolateGroupData().SetChildIsolatePreparer(
515  [buffers = kernel_buffers_](DartIsolate* isolate) {
516  for (uint64_t i = 0; i < buffers.size(); i++) {
517  bool last_piece = i + 1 == buffers.size();
518  const std::shared_ptr<const fml::Mapping>& buffer = buffers.at(i);
519  if (!isolate->PrepareForRunningFromKernel(buffer, last_piece)) {
520  return false;
521  }
522  }
523  return true;
524  });
525  }
526 
527  const fml::closure& isolate_create_callback =
528  GetIsolateGroupData().GetIsolateCreateCallback();
529  if (isolate_create_callback) {
530  isolate_create_callback();
531  }
532 
533  phase_ = Phase::Ready;
534 
535  return true;
536 }
537 
539  std::vector<std::shared_ptr<const fml::Mapping>> kernels) {
540  const auto count = kernels.size();
541  if (count == 0) {
542  return false;
543  }
544 
545  for (size_t i = 0; i < count; ++i) {
546  bool last = (i == (count - 1));
547  if (!PrepareForRunningFromKernel(kernels[i], last)) {
548  return false;
549  }
550  }
551 
552  return true;
553 }
554 
556  std::vector<std::unique_ptr<const fml::Mapping>> kernels) {
557  std::vector<std::shared_ptr<const fml::Mapping>> shared_kernels;
558  for (auto& kernel : kernels) {
559  shared_kernels.emplace_back(std::move(kernel));
560  }
561  return PrepareForRunningFromKernels(shared_kernels);
562 }
563 
564 bool DartIsolate::MarkIsolateRunnable() {
565  TRACE_EVENT0("flutter", "DartIsolate::MarkIsolateRunnable");
566  if (phase_ != Phase::LibrariesSetup) {
567  return false;
568  }
569 
570  // This function may only be called from an active isolate scope.
571  if (Dart_CurrentIsolate() != isolate()) {
572  return false;
573  }
574 
575  // There must be no current isolate to mark an isolate as being runnable.
576  Dart_ExitIsolate();
577 
578  char* error = Dart_IsolateMakeRunnable(isolate());
579  if (error) {
580  FML_DLOG(ERROR) << error;
581  ::free(error);
582  // Failed. Restore the isolate.
583  Dart_EnterIsolate(isolate());
584  return false;
585  }
586  // Success. Restore the isolate.
587  Dart_EnterIsolate(isolate());
588  return true;
589 }
590 
591 [[nodiscard]] static bool InvokeMainEntrypoint(
592  Dart_Handle user_entrypoint_function,
593  Dart_Handle args) {
594  if (tonic::LogIfError(user_entrypoint_function)) {
595  FML_LOG(ERROR) << "Could not resolve main entrypoint function.";
596  return false;
597  }
598 
599  Dart_Handle start_main_isolate_function =
600  tonic::DartInvokeField(Dart_LookupLibrary(tonic::ToDart("dart:isolate")),
601  "_getStartMainIsolateFunction", {});
602 
603  if (tonic::LogIfError(start_main_isolate_function)) {
604  FML_LOG(ERROR) << "Could not resolve main entrypoint trampoline.";
605  return false;
606  }
607 
609  Dart_LookupLibrary(tonic::ToDart("dart:ui")), "_runMainZoned",
610  {start_main_isolate_function, user_entrypoint_function, args}))) {
611  FML_LOG(ERROR) << "Could not invoke the main entrypoint.";
612  return false;
613  }
614 
615  return true;
616 }
617 
618 bool DartIsolate::RunFromLibrary(std::optional<std::string> library_name,
619  std::optional<std::string> entrypoint,
620  const std::vector<std::string>& args) {
621  TRACE_EVENT0("flutter", "DartIsolate::RunFromLibrary");
622  if (phase_ != Phase::Ready) {
623  return false;
624  }
625 
626  tonic::DartState::Scope scope(this);
627 
628  auto library_handle =
629  library_name.has_value() && !library_name.value().empty()
630  ? ::Dart_LookupLibrary(tonic::ToDart(library_name.value().c_str()))
631  : ::Dart_RootLibrary();
632  auto entrypoint_handle = entrypoint.has_value() && !entrypoint.value().empty()
633  ? tonic::ToDart(entrypoint.value().c_str())
634  : tonic::ToDart("main");
635  auto user_entrypoint_function =
636  ::Dart_GetField(library_handle, entrypoint_handle);
637 
638  auto entrypoint_args = tonic::ToDart(args);
639 
640  if (!InvokeMainEntrypoint(user_entrypoint_function, entrypoint_args)) {
641  return false;
642  }
643 
644  phase_ = Phase::Running;
645 
646  return true;
647 }
648 
650  TRACE_EVENT0("flutter", "DartIsolate::Shutdown");
651  // This call may be re-entrant since Dart_ShutdownIsolate can invoke the
652  // cleanup callback which deletes the embedder side object of the dart isolate
653  // (a.k.a. this).
654  if (phase_ == Phase::Shutdown) {
655  return false;
656  }
657  phase_ = Phase::Shutdown;
658  Dart_Isolate vm_isolate = isolate();
659  // The isolate can be nullptr if this instance is the stub isolate data used
660  // during root isolate creation.
661  if (vm_isolate != nullptr) {
662  // We need to enter the isolate because Dart_ShutdownIsolate does not take
663  // the isolate to shutdown as a parameter.
664  FML_DCHECK(Dart_CurrentIsolate() == nullptr);
665  Dart_EnterIsolate(vm_isolate);
666  Dart_ShutdownIsolate();
667  FML_DCHECK(Dart_CurrentIsolate() == nullptr);
668  }
669  return true;
670 }
671 
672 Dart_Isolate DartIsolate::DartCreateAndStartServiceIsolate(
673  const char* package_root,
674  const char* package_config,
675  Dart_IsolateFlags* flags,
676  char** error) {
677  auto vm_data = DartVMRef::GetVMData();
678 
679  if (!vm_data) {
680  *error = fml::strdup(
681  "Could not access VM data to initialize isolates. This may be because "
682  "the VM has initialized shutdown on another thread already.");
683  return nullptr;
684  }
685 
686  const auto& settings = vm_data->GetSettings();
687 
688  if (!settings.enable_observatory) {
689  return nullptr;
690  }
691 
692  TaskRunners null_task_runners("io.flutter." DART_VM_SERVICE_ISOLATE_NAME,
693  nullptr, nullptr, nullptr, nullptr);
694 
695  flags->load_vmservice_library = true;
696 
697 #if (FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_DEBUG)
698  // TODO(68663): The service isolate in debug mode is always launched without
699  // sound null safety. Fix after the isolate snapshot data is created with the
700  // right flags.
701  flags->null_safety =
702  vm_data->GetIsolateSnapshot()->IsNullSafetyEnabled(nullptr);
703 #endif
704 
705  std::weak_ptr<DartIsolate> weak_service_isolate =
706  DartIsolate::CreateRootIsolate(
707  vm_data->GetSettings(), // settings
708  vm_data->GetIsolateSnapshot(), // isolate snapshot
709  null_task_runners, // task runners
710  nullptr, // platform_configuration
711  {}, // snapshot delegate
712  {}, // Hint freed delegate
713  {}, // IO Manager
714  {}, // Skia unref queue
715  {}, // Image Decoder
716  DART_VM_SERVICE_ISOLATE_NAME, // script uri
717  DART_VM_SERVICE_ISOLATE_NAME, // script entrypoint
718  DartIsolate::Flags{flags}, // flags
719  nullptr, // isolate create callback
720  nullptr // isolate shutdown callback
721  );
722 
723  std::shared_ptr<DartIsolate> service_isolate = weak_service_isolate.lock();
724  if (!service_isolate) {
725  *error = fml::strdup("Could not create the service isolate.");
726  FML_DLOG(ERROR) << *error;
727  return nullptr;
728  }
729 
730  tonic::DartState::Scope scope(service_isolate);
732  settings.observatory_host, // server IP address
733  settings.observatory_port, // server observatory port
734  tonic::DartState::HandleLibraryTag, // embedder library tag handler
735  false, // disable websocket origin check
736  settings.disable_service_auth_codes, // disable VM service auth codes
737  settings.enable_service_port_fallback, // enable fallback to port 0
738  // when bind fails.
739  error // error (out)
740  )) {
741  // Error is populated by call to startup.
742  FML_DLOG(ERROR) << *error;
743  return nullptr;
744  }
745 
746  if (auto callback = vm_data->GetSettings().service_isolate_create_callback) {
747  callback();
748  }
749 
750  if (auto service_protocol = DartVMRef::GetServiceProtocol()) {
751  service_protocol->ToggleHooks(true);
752  } else {
753  FML_DLOG(ERROR)
754  << "Could not acquire the service protocol handlers. This might be "
755  "because the VM has already begun teardown on another thread.";
756  }
757 
758  return service_isolate->isolate();
759 }
760 
761 DartIsolateGroupData& DartIsolate::GetIsolateGroupData() {
762  std::shared_ptr<DartIsolateGroupData>* isolate_group_data =
763  static_cast<std::shared_ptr<DartIsolateGroupData>*>(
764  Dart_IsolateGroupData(isolate()));
765  return **isolate_group_data;
766 }
767 
768 // |Dart_IsolateGroupCreateCallback|
769 Dart_Isolate DartIsolate::DartIsolateGroupCreateCallback(
770  const char* advisory_script_uri,
771  const char* advisory_script_entrypoint,
772  const char* package_root,
773  const char* package_config,
774  Dart_IsolateFlags* flags,
775  std::shared_ptr<DartIsolate>* parent_isolate_data,
776  char** error) {
777  TRACE_EVENT0("flutter", "DartIsolate::DartIsolateGroupCreateCallback");
778  if (parent_isolate_data == nullptr &&
779  strcmp(advisory_script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0) {
780  // The VM attempts to start the VM service for us on |Dart_Initialize|. In
781  // such a case, the callback data will be null and the script URI will be
782  // DART_VM_SERVICE_ISOLATE_NAME. In such cases, we just create the service
783  // isolate like normal but dont hold a reference to it at all. We also start
784  // this isolate since we will never again reference it from the engine.
785  return DartCreateAndStartServiceIsolate(package_root, //
786  package_config, //
787  flags, //
788  error //
789  );
790  }
791 
792  if (!parent_isolate_data) {
793  return nullptr;
794  }
795 
796  DartIsolateGroupData& parent_group_data =
797  (*parent_isolate_data)->GetIsolateGroupData();
798 
799  auto isolate_group_data =
800  std::make_unique<std::shared_ptr<DartIsolateGroupData>>(
801  std::shared_ptr<DartIsolateGroupData>(new DartIsolateGroupData(
802  parent_group_data.GetSettings(),
803  parent_group_data.GetIsolateSnapshot(), advisory_script_uri,
804  advisory_script_entrypoint,
805  parent_group_data.GetChildIsolatePreparer(),
806  parent_group_data.GetIsolateCreateCallback(),
807  parent_group_data.GetIsolateShutdownCallback())));
808 
809  TaskRunners null_task_runners(advisory_script_uri,
810  /* platform= */ nullptr,
811  /* raster= */ nullptr,
812  /* ui= */ nullptr,
813  /* io= */ nullptr);
814 
815  auto isolate_data = std::make_unique<std::shared_ptr<DartIsolate>>(
816  std::shared_ptr<DartIsolate>(new DartIsolate(
817  (*isolate_group_data)->GetSettings(), // settings
818  null_task_runners, // task_runners
819  fml::WeakPtr<SnapshotDelegate>{}, // snapshot_delegate
820  fml::WeakPtr<HintFreedDelegate>{}, // hint_freed_delegate
821  fml::WeakPtr<IOManager>{}, // io_manager
822  fml::RefPtr<SkiaUnrefQueue>{}, // unref_queue
823  fml::WeakPtr<ImageDecoder>{}, // image_decoder
824  advisory_script_uri, // advisory_script_uri
825  advisory_script_entrypoint, // advisory_script_entrypoint
826  false))); // is_root_isolate
827 
828  Dart_Isolate vm_isolate = CreateDartIsolateGroup(
829  std::move(isolate_group_data), std::move(isolate_data), flags, error);
830 
831  if (*error) {
832  FML_LOG(ERROR) << "CreateDartIsolateGroup failed: " << error;
833  }
834 
835  return vm_isolate;
836 }
837 
838 // |Dart_IsolateInitializeCallback|
839 bool DartIsolate::DartIsolateInitializeCallback(void** child_callback_data,
840  char** error) {
841  TRACE_EVENT0("flutter", "DartIsolate::DartIsolateInitializeCallback");
842  Dart_Isolate isolate = Dart_CurrentIsolate();
843  if (isolate == nullptr) {
844  *error = fml::strdup("Isolate should be available in initialize callback.");
845  FML_DLOG(ERROR) << *error;
846  return false;
847  }
848 
849  auto* isolate_group_data =
850  static_cast<std::shared_ptr<DartIsolateGroupData>*>(
851  Dart_CurrentIsolateGroupData());
852 
853  TaskRunners null_task_runners((*isolate_group_data)->GetAdvisoryScriptURI(),
854  /* platform= */ nullptr,
855  /* raster= */ nullptr,
856  /* ui= */ nullptr,
857  /* io= */ nullptr);
858 
859  auto embedder_isolate = std::make_unique<std::shared_ptr<DartIsolate>>(
860  std::shared_ptr<DartIsolate>(new DartIsolate(
861  (*isolate_group_data)->GetSettings(), // settings
862  null_task_runners, // task_runners
863  fml::WeakPtr<SnapshotDelegate>{}, // snapshot_delegate
864  fml::WeakPtr<HintFreedDelegate>{}, // hint_freed_delegate
865  fml::WeakPtr<IOManager>{}, // io_manager
866  fml::RefPtr<SkiaUnrefQueue>{}, // unref_queue
867  fml::WeakPtr<ImageDecoder>{}, // image_decoder
868  (*isolate_group_data)->GetAdvisoryScriptURI(), // advisory_script_uri
869  (*isolate_group_data)
870  ->GetAdvisoryScriptEntrypoint(), // advisory_script_entrypoint
871  false))); // is_root_isolate
872 
873  // root isolate should have been created via CreateRootIsolate
874  if (!InitializeIsolate(*embedder_isolate, isolate, error)) {
875  return false;
876  }
877 
878  // The ownership of the embedder object is controlled by the Dart VM. So the
879  // only reference returned to the caller is weak.
880  *child_callback_data = embedder_isolate.release();
881 
882  Dart_EnterIsolate(isolate);
883  return true;
884 }
885 
886 Dart_Isolate DartIsolate::CreateDartIsolateGroup(
887  std::unique_ptr<std::shared_ptr<DartIsolateGroupData>> isolate_group_data,
888  std::unique_ptr<std::shared_ptr<DartIsolate>> isolate_data,
889  Dart_IsolateFlags* flags,
890  char** error) {
891  TRACE_EVENT0("flutter", "DartIsolate::CreateDartIsolateGroup");
892 
893  // Create the Dart VM isolate and give it the embedder object as the baton.
894  Dart_Isolate isolate = Dart_CreateIsolateGroup(
895  (*isolate_group_data)->GetAdvisoryScriptURI().c_str(),
896  (*isolate_group_data)->GetAdvisoryScriptEntrypoint().c_str(),
897  (*isolate_group_data)->GetIsolateSnapshot()->GetDataMapping(),
898  (*isolate_group_data)->GetIsolateSnapshot()->GetInstructionsMapping(),
899  flags, isolate_group_data.get(), isolate_data.get(), error);
900 
901  if (isolate == nullptr) {
902  return nullptr;
903  }
904 
905  // Ownership of the isolate data objects has been transferred to the Dart VM.
906  std::shared_ptr<DartIsolate> embedder_isolate(*isolate_data);
907  isolate_group_data.release();
908  isolate_data.release();
909 
910  if (!InitializeIsolate(std::move(embedder_isolate), isolate, error)) {
911  return nullptr;
912  }
913 
914  return isolate;
915 }
916 
917 bool DartIsolate::InitializeIsolate(
918  std::shared_ptr<DartIsolate> embedder_isolate,
919  Dart_Isolate isolate,
920  char** error) {
921  TRACE_EVENT0("flutter", "DartIsolate::InitializeIsolate");
922  if (!embedder_isolate->Initialize(isolate)) {
923  *error = fml::strdup("Embedder could not initialize the Dart isolate.");
924  FML_DLOG(ERROR) << *error;
925  return false;
926  }
927 
928  if (!embedder_isolate->LoadLibraries()) {
929  *error = fml::strdup(
930  "Embedder could not load libraries in the new Dart isolate.");
931  FML_DLOG(ERROR) << *error;
932  return false;
933  }
934 
935  // Root isolates will be setup by the engine and the service isolate (which is
936  // also a root isolate) by the utility routines in the VM. However, secondary
937  // isolates will be run by the VM if they are marked as runnable.
938  if (!embedder_isolate->IsRootIsolate()) {
939  auto child_isolate_preparer =
940  embedder_isolate->GetIsolateGroupData().GetChildIsolatePreparer();
941  FML_DCHECK(child_isolate_preparer);
942  if (!child_isolate_preparer(embedder_isolate.get())) {
943  *error = fml::strdup("Could not prepare the child isolate to run.");
944  FML_DLOG(ERROR) << *error;
945  return false;
946  }
947  }
948 
949  return true;
950 }
951 
952 // |Dart_IsolateShutdownCallback|
953 void DartIsolate::DartIsolateShutdownCallback(
954  std::shared_ptr<DartIsolateGroupData>* isolate_group_data,
955  std::shared_ptr<DartIsolate>* isolate_data) {
956  TRACE_EVENT0("flutter", "DartIsolate::DartIsolateShutdownCallback");
957  isolate_data->get()->OnShutdownCallback();
958 }
959 
960 // |Dart_IsolateGroupCleanupCallback|
961 void DartIsolate::DartIsolateGroupCleanupCallback(
962  std::shared_ptr<DartIsolateGroupData>* isolate_data) {
963  TRACE_EVENT0("flutter", "DartIsolate::DartIsolateGroupCleanupCallback");
964  delete isolate_data;
965 }
966 
967 // |Dart_IsolateCleanupCallback|
968 void DartIsolate::DartIsolateCleanupCallback(
969  std::shared_ptr<DartIsolateGroupData>* isolate_group_data,
970  std::shared_ptr<DartIsolate>* isolate_data) {
971  TRACE_EVENT0("flutter", "DartIsolate::DartIsolateCleanupCallback");
972  delete isolate_data;
973 }
974 
975 std::weak_ptr<DartIsolate> DartIsolate::GetWeakIsolatePtr() {
976  return std::static_pointer_cast<DartIsolate>(shared_from_this());
977 }
978 
980  shutdown_callbacks_.emplace_back(std::make_unique<AutoFireClosure>(closure));
981 }
982 
983 void DartIsolate::OnShutdownCallback() {
984  {
985  tonic::DartApiScope api_scope;
986  Dart_Handle sticky_error = Dart_GetStickyError();
987  if (!Dart_IsNull(sticky_error) && !Dart_IsFatalError(sticky_error)) {
988  FML_LOG(ERROR) << Dart_GetError(sticky_error);
989  }
990  }
991 
992  shutdown_callbacks_.clear();
993 
994  const fml::closure& isolate_shutdown_callback =
995  GetIsolateGroupData().GetIsolateShutdownCallback();
996  if (isolate_shutdown_callback) {
997  isolate_shutdown_callback();
998  }
999 }
1000 
1001 DartIsolate::AutoFireClosure::AutoFireClosure(const fml::closure& closure)
1002  : closure_(closure) {}
1003 
1004 DartIsolate::AutoFireClosure::~AutoFireClosure() {
1005  if (closure_) {
1006  closure_();
1007  }
1008 }
1009 
1010 } // namespace flutter
bool PrepareForRunningFromKernel(std::shared_ptr< const fml::Mapping > kernel, bool last_piece=true)
Prepare the isolate for running for a a list of kernel files.
G_BEGIN_DECLS FlValue * args
ChildIsolatePreparer GetChildIsolatePreparer() const
Phase GetPhase() const
The current phase of the isolate. The engine represents all dart isolates as being in one of the know...
Dart_IsolateFlags Get() const
Definition: dart_isolate.cc:72
void SetIsolate(Dart_Isolate isolate)
Definition: dart_state.cc:34
const fml::closure & GetIsolateShutdownCallback() const
void add_provider(const std::string &library_name, std::unique_ptr< DartClassProvider > provider)
static bool Startup(std::string server_ip, intptr_t server_port, Dart_LibraryTagHandler embedder_tag_handler, bool disable_origin_check, bool disable_service_auth_codes, bool enable_service_port_fallback, char **error)
Start the service isolate. This call may only be made in the Dart VM initiated isolate creation callb...
Dart_Isolate isolate()
Definition: dart_state.h:49
bool RunFromLibrary(std::optional< std::string > library_name, std::optional< std::string > entrypoint, const std::vector< std::string > &args)
Transition the root isolate to the Phase::Running phase and invoke the main entrypoint (the "main" me...
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:75
#define FML_DCHECK(condition)
Definition: logging.h:86
Phase
The engine represents all dart isolates as being in one of the known phases. By invoking various meth...
Definition: dart_isolate.h:92
std::vector< std::string > dart_entrypoint_args
Definition: settings.h:98
std::function< void(const DartIsolate &)> root_isolate_create_callback
Definition: settings.h:174
const Settings & GetSettings() const
FlMethodResponse GError ** error
static std::shared_ptr< ServiceProtocol > GetServiceProtocol()
uint32_t observatory_port
Definition: settings.h:142
static void Install(bool is_ui_isolate, const std::string &script_uri)
Dart_NativeFunction function
Definition: fuchsia.cc:51
fml::RefPtr< fml::TaskRunner > GetPlatformTaskRunner() const
Definition: task_runners.cc:30
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
virtual void PostTask(const fml::closure &task)
Definition: task_runner.cc:24
static std::shared_ptr< const DartVMData > GetVMData()
#define FML_LOG(severity)
Definition: logging.h:65
static void InitForIsolate()
Definition: dart_ui.cc:93
fml::RefPtr< fml::TaskRunner > GetRasterTaskRunner() const
Definition: task_runners.cc:42
Dart_Handle DartInvokeField(Dart_Handle target, const char *name, std::initializer_list< Dart_Handle > args)
Definition: dart_invoke.cc:12
UIDartState(TaskRunners task_runners, TaskObserverAdd add_callback, TaskObserverRemove remove_callback, 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, std::string logger_prefix, UnhandledExceptionCallback unhandled_exception_callback, std::shared_ptr< IsolateNameServer > isolate_name_server, bool is_root_isolate_)
void SetNullSafetyEnabled(bool enabled)
Definition: dart_isolate.cc:68
UnhandledExceptionCallback unhandled_exception_callback
Definition: settings.h:200
Wraps a closure that is invoked in the destructor unless released by the caller.
Definition: closure.h:32
std::function< void()> closure
Definition: closure.h:14
void AddIsolateShutdownCallback(const fml::closure &closure)
Registers a callback that will be invoked in isolate scope just before the isolate transitions to the...
fml::closure root_isolate_shutdown_callback
Definition: settings.h:180
bool IsRootIsolate() const
Definition: ui_dart_state.h:39
std::string domain_network_policy
Definition: settings.h:117
static Dart_Handle HandleLibraryTag(Dart_LibraryTag tag, Dart_Handle library, Dart_Handle url)
Definition: dart_state.cc:78
DartClassLibrary & class_library()
Definition: dart_state.h:58
Represents an instance of a live isolate. An isolate is a separate Dart execution context...
Definition: dart_isolate.h:62
static std::shared_ptr< IsolateNameServer > GetIsolateNameServer()
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
PlatformConfiguration * platform_configuration() const
Definition: ui_dart_state.h:48
std::string observatory_host
Definition: settings.h:137
TaskObserverAdd task_observer_add
Definition: settings.h:170
static bool InvokeMainEntrypoint(Dart_Handle user_entrypoint_function, Dart_Handle args)
std::string GetServiceId()
Returns the ID for an isolate which is used to query the service protocol.
fml::RefPtr< fml::TaskRunner > GetIOTaskRunner() const
Definition: task_runners.cc:38
fml::RefPtr< fml::TaskRunner > GetUITaskRunner() const
Definition: task_runners.cc:34
bool disable_service_auth_codes
Definition: settings.h:146
const std::string & GetAdvisoryScriptURI() const
bool enable_observatory
Definition: settings.h:129
void Initialize(TaskDispatcher dispatcher)
const fml::closure & GetIsolateCreateCallback() const
bool may_insecurely_connect_to_all_domains
Definition: settings.h:115
const TaskRunners & GetTaskRunners() const
static void InitForIsolate(bool may_insecurely_connect_to_all_domains, std::string domain_network_policy)
Definition: dart_io.cc:18
#define FML_DLOG(severity)
Definition: logging.h:85
char * strdup(const char *str1)
fml::RefPtr< fml::TaskRunner > GetMessageHandlingTaskRunner() const
The task runner on which the Dart code for the root isolate is running. For the root isolate...
Dart_Handle ToDart(const T &object)
bool LogIfError(Dart_Handle handle)
Definition: dart_error.cc:15
TaskObserverRemove task_observer_remove
Definition: settings.h:171
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: macros.h:27
bool Shutdown()
Transition the isolate to the Phase::Shutdown phase. The only thing left to do is to collect the isol...
bool PrepareForRunningFromKernels(std::vector< std::shared_ptr< const fml::Mapping >> kernels)
Prepare the isolate for running for a a list of kernel files.
std::weak_ptr< DartIsolate > GetWeakIsolatePtr()
A weak pointer to the Dart isolate instance. This instance may only be used on the task runner that c...
DartMessageHandler & message_handler()
Definition: dart_state.h:59
std::string log_tag
Definition: settings.h:204
bool PrepareForRunningFromPrecompiledCode()
Prepare the isolate for running for a precompiled code bundle. The Dart VM must be configured for run...
const std::string & GetLabel() const
Definition: task_runners.cc:26
DEF_SWITCHES_START snapshot asset Path to the directory containing the four files specified by VmSnapshotInstructions and IsolateSnapshotInstructions vm snapshot The VM instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present isolate snapshot The isolate instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present icu symbol Prefix for the symbols representing ICU data linked into the Flutter library dart flags
Definition: switches.h:66
bool enable_service_port_fallback
Definition: settings.h:150
fml::RefPtr< const DartSnapshot > GetIsolateSnapshot() const