text: // 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),
        disable_http_(settings.disable_http) {
    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(disable_http_);
  
    DartUI::InitForIsolate();
  
    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
  