blob: c8d7940c7baed0b1d4df070c2f7a735b7df813a2 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/runtime/dart_isolate.h"
#include <cstdlib>
#include <tuple>
#include "flutter/fml/paths.h"
#include "flutter/fml/posix_wrappers.h"
#include "flutter/fml/trace_event.h"
#include "flutter/lib/io/dart_io.h"
#include "flutter/lib/ui/dart_runtime_hooks.h"
#include "flutter/lib/ui/dart_ui.h"
#include "flutter/runtime/dart_isolate_group_data.h"
#include "flutter/runtime/dart_service_isolate.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/runtime/dart_vm_lifecycle.h"
#include "third_party/dart/runtime/include/dart_api.h"
#include "third_party/dart/runtime/include/dart_tools_api.h"
#include "third_party/tonic/converter/dart_converter.h"
#include "third_party/tonic/dart_class_library.h"
#include "third_party/tonic/dart_class_provider.h"
#include "third_party/tonic/dart_message_handler.h"
#include "third_party/tonic/dart_state.h"
#include "third_party/tonic/file_loader/file_loader.h"
#include "third_party/tonic/logging/dart_invoke.h"
#include "third_party/tonic/scopes/dart_api_scope.h"
#include "third_party/tonic/scopes/dart_isolate_scope.h"
namespace flutter {
namespace {
class DartErrorString {
public:
DartErrorString() : str_(nullptr) {}
~DartErrorString() {
if (str_) {
::free(str_);
}
}
char** error() { return &str_; }
const char* str() const { return str_; }
operator bool() const { return str_ != nullptr; }
private:
FML_DISALLOW_COPY_AND_ASSIGN(DartErrorString);
char* str_;
};
} // anonymous namespace
std::weak_ptr<DartIsolate> DartIsolate::CreateRootIsolate(
const Settings& settings,
fml::RefPtr<const DartSnapshot> isolate_snapshot,
TaskRunners task_runners,
std::unique_ptr<Window> window,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<IOManager> io_manager,
fml::RefPtr<SkiaUnrefQueue> unref_queue,
fml::WeakPtr<ImageDecoder> image_decoder,
std::string advisory_script_uri,
std::string advisory_script_entrypoint,
Dart_IsolateFlags* flags,
const fml::closure& isolate_create_callback,
const fml::closure& isolate_shutdown_callback) {
TRACE_EVENT0("flutter", "DartIsolate::CreateRootIsolate");
// The child isolate preparer is null but will be set when the isolate is
// being prepared to run.
auto isolate_group_data =
std::make_unique<std::shared_ptr<DartIsolateGroupData>>(
std::shared_ptr<DartIsolateGroupData>(new DartIsolateGroupData(
settings, // settings
std::move(isolate_snapshot), // isolate snapshot
advisory_script_uri, // advisory URI
advisory_script_entrypoint, // advisory entrypoint
nullptr, // child isolate preparer
isolate_create_callback, // isolate create callback
isolate_shutdown_callback // isolate shutdown callback
)));
auto isolate_data = std::make_unique<std::shared_ptr<DartIsolate>>(
std::shared_ptr<DartIsolate>(new DartIsolate(
settings, // settings
task_runners, // task runners
std::move(snapshot_delegate), // snapshot delegate
std::move(io_manager), // IO manager
std::move(unref_queue), // Skia unref queue
std::move(image_decoder), // Image Decoder
advisory_script_uri, // advisory URI
advisory_script_entrypoint, // advisory entrypoint
true // is_root_isolate
)));
DartErrorString error;
Dart_Isolate vm_isolate =
CreateDartIsolateGroup(std::move(isolate_group_data),
std::move(isolate_data), flags, error.error());
if (error) {
FML_LOG(ERROR) << "CreateDartIsolateGroup failed: " << error.str();
}
if (vm_isolate == nullptr) {
return {};
}
std::shared_ptr<DartIsolate>* root_isolate_data =
static_cast<std::shared_ptr<DartIsolate>*>(Dart_IsolateData(vm_isolate));
(*root_isolate_data)->SetWindow(std::move(window));
return (*root_isolate_data)->GetWeakIsolatePtr();
}
DartIsolate::DartIsolate(const Settings& settings,
TaskRunners task_runners,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::WeakPtr<IOManager> io_manager,
fml::RefPtr<SkiaUnrefQueue> unref_queue,
fml::WeakPtr<ImageDecoder> image_decoder,
std::string advisory_script_uri,
std::string advisory_script_entrypoint,
bool is_root_isolate)
: UIDartState(std::move(task_runners),
settings.task_observer_add,
settings.task_observer_remove,
std::move(snapshot_delegate),
std::move(io_manager),
std::move(unref_queue),
std::move(image_decoder),
advisory_script_uri,
advisory_script_entrypoint,
settings.log_tag,
settings.unhandled_exception_callback,
DartVMRef::GetIsolateNameServer()),
is_root_isolate_(is_root_isolate) {
phase_ = Phase::Uninitialized;
}
DartIsolate::~DartIsolate() {
if (IsRootIsolate() && GetMessageHandlingTaskRunner()) {
FML_DCHECK(GetMessageHandlingTaskRunner()->RunsTasksOnCurrentThread());
}
}
DartIsolate::Phase DartIsolate::GetPhase() const {
return phase_;
}
std::string DartIsolate::GetServiceId() {
const char* service_id_buf = Dart_IsolateServiceId(isolate());
std::string service_id(service_id_buf);
free(const_cast<char*>(service_id_buf));
return service_id;
}
bool DartIsolate::Initialize(Dart_Isolate dart_isolate) {
TRACE_EVENT0("flutter", "DartIsolate::Initialize");
if (phase_ != Phase::Uninitialized) {
return false;
}
if (dart_isolate == nullptr) {
return false;
}
if (Dart_CurrentIsolate() != dart_isolate) {
return false;
}
// After this point, isolate scopes can be safely used.
SetIsolate(dart_isolate);
// We are entering a new scope (for the first time since initialization) and
// we want to restore the current scope to null when we exit out of this
// method. This balances the implicit Dart_EnterIsolate call made by
// Dart_CreateIsolateGroup (which calls the Initialize).
Dart_ExitIsolate();
tonic::DartIsolateScope scope(isolate());
SetMessageHandlingTaskRunner(GetTaskRunners().GetUITaskRunner());
if (tonic::LogIfError(
Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))) {
return false;
}
if (!UpdateThreadPoolNames()) {
return false;
}
phase_ = Phase::Initialized;
return true;
}
fml::RefPtr<fml::TaskRunner> DartIsolate::GetMessageHandlingTaskRunner() const {
return message_handling_task_runner_;
}
void DartIsolate::SetMessageHandlingTaskRunner(
fml::RefPtr<fml::TaskRunner> runner) {
if (!IsRootIsolate() || !runner) {
return;
}
message_handling_task_runner_ = runner;
message_handler().Initialize(
[runner](std::function<void()> task) { runner->PostTask(task); });
}
// Updating thread names here does not change the underlying OS thread names.
// Instead, this is just additional metadata for the Observatory to show the
// thread name of the isolate.
bool DartIsolate::UpdateThreadPoolNames() const {
// TODO(chinmaygarde): This implementation does not account for multiple
// shells sharing the same (or subset of) threads.
const auto& task_runners = GetTaskRunners();
if (auto task_runner = task_runners.GetRasterTaskRunner()) {
task_runner->PostTask(
[label = task_runners.GetLabel() + std::string{".raster"}]() {
Dart_SetThreadName(label.c_str());
});
}
if (auto task_runner = task_runners.GetUITaskRunner()) {
task_runner->PostTask(
[label = task_runners.GetLabel() + std::string{".ui"}]() {
Dart_SetThreadName(label.c_str());
});
}
if (auto task_runner = task_runners.GetIOTaskRunner()) {
task_runner->PostTask(
[label = task_runners.GetLabel() + std::string{".io"}]() {
Dart_SetThreadName(label.c_str());
});
}
if (auto task_runner = task_runners.GetPlatformTaskRunner()) {
task_runner->PostTask(
[label = task_runners.GetLabel() + std::string{".platform"}]() {
Dart_SetThreadName(label.c_str());
});
}
return true;
}
bool DartIsolate::LoadLibraries() {
TRACE_EVENT0("flutter", "DartIsolate::LoadLibraries");
if (phase_ != Phase::Initialized) {
return false;
}
tonic::DartState::Scope scope(this);
DartIO::InitForIsolate();
DartUI::InitForIsolate(IsRootIsolate());
const bool is_service_isolate = Dart_IsServiceIsolate(isolate());
DartRuntimeHooks::Install(IsRootIsolate() && !is_service_isolate,
GetAdvisoryScriptURI());
if (!is_service_isolate) {
class_library().add_provider(
"ui", std::make_unique<tonic::DartClassProvider>(this, "dart:ui"));
}
phase_ = Phase::LibrariesSetup;
return true;
}
bool DartIsolate::PrepareForRunningFromPrecompiledCode() {
TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromPrecompiledCode");
if (phase_ != Phase::LibrariesSetup) {
return false;
}
tonic::DartState::Scope scope(this);
if (Dart_IsNull(Dart_RootLibrary())) {
return false;
}
if (!MarkIsolateRunnable()) {
return false;
}
if (GetIsolateGroupData().GetChildIsolatePreparer() == nullptr) {
GetIsolateGroupData().SetChildIsolatePreparer([](DartIsolate* isolate) {
return isolate->PrepareForRunningFromPrecompiledCode();
});
}
const fml::closure& isolate_create_callback =
GetIsolateGroupData().GetIsolateCreateCallback();
if (isolate_create_callback) {
isolate_create_callback();
}
phase_ = Phase::Ready;
return true;
}
bool DartIsolate::LoadKernel(std::shared_ptr<const fml::Mapping> mapping,
bool last_piece) {
if (!Dart_IsKernel(mapping->GetMapping(), mapping->GetSize())) {
return false;
}
// Mapping must be retained until isolate shutdown.
kernel_buffers_.push_back(mapping);
Dart_Handle library =
Dart_LoadLibraryFromKernel(mapping->GetMapping(), mapping->GetSize());
if (tonic::LogIfError(library)) {
return false;
}
if (!last_piece) {
// More to come.
return true;
}
Dart_SetRootLibrary(library);
if (tonic::LogIfError(Dart_FinalizeLoading(false))) {
return false;
}
return true;
}
[[nodiscard]] bool DartIsolate::PrepareForRunningFromKernel(
std::shared_ptr<const fml::Mapping> mapping,
bool last_piece) {
TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromKernel");
if (phase_ != Phase::LibrariesSetup) {
return false;
}
if (DartVM::IsRunningPrecompiledCode()) {
return false;
}
if (!mapping || mapping->GetSize() == 0) {
return false;
}
tonic::DartState::Scope scope(this);
// Use root library provided by kernel in favor of one provided by snapshot.
Dart_SetRootLibrary(Dart_Null());
if (!LoadKernel(mapping, last_piece)) {
return false;
}
if (!last_piece) {
// More to come.
return true;
}
if (Dart_IsNull(Dart_RootLibrary())) {
return false;
}
if (!MarkIsolateRunnable()) {
return false;
}
// Child isolate shares root isolate embedder_isolate (lines 691 and 693
// below). Re-initializing child_isolate_preparer_ lambda while it is being
// executed leads to crashes.
if (GetIsolateGroupData().GetChildIsolatePreparer() == nullptr) {
GetIsolateGroupData().SetChildIsolatePreparer(
[buffers = kernel_buffers_](DartIsolate* isolate) {
for (unsigned long i = 0; i < buffers.size(); i++) {
bool last_piece = i + 1 == buffers.size();
const std::shared_ptr<const fml::Mapping>& buffer = buffers.at(i);
if (!isolate->PrepareForRunningFromKernel(buffer, last_piece)) {
return false;
}
}
return true;
});
}
const fml::closure& isolate_create_callback =
GetIsolateGroupData().GetIsolateCreateCallback();
if (isolate_create_callback) {
isolate_create_callback();
}
phase_ = Phase::Ready;
return true;
}
[[nodiscard]] bool DartIsolate::PrepareForRunningFromKernels(
std::vector<std::shared_ptr<const fml::Mapping>> kernels) {
const auto count = kernels.size();
if (count == 0) {
return false;
}
for (size_t i = 0; i < count; ++i) {
bool last = (i == (count - 1));
if (!PrepareForRunningFromKernel(kernels[i], last)) {
return false;
}
}
return true;
}
[[nodiscard]] bool DartIsolate::PrepareForRunningFromKernels(
std::vector<std::unique_ptr<const fml::Mapping>> kernels) {
std::vector<std::shared_ptr<const fml::Mapping>> shared_kernels;
for (auto& kernel : kernels) {
shared_kernels.emplace_back(std::move(kernel));
}
return PrepareForRunningFromKernels(shared_kernels);
}
bool DartIsolate::MarkIsolateRunnable() {
TRACE_EVENT0("flutter", "DartIsolate::MarkIsolateRunnable");
if (phase_ != Phase::LibrariesSetup) {
return false;
}
// This function may only be called from an active isolate scope.
if (Dart_CurrentIsolate() != isolate()) {
return false;
}
// There must be no current isolate to mark an isolate as being runnable.
Dart_ExitIsolate();
char* error = Dart_IsolateMakeRunnable(isolate());
if (error) {
FML_DLOG(ERROR) << error;
::free(error);
// Failed. Restore the isolate.
Dart_EnterIsolate(isolate());
return false;
}
// Success. Restore the isolate.
Dart_EnterIsolate(isolate());
return true;
}
[[nodiscard]] static bool InvokeMainEntrypoint(
Dart_Handle user_entrypoint_function,
Dart_Handle args) {
if (tonic::LogIfError(user_entrypoint_function)) {
FML_LOG(ERROR) << "Could not resolve main entrypoint function.";
return false;
}
Dart_Handle start_main_isolate_function =
tonic::DartInvokeField(Dart_LookupLibrary(tonic::ToDart("dart:isolate")),
"_getStartMainIsolateFunction", {});
if (tonic::LogIfError(start_main_isolate_function)) {
FML_LOG(ERROR) << "Could not resolve main entrypoint trampoline.";
return false;
}
if (tonic::LogIfError(tonic::DartInvokeField(
Dart_LookupLibrary(tonic::ToDart("dart:ui")), "_runMainZoned",
{start_main_isolate_function, user_entrypoint_function, args}))) {
FML_LOG(ERROR) << "Could not invoke the main entrypoint.";
return false;
}
return true;
}
/// @note Procedure doesn't copy all closures.
[[nodiscard]] bool DartIsolate::Run(const std::string& entrypoint_name,
const std::vector<std::string>& args,
const fml::closure& on_run) {
TRACE_EVENT0("flutter", "DartIsolate::Run");
if (phase_ != Phase::Ready) {
return false;
}
tonic::DartState::Scope scope(this);
auto user_entrypoint_function =
Dart_GetField(Dart_RootLibrary(), tonic::ToDart(entrypoint_name.c_str()));
auto entrypoint_args = tonic::ToDart(args);
if (!InvokeMainEntrypoint(user_entrypoint_function, entrypoint_args)) {
return false;
}
phase_ = Phase::Running;
if (on_run) {
on_run();
}
return true;
}
/// @note Procedure doesn't copy all closures.
[[nodiscard]] bool DartIsolate::RunFromLibrary(
const std::string& library_name,
const std::string& entrypoint_name,
const std::vector<std::string>& args,
const fml::closure& on_run) {
TRACE_EVENT0("flutter", "DartIsolate::RunFromLibrary");
if (phase_ != Phase::Ready) {
return false;
}
tonic::DartState::Scope scope(this);
auto user_entrypoint_function =
Dart_GetField(Dart_LookupLibrary(tonic::ToDart(library_name.c_str())),
tonic::ToDart(entrypoint_name.c_str()));
auto entrypoint_args = tonic::ToDart(args);
if (!InvokeMainEntrypoint(user_entrypoint_function, entrypoint_args)) {
return false;
}
phase_ = Phase::Running;
if (on_run) {
on_run();
}
return true;
}
bool DartIsolate::Shutdown() {
TRACE_EVENT0("flutter", "DartIsolate::Shutdown");
// This call may be re-entrant since Dart_ShutdownIsolate can invoke the
// cleanup callback which deletes the embedder side object of the dart isolate
// (a.k.a. this).
if (phase_ == Phase::Shutdown) {
return false;
}
phase_ = Phase::Shutdown;
Dart_Isolate vm_isolate = isolate();
// The isolate can be nullptr if this instance is the stub isolate data used
// during root isolate creation.
if (vm_isolate != nullptr) {
// We need to enter the isolate because Dart_ShutdownIsolate does not take
// the isolate to shutdown as a parameter.
FML_DCHECK(Dart_CurrentIsolate() == nullptr);
Dart_EnterIsolate(vm_isolate);
Dart_ShutdownIsolate();
FML_DCHECK(Dart_CurrentIsolate() == nullptr);
}
return true;
}
Dart_Isolate DartIsolate::DartCreateAndStartServiceIsolate(
const char* package_root,
const char* package_config,
Dart_IsolateFlags* flags,
char** error) {
auto vm_data = DartVMRef::GetVMData();
if (!vm_data) {
*error = fml::strdup(
"Could not access VM data to initialize isolates. This may be because "
"the VM has initialized shutdown on another thread already.");
return nullptr;
}
const auto& settings = vm_data->GetSettings();
if (!settings.enable_observatory) {
return nullptr;
}
TaskRunners null_task_runners("io.flutter." DART_VM_SERVICE_ISOLATE_NAME,
nullptr, nullptr, nullptr, nullptr);
flags->load_vmservice_library = true;
std::weak_ptr<DartIsolate> weak_service_isolate =
DartIsolate::CreateRootIsolate(
vm_data->GetSettings(), // settings
vm_data->GetIsolateSnapshot(), // isolate snapshot
null_task_runners, // task runners
nullptr, // window
{}, // snapshot delegate
{}, // IO Manager
{}, // Skia unref queue
{}, // Image Decoder
DART_VM_SERVICE_ISOLATE_NAME, // script uri
DART_VM_SERVICE_ISOLATE_NAME, // script entrypoint
flags, // flags
nullptr, // isolate create callback
nullptr // isolate shutdown callback
);
std::shared_ptr<DartIsolate> service_isolate = weak_service_isolate.lock();
if (!service_isolate) {
*error = fml::strdup("Could not create the service isolate.");
FML_DLOG(ERROR) << *error;
return nullptr;
}
tonic::DartState::Scope scope(service_isolate);
if (!DartServiceIsolate::Startup(
settings.observatory_host, // server IP address
settings.observatory_port, // server observatory port
tonic::DartState::HandleLibraryTag, // embedder library tag handler
false, // disable websocket origin check
settings.disable_service_auth_codes, // disable VM service auth codes
settings.enable_service_port_fallback, // enable fallback to port 0
// when bind fails.
error // error (out)
)) {
// Error is populated by call to startup.
FML_DLOG(ERROR) << *error;
return nullptr;
}
if (auto service_protocol = DartVMRef::GetServiceProtocol()) {
service_protocol->ToggleHooks(true);
} else {
FML_DLOG(ERROR)
<< "Could not acquire the service protocol handlers. This might be "
"because the VM has already begun teardown on another thread.";
}
return service_isolate->isolate();
}
DartIsolateGroupData& DartIsolate::GetIsolateGroupData() {
std::shared_ptr<DartIsolateGroupData>* isolate_group_data =
static_cast<std::shared_ptr<DartIsolateGroupData>*>(
Dart_IsolateGroupData(isolate()));
return **isolate_group_data;
}
// |Dart_IsolateGroupCreateCallback|
Dart_Isolate DartIsolate::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_isolate_data,
char** error) {
TRACE_EVENT0("flutter", "DartIsolate::DartIsolateGroupCreateCallback");
if (parent_isolate_data == nullptr &&
strcmp(advisory_script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0) {
// The VM attempts to start the VM service for us on |Dart_Initialize|. In
// such a case, the callback data will be null and the script URI will be
// DART_VM_SERVICE_ISOLATE_NAME. In such cases, we just create the service
// isolate like normal but dont hold a reference to it at all. We also start
// this isolate since we will never again reference it from the engine.
return DartCreateAndStartServiceIsolate(package_root, //
package_config, //
flags, //
error //
);
}
DartIsolateGroupData& parent_group_data =
(*parent_isolate_data)->GetIsolateGroupData();
auto isolate_group_data =
std::make_unique<std::shared_ptr<DartIsolateGroupData>>(
std::shared_ptr<DartIsolateGroupData>(new DartIsolateGroupData(
parent_group_data.GetSettings(),
parent_group_data.GetIsolateSnapshot(), advisory_script_uri,
advisory_script_entrypoint,
parent_group_data.GetChildIsolatePreparer(),
parent_group_data.GetIsolateCreateCallback(),
parent_group_data.GetIsolateShutdownCallback())));
TaskRunners null_task_runners(advisory_script_uri,
/* platform= */ nullptr, /* raster= */ nullptr,
/* ui= */ nullptr,
/* io= */ nullptr);
auto isolate_data = std::make_unique<std::shared_ptr<DartIsolate>>(
std::shared_ptr<DartIsolate>(new DartIsolate(
(*isolate_group_data)->GetSettings(), // settings
null_task_runners, // task_runners
fml::WeakPtr<SnapshotDelegate>{}, // snapshot_delegate
fml::WeakPtr<IOManager>{}, // io_manager
fml::RefPtr<SkiaUnrefQueue>{}, // unref_queue
fml::WeakPtr<ImageDecoder>{}, // image_decoder
advisory_script_uri, // advisory_script_uri
advisory_script_entrypoint, // advisory_script_entrypoint
false))); // is_root_isolate
Dart_Isolate vm_isolate = CreateDartIsolateGroup(
std::move(isolate_group_data), std::move(isolate_data), flags, error);
if (*error) {
FML_LOG(ERROR) << "CreateDartIsolateGroup failed: " << error;
}
return vm_isolate;
}
// |Dart_IsolateInitializeCallback|
bool DartIsolate::DartIsolateInitializeCallback(void** child_callback_data,
char** error) {
TRACE_EVENT0("flutter", "DartIsolate::DartIsolateInitializeCallback");
Dart_Isolate isolate = Dart_CurrentIsolate();
if (isolate == nullptr) {
*error = fml::strdup("Isolate should be available in initialize callback.");
FML_DLOG(ERROR) << *error;
return false;
}
auto* isolate_group_data =
static_cast<std::shared_ptr<DartIsolateGroupData>*>(
Dart_CurrentIsolateGroupData());
TaskRunners null_task_runners((*isolate_group_data)->GetAdvisoryScriptURI(),
/* platform= */ nullptr, /* raster= */ nullptr,
/* ui= */ nullptr,
/* io= */ nullptr);
auto embedder_isolate = std::make_unique<std::shared_ptr<DartIsolate>>(
std::shared_ptr<DartIsolate>(new DartIsolate(
(*isolate_group_data)->GetSettings(), // settings
null_task_runners, // task_runners
fml::WeakPtr<SnapshotDelegate>{}, // snapshot_delegate
fml::WeakPtr<IOManager>{}, // io_manager
fml::RefPtr<SkiaUnrefQueue>{}, // unref_queue
fml::WeakPtr<ImageDecoder>{}, // image_decoder
(*isolate_group_data)->GetAdvisoryScriptURI(), // advisory_script_uri
(*isolate_group_data)
->GetAdvisoryScriptEntrypoint(), // advisory_script_entrypoint
false))); // is_root_isolate
// root isolate should have been created via CreateRootIsolate
if (!InitializeIsolate(*embedder_isolate, isolate, error)) {
return false;
}
// The ownership of the embedder object is controlled by the Dart VM. So the
// only reference returned to the caller is weak.
*child_callback_data = embedder_isolate.release();
Dart_EnterIsolate(isolate);
return true;
}
Dart_Isolate DartIsolate::CreateDartIsolateGroup(
std::unique_ptr<std::shared_ptr<DartIsolateGroupData>> isolate_group_data,
std::unique_ptr<std::shared_ptr<DartIsolate>> isolate_data,
Dart_IsolateFlags* flags,
char** error) {
TRACE_EVENT0("flutter", "DartIsolate::CreateDartIsolateGroup");
// Create the Dart VM isolate and give it the embedder object as the baton.
Dart_Isolate isolate = Dart_CreateIsolateGroup(
(*isolate_group_data)->GetAdvisoryScriptURI().c_str(),
(*isolate_group_data)->GetAdvisoryScriptEntrypoint().c_str(),
(*isolate_group_data)->GetIsolateSnapshot()->GetDataMapping(),
(*isolate_group_data)->GetIsolateSnapshot()->GetInstructionsMapping(),
flags, isolate_group_data.get(), isolate_data.get(), error);
if (isolate == nullptr) {
return nullptr;
}
// Ownership of the isolate data objects has been transferred to the Dart VM.
std::shared_ptr<DartIsolate> embedder_isolate(*isolate_data);
isolate_group_data.release();
isolate_data.release();
if (!InitializeIsolate(std::move(embedder_isolate), isolate, error)) {
return nullptr;
}
return isolate;
}
bool DartIsolate::InitializeIsolate(
std::shared_ptr<DartIsolate> embedder_isolate,
Dart_Isolate isolate,
char** error) {
TRACE_EVENT0("flutter", "DartIsolate::InitializeIsolate");
if (!embedder_isolate->Initialize(isolate)) {
*error = fml::strdup("Embedder could not initialize the Dart isolate.");
FML_DLOG(ERROR) << *error;
return false;
}
if (!embedder_isolate->LoadLibraries()) {
*error = fml::strdup(
"Embedder could not load libraries in the new Dart isolate.");
FML_DLOG(ERROR) << *error;
return false;
}
// Root isolates will be setup by the engine and the service isolate (which is
// also a root isolate) by the utility routines in the VM. However, secondary
// isolates will be run by the VM if they are marked as runnable.
if (!embedder_isolate->IsRootIsolate()) {
auto child_isolate_preparer =
embedder_isolate->GetIsolateGroupData().GetChildIsolatePreparer();
FML_DCHECK(child_isolate_preparer);
if (!child_isolate_preparer(embedder_isolate.get())) {
*error = fml::strdup("Could not prepare the child isolate to run.");
FML_DLOG(ERROR) << *error;
return false;
}
}
return true;
}
// |Dart_IsolateShutdownCallback|
void DartIsolate::DartIsolateShutdownCallback(
std::shared_ptr<DartIsolateGroupData>* isolate_group_data,
std::shared_ptr<DartIsolate>* isolate_data) {
TRACE_EVENT0("flutter", "DartIsolate::DartIsolateShutdownCallback");
isolate_data->get()->OnShutdownCallback();
}
// |Dart_IsolateGroupCleanupCallback|
void DartIsolate::DartIsolateGroupCleanupCallback(
std::shared_ptr<DartIsolateGroupData>* isolate_data) {
TRACE_EVENT0("flutter", "DartIsolate::DartIsolateGroupCleanupCallback");
delete isolate_data;
}
// |Dart_IsolateCleanupCallback|
void DartIsolate::DartIsolateCleanupCallback(
std::shared_ptr<DartIsolateGroupData>* isolate_group_data,
std::shared_ptr<DartIsolate>* isolate_data) {
TRACE_EVENT0("flutter", "DartIsolate::DartIsolateCleanupCallback");
delete isolate_data;
}
std::weak_ptr<DartIsolate> DartIsolate::GetWeakIsolatePtr() {
return std::static_pointer_cast<DartIsolate>(shared_from_this());
}
void DartIsolate::AddIsolateShutdownCallback(const fml::closure& closure) {
shutdown_callbacks_.emplace_back(std::make_unique<AutoFireClosure>(closure));
}
void DartIsolate::OnShutdownCallback() {
{
tonic::DartApiScope api_scope;
Dart_Handle sticky_error = Dart_GetStickyError();
if (!Dart_IsNull(sticky_error) && !Dart_IsFatalError(sticky_error)) {
FML_LOG(ERROR) << Dart_GetError(sticky_error);
}
}
shutdown_callbacks_.clear();
const fml::closure& isolate_shutdown_callback =
GetIsolateGroupData().GetIsolateShutdownCallback();
if (isolate_shutdown_callback) {
isolate_shutdown_callback();
}
}
DartIsolate::AutoFireClosure::AutoFireClosure(const fml::closure& closure)
: closure_(closure) {}
DartIsolate::AutoFireClosure::~AutoFireClosure() {
if (closure_) {
closure_();
}
}
} // namespace flutter