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 "third_party/dart/runtime/include/dart_api.h"
21#include "third_party/dart/runtime/include/dart_tools_api.h"
22#include "third_party/tonic/converter/dart_converter.h"
23#include "third_party/tonic/dart_class_library.h"
24#include "third_party/tonic/dart_class_provider.h"
25#include "third_party/tonic/dart_message_handler.h"
26#include "third_party/tonic/dart_state.h"
27#include "third_party/tonic/file_loader/file_loader.h"
28#include "third_party/tonic/logging/dart_invoke.h"
29#include "third_party/tonic/scopes/dart_api_scope.h"
30#include "third_party/tonic/scopes/dart_isolate_scope.h"
31
32namespace flutter {
33
34namespace {
35
36class DartErrorString {
37 public:
38 DartErrorString() : str_(nullptr) {}
39 ~DartErrorString() {
40 if (str_) {
41 ::free(str_);
42 }
43 }
44 char** error() { return &str_; }
45 const char* str() const { return str_; }
46 explicit operator bool() const { return str_ != nullptr; }
47
48 private:
49 FML_DISALLOW_COPY_AND_ASSIGN(DartErrorString);
50 char* str_;
51};
52
53} // anonymous namespace
54
55std::weak_ptr<DartIsolate> DartIsolate::CreateRootIsolate(
56 const Settings& settings,
57 fml::RefPtr<const DartSnapshot> isolate_snapshot,
58 TaskRunners task_runners,
59 std::unique_ptr<PlatformConfiguration> platform_configuration,
60 fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
61 fml::WeakPtr<IOManager> io_manager,
62 fml::RefPtr<SkiaUnrefQueue> unref_queue,
63 fml::WeakPtr<ImageDecoder> image_decoder,
64 std::string advisory_script_uri,
65 std::string advisory_script_entrypoint,
66 Dart_IsolateFlags* flags,
67 const fml::closure& isolate_create_callback,
68 const fml::closure& isolate_shutdown_callback) {
69 TRACE_EVENT0("flutter", "DartIsolate::CreateRootIsolate");
70
71 // The child isolate preparer is null but will be set when the isolate is
72 // being prepared to run.
73 auto isolate_group_data =
74 std::make_unique<std::shared_ptr<DartIsolateGroupData>>(
75 std::shared_ptr<DartIsolateGroupData>(new DartIsolateGroupData(
76 settings, // settings
77 std::move(isolate_snapshot), // isolate snapshot
78 advisory_script_uri, // advisory URI
79 advisory_script_entrypoint, // advisory entrypoint
80 nullptr, // child isolate preparer
81 isolate_create_callback, // isolate create callback
82 isolate_shutdown_callback // isolate shutdown callback
83 )));
84
85 auto isolate_data = std::make_unique<std::shared_ptr<DartIsolate>>(
86 std::shared_ptr<DartIsolate>(new DartIsolate(
87 settings, // settings
88 task_runners, // task runners
89 std::move(snapshot_delegate), // snapshot delegate
90 std::move(io_manager), // IO manager
91 std::move(unref_queue), // Skia unref queue
92 std::move(image_decoder), // Image Decoder
93 advisory_script_uri, // advisory URI
94 advisory_script_entrypoint, // advisory entrypoint
95 true // is_root_isolate
96 )));
97
98 DartErrorString error;
99 Dart_Isolate vm_isolate =
100 CreateDartIsolateGroup(std::move(isolate_group_data),
101 std::move(isolate_data), flags, error.error());
102
103 if (error) {
104 FML_LOG(ERROR) << "CreateDartIsolateGroup failed: " << error.str();
105 }
106
107 if (vm_isolate == nullptr) {
108 return {};
109 }
110
111 std::shared_ptr<DartIsolate>* root_isolate_data =
112 static_cast<std::shared_ptr<DartIsolate>*>(Dart_IsolateData(vm_isolate));
113
114 (*root_isolate_data)
115 ->SetPlatformConfiguration(std::move(platform_configuration));
116
117 return (*root_isolate_data)->GetWeakIsolatePtr();
118}
119
120DartIsolate::DartIsolate(const Settings& settings,
121 TaskRunners task_runners,
122 fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
123 fml::WeakPtr<IOManager> io_manager,
124 fml::RefPtr<SkiaUnrefQueue> unref_queue,
125 fml::WeakPtr<ImageDecoder> image_decoder,
126 std::string advisory_script_uri,
127 std::string advisory_script_entrypoint,
128 bool is_root_isolate)
129 : UIDartState(std::move(task_runners),
130 settings.task_observer_add,
131 settings.task_observer_remove,
132 std::move(snapshot_delegate),
133 std::move(io_manager),
134 std::move(unref_queue),
135 std::move(image_decoder),
136 advisory_script_uri,
137 advisory_script_entrypoint,
138 settings.log_tag,
139 settings.unhandled_exception_callback,
140 DartVMRef::GetIsolateNameServer(),
141 is_root_isolate),
142 may_insecurely_connect_to_all_domains_(
143 settings.may_insecurely_connect_to_all_domains),
144 domain_network_policy_(settings.domain_network_policy) {
145 phase_ = Phase::Uninitialized;
146}
147
148DartIsolate::~DartIsolate() {
149 if (IsRootIsolate() && GetMessageHandlingTaskRunner()) {
150 FML_DCHECK(GetMessageHandlingTaskRunner()->RunsTasksOnCurrentThread());
151 }
152}
153
154DartIsolate::Phase DartIsolate::GetPhase() const {
155 return phase_;
156}
157
158std::string DartIsolate::GetServiceId() {
159 const char* service_id_buf = Dart_IsolateServiceId(isolate());
160 std::string service_id(service_id_buf);
161 free(const_cast<char*>(service_id_buf));
162 return service_id;
163}
164
165bool DartIsolate::Initialize(Dart_Isolate dart_isolate) {
166 TRACE_EVENT0("flutter", "DartIsolate::Initialize");
167 if (phase_ != Phase::Uninitialized) {
168 return false;
169 }
170
171 if (dart_isolate == nullptr) {
172 return false;
173 }
174
175 if (Dart_CurrentIsolate() != dart_isolate) {
176 return false;
177 }
178
179 // After this point, isolate scopes can be safely used.
180 SetIsolate(dart_isolate);
181
182 // We are entering a new scope (for the first time since initialization) and
183 // we want to restore the current scope to null when we exit out of this
184 // method. This balances the implicit Dart_EnterIsolate call made by
185 // Dart_CreateIsolateGroup (which calls the Initialize).
186 Dart_ExitIsolate();
187
188 tonic::DartIsolateScope scope(isolate());
189
190 SetMessageHandlingTaskRunner(GetTaskRunners().GetUITaskRunner());
191
192 if (tonic::LogIfError(
193 Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))) {
194 return false;
195 }
196
197 if (!UpdateThreadPoolNames()) {
198 return false;
199 }
200
201 phase_ = Phase::Initialized;
202 return true;
203}
204
205fml::RefPtr<fml::TaskRunner> DartIsolate::GetMessageHandlingTaskRunner() const {
206 return message_handling_task_runner_;
207}
208
209void DartIsolate::SetMessageHandlingTaskRunner(
210 fml::RefPtr<fml::TaskRunner> runner) {
211 if (!IsRootIsolate() || !runner) {
212 return;
213 }
214
215 message_handling_task_runner_ = runner;
216
217 message_handler().Initialize(
218 [runner](std::function<void()> task) { runner->PostTask(task); });
219}
220
221// Updating thread names here does not change the underlying OS thread names.
222// Instead, this is just additional metadata for the Observatory to show the
223// thread name of the isolate.
224bool DartIsolate::UpdateThreadPoolNames() const {
225 // TODO(chinmaygarde): This implementation does not account for multiple
226 // shells sharing the same (or subset of) threads.
227 const auto& task_runners = GetTaskRunners();
228
229 if (auto task_runner = task_runners.GetRasterTaskRunner()) {
230 task_runner->PostTask(
231 [label = task_runners.GetLabel() + std::string{".raster"}]() {
232 Dart_SetThreadName(label.c_str());
233 });
234 }
235
236 if (auto task_runner = task_runners.GetUITaskRunner()) {
237 task_runner->PostTask(
238 [label = task_runners.GetLabel() + std::string{".ui"}]() {
239 Dart_SetThreadName(label.c_str());
240 });
241 }
242
243 if (auto task_runner = task_runners.GetIOTaskRunner()) {
244 task_runner->PostTask(
245 [label = task_runners.GetLabel() + std::string{".io"}]() {
246 Dart_SetThreadName(label.c_str());
247 });
248 }
249
250 if (auto task_runner = task_runners.GetPlatformTaskRunner()) {
251 task_runner->PostTask(
252 [label = task_runners.GetLabel() + std::string{".platform"}]() {
253 Dart_SetThreadName(label.c_str());
254 });
255 }
256
257 return true;
258}
259
260bool DartIsolate::LoadLibraries() {
261 TRACE_EVENT0("flutter", "DartIsolate::LoadLibraries");
262 if (phase_ != Phase::Initialized) {
263 return false;
264 }
265
266 tonic::DartState::Scope scope(this);
267
268 DartIO::InitForIsolate(may_insecurely_connect_to_all_domains_,
269 domain_network_policy_);
270
271 DartUI::InitForIsolate();
272
273 const bool is_service_isolate = Dart_IsServiceIsolate(isolate());
274
275 DartRuntimeHooks::Install(IsRootIsolate() && !is_service_isolate,
276 GetAdvisoryScriptURI());
277
278 if (!is_service_isolate) {
279 class_library().add_provider(
280 "ui", std::make_unique<tonic::DartClassProvider>(this, "dart:ui"));
281 }
282
283 phase_ = Phase::LibrariesSetup;
284 return true;
285}
286
287bool DartIsolate::PrepareForRunningFromPrecompiledCode() {
288 TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromPrecompiledCode");
289 if (phase_ != Phase::LibrariesSetup) {
290 return false;
291 }
292
293 tonic::DartState::Scope scope(this);
294
295 if (Dart_IsNull(Dart_RootLibrary())) {
296 return false;
297 }
298
299 if (!MarkIsolateRunnable()) {
300 return false;
301 }
302
303 if (GetIsolateGroupData().GetChildIsolatePreparer() == nullptr) {
304 GetIsolateGroupData().SetChildIsolatePreparer([](DartIsolate* isolate) {
305 return isolate->PrepareForRunningFromPrecompiledCode();
306 });
307 }
308
309 const fml::closure& isolate_create_callback =
310 GetIsolateGroupData().GetIsolateCreateCallback();
311 if (isolate_create_callback) {
312 isolate_create_callback();
313 }
314
315 phase_ = Phase::Ready;
316 return true;
317}
318
319bool DartIsolate::LoadKernel(std::shared_ptr<const fml::Mapping> mapping,
320 bool last_piece) {
321 if (!Dart_IsKernel(mapping->GetMapping(), mapping->GetSize())) {
322 return false;
323 }
324
325 // Mapping must be retained until isolate shutdown.
326 kernel_buffers_.push_back(mapping);
327
328 Dart_Handle library =
329 Dart_LoadLibraryFromKernel(mapping->GetMapping(), mapping->GetSize());
330 if (tonic::LogIfError(library)) {
331 return false;
332 }
333
334 if (!last_piece) {
335 // More to come.
336 return true;
337 }
338
339 Dart_SetRootLibrary(library);
340 if (tonic::LogIfError(Dart_FinalizeLoading(false))) {
341 return false;
342 }
343 return true;
344}
345
346[[nodiscard]] bool DartIsolate::PrepareForRunningFromKernel(
347 std::shared_ptr<const fml::Mapping> mapping,
348 bool last_piece) {
349 TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromKernel");
350 if (phase_ != Phase::LibrariesSetup) {
351 return false;
352 }
353
354 if (DartVM::IsRunningPrecompiledCode()) {
355 return false;
356 }
357
358 if (!mapping || mapping->GetSize() == 0) {
359 return false;
360 }
361
362 tonic::DartState::Scope scope(this);
363
364 // Use root library provided by kernel in favor of one provided by snapshot.
365 Dart_SetRootLibrary(Dart_Null());
366
367 if (!LoadKernel(mapping, last_piece)) {
368 return false;
369 }
370
371 if (!last_piece) {
372 // More to come.
373 return true;
374 }
375
376 if (Dart_IsNull(Dart_RootLibrary())) {
377 return false;
378 }
379
380 if (!MarkIsolateRunnable()) {
381 return false;
382 }
383
384 // Child isolate shares root isolate embedder_isolate (lines 691 and 693
385 // below). Re-initializing child_isolate_preparer_ lambda while it is being
386 // executed leads to crashes.
387 if (GetIsolateGroupData().GetChildIsolatePreparer() == nullptr) {
388 GetIsolateGroupData().SetChildIsolatePreparer(
389 [buffers = kernel_buffers_](DartIsolate* isolate) {
390 for (uint64_t i = 0; i < buffers.size(); i++) {
391 bool last_piece = i + 1 == buffers.size();
392 const std::shared_ptr<const fml::Mapping>& buffer = buffers.at(i);
393 if (!isolate->PrepareForRunningFromKernel(buffer, last_piece)) {
394 return false;
395 }
396 }
397 return true;
398 });
399 }
400
401 const fml::closure& isolate_create_callback =
402 GetIsolateGroupData().GetIsolateCreateCallback();
403 if (isolate_create_callback) {
404 isolate_create_callback();
405 }
406
407 phase_ = Phase::Ready;
408
409 return true;
410}
411
412[[nodiscard]] bool DartIsolate::PrepareForRunningFromKernels(
413 std::vector<std::shared_ptr<const fml::Mapping>> kernels) {
414 const auto count = kernels.size();
415 if (count == 0) {
416 return false;
417 }
418
419 for (size_t i = 0; i < count; ++i) {
420 bool last = (i == (count - 1));
421 if (!PrepareForRunningFromKernel(kernels[i], last)) {
422 return false;
423 }
424 }
425
426 return true;
427}
428
429[[nodiscard]] bool DartIsolate::PrepareForRunningFromKernels(
430 std::vector<std::unique_ptr<const fml::Mapping>> kernels) {
431 std::vector<std::shared_ptr<const fml::Mapping>> shared_kernels;
432 for (auto& kernel : kernels) {
433 shared_kernels.emplace_back(std::move(kernel));
434 }
435 return PrepareForRunningFromKernels(shared_kernels);
436}
437
438bool DartIsolate::MarkIsolateRunnable() {
439 TRACE_EVENT0("flutter", "DartIsolate::MarkIsolateRunnable");
440 if (phase_ != Phase::LibrariesSetup) {
441 return false;
442 }
443
444 // This function may only be called from an active isolate scope.
445 if (Dart_CurrentIsolate() != isolate()) {
446 return false;
447 }
448
449 // There must be no current isolate to mark an isolate as being runnable.
450 Dart_ExitIsolate();
451
452 char* error = Dart_IsolateMakeRunnable(isolate());
453 if (error) {
454 FML_DLOG(ERROR) << error;
455 ::free(error);
456 // Failed. Restore the isolate.
457 Dart_EnterIsolate(isolate());
458 return false;
459 }
460 // Success. Restore the isolate.
461 Dart_EnterIsolate(isolate());
462 return true;
463}
464
465[[nodiscard]] static bool InvokeMainEntrypoint(
466 Dart_Handle user_entrypoint_function,
467 Dart_Handle args) {
468 if (tonic::LogIfError(user_entrypoint_function)) {
469 FML_LOG(ERROR) << "Could not resolve main entrypoint function.";
470 return false;
471 }
472
473 Dart_Handle start_main_isolate_function =
474 tonic::DartInvokeField(Dart_LookupLibrary(tonic::ToDart("dart:isolate")),
475 "_getStartMainIsolateFunction", {});
476
477 if (tonic::LogIfError(start_main_isolate_function)) {
478 FML_LOG(ERROR) << "Could not resolve main entrypoint trampoline.";
479 return false;
480 }
481
482 if (tonic::LogIfError(tonic::DartInvokeField(
483 Dart_LookupLibrary(tonic::ToDart("dart:ui")), "_runMainZoned",
484 {start_main_isolate_function, user_entrypoint_function, args}))) {
485 FML_LOG(ERROR) << "Could not invoke the main entrypoint.";
486 return false;
487 }
488
489 return true;
490}
491
492/// @note Procedure doesn't copy all closures.
493[[nodiscard]] bool DartIsolate::Run(const std::string& entrypoint_name,
494 const std::vector<std::string>& args,
495 const fml::closure& on_run) {
496 TRACE_EVENT0("flutter", "DartIsolate::Run");
497 if (phase_ != Phase::Ready) {
498 return false;
499 }
500
501 tonic::DartState::Scope scope(this);
502
503 auto user_entrypoint_function =
504 Dart_GetField(Dart_RootLibrary(), tonic::ToDart(entrypoint_name.c_str()));
505
506 auto entrypoint_args = tonic::ToDart(args);
507
508 if (!InvokeMainEntrypoint(user_entrypoint_function, entrypoint_args)) {
509 return false;
510 }
511
512 phase_ = Phase::Running;
513
514 if (on_run) {
515 on_run();
516 }
517 return true;
518}
519
520/// @note Procedure doesn't copy all closures.
521[[nodiscard]] bool DartIsolate::RunFromLibrary(
522 const std::string& library_name,
523 const std::string& entrypoint_name,
524 const std::vector<std::string>& args,
525 const fml::closure& on_run) {
526 TRACE_EVENT0("flutter", "DartIsolate::RunFromLibrary");
527 if (phase_ != Phase::Ready) {
528 return false;
529 }
530
531 tonic::DartState::Scope scope(this);
532
533 auto user_entrypoint_function =
534 Dart_GetField(Dart_LookupLibrary(tonic::ToDart(library_name.c_str())),
535 tonic::ToDart(entrypoint_name.c_str()));
536
537 auto entrypoint_args = tonic::ToDart(args);
538
539 if (!InvokeMainEntrypoint(user_entrypoint_function, entrypoint_args)) {
540 return false;
541 }
542
543 phase_ = Phase::Running;
544
545 if (on_run) {
546 on_run();
547 }
548 return true;
549}
550
551bool DartIsolate::Shutdown() {
552 TRACE_EVENT0("flutter", "DartIsolate::Shutdown");
553 // This call may be re-entrant since Dart_ShutdownIsolate can invoke the
554 // cleanup callback which deletes the embedder side object of the dart isolate
555 // (a.k.a. this).
556 if (phase_ == Phase::Shutdown) {
557 return false;
558 }
559 phase_ = Phase::Shutdown;
560 Dart_Isolate vm_isolate = isolate();
561 // The isolate can be nullptr if this instance is the stub isolate data used
562 // during root isolate creation.
563 if (vm_isolate != nullptr) {
564 // We need to enter the isolate because Dart_ShutdownIsolate does not take
565 // the isolate to shutdown as a parameter.
566 FML_DCHECK(Dart_CurrentIsolate() == nullptr);
567 Dart_EnterIsolate(vm_isolate);
568 Dart_ShutdownIsolate();
569 FML_DCHECK(Dart_CurrentIsolate() == nullptr);
570 }
571 return true;
572}
573
574Dart_Isolate DartIsolate::DartCreateAndStartServiceIsolate(
575 const char* package_root,
576 const char* package_config,
577 Dart_IsolateFlags* flags,
578 char** error) {
579 auto vm_data = DartVMRef::GetVMData();
580
581 if (!vm_data) {
582 *error = fml::strdup(
583 "Could not access VM data to initialize isolates. This may be because "
584 "the VM has initialized shutdown on another thread already.");
585 return nullptr;
586 }
587
588 const auto& settings = vm_data->GetSettings();
589
590 if (!settings.enable_observatory) {
591 return nullptr;
592 }
593
594 TaskRunners null_task_runners("io.flutter." DART_VM_SERVICE_ISOLATE_NAME,
595 nullptr, nullptr, nullptr, nullptr);
596
597 flags->load_vmservice_library = true;
598
599 std::weak_ptr<DartIsolate> weak_service_isolate =
600 DartIsolate::CreateRootIsolate(
601 vm_data->GetSettings(), // settings
602 vm_data->GetIsolateSnapshot(), // isolate snapshot
603 null_task_runners, // task runners
604 nullptr, // platform_configuration
605 {}, // snapshot delegate
606 {}, // IO Manager
607 {}, // Skia unref queue
608 {}, // Image Decoder
609 DART_VM_SERVICE_ISOLATE_NAME, // script uri
610 DART_VM_SERVICE_ISOLATE_NAME, // script entrypoint
611 flags, // flags
612 nullptr, // isolate create callback
613 nullptr // isolate shutdown callback
614 );
615
616 std::shared_ptr<DartIsolate> service_isolate = weak_service_isolate.lock();
617 if (!service_isolate) {
618 *error = fml::strdup("Could not create the service isolate.");
619 FML_DLOG(ERROR) << *error;
620 return nullptr;
621 }
622
623 tonic::DartState::Scope scope(service_isolate);
624 if (!DartServiceIsolate::Startup(
625 settings.observatory_host, // server IP address
626 settings.observatory_port, // server observatory port
627 tonic::DartState::HandleLibraryTag, // embedder library tag handler
628 false, // disable websocket origin check
629 settings.disable_service_auth_codes, // disable VM service auth codes
630 settings.enable_service_port_fallback, // enable fallback to port 0
631 // when bind fails.
632 error // error (out)
633 )) {
634 // Error is populated by call to startup.
635 FML_DLOG(ERROR) << *error;
636 return nullptr;
637 }
638
639 if (auto service_protocol = DartVMRef::GetServiceProtocol()) {
640 service_protocol->ToggleHooks(true);
641 } else {
642 FML_DLOG(ERROR)
643 << "Could not acquire the service protocol handlers. This might be "
644 "because the VM has already begun teardown on another thread.";
645 }
646
647 return service_isolate->isolate();
648}
649
650DartIsolateGroupData& DartIsolate::GetIsolateGroupData() {
651 std::shared_ptr<DartIsolateGroupData>* isolate_group_data =
652 static_cast<std::shared_ptr<DartIsolateGroupData>*>(
653 Dart_IsolateGroupData(isolate()));
654 return **isolate_group_data;
655}
656
657// |Dart_IsolateGroupCreateCallback|
658Dart_Isolate DartIsolate::DartIsolateGroupCreateCallback(
659 const char* advisory_script_uri,
660 const char* advisory_script_entrypoint,
661 const char* package_root,
662 const char* package_config,
663 Dart_IsolateFlags* flags,
664 std::shared_ptr<DartIsolate>* parent_isolate_data,
665 char** error) {
666 TRACE_EVENT0("flutter", "DartIsolate::DartIsolateGroupCreateCallback");
667 if (parent_isolate_data == nullptr &&
668 strcmp(advisory_script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0) {
669 // The VM attempts to start the VM service for us on |Dart_Initialize|. In
670 // such a case, the callback data will be null and the script URI will be
671 // DART_VM_SERVICE_ISOLATE_NAME. In such cases, we just create the service
672 // isolate like normal but dont hold a reference to it at all. We also start
673 // this isolate since we will never again reference it from the engine.
674 return DartCreateAndStartServiceIsolate(package_root, //
675 package_config, //
676 flags, //
677 error //
678 );
679 }
680
681 if (!parent_isolate_data) {
682 return nullptr;
683 }
684
685 DartIsolateGroupData& parent_group_data =
686 (*parent_isolate_data)->GetIsolateGroupData();
687
688 auto isolate_group_data =
689 std::make_unique<std::shared_ptr<DartIsolateGroupData>>(
690 std::shared_ptr<DartIsolateGroupData>(new DartIsolateGroupData(
691 parent_group_data.GetSettings(),
692 parent_group_data.GetIsolateSnapshot(), advisory_script_uri,
693 advisory_script_entrypoint,
694 parent_group_data.GetChildIsolatePreparer(),
695 parent_group_data.GetIsolateCreateCallback(),
696 parent_group_data.GetIsolateShutdownCallback())));
697
698 TaskRunners null_task_runners(advisory_script_uri,
699 /* platform= */ nullptr,
700 /* raster= */ nullptr,
701 /* ui= */ nullptr,
702 /* io= */ nullptr);
703
704 auto isolate_data = std::make_unique<std::shared_ptr<DartIsolate>>(
705 std::shared_ptr<DartIsolate>(new DartIsolate(
706 (*isolate_group_data)->GetSettings(), // settings
707 null_task_runners, // task_runners
708 fml::WeakPtr<SnapshotDelegate>{}, // snapshot_delegate
709 fml::WeakPtr<IOManager>{}, // io_manager
710 fml::RefPtr<SkiaUnrefQueue>{}, // unref_queue
711 fml::WeakPtr<ImageDecoder>{}, // image_decoder
712 advisory_script_uri, // advisory_script_uri
713 advisory_script_entrypoint, // advisory_script_entrypoint
714 false))); // is_root_isolate
715
716 Dart_Isolate vm_isolate = CreateDartIsolateGroup(
717 std::move(isolate_group_data), std::move(isolate_data), flags, error);
718
719 if (*error) {
720 FML_LOG(ERROR) << "CreateDartIsolateGroup failed: " << error;
721 }
722
723 return vm_isolate;
724}
725
726// |Dart_IsolateInitializeCallback|
727bool DartIsolate::DartIsolateInitializeCallback(void** child_callback_data,
728 char** error) {
729 TRACE_EVENT0("flutter", "DartIsolate::DartIsolateInitializeCallback");
730 Dart_Isolate isolate = Dart_CurrentIsolate();
731 if (isolate == nullptr) {
732 *error = fml::strdup("Isolate should be available in initialize callback.");
733 FML_DLOG(ERROR) << *error;
734 return false;
735 }
736
737 auto* isolate_group_data =
738 static_cast<std::shared_ptr<DartIsolateGroupData>*>(
739 Dart_CurrentIsolateGroupData());
740
741 TaskRunners null_task_runners((*isolate_group_data)->GetAdvisoryScriptURI(),
742 /* platform= */ nullptr,
743 /* raster= */ nullptr,
744 /* ui= */ nullptr,
745 /* io= */ nullptr);
746
747 auto embedder_isolate = std::make_unique<std::shared_ptr<DartIsolate>>(
748 std::shared_ptr<DartIsolate>(new DartIsolate(
749 (*isolate_group_data)->GetSettings(), // settings
750 null_task_runners, // task_runners
751 fml::WeakPtr<SnapshotDelegate>{}, // snapshot_delegate
752 fml::WeakPtr<IOManager>{}, // io_manager
753 fml::RefPtr<SkiaUnrefQueue>{}, // unref_queue
754 fml::WeakPtr<ImageDecoder>{}, // image_decoder
755 (*isolate_group_data)->GetAdvisoryScriptURI(), // advisory_script_uri
756 (*isolate_group_data)
757 ->GetAdvisoryScriptEntrypoint(), // advisory_script_entrypoint
758 false))); // is_root_isolate
759
760 // root isolate should have been created via CreateRootIsolate
761 if (!InitializeIsolate(*embedder_isolate, isolate, error)) {
762 return false;
763 }
764
765 // The ownership of the embedder object is controlled by the Dart VM. So the
766 // only reference returned to the caller is weak.
767 *child_callback_data = embedder_isolate.release();
768
769 Dart_EnterIsolate(isolate);
770 return true;
771}
772
773Dart_Isolate DartIsolate::CreateDartIsolateGroup(
774 std::unique_ptr<std::shared_ptr<DartIsolateGroupData>> isolate_group_data,
775 std::unique_ptr<std::shared_ptr<DartIsolate>> isolate_data,
776 Dart_IsolateFlags* flags,
777 char** error) {
778 TRACE_EVENT0("flutter", "DartIsolate::CreateDartIsolateGroup");
779
780 // Create the Dart VM isolate and give it the embedder object as the baton.
781 Dart_Isolate isolate = Dart_CreateIsolateGroup(
782 (*isolate_group_data)->GetAdvisoryScriptURI().c_str(),
783 (*isolate_group_data)->GetAdvisoryScriptEntrypoint().c_str(),
784 (*isolate_group_data)->GetIsolateSnapshot()->GetDataMapping(),
785 (*isolate_group_data)->GetIsolateSnapshot()->GetInstructionsMapping(),
786 flags, isolate_group_data.get(), isolate_data.get(), error);
787
788 if (isolate == nullptr) {
789 return nullptr;
790 }
791
792 // Ownership of the isolate data objects has been transferred to the Dart VM.
793 std::shared_ptr<DartIsolate> embedder_isolate(*isolate_data);
794 isolate_group_data.release();
795 isolate_data.release();
796
797 if (!InitializeIsolate(std::move(embedder_isolate), isolate, error)) {
798 return nullptr;
799 }
800
801 return isolate;
802}
803
804bool DartIsolate::InitializeIsolate(
805 std::shared_ptr<DartIsolate> embedder_isolate,
806 Dart_Isolate isolate,
807 char** error) {
808 TRACE_EVENT0("flutter", "DartIsolate::InitializeIsolate");
809 if (!embedder_isolate->Initialize(isolate)) {
810 *error = fml::strdup("Embedder could not initialize the Dart isolate.");
811 FML_DLOG(ERROR) << *error;
812 return false;
813 }
814
815 if (!embedder_isolate->LoadLibraries()) {
816 *error = fml::strdup(
817 "Embedder could not load libraries in the new Dart isolate.");
818 FML_DLOG(ERROR) << *error;
819 return false;
820 }
821
822 // Root isolates will be setup by the engine and the service isolate (which is
823 // also a root isolate) by the utility routines in the VM. However, secondary
824 // isolates will be run by the VM if they are marked as runnable.
825 if (!embedder_isolate->IsRootIsolate()) {
826 auto child_isolate_preparer =
827 embedder_isolate->GetIsolateGroupData().GetChildIsolatePreparer();
828 FML_DCHECK(child_isolate_preparer);
829 if (!child_isolate_preparer(embedder_isolate.get())) {
830 *error = fml::strdup("Could not prepare the child isolate to run.");
831 FML_DLOG(ERROR) << *error;
832 return false;
833 }
834 }
835
836 return true;
837}
838
839// |Dart_IsolateShutdownCallback|
840void DartIsolate::DartIsolateShutdownCallback(
841 std::shared_ptr<DartIsolateGroupData>* isolate_group_data,
842 std::shared_ptr<DartIsolate>* isolate_data) {
843 TRACE_EVENT0("flutter", "DartIsolate::DartIsolateShutdownCallback");
844 isolate_data->get()->OnShutdownCallback();
845}
846
847// |Dart_IsolateGroupCleanupCallback|
848void DartIsolate::DartIsolateGroupCleanupCallback(
849 std::shared_ptr<DartIsolateGroupData>* isolate_data) {
850 TRACE_EVENT0("flutter", "DartIsolate::DartIsolateGroupCleanupCallback");
851 delete isolate_data;
852}
853
854// |Dart_IsolateCleanupCallback|
855void DartIsolate::DartIsolateCleanupCallback(
856 std::shared_ptr<DartIsolateGroupData>* isolate_group_data,
857 std::shared_ptr<DartIsolate>* isolate_data) {
858 TRACE_EVENT0("flutter", "DartIsolate::DartIsolateCleanupCallback");
859 delete isolate_data;
860}
861
862std::weak_ptr<DartIsolate> DartIsolate::GetWeakIsolatePtr() {
863 return std::static_pointer_cast<DartIsolate>(shared_from_this());
864}
865
866void DartIsolate::AddIsolateShutdownCallback(const fml::closure& closure) {
867 shutdown_callbacks_.emplace_back(std::make_unique<AutoFireClosure>(closure));
868}
869
870void DartIsolate::OnShutdownCallback() {
871 {
872 tonic::DartApiScope api_scope;
873 Dart_Handle sticky_error = Dart_GetStickyError();
874 if (!Dart_IsNull(sticky_error) && !Dart_IsFatalError(sticky_error)) {
875 FML_LOG(ERROR) << Dart_GetError(sticky_error);
876 }
877 }
878
879 shutdown_callbacks_.clear();
880
881 const fml::closure& isolate_shutdown_callback =
882 GetIsolateGroupData().GetIsolateShutdownCallback();
883 if (isolate_shutdown_callback) {
884 isolate_shutdown_callback();
885 }
886}
887
888DartIsolate::AutoFireClosure::AutoFireClosure(const fml::closure& closure)
889 : closure_(closure) {}
890
891DartIsolate::AutoFireClosure::~AutoFireClosure() {
892 if (closure_) {
893 closure_();
894 }
895}
896
897} // namespace flutter
898