• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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