Flutter Engine
dart_isolate.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef FLUTTER_RUNTIME_DART_ISOLATE_H_
6 #define FLUTTER_RUNTIME_DART_ISOLATE_H_
7 
8 #include <memory>
9 #include <optional>
10 #include <set>
11 #include <string>
12 
13 #include "flutter/common/task_runners.h"
14 #include "flutter/fml/compiler_specific.h"
15 #include "flutter/fml/macros.h"
16 #include "flutter/fml/mapping.h"
17 #include "flutter/lib/ui/hint_freed_delegate.h"
18 #include "flutter/lib/ui/io_manager.h"
19 #include "flutter/lib/ui/snapshot_delegate.h"
20 #include "flutter/lib/ui/ui_dart_state.h"
21 #include "flutter/lib/ui/window/platform_configuration.h"
22 #include "flutter/runtime/dart_snapshot.h"
23 #include "third_party/dart/runtime/include/dart_api.h"
25 
26 namespace flutter {
27 
28 class DartVM;
29 class DartIsolateGroupData;
30 class IsolateConfiguration;
31 
32 //------------------------------------------------------------------------------
33 /// @brief Represents an instance of a live isolate. An isolate is a
34 /// separate Dart execution context. Different Dart isolates don't
35 /// share memory and can be scheduled concurrently by the Dart VM on
36 /// one of the Dart VM managed worker pool threads.
37 ///
38 /// The entire lifecycle of a Dart isolate is controlled by the Dart
39 /// VM. Because of this, the engine never holds a strong pointer to
40 /// the Dart VM for extended periods of time. This allows the VM (or
41 /// the isolates themselves) to terminate Dart execution without
42 /// consulting the engine.
43 ///
44 /// The isolate that the engine creates to act as the host for the
45 /// Flutter application code with UI bindings is called the root
46 /// isolate.
47 ///
48 /// The root isolate is special in the following ways:
49 /// * The root isolate forms a new isolate group. Child isolates are
50 /// added to their parents groups. When the root isolate dies, all
51 /// isolates in its group are terminated.
52 /// * Only root isolates get UI bindings.
53 /// * Root isolates execute their code on engine managed threads.
54 /// All other isolates run their Dart code on Dart VM managed
55 /// thread pool workers that the engine has no control over.
56 /// * Since the engine does not know the thread on which non-root
57 /// isolates are run, the engine has no opportunity to get a
58 /// reference to non-root isolates. Such isolates can only be
59 /// terminated if they terminate themselves or their isolate group
60 /// is torn down.
61 ///
62 class DartIsolate : public UIDartState {
63  public:
64  class Flags {
65  public:
66  Flags();
67 
68  explicit Flags(const Dart_IsolateFlags* flags);
69 
70  ~Flags();
71 
72  void SetNullSafetyEnabled(bool enabled);
73 
74  Dart_IsolateFlags Get() const;
75 
76  private:
77  Dart_IsolateFlags flags_;
78  };
79 
80  //----------------------------------------------------------------------------
81  /// @brief The engine represents all dart isolates as being in one of the
82  /// known phases. By invoking various methods on the Dart isolate,
83  /// the engine transition the Dart isolate from one phase to the
84  /// next. The Dart isolate will only move from one phase to the
85  /// next in the order specified in the `DartIsolate::Phase` enum.
86  /// That is, once the isolate has moved out of a particular phase,
87  /// it can never transition back to that phase in the future.
88  /// There is no error recovery mechanism and callers that find
89  /// their isolates in an undesirable phase must discard the
90  /// isolate and start over.
91  ///
92  enum class Phase {
93  //--------------------------------------------------------------------------
94  /// The initial phase of all Dart isolates. This is an internal phase and
95  /// callers can never get a reference to a Dart isolate in this phase.
96  ///
97  Unknown,
98  //--------------------------------------------------------------------------
99  /// The Dart isolate has been created but none of the library tag or message
100  /// handers have been set yet. The is an internal phase and callers can
101  /// never get a reference to a Dart isolate in this phase.
102  ///
103  Uninitialized,
104  //--------------------------------------------------------------------------
105  /// The Dart isolate has been been fully initialized but none of the
106  /// libraries referenced by that isolate have been loaded yet. This is an
107  /// internal phase and callers can never get a reference to a Dart isolate
108  /// in this phase.
109  ///
110  Initialized,
111  //--------------------------------------------------------------------------
112  /// The isolate has been fully initialized and is waiting for the caller to
113  /// associate isolate snapshots with the same. The isolate will only be
114  /// ready to execute Dart code once one of the `Prepare` calls are
115  /// successfully made.
116  ///
117  LibrariesSetup,
118  //--------------------------------------------------------------------------
119  /// The isolate is fully ready to start running Dart code. Callers can
120  /// transition the isolate to the next state by calling the `Run` or
121  /// `RunFromLibrary` methods.
122  ///
123  Ready,
124  //--------------------------------------------------------------------------
125  /// The isolate is currently running Dart code.
126  ///
127  Running,
128  //--------------------------------------------------------------------------
129  /// The isolate is no longer running Dart code and is in the middle of being
130  /// collected. This is in internal phase and callers can never get a
131  /// reference to a Dart isolate in this phase.
132  ///
133  Shutdown,
134  };
135 
136  //----------------------------------------------------------------------------
137  /// @brief Creates an instance of a root isolate and returns a weak
138  /// pointer to the same. The isolate instance may only be used
139  /// safely on the engine thread on which it was created. In the
140  /// shell, this is the UI thread and task runner. Using the
141  /// isolate on any other thread is user error.
142  ///
143  /// The isolate that the engine creates to act as the host for the
144  /// Flutter application code with UI bindings is called the root
145  /// isolate.
146  ///
147  /// The root isolate is special in the following ways:
148  /// * The root isolate forms a new isolate group. Child isolates
149  /// are added to their parents groups. When the root isolate
150  /// dies, all isolates in its group are terminated.
151  /// * Only root isolates get UI bindings.
152  /// * Root isolates execute their code on engine managed threads.
153  /// All other isolates run their Dart code on Dart VM managed
154  /// thread pool workers that the engine has no control over.
155  /// * Since the engine does not know the thread on which non-root
156  /// isolates are run, the engine has no opportunity to get a
157  /// reference to non-root isolates. Such isolates can only be
158  /// terminated if they terminate themselves or their isolate
159  /// group is torn down.
160  ///
161  /// @param[in] settings The settings used to create the
162  /// isolate.
163  /// @param[in] isolate_snapshot The isolate snapshot. This is
164  /// usually obtained from the
165  /// DartVMData associated with the
166  /// running Dart VM instance.
167  /// @param[in] task_runners The task runners used by the
168  /// isolate. Via UI bindings, the
169  /// isolate will use the IO task
170  /// runner to scheduled texture
171  /// decompression jobs and post tasks
172  /// back to the UI task runner.
173  /// @param[in] window The weak pointer to the window
174  /// associated with this root isolate.
175  /// @param[in] io_manager The i/o manager.
176  /// @param[in] unref_queue The Skia unref queue.
177  /// @param[in] image_decoder The image decoder.
178  /// @param[in] advisory_script_uri The advisory script uri. This is
179  /// only used in instrumentation.
180  /// @param[in] advisory_script_entrypoint The advisory script entrypoint.
181  /// This is only used in
182  /// instrumentation. Notably, this is
183  /// NOT the main entrypoint of Dart
184  /// code in the isolate. That is
185  /// specified when making one of the
186  /// `Run` calls.
187  /// @param[in] flags The Dart isolate flags for this
188  /// isolate instance.
189  /// @param[in] isolate_create_callback The isolate create callback. This
190  /// will be called when the before the
191  /// main Dart entrypoint is invoked in
192  /// the root isolate. The isolate is
193  /// already in the running state at
194  /// this point and an isolate scope is
195  /// current. This callback is made for
196  /// all isolate launches (including
197  /// the children of the root isolate).
198  /// @param[in] isolate_shutdown_callback The isolate shutdown callback.
199  /// This will be called before the
200  /// isolate is about to transition
201  /// into the Shutdown phase. The
202  /// isolate is still running at this
203  /// point and an isolate scope is
204  /// current. This callback is made
205  /// for all isolate shutdowns
206  /// (including the children of the
207  /// root isolate).
208  ///
209  /// @return A weak pointer to the root Dart isolate. The caller must
210  /// ensure that the isolate is not referenced for long periods of
211  /// time as it prevents isolate collection when the isolate
212  /// terminates itself. The caller may also only use the isolate on
213  /// the thread on which the isolate was created.
214  ///
215  static std::weak_ptr<DartIsolate> CreateRunningRootIsolate(
216  const Settings& settings,
217  fml::RefPtr<const DartSnapshot> isolate_snapshot,
218  TaskRunners task_runners,
219  std::unique_ptr<PlatformConfiguration> platform_configuration,
220  fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
221  fml::WeakPtr<HintFreedDelegate> hint_freed_delegate,
222  fml::WeakPtr<IOManager> io_manager,
223  fml::RefPtr<SkiaUnrefQueue> skia_unref_queue,
224  fml::WeakPtr<ImageDecoder> image_decoder,
225  std::string advisory_script_uri,
226  std::string advisory_script_entrypoint,
227  Flags flags,
228  const fml::closure& isolate_create_callback,
229  const fml::closure& isolate_shutdown_callback,
230  std::optional<std::string> dart_entrypoint,
231  std::optional<std::string> dart_entrypoint_library,
232  std::unique_ptr<IsolateConfiguration> isolate_configration);
233 
234  // |UIDartState|
235  ~DartIsolate() override;
236 
237  //----------------------------------------------------------------------------
238  /// @brief The current phase of the isolate. The engine represents all
239  /// dart isolates as being in one of the known phases. By invoking
240  /// various methods on the Dart isolate, the engine transitions
241  /// the Dart isolate from one phase to the next. The Dart isolate
242  /// will only move from one phase to the next in the order
243  /// specified in the `DartIsolate::Phase` enum. That is, the once
244  /// the isolate has moved out of a particular phase, it can never
245  /// transition back to that phase in the future. There is no error
246  /// recovery mechanism and callers that find their isolates in an
247  /// undesirable phase must discard the isolate and start over.
248  ///
249  /// @return The current isolate phase.
250  ///
251  Phase GetPhase() const;
252 
253  //----------------------------------------------------------------------------
254  /// @brief Returns the ID for an isolate which is used to query the
255  /// service protocol.
256  ///
257  /// @return The service identifier for this isolate.
258  ///
259  std::string GetServiceId();
260 
261  //----------------------------------------------------------------------------
262  /// @brief Prepare the isolate for running for a precompiled code bundle.
263  /// The Dart VM must be configured for running precompiled code.
264  ///
265  /// The isolate must already be in the `Phase::LibrariesSetup`
266  /// phase. After a successful call to this method, the isolate
267  /// will transition to the `Phase::Ready` phase.
268  ///
269  /// @return Whether the isolate was prepared and the described phase
270  /// transition made.
271  ///
272  [[nodiscard]] bool PrepareForRunningFromPrecompiledCode();
273 
274  //----------------------------------------------------------------------------
275  /// @brief Prepare the isolate for running for a a list of kernel files.
276  ///
277  /// The Dart VM must be configured for running from kernel
278  /// snapshots.
279  ///
280  /// The isolate must already be in the `Phase::LibrariesSetup`
281  /// phase. This call can be made multiple times. After a series of
282  /// successful calls to this method, the caller can specify the
283  /// last kernel file mapping by specifying `last_piece` to `true`.
284  /// On success, the isolate will transition to the `Phase::Ready`
285  /// phase.
286  ///
287  /// @param[in] kernel The kernel mapping.
288  /// @param[in] last_piece Indicates if this is the last kernel mapping
289  /// expected. After this point, the isolate will
290  /// attempt a transition to the `Phase::Ready` phase.
291  ///
292  /// @return If the kernel mapping supplied was successfully used to
293  /// prepare the isolate.
294  ///
295  [[nodiscard]] bool PrepareForRunningFromKernel(
296  std::shared_ptr<const fml::Mapping> kernel,
297  bool last_piece = true);
298 
299  //----------------------------------------------------------------------------
300  /// @brief Prepare the isolate for running for a a list of kernel files.
301  ///
302  /// The Dart VM must be configured for running from kernel
303  /// snapshots.
304  ///
305  /// The isolate must already be in the `Phase::LibrariesSetup`
306  /// phase. After a successful call to this method, the isolate
307  /// will transition to the `Phase::Ready` phase.
308  ///
309  /// @param[in] kernels The kernels
310  ///
311  /// @return If the kernel mappings supplied were successfully used to
312  /// prepare the isolate.
313  ///
314  [[nodiscard]] bool PrepareForRunningFromKernels(
315  std::vector<std::shared_ptr<const fml::Mapping>> kernels);
316 
317  //----------------------------------------------------------------------------
318  /// @brief Prepare the isolate for running for a a list of kernel files.
319  ///
320  /// The Dart VM must be configured for running from kernel
321  /// snapshots.
322  ///
323  /// The isolate must already be in the `Phase::LibrariesSetup`
324  /// phase. After a successful call to this method, the isolate
325  /// will transition to the `Phase::Ready` phase.
326  ///
327  /// @param[in] kernels The kernels
328  ///
329  /// @return If the kernel mappings supplied were successfully used to
330  /// prepare the isolate.
331  ///
332  [[nodiscard]] bool PrepareForRunningFromKernels(
333  std::vector<std::unique_ptr<const fml::Mapping>> kernels);
334 
335  //----------------------------------------------------------------------------
336  /// @brief Transition the root isolate to the `Phase::Running` phase and
337  /// invoke the main entrypoint (the "main" method) in the
338  /// specified library. The isolate must already be in the
339  /// `Phase::Ready` phase.
340  ///
341  /// @param[in] library_name The name of the library in which to invoke the
342  /// supplied entrypoint.
343  /// @param[in] entrypoint The entrypoint in `library_name`
344  /// @param[in] args A list of string arguments to the entrypoint.
345  ///
346  /// @return If the isolate successfully transitioned to the running phase
347  /// and the main entrypoint was invoked.
348  ///
349  [[nodiscard]] bool RunFromLibrary(std::optional<std::string> library_name,
350  std::optional<std::string> entrypoint,
351  const std::vector<std::string>& args);
352 
353  //----------------------------------------------------------------------------
354  /// @brief Transition the isolate to the `Phase::Shutdown` phase. The
355  /// only thing left to do is to collect the isolate.
356  ///
357  /// @return If the isolate succesfully transitioned to the shutdown phase.
358  ///
359  [[nodiscard]] bool Shutdown();
360 
361  //----------------------------------------------------------------------------
362  /// @brief Registers a callback that will be invoked in isolate scope
363  /// just before the isolate transitions to the `Phase::Shutdown`
364  /// phase.
365  ///
366  /// @param[in] closure The callback to invoke on isolate shutdown.
367  ///
369 
370  //----------------------------------------------------------------------------
371  /// @brief A weak pointer to the Dart isolate instance. This instance may
372  /// only be used on the task runner that created the root isolate.
373  ///
374  /// @return The weak isolate pointer.
375  ///
376  std::weak_ptr<DartIsolate> GetWeakIsolatePtr();
377 
378  //----------------------------------------------------------------------------
379  /// @brief The task runner on which the Dart code for the root isolate is
380  /// running. For the root isolate, this is the UI task runner for
381  /// the shell that owns the root isolate.
382  ///
383  /// @return The message handling task runner.
384  ///
386 
387  private:
388  friend class IsolateConfiguration;
389  class AutoFireClosure {
390  public:
391  AutoFireClosure(const fml::closure& closure);
392 
393  ~AutoFireClosure();
394 
395  private:
396  fml::closure closure_;
397  FML_DISALLOW_COPY_AND_ASSIGN(AutoFireClosure);
398  };
399  friend class DartVM;
400 
401  Phase phase_ = Phase::Unknown;
402  std::vector<std::shared_ptr<const fml::Mapping>> kernel_buffers_;
403  std::vector<std::unique_ptr<AutoFireClosure>> shutdown_callbacks_;
404  fml::RefPtr<fml::TaskRunner> message_handling_task_runner_;
405  const bool may_insecurely_connect_to_all_domains_;
406  std::string domain_network_policy_;
407 
408  static std::weak_ptr<DartIsolate> CreateRootIsolate(
409  const Settings& settings,
410  fml::RefPtr<const DartSnapshot> isolate_snapshot,
411  TaskRunners task_runners,
412  std::unique_ptr<PlatformConfiguration> platform_configuration,
413  fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
414  fml::WeakPtr<HintFreedDelegate> hint_freed_delegate,
415  fml::WeakPtr<IOManager> io_manager,
416  fml::RefPtr<SkiaUnrefQueue> skia_unref_queue,
417  fml::WeakPtr<ImageDecoder> image_decoder,
418  std::string advisory_script_uri,
419  std::string advisory_script_entrypoint,
420  Flags flags,
421  const fml::closure& isolate_create_callback,
422  const fml::closure& isolate_shutdown_callback);
423 
424  DartIsolate(const Settings& settings,
425  TaskRunners task_runners,
426  fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
427  fml::WeakPtr<HintFreedDelegate> hint_freed_delegate,
428  fml::WeakPtr<IOManager> io_manager,
429  fml::RefPtr<SkiaUnrefQueue> unref_queue,
430  fml::WeakPtr<ImageDecoder> image_decoder,
431  std::string advisory_script_uri,
432  std::string advisory_script_entrypoint,
433  bool is_root_isolate);
434 
435  [[nodiscard]] bool Initialize(Dart_Isolate isolate);
436 
437  void SetMessageHandlingTaskRunner(fml::RefPtr<fml::TaskRunner> runner);
438 
439  bool LoadKernel(std::shared_ptr<const fml::Mapping> mapping, bool last_piece);
440 
441  [[nodiscard]] bool LoadLibraries();
442 
443  bool UpdateThreadPoolNames() const;
444 
445  [[nodiscard]] bool MarkIsolateRunnable();
446 
447  void OnShutdownCallback();
448 
449  DartIsolateGroupData& GetIsolateGroupData();
450 
451  // |Dart_IsolateGroupCreateCallback|
452  static Dart_Isolate DartIsolateGroupCreateCallback(
453  const char* advisory_script_uri,
454  const char* advisory_script_entrypoint,
455  const char* package_root,
456  const char* package_config,
457  Dart_IsolateFlags* flags,
458  std::shared_ptr<DartIsolate>* parent_isolate_group,
459  char** error);
460 
461  // |Dart_IsolateInitializeCallback|
462  static bool DartIsolateInitializeCallback(void** child_callback_data,
463  char** error);
464 
465  static Dart_Isolate DartCreateAndStartServiceIsolate(
466  const char* package_root,
467  const char* package_config,
468  Dart_IsolateFlags* flags,
469  char** error);
470 
471  static Dart_Isolate CreateDartIsolateGroup(
472  std::unique_ptr<std::shared_ptr<DartIsolateGroupData>> isolate_group_data,
473  std::unique_ptr<std::shared_ptr<DartIsolate>> isolate_data,
474  Dart_IsolateFlags* flags,
475  char** error);
476 
477  static bool InitializeIsolate(std::shared_ptr<DartIsolate> embedder_isolate,
478  Dart_Isolate isolate,
479  char** error);
480 
481  // |Dart_IsolateShutdownCallback|
482  static void DartIsolateShutdownCallback(
483  std::shared_ptr<DartIsolateGroupData>* isolate_group_data,
484  std::shared_ptr<DartIsolate>* isolate_data);
485 
486  // |Dart_IsolateCleanupCallback|
487  static void DartIsolateCleanupCallback(
488  std::shared_ptr<DartIsolateGroupData>* isolate_group_data,
489  std::shared_ptr<DartIsolate>* isolate_data);
490 
491  // |Dart_IsolateGroupCleanupCallback|
492  static void DartIsolateGroupCleanupCallback(
493  std::shared_ptr<DartIsolateGroupData>* isolate_group_data);
494 
496 };
497 
498 } // namespace flutter
499 
500 #endif // FLUTTER_RUNTIME_DART_ISOLATE_H_
bool PrepareForRunningFromKernel(std::shared_ptr< const fml::Mapping > kernel, bool last_piece=true)
Prepare the isolate for running for a a list of kernel files.
G_BEGIN_DECLS FlValue * args
Phase GetPhase() const
The current phase of the isolate. The engine represents all dart isolates as being in one of the know...
Dart_IsolateFlags Get() const
Definition: dart_isolate.cc:72
Dart_Isolate isolate()
Definition: dart_state.h:49
bool RunFromLibrary(std::optional< std::string > library_name, std::optional< std::string > entrypoint, const std::vector< std::string > &args)
Transition the root isolate to the Phase::Running phase and invoke the main entrypoint (the "main" me...
Phase
The engine represents all dart isolates as being in one of the known phases. By invoking various meth...
Definition: dart_isolate.h:92
FlMethodResponse GError ** error
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)
Creates an instance of a root isolate and returns a weak pointer to the same. The isolate instance ma...
Definition: dart_isolate.cc:76
void SetNullSafetyEnabled(bool enabled)
Definition: dart_isolate.cc:68
std::function< void()> closure
Definition: closure.h:14
void AddIsolateShutdownCallback(const fml::closure &closure)
Registers a callback that will be invoked in isolate scope just before the isolate transitions to the...
void Initialize(fidl::InterfaceHandle< fuchsia::sys::Environment > environment, zx::channel directory_request, std::optional< zx::eventpair > view_ref)
Definition: fuchsia.cc:103
Represents an instance of a live isolate. An isolate is a separate Dart execution context...
Definition: dart_isolate.h:62
PlatformConfiguration * platform_configuration() const
Definition: ui_dart_state.h:48
std::string GetServiceId()
Returns the ID for an isolate which is used to query the service protocol.
Describes a running instance of the Dart VM. There may only be one running instance of the Dart VM in...
Definition: dart_vm.h:61
fml::RefPtr< fml::TaskRunner > GetMessageHandlingTaskRunner() const
The task runner on which the Dart code for the root isolate is running. For the root isolate...
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: macros.h:27
bool Shutdown()
Transition the isolate to the Phase::Shutdown phase. The only thing left to do is to collect the isol...
bool PrepareForRunningFromKernels(std::vector< std::shared_ptr< const fml::Mapping >> kernels)
Prepare the isolate for running for a a list of kernel files.
std::weak_ptr< DartIsolate > GetWeakIsolatePtr()
A weak pointer to the Dart isolate instance. This instance may only be used on the task runner that c...
An isolate configuration is a collection of snapshots and asset managers that the engine will use to ...
bool PrepareForRunningFromPrecompiledCode()
Prepare the isolate for running for a precompiled code bundle. The Dart VM must be configured for run...
DEF_SWITCHES_START snapshot asset Path to the directory containing the four files specified by VmSnapshotInstructions and IsolateSnapshotInstructions vm snapshot The VM instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present isolate snapshot The isolate instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present icu symbol Prefix for the symbols representing ICU data linked into the Flutter library dart flags
Definition: switches.h:66