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.
  
  #ifndef FLUTTER_RUNTIME_DART_ISOLATE_H_
  #define FLUTTER_RUNTIME_DART_ISOLATE_H_
  
  #include <memory>
  #include <optional>
  #include <set>
  #include <string>
  
  #include "flutter/common/task_runners.h"
  #include "flutter/fml/compiler_specific.h"
  #include "flutter/fml/macros.h"
  #include "flutter/fml/mapping.h"
  #include "flutter/lib/ui/hint_freed_delegate.h"
  #include "flutter/lib/ui/io_manager.h"
  #include "flutter/lib/ui/snapshot_delegate.h"
  #include "flutter/lib/ui/ui_dart_state.h"
  #include "flutter/lib/ui/window/platform_configuration.h"
  #include "flutter/runtime/dart_snapshot.h"
  #include "third_party/dart/runtime/include/dart_api.h"
  #include "third_party/tonic/dart_state.h"
  
  namespace flutter {
  
  class DartVM;
  class DartIsolateGroupData;
  class IsolateConfiguration;
  
  //------------------------------------------------------------------------------
  /// @brief      Represents an instance of a live isolate. An isolate is a
  ///             separate Dart execution context. Different Dart isolates don't
  ///             share memory and can be scheduled concurrently by the Dart VM on
  ///             one of the Dart VM managed worker pool threads.
  ///
  ///             The entire lifecycle of a Dart isolate is controlled by the Dart
  ///             VM. Because of this, the engine never holds a strong pointer to
  ///             the Dart VM for extended periods of time. This allows the VM (or
  ///             the isolates themselves) to terminate Dart execution without
  ///             consulting the engine.
  ///
  ///             The isolate that the engine creates to act as the host for the
  ///             Flutter application code with UI bindings is called the root
  ///             isolate.
  ///
  ///             The root isolate is special in the following ways:
  ///             * The root isolate forms a new isolate group. Child isolates are
  ///               added to their parents groups. When the root isolate dies, all
  ///               isolates in its group are terminated.
  ///             * Only root isolates get UI bindings.
  ///             * Root isolates execute their code on engine managed threads.
  ///               All other isolates run their Dart code on Dart VM managed
  ///               thread pool workers that the engine has no control over.
  ///             * Since the engine does not know the thread on which non-root
  ///               isolates are run, the engine has no opportunity to get a
  ///               reference to non-root isolates. Such isolates can only be
  ///               terminated if they terminate themselves or their isolate group
  ///               is torn down.
  ///
  class DartIsolate : public UIDartState {
   public:
    class Flags {
     public:
      Flags();
  
      explicit Flags(const Dart_IsolateFlags* flags);
  
      ~Flags();
  
      void SetNullSafetyEnabled(bool enabled);
  
      Dart_IsolateFlags Get() const;
  
     private:
      Dart_IsolateFlags flags_;
    };
  
    //----------------------------------------------------------------------------
    /// @brief      The engine represents all dart isolates as being in one of the
    ///             known phases. By invoking various methods on the Dart isolate,
    ///             the engine transition the Dart isolate from one phase to the
    ///             next. The Dart isolate will only move from one phase to the
    ///             next in the order specified in the `DartIsolate::Phase` enum.
    ///             That is, once the isolate has moved out of a particular phase,
    ///             it can never transition back to that phase in the future.
    ///             There is no error recovery mechanism and callers that find
    ///             their isolates in an undesirable phase must discard the
    ///             isolate and start over.
    ///
    enum class Phase {
      //--------------------------------------------------------------------------
      /// The initial phase of all Dart isolates. This is an internal phase and
      /// callers can never get a reference to a Dart isolate in this phase.
      ///
      Unknown,
      //--------------------------------------------------------------------------
      /// The Dart isolate has been created but none of the library tag or message
      /// handers have been set yet. The is an internal phase and callers can
      /// never get a reference to a Dart isolate in this phase.
      ///
      Uninitialized,
      //--------------------------------------------------------------------------
      /// The Dart isolate has been been fully initialized but none of the
      /// libraries referenced by that isolate have been loaded yet. This is an
      /// internal phase and callers can never get a reference to a Dart isolate
      /// in this phase.
      ///
      Initialized,
      //--------------------------------------------------------------------------
      /// The isolate has been fully initialized and is waiting for the caller to
      /// associate isolate snapshots with the same. The isolate will only be
      /// ready to execute Dart code once one of the `Prepare` calls are
      /// successfully made.
      ///
      LibrariesSetup,
      //--------------------------------------------------------------------------
      /// The isolate is fully ready to start running Dart code. Callers can
      /// transition the isolate to the next state by calling the `Run` or
      /// `RunFromLibrary` methods.
      ///
      Ready,
      //--------------------------------------------------------------------------
      /// The isolate is currently running Dart code.
      ///
      Running,
      //--------------------------------------------------------------------------
      /// The isolate is no longer running Dart code and is in the middle of being
      /// collected. This is in internal phase and callers can never get a
      /// reference to a Dart isolate in this phase.
      ///
      Shutdown,
    };
  
    //----------------------------------------------------------------------------
    /// @brief      Creates an instance of a root isolate and returns a weak
    ///             pointer to the same. The isolate instance may only be used
    ///             safely on the engine thread on which it was created. In the
    ///             shell, this is the UI thread and task runner. Using the
    ///             isolate on any other thread is user error.
    ///
    ///             The isolate that the engine creates to act as the host for the
    ///             Flutter application code with UI bindings is called the root
    ///             isolate.
    ///
    ///             The root isolate is special in the following ways:
    ///             * The root isolate forms a new isolate group. Child isolates
    ///               are added to their parents groups. When the root isolate
    ///               dies, all isolates in its group are terminated.
    ///             * Only root isolates get UI bindings.
    ///             * Root isolates execute their code on engine managed threads.
    ///               All other isolates run their Dart code on Dart VM managed
    ///               thread pool workers that the engine has no control over.
    ///             * Since the engine does not know the thread on which non-root
    ///               isolates are run, the engine has no opportunity to get a
    ///               reference to non-root isolates. Such isolates can only be
    ///               terminated if they terminate themselves or their isolate
    ///               group is torn down.
    ///
    /// @param[in]  settings                    The settings used to create the
    ///                                         isolate.
    /// @param[in]  isolate_snapshot            The isolate snapshot. This is
    ///                                         usually obtained from the
    ///                                         DartVMData associated with the
    ///                                         running Dart VM instance.
    /// @param[in]  task_runners                The task runners used by the
    ///                                         isolate. Via UI bindings, the
    ///                                         isolate will use the IO task
    ///                                         runner to scheduled texture
    ///                                         decompression jobs and post tasks
    ///                                         back to the UI task runner.
    /// @param[in]  window                      The weak pointer to the window
    ///                                         associated with this root isolate.
    /// @param[in]  io_manager                  The i/o manager.
    /// @param[in]  unref_queue                 The Skia unref queue.
    /// @param[in]  image_decoder               The image decoder.
    /// @param[in]  advisory_script_uri         The advisory script uri. This is
    ///                                         only used in instrumentation.
    /// @param[in]  advisory_script_entrypoint  The advisory script entrypoint.
    ///                                         This is only used in
    ///                                         instrumentation. Notably, this is
    ///                                         NOT the main entrypoint of Dart
    ///                                         code in the isolate. That is
    ///                                         specified when making one of the
    ///                                         `Run` calls.
    /// @param[in]  flags                       The Dart isolate flags for this
    ///                                         isolate instance.
    /// @param[in]  isolate_create_callback     The isolate create callback. This
    ///                                         will be called when the before the
    ///                                         main Dart entrypoint is invoked in
    ///                                         the root isolate. The isolate is
    ///                                         already in the running state at
    ///                                         this point and an isolate scope is
    ///                                         current. This callback is made for
    ///                                         all isolate launches (including
    ///                                         the children of the root isolate).
    /// @param[in]  isolate_shutdown_callback   The isolate shutdown callback.
    ///                                         This will be called before the
    ///                                         isolate is about to transition
    ///                                         into the Shutdown phase. The
    ///                                         isolate is still running at this
    ///                                         point and an isolate scope is
    ///                                         current.  This callback is made
    ///                                         for all isolate shutdowns
    ///                                         (including the children of the
    ///                                         root isolate).
    ///
    /// @return     A weak pointer to the root Dart isolate. The caller must
    ///             ensure that the isolate is not referenced for long periods of
    ///             time as it prevents isolate collection when the isolate
    ///             terminates itself. The caller may also only use the isolate on
    ///             the thread on which the isolate was created.
    ///
    static std::weak_ptr<DartIsolate> CreateRunningRootIsolate(
        const Settings& settings,
        fml::RefPtr<const DartSnapshot> isolate_snapshot,
        TaskRunners task_runners,
        std::unique_ptr<PlatformConfiguration> platform_configuration,
        fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
        fml::WeakPtr<HintFreedDelegate> hint_freed_delegate,
        fml::WeakPtr<IOManager> io_manager,
        fml::RefPtr<SkiaUnrefQueue> skia_unref_queue,
        fml::WeakPtr<ImageDecoder> image_decoder,
        std::string advisory_script_uri,
        std::string advisory_script_entrypoint,
        Flags flags,
        const fml::closure& isolate_create_callback,
        const fml::closure& isolate_shutdown_callback,
        std::optional<std::string> dart_entrypoint,
        std::optional<std::string> dart_entrypoint_library,
        std::unique_ptr<IsolateConfiguration> isolate_configration);
  
    // |UIDartState|
    ~DartIsolate() override;
  
    //----------------------------------------------------------------------------
    /// @brief      The current phase of the isolate. The engine represents all
    ///             dart isolates as being in one of the known phases. By invoking
    ///             various methods on the Dart isolate, the engine transitions
    ///             the Dart isolate from one phase to the next. The Dart isolate
    ///             will only move from one phase to the next in the order
    ///             specified in the `DartIsolate::Phase` enum. That is, the once
    ///             the isolate has moved out of a particular phase, it can never
    ///             transition back to that phase in the future. There is no error
    ///             recovery mechanism and callers that find their isolates in an
    ///             undesirable phase must discard the isolate and start over.
    ///
    /// @return     The current isolate phase.
    ///
    Phase GetPhase() const;
  
    //----------------------------------------------------------------------------
    /// @brief      Returns the ID for an isolate which is used to query the
    ///             service protocol.
    ///
    /// @return     The service identifier for this isolate.
    ///
    std::string GetServiceId();
  
    //----------------------------------------------------------------------------
    /// @brief      Prepare the isolate for running for a precompiled code bundle.
    ///             The Dart VM must be configured for running precompiled code.
    ///
    ///             The isolate must already be in the `Phase::LibrariesSetup`
    ///             phase. After a successful call to this method, the isolate
    ///             will transition to the `Phase::Ready` phase.
    ///
    /// @return     Whether the isolate was prepared and the described phase
    ///             transition made.
    ///
    [[nodiscard]] bool PrepareForRunningFromPrecompiledCode();
  
    //----------------------------------------------------------------------------
    /// @brief      Prepare the isolate for running for a a list of kernel files.
    ///
    ///             The Dart VM must be configured for running from kernel
    ///             snapshots.
    ///
    ///             The isolate must already be in the `Phase::LibrariesSetup`
    ///             phase. This call can be made multiple times. After a series of
    ///             successful calls to this method, the caller can specify the
    ///             last kernel file mapping by specifying `last_piece` to `true`.
    ///             On success, the isolate will transition to the `Phase::Ready`
    ///             phase.
    ///
    /// @param[in]  kernel      The kernel mapping.
    /// @param[in]  last_piece  Indicates if this is the last kernel mapping
    ///                         expected. After this point, the isolate will
    ///                         attempt a transition to the `Phase::Ready` phase.
    ///
    /// @return     If the kernel mapping supplied was successfully used to
    ///             prepare the isolate.
    ///
    [[nodiscard]] bool PrepareForRunningFromKernel(
        std::shared_ptr<const fml::Mapping> kernel,
        bool last_piece = true);
  
    //----------------------------------------------------------------------------
    /// @brief      Prepare the isolate for running for a a list of kernel files.
    ///
    ///             The Dart VM must be configured for running from kernel
    ///             snapshots.
    ///
    ///             The isolate must already be in the `Phase::LibrariesSetup`
    ///             phase. After a successful call to this method, the isolate
    ///             will transition to the `Phase::Ready` phase.
    ///
    /// @param[in]  kernels  The kernels
    ///
    /// @return     If the kernel mappings supplied were successfully used to
    ///             prepare the isolate.
    ///
    [[nodiscard]] bool PrepareForRunningFromKernels(
        std::vector<std::shared_ptr<const fml::Mapping>> kernels);
  
    //----------------------------------------------------------------------------
    /// @brief      Prepare the isolate for running for a a list of kernel files.
    ///
    ///             The Dart VM must be configured for running from kernel
    ///             snapshots.
    ///
    ///             The isolate must already be in the `Phase::LibrariesSetup`
    ///             phase. After a successful call to this method, the isolate
    ///             will transition to the `Phase::Ready` phase.
    ///
    /// @param[in]  kernels  The kernels
    ///
    /// @return     If the kernel mappings supplied were successfully used to
    ///             prepare the isolate.
    ///
    [[nodiscard]] bool PrepareForRunningFromKernels(
        std::vector<std::unique_ptr<const fml::Mapping>> kernels);
  
    //----------------------------------------------------------------------------
    /// @brief      Transition the root isolate to the `Phase::Running` phase and
    ///             invoke the main entrypoint (the "main" method) in the
    ///             specified library. The isolate must already be in the
    ///             `Phase::Ready` phase.
    ///
    /// @param[in]  library_name  The name of the library in which to invoke the
    ///                           supplied entrypoint.
    /// @param[in]  entrypoint    The entrypoint in `library_name`
    /// @param[in]  args          A list of string arguments to the entrypoint.
    /// @param[in]  on_run        A callback to run in isolate scope after the
    ///                           main entrypoint has been invoked. There is no
    ///                           isolate scope current on the thread once this
    ///                           method returns.
    ///
    /// @return     If the isolate successfully transitioned to the running phase
    ///             and the main entrypoint was invoked.
    ///
    [[nodiscard]] bool RunFromLibrary(std::optional<std::string> library_name,
                                      std::optional<std::string> entrypoint,
                                      const std::vector<std::string>& args,
                                      const fml::closure& on_run = nullptr);
  
   public:
    //----------------------------------------------------------------------------
    /// @brief      Transition the isolate to the `Phase::Shutdown` phase. The
    ///             only thing left to do is to collect the isolate.
    ///
    /// @return     If the isolate succesfully transitioned to the shutdown phase.
    ///
    [[nodiscard]] bool Shutdown();
  
    //----------------------------------------------------------------------------
    /// @brief      Registers a callback that will be invoked in isolate scope
    ///             just before the isolate transitions to the `Phase::Shutdown`
    ///             phase.
    ///
    /// @param[in]  closure  The callback to invoke on isolate shutdown.
    ///
    void AddIsolateShutdownCallback(const fml::closure& closure);
  
    //----------------------------------------------------------------------------
    /// @brief      A weak pointer to the Dart isolate instance. This instance may
    ///             only be used on the task runner that created the root isolate.
    ///
    /// @return     The weak isolate pointer.
    ///
    std::weak_ptr<DartIsolate> GetWeakIsolatePtr();
  
    //----------------------------------------------------------------------------
    /// @brief      The task runner on which the Dart code for the root isolate is
    ///             running. For the root isolate, this is the UI task runner for
    ///             the shell that owns the root isolate.
    ///
    /// @return     The message handling task runner.
    ///
    fml::RefPtr<fml::TaskRunner> GetMessageHandlingTaskRunner() const;
  
   private:
    friend class IsolateConfiguration;
    class AutoFireClosure {
     public:
      AutoFireClosure(const fml::closure& closure);
  
      ~AutoFireClosure();
  
     private:
      fml::closure closure_;
      FML_DISALLOW_COPY_AND_ASSIGN(AutoFireClosure);
    };
    friend class DartVM;
  
    Phase phase_ = Phase::Unknown;
    std::vector<std::shared_ptr<const fml::Mapping>> kernel_buffers_;
    std::vector<std::unique_ptr<AutoFireClosure>> shutdown_callbacks_;
    fml::RefPtr<fml::TaskRunner> message_handling_task_runner_;
    const bool may_insecurely_connect_to_all_domains_;
    std::string domain_network_policy_;
  
    static std::weak_ptr<DartIsolate> CreateRootIsolate(
        const Settings& settings,
        fml::RefPtr<const DartSnapshot> isolate_snapshot,
        TaskRunners task_runners,
        std::unique_ptr<PlatformConfiguration> platform_configuration,
        fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
        fml::WeakPtr<HintFreedDelegate> hint_freed_delegate,
        fml::WeakPtr<IOManager> io_manager,
        fml::RefPtr<SkiaUnrefQueue> skia_unref_queue,
        fml::WeakPtr<ImageDecoder> image_decoder,
        std::string advisory_script_uri,
        std::string advisory_script_entrypoint,
        Flags flags,
        const fml::closure& isolate_create_callback,
        const fml::closure& isolate_shutdown_callback);
  
    DartIsolate(const Settings& settings,
                TaskRunners task_runners,
                fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
                fml::WeakPtr<HintFreedDelegate> hint_freed_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);
  
    [[nodiscard]] bool Initialize(Dart_Isolate isolate);
  
    void SetMessageHandlingTaskRunner(fml::RefPtr<fml::TaskRunner> runner);
  
    bool LoadKernel(std::shared_ptr<const fml::Mapping> mapping, bool last_piece);
  
    [[nodiscard]] bool LoadLibraries();
  
    bool UpdateThreadPoolNames() const;
  
    [[nodiscard]] bool MarkIsolateRunnable();
  
    void OnShutdownCallback();
  
    DartIsolateGroupData& GetIsolateGroupData();
  
    // |Dart_IsolateGroupCreateCallback|
    static Dart_Isolate 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_group,
        char** error);
  
    // |Dart_IsolateInitializeCallback|
    static bool DartIsolateInitializeCallback(void** child_callback_data,
                                              char** error);
  
    static Dart_Isolate DartCreateAndStartServiceIsolate(
        const char* package_root,
        const char* package_config,
        Dart_IsolateFlags* flags,
        char** error);
  
    static Dart_Isolate 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);
  
    static bool InitializeIsolate(std::shared_ptr<DartIsolate> embedder_isolate,
                                  Dart_Isolate isolate,
                                  char** error);
  
    // |Dart_IsolateShutdownCallback|
    static void DartIsolateShutdownCallback(
        std::shared_ptr<DartIsolateGroupData>* isolate_group_data,
        std::shared_ptr<DartIsolate>* isolate_data);
  
    // |Dart_IsolateCleanupCallback|
    static void DartIsolateCleanupCallback(
        std::shared_ptr<DartIsolateGroupData>* isolate_group_data,
        std::shared_ptr<DartIsolate>* isolate_data);
  
    // |Dart_IsolateGroupCleanupCallback|
    static void DartIsolateGroupCleanupCallback(
        std::shared_ptr<DartIsolateGroupData>* isolate_group_data);
  
    FML_DISALLOW_COPY_AND_ASSIGN(DartIsolate);
  };
  
  }  // namespace flutter
  
  #endif  // FLUTTER_RUNTIME_DART_ISOLATE_H_
  