mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
522 lines
24 KiB
C++
522 lines
24 KiB
C++
// 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 <unordered_set>
|
|
|
|
#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/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] platform_configuration The platform configuration for
|
|
/// handling communication with the
|
|
/// framework.
|
|
/// @param[in] flags The Dart isolate flags for this
|
|
/// isolate instance.
|
|
/// @param[in] dart_entrypoint The name of the dart entrypoint
|
|
/// function to invoke.
|
|
/// @param[in] dart_entrypoint_library The name of the dart library
|
|
/// containing the entrypoint.
|
|
/// @param[in] isolate_configuration The isolate configuration used to
|
|
/// configure the isolate before
|
|
/// invoking the entrypoint.
|
|
/// @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.
|
|
/// @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.
|
|
/// @param[in] context Engine-owned state which is
|
|
/// accessed by the root dart isolate.
|
|
/// @param[in] spawning_isolate The isolate that is spawning the
|
|
/// new isolate. See also
|
|
/// DartIsolate::SpawnIsolate.
|
|
/// @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,
|
|
std::unique_ptr<PlatformConfiguration> platform_configuration,
|
|
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,
|
|
const UIDartState::Context& context,
|
|
const DartIsolate* spawning_isolate = nullptr);
|
|
|
|
//----------------------------------------------------------------------------
|
|
/// @brief Creates a running DartIsolate who shares as many resources as
|
|
/// possible with the caller DartIsolate. This allows them to
|
|
/// occupy less memory together and to be created faster.
|
|
/// @details Shared components will be destroyed when the last live
|
|
/// DartIsolate is destroyed. SpawnIsolate can only be used to
|
|
/// create DartIsolates whose executable code is shared with the
|
|
/// calling DartIsolate.
|
|
/// @attention Only certain setups can take advantage of the most savings
|
|
/// currently, AOT specifically.
|
|
/// @return A weak pointer to a new running DartIsolate. 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.
|
|
std::weak_ptr<DartIsolate> SpawnIsolate(
|
|
const Settings& settings,
|
|
std::unique_ptr<PlatformConfiguration> platform_configuration,
|
|
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
|
|
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) const;
|
|
|
|
// |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.
|
|
///
|
|
/// @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);
|
|
|
|
//----------------------------------------------------------------------------
|
|
/// @brief Transition the isolate to the `Phase::Shutdown` phase. The
|
|
/// only thing left to do is to collect the isolate.
|
|
///
|
|
/// @return If the isolate successfully 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;
|
|
|
|
bool LoadLoadingUnit(
|
|
intptr_t loading_unit_id,
|
|
std::unique_ptr<const fml::Mapping> snapshot_data,
|
|
std::unique_ptr<const fml::Mapping> snapshot_instructions);
|
|
|
|
void LoadLoadingUnitError(intptr_t loading_unit_id,
|
|
const std::string error_message,
|
|
bool transient);
|
|
|
|
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_;
|
|
std::unordered_set<fml::RefPtr<DartSnapshot>> loading_unit_snapshots_;
|
|
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,
|
|
std::unique_ptr<PlatformConfiguration> platform_configuration,
|
|
Flags flags,
|
|
const fml::closure& isolate_create_callback,
|
|
const fml::closure& isolate_shutdown_callback,
|
|
const UIDartState::Context& context,
|
|
const DartIsolate* spawning_isolate = nullptr);
|
|
|
|
DartIsolate(const Settings& settings,
|
|
bool is_root_isolate,
|
|
const UIDartState::Context& context);
|
|
|
|
[[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();
|
|
|
|
const DartIsolateGroupData& GetIsolateGroupData() const;
|
|
|
|
// |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);
|
|
|
|
typedef std::function<Dart_Isolate(std::shared_ptr<DartIsolateGroupData>*,
|
|
std::shared_ptr<DartIsolate>*,
|
|
Dart_IsolateFlags*,
|
|
char**)>
|
|
IsolateMaker;
|
|
|
|
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,
|
|
const IsolateMaker& make_isolate);
|
|
|
|
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);
|
|
|
|
// |Dart_DeferredLoadHandler|
|
|
static Dart_Handle OnDartLoadLibrary(intptr_t loading_unit_id);
|
|
|
|
static void SpawnIsolateShutdownCallback(
|
|
std::shared_ptr<DartIsolateGroupData>* isolate_group_data,
|
|
std::shared_ptr<DartIsolate>* isolate_data);
|
|
|
|
FML_DISALLOW_COPY_AND_ASSIGN(DartIsolate);
|
|
};
|
|
|
|
} // namespace flutter
|
|
|
|
#endif // FLUTTER_RUNTIME_DART_ISOLATE_H_
|