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