Flutter Engine
engine.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 SHELL_COMMON_ENGINE_H_
6 #define SHELL_COMMON_ENGINE_H_
7 
8 #include <memory>
9 #include <string>
10 
11 #include "flutter/assets/asset_manager.h"
12 #include "flutter/common/task_runners.h"
13 #include "flutter/fml/macros.h"
14 #include "flutter/fml/memory/weak_ptr.h"
15 #include "flutter/lib/ui/hint_freed_delegate.h"
16 #include "flutter/lib/ui/painting/image_decoder.h"
17 #include "flutter/lib/ui/semantics/custom_accessibility_action.h"
18 #include "flutter/lib/ui/semantics/semantics_node.h"
19 #include "flutter/lib/ui/snapshot_delegate.h"
20 #include "flutter/lib/ui/text/font_collection.h"
21 #include "flutter/lib/ui/window/platform_message.h"
22 #include "flutter/lib/ui/window/viewport_metrics.h"
23 #include "flutter/runtime/dart_vm.h"
24 #include "flutter/runtime/runtime_controller.h"
25 #include "flutter/runtime/runtime_delegate.h"
26 #include "flutter/shell/common/animator.h"
27 #include "flutter/shell/common/display_manager.h"
28 #include "flutter/shell/common/platform_view.h"
29 #include "flutter/shell/common/pointer_data_dispatcher.h"
30 #include "flutter/shell/common/rasterizer.h"
31 #include "flutter/shell/common/run_configuration.h"
32 #include "flutter/shell/common/shell_io_manager.h"
33 #include "third_party/skia/include/core/SkPicture.h"
34 
35 namespace flutter {
36 
37 //------------------------------------------------------------------------------
38 /// The engine is a component owned by the shell that resides on the UI task
39 /// runner and is responsible for managing the needs of the root isolate and its
40 /// runtime. The engine can only be created, accessed and collected on the UI
41 /// task runner. Each shell owns exactly one instance of the engine.
42 ///
43 /// The root isolate of Flutter application gets "window" bindings. Using these
44 /// bindings, the application can schedule frames, post layer-trees for
45 /// rendering, ask to decompress images and upload them to the GPU, etc..
46 /// Non-root isolates of the VM do not get any of these capabilities and are run
47 /// in a VM managed thread pool (so if they did have "window", the threading
48 /// guarantees needed for engine operation would be violated).
49 ///
50 /// The engine is responsible for the entire life-cycle of the root isolate.
51 /// When the engine is collected, its owner assumes that the root isolate has
52 /// been shutdown and appropriate resources collected. While each engine
53 /// instance can only manage a single instance of a root isolate, it may restart
54 /// that isolate on request. This is how the cold-restart development scenario
55 /// is supported.
56 ///
57 /// When the engine instance is initially created, the root isolate is created
58 /// but it is not in the |DartIsolate::Phase::Running| phase yet. It only moves
59 /// into that phase when a successful call to `Engine::Run` is made.
60 ///
61 /// @see `Shell`
62 ///
63 /// @note This name of this class is perhaps a bit unfortunate and has
64 /// sometimes been the cause of confusion. For a class named "Engine"
65 /// in the Flutter "Engine" repository, its responsibilities are
66 /// decidedly unremarkable. But, it does happen to be the primary
67 /// entry-point used by components higher up in the Flutter tech stack
68 /// (usually in Dart code) to peer into the lower level functionality.
69 /// Besides, the authors haven't been able to come up with a more apt
70 /// name and it does happen to be one of the older classes in the
71 /// repository.
72 ///
73 class Engine final : public RuntimeDelegate,
74  public HintFreedDelegate,
76  public:
77  //----------------------------------------------------------------------------
78  /// @brief Indicates the result of the call to `Engine::Run`.
79  ///
80  enum class RunStatus {
81  //--------------------------------------------------------------------------
82  /// The call to |Engine::Run| was successful and the root isolate is in the
83  /// `DartIsolate::Phase::Running` phase with its entry-point invocation
84  /// already pending in the task queue.
85  ///
86  Success,
87 
88  //--------------------------------------------------------------------------
89  /// The engine can only manage a single instance of a root isolate. If a
90  /// previous call to run the root isolate was successful, subsequent calls
91  /// to run the isolate (even if the new run configuration is different) will
92  /// be rejected.
93  ///
94  /// It is up to the caller to decide to re-purpose the running isolate,
95  /// terminate it, or use another shell to host the new isolate. This is
96  /// mostly used by embedders which have a fire-and-forget strategy to root
97  /// isolate launch. For example, the application may try to "launch" and
98  /// isolate when the embedders launches or resumes from a paused state. That
99  /// the isolate is running is not necessarily a failure condition for them.
100  /// But from the engine's perspective, the run configuration was rejected.
101  ///
103 
104  //--------------------------------------------------------------------------
105  /// Used to indicate to the embedder that a root isolate was not already
106  /// running but the run configuration was not valid and root isolate could
107  /// not be moved into the `DartIsolate::Phase::Running` phase.
108  ///
109  /// The caller must attempt the run call again with a valid configuration.
110  /// The set of all failure modes is massive and can originate from a variety
111  /// of sub-components. The engine will attempt to log the same when
112  /// possible. With the aid of logs, the common causes of failure are:
113  ///
114  /// * AOT assets give to JIT/DBC mode VM's and vice-versa.
115  /// * The assets could not be found in the asset manager. Callers must make
116  /// sure their run configuration asset managers have been correctly setup.
117  /// * The assets themselves were corrupt or invalid. Callers must make sure
118  /// their asset delivery mechanisms are sound.
119  /// * The application entry-point or the root library of the entry-point
120  /// specified in the run configuration was invalid. Callers must make sure
121  /// that the entry-point is present in the application. If the name of the
122  /// entrypoint is not "main" in the root library, callers must also ensure
123  /// that the snapshotting process has not tree-shaken away this
124  /// entrypoint. This requires the decoration of the entrypoint with the
125  /// `@pragma('vm:entry-point')` directive. This problem will manifest in
126  /// AOT mode operation of the Dart VM.
127  ///
128  Failure,
129  };
130 
131  //----------------------------------------------------------------------------
132  /// @brief While the engine operates entirely on the UI task runner, it
133  /// needs the capabilities of the other components to fulfill the
134  /// requirements of the root isolate. The shell is the only class
135  /// that implements this interface as no other component has
136  /// access to all components in a thread safe manner. The engine
137  /// delegates these tasks to the shell via this interface.
138  ///
139  class Delegate {
140  public:
141  //--------------------------------------------------------------------------
142  /// @brief When the accessibility tree has been updated by the Flutter
143  /// application, this new information needs to be conveyed to
144  /// the underlying platform. The engine delegates this task to
145  /// the shell via this call. The engine cannot access the
146  /// underlying platform directly because of threading
147  /// considerations. Most platform specific APIs to convey
148  /// accessibility information are only safe to access on the
149  /// platform task runner while the engine is running on the UI
150  /// task runner.
151  ///
152  /// @see `SemanticsNode`, `SemticsNodeUpdates`,
153  /// `CustomAccessibilityActionUpdates`,
154  /// `PlatformView::UpdateSemantics`
155  ///
156  /// @param[in] updates A map with the stable semantics node identifier as
157  /// key and the node properties as the value.
158  /// @param[in] actions A map with the stable semantics node identifier as
159  /// key and the custom node action as the value.
160  ///
161  virtual void OnEngineUpdateSemantics(
162  SemanticsNodeUpdates updates,
164 
165  //--------------------------------------------------------------------------
166  /// @brief When the Flutter application has a message to send to the
167  /// underlying platform, the message needs to be forwarded to
168  /// the platform on the appropriate thread (via the platform
169  /// task runner). The engine delegates this task to the shell
170  /// via this method.
171  ///
172  /// @see `PlatformView::HandlePlatformMessage`
173  ///
174  /// @param[in] message The message from the Flutter application to send to
175  /// the underlying platform.
176  ///
177  virtual void OnEngineHandlePlatformMessage(
178  fml::RefPtr<PlatformMessage> message) = 0;
179 
180  //--------------------------------------------------------------------------
181  /// @brief Notifies the delegate that the root isolate of the
182  /// application is about to be discarded and a new isolate with
183  /// the same runtime started in its place. This should only
184  /// happen in the Flutter "debug" runtime mode in the
185  /// cold-restart scenario. The embedder may need to reset native
186  /// resource in response to the restart.
187  ///
188  /// @see `PlatformView::OnPreEngineRestart`
189  ///
190  virtual void OnPreEngineRestart() = 0;
191 
192  //--------------------------------------------------------------------------
193  /// @brief Notifies the shell that the root isolate is created.
194  /// Currently, this information is to add to the service
195  /// protocol list of available root isolates running in the VM
196  /// and their names so that the appropriate isolate can be
197  /// selected in the tools for debugging and instrumentation.
198  ///
199  virtual void OnRootIsolateCreated() = 0;
200 
201  //--------------------------------------------------------------------------
202  /// @brief Notifies the shell of the name of the root isolate and its
203  /// port when that isolate is launched, restarted (in the
204  /// cold-restart scenario) or the application itself updates the
205  /// name of the root isolate (via `Window.setIsolateDebugName`
206  /// in `window.dart`). The name of the isolate is meaningless to
207  /// the engine but is used in instrumentation and tooling.
208  /// Currently, this information is to update the service
209  /// protocol list of available root isolates running in the VM
210  /// and their names so that the appropriate isolate can be
211  /// selected in the tools for debugging and instrumentation.
212  ///
213  /// @param[in] isolate_name The isolate name
214  /// @param[in] isolate_port The isolate port
215  ///
216  virtual void UpdateIsolateDescription(const std::string isolate_name,
217  int64_t isolate_port) = 0;
218 
219  //--------------------------------------------------------------------------
220  /// @brief Notifies the shell that the application has an opinion about
221  /// whether its frame timings need to be reported backed to it.
222  /// Due to the asynchronous nature of rendering in Flutter, it
223  /// is not possible for the application to determine the total
224  /// time it took to render a specific frame. While the
225  /// layer-tree is constructed on the UI thread, it needs to be
226  /// rendering on the raster thread. Dart code cannot execute on
227  /// this thread. So any instrumentation about the frame times
228  /// gathered on this thread needs to be aggregated and sent back
229  /// to the UI thread for processing in Dart.
230  ///
231  /// When the application indicates that frame times need to be
232  /// reported, it collects this information till a specified
233  /// number of data points are gathered. Then this information is
234  /// sent back to Dart code via `Engine::ReportTimings`.
235  ///
236  /// This option is engine counterpart of the
237  /// `Window._setNeedsReportTimings` in `window.dart`.
238  ///
239  /// @param[in] needs_reporting If reporting information should be
240  /// collected and send back to Dart.
241  ///
242  virtual void SetNeedsReportTimings(bool needs_reporting) = 0;
243 
244  //--------------------------------------------------------------------------
245  /// @brief Directly invokes platform-specific APIs to compute the
246  /// locale the platform would have natively resolved to.
247  ///
248  /// @param[in] supported_locale_data The vector of strings that represents
249  /// the locales supported by the app.
250  /// Each locale consists of three
251  /// strings: languageCode, countryCode,
252  /// and scriptCode in that order.
253  ///
254  /// @return A vector of 3 strings languageCode, countryCode, and
255  /// scriptCode that represents the locale selected by the
256  /// platform. Empty strings mean the value was unassigned. Empty
257  /// vector represents a null locale.
258  ///
259  virtual std::unique_ptr<std::vector<std::string>>
261  const std::vector<std::string>& supported_locale_data) = 0;
262  };
263 
264  //----------------------------------------------------------------------------
265  /// @brief Creates an instance of the engine with a supplied
266  /// `RuntimeController`. Use the other constructor except for
267  /// tests.
268  ///
269  Engine(Delegate& delegate,
270  const PointerDataDispatcherMaker& dispatcher_maker,
271  std::shared_ptr<fml::ConcurrentTaskRunner> image_decoder_task_runner,
272  TaskRunners task_runners,
273  Settings settings,
274  std::unique_ptr<Animator> animator,
275  fml::WeakPtr<IOManager> io_manager,
276  std::unique_ptr<RuntimeController> runtime_controller);
277 
278  //----------------------------------------------------------------------------
279  /// @brief Creates an instance of the engine. This is done by the Shell
280  /// on the UI task runner.
281  ///
282  /// @param delegate The object used by the engine to perform
283  /// tasks that require access to components
284  /// that cannot be safely accessed by the
285  /// engine. This is the shell.
286  /// @param dispatcher_maker The callback provided by `PlatformView` for
287  /// engine to create the pointer data
288  /// dispatcher. Similar to other engine
289  /// resources, this dispatcher_maker and its
290  /// returned dispatcher is only safe to be
291  /// called from the UI thread.
292  /// @param vm An instance of the running Dart VM.
293  /// @param[in] isolate_snapshot The snapshot used to create the root
294  /// isolate. Even though the isolate is not
295  /// `DartIsolate::Phase::Running` phase, it is
296  /// created when the engine is created. This
297  /// requires access to the isolate snapshot
298  /// upfront.
299  // TODO(chinmaygarde): This is probably redundant now that the IO manager is
300  // it's own object.
301  /// @param[in] task_runners The task runners used by the shell that
302  /// hosts this engine.
303  /// @param[in] settings The settings used to initialize the shell
304  /// and the engine.
305  /// @param[in] animator The animator used to schedule frames.
306  // TODO(chinmaygarde): Move this to `Engine::Delegate`
307  /// @param[in] snapshot_delegate The delegate used to fulfill requests to
308  /// snapshot a specified scene. The engine
309  /// cannot snapshot a scene on the UI thread
310  /// directly because the scene (described via
311  /// an `SkPicture`) may reference resources on
312  /// the GPU and there is no GPU context current
313  /// on the UI thread. The delegate is a
314  /// component that has access to all the
315  /// requisite GPU resources.
316  /// @param[in] io_manager The IO manager used by this root isolate to
317  /// schedule tasks that manage resources on the
318  /// GPU.
319  ///
320  Engine(Delegate& delegate,
321  const PointerDataDispatcherMaker& dispatcher_maker,
322  DartVM& vm,
323  fml::RefPtr<const DartSnapshot> isolate_snapshot,
324  TaskRunners task_runners,
325  const PlatformData platform_data,
326  Settings settings,
327  std::unique_ptr<Animator> animator,
328  fml::WeakPtr<IOManager> io_manager,
329  fml::RefPtr<SkiaUnrefQueue> unref_queue,
330  fml::WeakPtr<SnapshotDelegate> snapshot_delegate);
331 
332  //----------------------------------------------------------------------------
333  /// @brief Destroys the engine engine. Called by the shell on the UI task
334  /// runner. The running root isolate is terminated and will no
335  /// longer access the task runner after this call returns. This
336  /// allows the embedder to tear down the thread immediately if
337  /// needed.
338  ///
339  ~Engine() override;
340 
341  //----------------------------------------------------------------------------
342  /// @return The pointer to this instance of the engine. The engine may
343  /// only be accessed safely on the UI task runner.
344  ///
346 
347  //----------------------------------------------------------------------------
348  /// @brief Moves the root isolate to the `DartIsolate::Phase::Running`
349  /// phase on a successful call to this method.
350  ///
351  /// The isolate itself is created when the engine is created, but
352  /// it is not yet in the running phase. This is done to amortize
353  /// initial time taken to launch the root isolate. The isolate
354  /// snapshots used to run the isolate can be fetched on another
355  /// thread while the engine itself is launched on the UI task
356  /// runner.
357  ///
358  /// Repeated calls to this method after a successful run will be
359  /// rejected even if the run configuration is valid (with the
360  /// appropriate error returned).
361  ///
362  /// @param[in] configuration The configuration used to run the root isolate.
363  /// The configuration must be valid.
364  ///
365  /// @return The result of the call to run the root isolate.
366  ///
367  [[nodiscard]] RunStatus Run(RunConfiguration configuration);
368 
369  //----------------------------------------------------------------------------
370  /// @brief Tears down an existing root isolate, reuses the components of
371  /// that isolate and attempts to launch a new isolate using the
372  /// given the run configuration. This is only used in the
373  /// "debug" Flutter runtime mode in the cold-restart scenario.
374  ///
375  /// @attention This operation must be performed with care as even a
376  /// non-successful restart will still tear down any existing root
377  /// isolate. In such cases, the engine and its shell must be
378  /// discarded.
379  ///
380  /// @param[in] configuration The configuration used to launch the new
381  /// isolate.
382  ///
383  /// @return Whether the restart was successful. If not, the engine and its
384  /// shell must be discarded.
385  ///
386  [[nodiscard]] bool Restart(RunConfiguration configuration);
387 
388  //----------------------------------------------------------------------------
389  /// @brief Setup default font manager according to specific platform.
390  ///
392 
393  //----------------------------------------------------------------------------
394  /// @brief Updates the asset manager referenced by the root isolate of a
395  /// Flutter application. This happens implicitly in the call to
396  /// `Engine::Run` and `Engine::Restart` as the asset manager is
397  /// referenced from the run configuration provided to those calls.
398  /// In addition to the `Engine::Run` and `Engine::Restart`
399  /// calls, the tooling may need to update the assets available to
400  /// the application as the user adds them to their project. For
401  /// example, these assets may be referenced by code that is newly
402  /// patched in after a hot-reload. Neither the shell or the
403  /// isolate in relaunched in such cases. The tooling usually
404  /// patches in the new assets in a temporary location and updates
405  /// the asset manager to point to that location.
406  ///
407  /// @param[in] asset_manager The new asset manager to use for the running
408  /// root isolate.
409  ///
410  /// @return If the asset manager was successfully replaced. This may fail
411  /// if the new asset manager is invalid.
412  ///
413  bool UpdateAssetManager(std::shared_ptr<AssetManager> asset_manager);
414 
415  //----------------------------------------------------------------------------
416  /// @brief Notifies the engine that it is time to begin working on a new
417  /// frame previously scheduled via a call to
418  /// `Engine::ScheduleFrame`. This call originates in the animator.
419  ///
420  /// The frame time given as the argument indicates the point at
421  /// which the current frame interval began. It is very slightly
422  /// (because of scheduling overhead) in the past. If a new layer
423  /// tree is not produced and given to the GPU task runner within
424  /// one frame interval from this point, the Flutter application
425  /// will jank.
426  ///
427  /// If a root isolate is running, this method calls the
428  /// `::_beginFrame` method in `hooks.dart`. If a root isolate is
429  /// not running, this call does nothing.
430  ///
431  /// This method encapsulates the entire UI thread frame workload.
432  /// The following (mis)behavior in the functioning of the method
433  /// will cause the jank in the Flutter application:
434  /// * The time taken by this method to create a layer-tree exceeds
435  /// on frame interval (for example, 16.66 ms on a 60Hz display).
436  /// * The time take by this method to generate a new layer-tree
437  /// causes the current layer-tree pipeline depth to change. To
438  /// illustrate this point, note that maximum pipeline depth used
439  /// by layer tree in the engine is 2. If both the UI and GPU
440  /// task runner tasks finish within one frame interval, the
441  /// pipeline depth is one. If the UI thread happens to be
442  /// working on a frame when the raster thread is still not done
443  /// with the previous frame, the pipeline depth is 2. When the
444  /// pipeline depth changes from 1 to 2, animations and UI
445  /// interactions that cause the generation of the new layer tree
446  /// appropriate for (frame_time + one frame interval) will
447  /// actually end up at (frame_time + two frame intervals). This
448  /// is not what code running on the UI thread expected would
449  /// happen. This causes perceptible jank.
450  ///
451  /// @param[in] frame_time The point at which the current frame interval
452  /// began. May be used by animation interpolators,
453  /// physics simulations, etc..
454  ///
455  void BeginFrame(fml::TimePoint frame_time);
456 
457  // |HintFreedDelegate|
458  void HintFreed(size_t size) override;
459 
460  //----------------------------------------------------------------------------
461  /// @brief Notifies the engine that the UI task runner is not expected to
462  /// undertake a new frame workload till a specified timepoint. The
463  /// timepoint is measured in microseconds against the system's
464  /// monotonic clock. It is recommended that the clock be accessed
465  /// via `Dart_TimelineGetMicros` from `dart_api.h` for
466  /// consistency. In reality, the clocks used by Dart, FML and
467  /// std::steady_clock are all the same and the timepoints can be
468  /// converted from on clock type to another.
469  ///
470  /// The Dart VM uses this notification to schedule book-keeping
471  /// tasks that may include a garbage collection. In this way, it
472  /// is less likely for the VM to perform such (potentially long
473  /// running) tasks in the middle of a frame workload.
474  ///
475  /// This notification is advisory. That is, not providing this
476  /// notification does not mean garbage collection is postponed
477  /// till this call is made. If this notification is not provided,
478  /// garbage collection will happen based on the usual heuristics
479  /// used by the Dart VM.
480  ///
481  /// Currently, this idle notification is delivered to the engine
482  /// at two points. Once, the deadline is calculated based on how
483  /// much time in the current frame interval is left on the UI task
484  /// runner. Since the next frame workload cannot begin till at
485  /// least the next callback from the vsync waiter, this period may
486  /// be used to used as a "small" idle notification. On the other
487  /// hand, if no more frames are scheduled, a large (but arbitrary)
488  /// idle notification deadline is chosen for a "big" idle
489  /// notification. Again, this notification does not guarantee
490  /// collection, just gives the Dart VM more hints about opportune
491  /// moments to perform collections.
492  ///
493  // TODO(chinmaygarde): This should just use fml::TimePoint instead of having
494  // to remember that the unit is microseconds (which is no used anywhere else
495  // in the engine).
496  ///
497  /// @param[in] deadline The deadline as a timepoint in microseconds measured
498  /// against the system monotonic clock. Use
499  /// `Dart_TimelineGetMicros()`, for consistency.
500  ///
501  void NotifyIdle(int64_t deadline);
502 
503  //----------------------------------------------------------------------------
504  /// @brief Dart code cannot fully measure the time it takes for a
505  /// specific frame to be rendered. This is because Dart code only
506  /// runs on the UI task runner. That is only a small part of the
507  /// overall frame workload. The GPU task runner frame workload is
508  /// executed on a thread where Dart code cannot run (and hence
509  /// instrument). Besides, due to the pipelined nature of rendering
510  /// in Flutter, there may be multiple frame workloads being
511  /// processed at any given time. However, for non-Timeline based
512  /// profiling, it is useful for trace collection and processing to
513  /// happen in Dart. To do this, the GPU task runner frame
514  /// workloads need to be instrumented separately. After a set
515  /// number of these profiles have been gathered, they need to be
516  /// reported back to Dart code. The shell reports this extra
517  /// instrumentation information back to Dart code running on the
518  /// engine by invoking this method at predefined intervals.
519  ///
520  /// @see `FrameTiming`
521  ///
522  // TODO(chinmaygarde): The use `int64_t` is added for ease of conversion to
523  // Dart but hurts readability. The phases and the units of the timepoints are
524  // not obvious without some sleuthing. The conversion can happen at the
525  // native interface boundary instead.
526  ///
527  /// @param[in] timings Collection of `FrameTiming::kCount` * `n` timestamps
528  /// for `n` frames whose timings have not been reported
529  /// yet. A collection of integers is reported here for
530  /// easier conversions to Dart objects. The timestamps
531  /// are measured against the system monotonic clock
532  /// measured in microseconds.
533  ///
534  void ReportTimings(std::vector<int64_t> timings);
535 
536  //----------------------------------------------------------------------------
537  /// @brief Gets the main port of the root isolate. Since the isolate is
538  /// created immediately in the constructor of the engine, it is
539  /// possible to get its main port immediately (even before a call
540  /// to `Run` can be made). This is useful in registering the port
541  /// in a race free manner with a port nameserver.
542  ///
543  /// @return The main port of the root isolate.
544  ///
545  Dart_Port GetUIIsolateMainPort();
546 
547  //----------------------------------------------------------------------------
548  /// @brief Gets the debug name of the root isolate. But default, the
549  /// debug name of the isolate is derived from its advisory script
550  /// URI, advisory main entrypoint and its main port name. For
551  /// example, "main.dart$main-1234" where the script URI is
552  /// "main.dart", the entrypoint is "main" and the port name
553  /// "1234". Once launched, the isolate may re-christen itself
554  /// using a name it selects via `setIsolateDebugName` in
555  /// `window.dart`. This name is purely advisory and only used by
556  /// instrumentation and reporting purposes.
557  ///
558  /// @return The debug name of the root isolate.
559  ///
560  std::string GetUIIsolateName();
561 
562  //----------------------------------------------------------------------------
563  /// @brief It is an unexpected challenge to determine when a Dart
564  /// application is "done". The application cannot simply terminate
565  /// the native process (and perhaps return an exit code) because
566  /// it does not have that power. After all, Flutter applications
567  /// reside within a host process that may have other
568  /// responsibilities besides just running Flutter applications.
569  /// Also, the `main` entry-points are run on an event loop and
570  /// returning from "main" (unlike in C/C++ applications) does not
571  /// mean termination of the process. Besides, the return value of
572  /// the main entrypoint is discarded.
573  ///
574  /// One technique used by embedders to determine "liveness" is to
575  /// count the outstanding live ports dedicated to the application.
576  /// These ports may be live as a result of pending timers,
577  /// scheduled tasks, pending IO on sockets, channels open with
578  /// other isolates, etc.. At regular intervals (sometimes as often
579  /// as after the UI task runner processes any task), embedders may
580  /// check for the "liveness" of the application and perform
581  /// teardown of the embedder when no more ports are live.
582  ///
583  /// @return Check if the root isolate has any live ports.
584  ///
585  bool UIIsolateHasLivePorts();
586 
587  //----------------------------------------------------------------------------
588  /// @brief Errors that are unhandled on the Dart message loop are kept
589  /// for further inspection till the next unhandled error comes
590  /// along. This accessor returns the last unhandled error
591  /// encountered by the root isolate.
592  ///
593  /// @return The ui isolate last error.
594  ///
596 
597  //----------------------------------------------------------------------------
598  /// @brief As described in the discussion for `UIIsolateHasLivePorts`,
599  /// the "done-ness" of a Dart application is tricky to ascertain
600  /// and the return value from the main entrypoint is discarded
601  /// (because the Dart isolate is still running after the main
602  /// entrypoint returns). But, the concept of an exit code akin to
603  /// those returned by native applications is still useful. Short
604  /// lived Dart applications (usually tests), emulate this by
605  /// setting a per isolate "return value" and then indicating their
606  /// "done-ness" (usually via closing all live ports). This
607  /// accessor returns that "return value" is present.
608  ///
609  /// @see `UIIsolateHasLivePorts`
610  ///
611  /// @return The return code (if specified) by the isolate.
612  ///
613  std::optional<uint32_t> GetUIIsolateReturnCode();
614 
615  //----------------------------------------------------------------------------
616  /// @brief Indicates to the Flutter application that it has obtained a
617  /// rendering surface. This is a good opportunity for the engine
618  /// to start servicing any outstanding frame requests from the
619  /// Flutter applications. Flutter application that have no
620  /// rendering concerns may never get a rendering surface. In such
621  /// cases, while their root isolate can perform as normal, any
622  /// frame requests made by them will never be serviced and layer
623  /// trees produced outside of frame workloads will be dropped.
624  ///
625  /// Very close to when this call is made, the application can
626  /// expect the updated viewport metrics. Rendering only begins
627  /// when the Flutter application gets an output surface and a
628  /// valid set of viewport metrics.
629  ///
630  /// @see `OnOutputSurfaceDestroyed`
631  ///
632  void OnOutputSurfaceCreated();
633 
634  //----------------------------------------------------------------------------
635  /// @brief Indicates to the Flutter application that a previously
636  /// acquired rendering surface has been lost. Further frame
637  /// requests will no longer be serviced and any layer tree
638  /// submitted for rendering will be dropped. If/when a new surface
639  /// is acquired, a new layer tree must be generated.
640  ///
641  /// @see `OnOutputSurfaceCreated`
642  ///
644 
645  //----------------------------------------------------------------------------
646  /// @brief Updates the viewport metrics for the currently running Flutter
647  /// application. The viewport metrics detail the size of the
648  /// rendering viewport in texels as well as edge insets if
649  /// present.
650  ///
651  /// @see `ViewportMetrics`
652  ///
653  /// @param[in] metrics The metrics
654  ///
655  void SetViewportMetrics(const ViewportMetrics& metrics);
656 
657  //----------------------------------------------------------------------------
658  /// @brief Notifies the engine that the embedder has sent it a message.
659  /// This call originates in the platform view and has been
660  /// forwarded to the engine on the UI task runner here.
661  ///
662  /// @param[in] message The message sent from the embedder to the Dart
663  /// application.
664  ///
666 
667  //----------------------------------------------------------------------------
668  /// @brief Notifies the engine that the embedder has sent it a pointer
669  /// data packet. A pointer data packet may contain multiple
670  /// input events. This call originates in the platform view and
671  /// the shell has forwarded the same to the engine on the UI task
672  /// runner here.
673  ///
674  /// @param[in] packet The pointer data packet containing multiple
675  /// input events.
676  /// @param[in] trace_flow_id The trace flow identifier associated with the
677  /// pointer data packet. The engine uses this trace
678  /// identifier to connect trace flows in the
679  /// timeline from the input event event to the
680  /// frames generated due to those input events.
681  /// These flows are tagged as "PointerEvent" in the
682  /// timeline and allow grouping frames and input
683  /// events into logical chunks.
684  ///
685  void DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet,
686  uint64_t trace_flow_id);
687 
688  //----------------------------------------------------------------------------
689  /// @brief Notifies the engine that the embedder encountered an
690  /// accessibility related action on the specified node. This call
691  /// originates on the platform view and has been forwarded to the
692  /// engine here on the UI task runner by the shell.
693  ///
694  /// @param[in] id The identifier of the accessibility node.
695  /// @param[in] action The accessibility related action performed on the
696  /// node of the specified ID.
697  /// @param[in] args Optional data that applies to the specified action.
698  ///
699  void DispatchSemanticsAction(int id,
701  std::vector<uint8_t> args);
702 
703  //----------------------------------------------------------------------------
704  /// @brief Notifies the engine that the embedder has expressed an opinion
705  /// about whether the accessibility tree should be generated or
706  /// not. This call originates in the platform view and is
707  /// forwarded to the engine here on the UI task runner by the
708  /// shell.
709  ///
710  /// @param[in] enabled Whether the accessibility tree is enabled or
711  /// disabled.
712  ///
713  void SetSemanticsEnabled(bool enabled);
714 
715  //----------------------------------------------------------------------------
716  /// @brief Notifies the engine that the embedder has expressed an opinion
717  /// about where the flags to set on the accessibility tree. This
718  /// flag originates in the platform view and is forwarded to the
719  /// engine here on the UI task runner by the shell.
720  ///
721  /// The engine does not care about the accessibility feature flags
722  /// as all it does is forward this information from the embedder
723  /// to the framework. However, curious readers may refer to
724  /// `AccessibilityFeatures` in `window.dart` for currently
725  /// supported accessibility feature flags.
726  ///
727  /// @param[in] flags The features to enable in the accessibility tree.
728  ///
729  void SetAccessibilityFeatures(int32_t flags);
730 
731  // |RuntimeDelegate|
732  void ScheduleFrame(bool regenerate_layer_tree) override;
733 
734  /// Schedule a frame with the default parameter of regenerating the layer
735  /// tree.
736  void ScheduleFrame() { ScheduleFrame(true); }
737 
738  // |RuntimeDelegate|
739  FontCollection& GetFontCollection() override;
740 
741  // Return the asset manager associated with the current engine, or nullptr.
742  std::shared_ptr<AssetManager> GetAssetManager();
743 
744  // |PointerDataDispatcher::Delegate|
745  void DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
746  uint64_t trace_flow_id) override;
747 
748  // |PointerDataDispatcher::Delegate|
749  void ScheduleSecondaryVsyncCallback(const fml::closure& callback) override;
750 
751  //----------------------------------------------------------------------------
752  /// @brief Get the last Entrypoint that was used in the RunConfiguration
753  /// when |Engine::Run| was called.
754  ///
755  const std::string& GetLastEntrypoint() const;
756 
757  //----------------------------------------------------------------------------
758  /// @brief Get the last Entrypoint Library that was used in the
759  /// RunConfiguration when |Engine::Run| was called.
760  ///
761  const std::string& GetLastEntrypointLibrary() const;
762 
763  //----------------------------------------------------------------------------
764  /// @brief Getter for the initial route. This can be set with a platform
765  /// message.
766  ///
767  const std::string& InitialRoute() const { return initial_route_; }
768 
769  private:
771  const Settings settings_;
772  std::unique_ptr<Animator> animator_;
773  std::unique_ptr<RuntimeController> runtime_controller_;
774 
775  // The pointer_data_dispatcher_ depends on animator_ and runtime_controller_.
776  // So it should be defined after them to ensure that pointer_data_dispatcher_
777  // is destructed first.
778  std::unique_ptr<PointerDataDispatcher> pointer_data_dispatcher_;
779 
780  std::string last_entry_point_;
781  std::string last_entry_point_library_;
782  std::string initial_route_;
783  ViewportMetrics viewport_metrics_;
784  std::shared_ptr<AssetManager> asset_manager_;
785  bool activity_running_;
786  bool have_surface_;
787  FontCollection font_collection_;
788  ImageDecoder image_decoder_;
790  size_t hint_freed_bytes_since_last_idle_ = 0;
791  fml::WeakPtrFactory<Engine> weak_factory_;
792 
793  // |RuntimeDelegate|
794  std::string DefaultRouteName() override;
795 
796  // |RuntimeDelegate|
797  void Render(std::unique_ptr<flutter::LayerTree> layer_tree) override;
798 
799  // |RuntimeDelegate|
800  void UpdateSemantics(SemanticsNodeUpdates update,
801  CustomAccessibilityActionUpdates actions) override;
802 
803  // |RuntimeDelegate|
804  void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) override;
805 
806  // |RuntimeDelegate|
807  void OnRootIsolateCreated() override;
808 
809  // |RuntimeDelegate|
810  void UpdateIsolateDescription(const std::string isolate_name,
811  int64_t isolate_port) override;
812 
813  // |RuntimeDelegate|
814  std::unique_ptr<std::vector<std::string>> ComputePlatformResolvedLocale(
815  const std::vector<std::string>& supported_locale_data) override;
816 
817  void SetNeedsReportTimings(bool value) override;
818 
819  void StopAnimator();
820 
821  void StartAnimatorIfPossible();
822 
823  bool HandleLifecyclePlatformMessage(PlatformMessage* message);
824 
825  bool HandleNavigationPlatformMessage(fml::RefPtr<PlatformMessage> message);
826 
827  bool HandleLocalizationPlatformMessage(PlatformMessage* message);
828 
829  void HandleSettingsPlatformMessage(PlatformMessage* message);
830 
831  void HandleAssetPlatformMessage(fml::RefPtr<PlatformMessage> message);
832 
833  bool GetAssetAsBuffer(const std::string& name, std::vector<uint8_t>* data);
834 
835  friend class testing::ShellTest;
836 
838 };
839 
840 } // namespace flutter
841 
842 #endif // SHELL_COMMON_ENGINE_H_
Settings settings_
While the engine operates entirely on the UI task runner, it needs the capabilities of the other comp...
Definition: engine.h:139
Dart_Port GetUIIsolateMainPort()
Gets the main port of the root isolate. Since the isolate is created immediately in the constructor o...
Definition: engine.cc:210
~Engine() override
Destroys the engine engine. Called by the shell on the UI task runner. The running root isolate is te...
void DispatchPointerDataPacket(std::unique_ptr< PointerDataPacket > packet, uint64_t trace_flow_id)
Notifies the engine that the embedder has sent it a pointer data packet. A pointer data packet may co...
Definition: engine.cc:376
Engine(Delegate &delegate, const PointerDataDispatcherMaker &dispatcher_maker, std::shared_ptr< fml::ConcurrentTaskRunner > image_decoder_task_runner, TaskRunners task_runners, Settings settings, std::unique_ptr< Animator > animator, fml::WeakPtr< IOManager > io_manager, std::unique_ptr< RuntimeController > runtime_controller)
Creates an instance of the engine with a supplied RuntimeController. Use the other constructor except...
Definition: engine.cc:38
void BeginFrame(fml::TimePoint frame_time)
Notifies the engine that it is time to begin working on a new frame previously scheduled via a call t...
Definition: engine.cc:184
void ScheduleSecondaryVsyncCallback(const fml::closure &callback) override
Schedule a secondary callback to be executed right after the main VsyncWaiter::AsyncWaitForVsync call...
Definition: engine.cc:476
void OnOutputSurfaceCreated()
Indicates to the Flutter application that it has obtained a rendering surface. This is a good opportu...
Definition: engine.cc:226
void SetAccessibilityFeatures(int32_t flags)
Notifies the engine that the embedder has expressed an opinion about where the flags to set on the ac...
Definition: engine.cc:394
tonic::DartErrorHandleType GetUIIsolateLastError()
Errors that are unhandled on the Dart message loop are kept for further inspection till the next unha...
Definition: engine.cc:222
fml::WeakPtr< Engine > GetWeakPtr() const
Definition: engine.cc:100
The interface for Engine to implement.
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
void SetupDefaultFontManager()
Setup default font manager according to specific platform.
Definition: engine.cc:104
std::function< std::unique_ptr< PointerDataDispatcher >(PointerDataDispatcher::Delegate &)> PointerDataDispatcherMaker
Signature for constructing PointerDataDispatcher.
std::unique_ptr< Animator > animator_
bool UpdateAssetManager(std::shared_ptr< AssetManager > asset_manager)
Updates the asset manager referenced by the root isolate of a Flutter application. This happens implicitly in the call to Engine::Run and Engine::Restart as the asset manager is referenced from the run configuration provided to those calls. In addition to the Engine::Run and Engine::Restart calls, the tooling may need to update the assets available to the application as the user adds them to their project. For example, these assets may be referenced by code that is newly patched in after a hot-reload. Neither the shell or the isolate in relaunched in such cases. The tooling usually patches in the new assets in a temporary location and updates the asset manager to point to that location.
Definition: engine.cc:113
std::unique_ptr< RuntimeController > runtime_controller_
void ScheduleFrame()
Definition: engine.h:736
bool Restart(RunConfiguration configuration)
Tears down an existing root isolate, reuses the components of that isolate and attempts to launch a n...
Definition: engine.cc:135
DartErrorHandleType
Definition: dart_error.h:18
TaskRunners task_runners_
FontCollection & GetFontCollection() override
Definition: engine.cc:464
MockDelegate delegate_
std::shared_ptr< AssetManager > GetAssetManager()
Definition: engine.cc:109
std::function< void()> closure
Definition: closure.h:14
uint8_t value
Specifies all the configuration required by the runtime library to launch the root isolate...
SemanticsAction action
Dart_Handle ComputePlatformResolvedLocale(Dart_Handle supportedLocalesHandle)
std::optional< uint32_t > GetUIIsolateReturnCode()
As described in the discussion for UIIsolateHasLivePorts, the "done-ness" of a Dart application is tr...
Definition: engine.cc:206
void DispatchSemanticsAction(int id, SemanticsAction action, std::vector< uint8_t > args)
Notifies the engine that the embedder encountered an accessibility related action on the specified no...
Definition: engine.cc:384
void DispatchPlatformMessage(fml::RefPtr< PlatformMessage > message)
Notifies the engine that the embedder has sent it a message. This call originates in the platform vie...
Definition: engine.cc:254
RunStatus Run(RunConfiguration configuration)
Moves the root isolate to the DartIsolate::Phase::Running phase on a successful call to this method...
Definition: engine.cc:147
bool UIIsolateHasLivePorts()
It is an unexpected challenge to determine when a Dart application is "done". The application cannot ...
Definition: engine.cc:218
const char * name
Definition: fuchsia.cc:50
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
void NotifyIdle(int64_t deadline)
Notifies the engine that the UI task runner is not expected to undertake a new frame workload till a ...
Definition: engine.cc:198
void OnOutputSurfaceDestroyed()
Indicates to the Flutter application that a previously acquired rendering surface has been lost...
Definition: engine.cc:232
void ReportTimings(std::vector< int64_t > timings)
Dart code cannot fully measure the time it takes for a specific frame to be rendered. This is because Dart code only runs on the UI task runner. That is only a small part of the overall frame workload. The GPU task runner frame workload is executed on a thread where Dart code cannot run (and hence instrument). Besides, due to the pipelined nature of rendering in Flutter, there may be multiple frame workloads being processed at any given time. However, for non-Timeline based profiling, it is useful for trace collection and processing to happen in Dart. To do this, the GPU task runner frame workloads need to be instrumented separately. After a set number of these profiles have been gathered, they need to be reported back to Dart code. The shell reports this extra instrumentation information back to Dart code running on the engine by invoking this method at predefined intervals.
Definition: engine.cc:189
RunStatus
Indicates the result of the call to Engine::Run.
Definition: engine.h:80
void HintFreed(size_t size) override
Notifies the engine that native bytes might be freed if a garbage collection ran at the next NotifyId...
Definition: engine.cc:194
const std::string & GetLastEntrypoint() const
Get the last Entrypoint that was used in the RunConfiguration when |Engine::Run| was called...
Definition: engine.cc:501
const std::string & InitialRoute() const
Getter for the initial route. This can be set with a platform message.
Definition: engine.h:767
std::unordered_map< int32_t, CustomAccessibilityAction > CustomAccessibilityActionUpdates
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: macros.h:27
void DoDispatchPacket(std::unique_ptr< PointerDataPacket > packet, uint64_t trace_flow_id) override
Definition: engine.cc:468
const std::string & GetLastEntrypointLibrary() const
Get the last Entrypoint Library that was used in the RunConfiguration when |Engine::Run| was called...
Definition: engine.cc:505
void SetSemanticsEnabled(bool enabled)
Notifies the engine that the embedder has expressed an opinion about whether the accessibility tree s...
Definition: engine.cc:390
std::string GetUIIsolateName()
Gets the debug name of the root isolate. But default, the debug name of the isolate is derived from i...
Definition: engine.cc:214
void SetViewportMetrics(const ViewportMetrics &metrics)
Updates the viewport metrics for the currently running Flutter application. The viewport metrics deta...
Definition: engine.cc:237
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