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 | |
32 | namespace flutter { |
33 | |
34 | namespace { |
35 | |
36 | class 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 | |
55 | std::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 | |
120 | DartIsolate::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 | |
148 | DartIsolate::~DartIsolate() { |
149 | if (IsRootIsolate() && GetMessageHandlingTaskRunner()) { |
150 | FML_DCHECK(GetMessageHandlingTaskRunner()->RunsTasksOnCurrentThread()); |
151 | } |
152 | } |
153 | |
154 | DartIsolate::Phase DartIsolate::GetPhase() const { |
155 | return phase_; |
156 | } |
157 | |
158 | std::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 | |
165 | bool 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 | |
205 | fml::RefPtr<fml::TaskRunner> DartIsolate::GetMessageHandlingTaskRunner() const { |
206 | return message_handling_task_runner_; |
207 | } |
208 | |
209 | void 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. |
224 | bool 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 | |
260 | bool 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 | |
287 | bool 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 | |
319 | bool 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 | |
438 | bool 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 | |
551 | bool 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 | |
574 | Dart_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 | |
650 | DartIsolateGroupData& 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| |
658 | Dart_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| |
727 | bool 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 | |
773 | Dart_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 | |
804 | bool 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| |
840 | void 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| |
848 | void DartIsolate::DartIsolateGroupCleanupCallback( |
849 | std::shared_ptr<DartIsolateGroupData>* isolate_data) { |
850 | TRACE_EVENT0("flutter" , "DartIsolate::DartIsolateGroupCleanupCallback" ); |
851 | delete isolate_data; |
852 | } |
853 | |
854 | // |Dart_IsolateCleanupCallback| |
855 | void 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 | |
862 | std::weak_ptr<DartIsolate> DartIsolate::GetWeakIsolatePtr() { |
863 | return std::static_pointer_cast<DartIsolate>(shared_from_this()); |
864 | } |
865 | |
866 | void DartIsolate::AddIsolateShutdownCallback(const fml::closure& closure) { |
867 | shutdown_callbacks_.emplace_back(std::make_unique<AutoFireClosure>(closure)); |
868 | } |
869 | |
870 | void 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 | |
888 | DartIsolate::AutoFireClosure::AutoFireClosure(const fml::closure& closure) |
889 | : closure_(closure) {} |
890 | |
891 | DartIsolate::AutoFireClosure::~AutoFireClosure() { |
892 | if (closure_) { |
893 | closure_(); |
894 | } |
895 | } |
896 | |
897 | } // namespace flutter |
898 | |