| // 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_SHELL_COMMON_ENGINE_H_ | 
 | #define FLUTTER_SHELL_COMMON_ENGINE_H_ | 
 |  | 
 | #include <memory> | 
 | #include <string> | 
 |  | 
 | #include "flutter/assets/asset_manager.h" | 
 | #include "flutter/common/task_runners.h" | 
 | #include "flutter/fml/macros.h" | 
 | #include "flutter/fml/mapping.h" | 
 | #include "flutter/fml/memory/weak_ptr.h" | 
 | #include "flutter/lib/ui/painting/image_decoder.h" | 
 | #include "flutter/lib/ui/painting/image_generator_registry.h" | 
 | #include "flutter/lib/ui/semantics/custom_accessibility_action.h" | 
 | #include "flutter/lib/ui/semantics/semantics_node.h" | 
 | #include "flutter/lib/ui/snapshot_delegate.h" | 
 | #include "flutter/lib/ui/text/font_collection.h" | 
 | #include "flutter/lib/ui/volatile_path_tracker.h" | 
 | #include "flutter/lib/ui/window/platform_message.h" | 
 | #include "flutter/lib/ui/window/viewport_metrics.h" | 
 | #include "flutter/runtime/dart_vm.h" | 
 | #include "flutter/runtime/runtime_controller.h" | 
 | #include "flutter/runtime/runtime_delegate.h" | 
 | #include "flutter/shell/common/animator.h" | 
 | #include "flutter/shell/common/display_manager.h" | 
 | #include "flutter/shell/common/platform_view.h" | 
 | #include "flutter/shell/common/pointer_data_dispatcher.h" | 
 | #include "flutter/shell/common/run_configuration.h" | 
 | #include "flutter/shell/common/shell_io_manager.h" | 
 |  | 
 | namespace flutter { | 
 |  | 
 | //------------------------------------------------------------------------------ | 
 | /// The engine is a component owned by the shell that resides on the UI task | 
 | /// runner and is responsible for managing the needs of the root isolate and its | 
 | /// runtime. The engine can only be created, accessed and collected on the UI | 
 | /// task runner. Each shell owns exactly one instance of the engine. | 
 | /// | 
 | /// The root isolate of Flutter application gets "window" bindings. Using these | 
 | /// bindings, the application can schedule frames, post layer-trees for | 
 | /// rendering, ask to decompress images and upload them to the GPU, etc.. | 
 | /// Non-root isolates of the VM do not get any of these capabilities and are run | 
 | /// in a VM managed thread pool (so if they did have "window", the threading | 
 | /// guarantees needed for engine operation would be violated). | 
 | /// | 
 | /// The engine is responsible for the entire life-cycle of the root isolate. | 
 | /// When the engine is collected, its owner assumes that the root isolate has | 
 | /// been shutdown and appropriate resources collected. While each engine | 
 | /// instance can only manage a single instance of a root isolate, it may restart | 
 | /// that isolate on request. This is how the cold-restart development scenario | 
 | /// is supported. | 
 | /// | 
 | /// When the engine instance is initially created, the root isolate is created | 
 | /// but it is not in the |DartIsolate::Phase::Running| phase yet. It only moves | 
 | /// into that phase when a successful call to `Engine::Run` is made. | 
 | /// | 
 | /// @see      `Shell` | 
 | /// | 
 | /// @note     This name of this class is perhaps a bit unfortunate and has | 
 | ///           sometimes been the cause of confusion. For a class named "Engine" | 
 | ///           in the Flutter "Engine" repository, its responsibilities are | 
 | ///           decidedly unremarkable. But, it does happen to be the primary | 
 | ///           entry-point used by components higher up in the Flutter tech stack | 
 | ///           (usually in Dart code) to peer into the lower level functionality. | 
 | ///           Besides, the authors haven't been able to come up with a more apt | 
 | ///           name and it does happen to be one of the older classes in the | 
 | ///           repository. | 
 | /// | 
 | class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { | 
 |  public: | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Indicates the result of the call to `Engine::Run`. | 
 |   /// | 
 |   enum class RunStatus { | 
 |     // NOLINTBEGIN(readability-identifier-naming) | 
 |     //-------------------------------------------------------------------------- | 
 |     /// The call to |Engine::Run| was successful and the root isolate is in the | 
 |     /// `DartIsolate::Phase::Running` phase with its entry-point invocation | 
 |     /// already pending in the task queue. | 
 |     /// | 
 |     Success, | 
 |  | 
 |     //-------------------------------------------------------------------------- | 
 |     /// The engine can only manage a single instance of a root isolate. If a | 
 |     /// previous call to run the root isolate was successful, subsequent calls | 
 |     /// to run the isolate (even if the new run configuration is different) will | 
 |     /// be rejected. | 
 |     /// | 
 |     /// It is up to the caller to decide to re-purpose the running isolate, | 
 |     /// terminate it, or use another shell to host the new isolate. This is | 
 |     /// mostly used by embedders which have a fire-and-forget strategy to root | 
 |     /// isolate launch. For example, the application may try to "launch" an | 
 |     /// isolate when the embedders launches or resumes from a paused state. That | 
 |     /// the isolate is running is not necessarily a failure condition for them. | 
 |     /// But from the engine's perspective, the run configuration was rejected. | 
 |     /// | 
 |     FailureAlreadyRunning, | 
 |  | 
 |     //-------------------------------------------------------------------------- | 
 |     /// Used to indicate to the embedder that a root isolate was not already | 
 |     /// running but the run configuration was not valid and root isolate could | 
 |     /// not be moved into the `DartIsolate::Phase::Running` phase. | 
 |     /// | 
 |     /// The caller must attempt the run call again with a valid configuration. | 
 |     /// The set of all failure modes is massive and can originate from a variety | 
 |     /// of sub-components. The engine will attempt to log the same when | 
 |     /// possible. With the aid of logs, the common causes of failure are: | 
 |     /// | 
 |     /// * AOT assets were given to JIT/DBC mode VM's and vice-versa. | 
 |     /// * The assets could not be found in the asset manager. Callers must make | 
 |     ///   sure their run configuration asset managers have been correctly set | 
 |     ///   up. | 
 |     /// * The assets themselves were corrupt or invalid. Callers must make sure | 
 |     ///   their asset delivery mechanisms are sound. | 
 |     /// * The application entry-point or the root library of the entry-point | 
 |     ///   specified in the run configuration was invalid. Callers must make sure | 
 |     ///   that the entry-point is present in the application. If the name of the | 
 |     ///   entrypoint is not "main" in the root library, callers must also ensure | 
 |     ///   that the snapshotting process has not tree-shaken away this | 
 |     ///   entrypoint. This requires the decoration of the entrypoint with the | 
 |     ///   `@pragma('vm:entry-point')` directive. This problem will manifest in | 
 |     ///   AOT mode operation of the Dart VM. | 
 |     /// | 
 |     Failure, | 
 |     // NOLINTEND(readability-identifier-naming) | 
 |   }; | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      While the engine operates entirely on the UI task runner, it | 
 |   ///             needs the capabilities of the other components to fulfill the | 
 |   ///             requirements of the root isolate. The shell is the only class | 
 |   ///             that implements this interface as no other component has | 
 |   ///             access to all components in a thread safe manner. The engine | 
 |   ///             delegates these tasks to the shell via this interface. | 
 |   /// | 
 |   class Delegate { | 
 |    public: | 
 |     //-------------------------------------------------------------------------- | 
 |     /// @brief      When the accessibility tree has been updated by the Flutter | 
 |     ///             application, this new information needs to be conveyed to | 
 |     ///             the underlying platform. The engine delegates this task to | 
 |     ///             the shell via this call. The engine cannot access the | 
 |     ///             underlying platform directly because of threading | 
 |     ///             considerations. Most platform specific APIs to convey | 
 |     ///             accessibility information are only safe to access on the | 
 |     ///             platform task runner while the engine is running on the UI | 
 |     ///             task runner. | 
 |     /// | 
 |     /// @see        `SemanticsNode`, `SemanticsNodeUpdates`, | 
 |     ///             `CustomAccessibilityActionUpdates`, | 
 |     ///             `PlatformView::UpdateSemantics` | 
 |     /// | 
 |     /// @param[in]  updates  A map with the stable semantics node identifier as | 
 |     ///                      key and the node properties as the value. | 
 |     /// @param[in]  actions  A map with the stable semantics node identifier as | 
 |     ///                      key and the custom node action as the value. | 
 |     /// | 
 |     virtual void OnEngineUpdateSemantics( | 
 |         SemanticsNodeUpdates updates, | 
 |         CustomAccessibilityActionUpdates actions) = 0; | 
 |  | 
 |     //-------------------------------------------------------------------------- | 
 |     /// @brief      When the Flutter application has a message to send to the | 
 |     ///             underlying platform, the message needs to be forwarded to | 
 |     ///             the platform on the appropriate thread (via the platform | 
 |     ///             task runner). The engine delegates this task to the shell | 
 |     ///             via this method. | 
 |     /// | 
 |     /// @see        `PlatformView::HandlePlatformMessage` | 
 |     /// | 
 |     /// @param[in]  message  The message from the Flutter application to send to | 
 |     ///                      the underlying platform. | 
 |     /// | 
 |     virtual void OnEngineHandlePlatformMessage( | 
 |         std::unique_ptr<PlatformMessage> message) = 0; | 
 |  | 
 |     //-------------------------------------------------------------------------- | 
 |     /// @brief      Notifies the delegate that the root isolate of the | 
 |     ///             application is about to be discarded and a new isolate with | 
 |     ///             the same runtime started in its place. This should only | 
 |     ///             happen in the Flutter "debug" runtime mode in the | 
 |     ///             cold-restart scenario. The embedder may need to reset native | 
 |     ///             resource in response to the restart. | 
 |     /// | 
 |     /// @see        `PlatformView::OnPreEngineRestart` | 
 |     /// | 
 |     virtual void OnPreEngineRestart() = 0; | 
 |  | 
 |     //-------------------------------------------------------------------------- | 
 |     /// @brief      Notifies the shell that the root isolate is created. | 
 |     ///             Currently, this information is to add to the service | 
 |     ///             protocol list of available root isolates running in the VM | 
 |     ///             and their names so that the appropriate isolate can be | 
 |     ///             selected in the tools for debugging and instrumentation. | 
 |     /// | 
 |     virtual void OnRootIsolateCreated() = 0; | 
 |  | 
 |     //-------------------------------------------------------------------------- | 
 |     /// @brief      Notifies the shell of the name of the root isolate and its | 
 |     ///             port when that isolate is launched, restarted (in the | 
 |     ///             cold-restart scenario) or the application itself updates the | 
 |     ///             name of the root isolate (via | 
 |     ///             `PlatformDispatcher.setIsolateDebugName` in | 
 |     ///             `platform_dispatcher.dart`). The name of the isolate is | 
 |     ///             meaningless to the engine but is used in instrumentation and | 
 |     ///             tooling. Currently, this information is to update the | 
 |     ///             service protocol list of available root isolates running in | 
 |     ///             the VM and their names so that the appropriate isolate can | 
 |     ///             be selected in the tools for debugging and instrumentation. | 
 |     /// | 
 |     /// @param[in]  isolate_name  The isolate name | 
 |     /// @param[in]  isolate_port  The isolate port | 
 |     /// | 
 |     virtual void UpdateIsolateDescription(const std::string isolate_name, | 
 |                                           int64_t isolate_port) = 0; | 
 |  | 
 |     //-------------------------------------------------------------------------- | 
 |     /// @brief      Notifies the shell that the application has an opinion about | 
 |     ///             whether its frame timings need to be reported backed to it. | 
 |     ///             Due to the asynchronous nature of rendering in Flutter, it | 
 |     ///             is not possible for the application to determine the total | 
 |     ///             time it took to render a specific frame. While the | 
 |     ///             layer-tree is constructed on the UI thread, it needs to be | 
 |     ///             rendering on the raster thread. Dart code cannot execute on | 
 |     ///             this thread. So any instrumentation about the frame times | 
 |     ///             gathered on this thread needs to be aggregated and sent back | 
 |     ///             to the UI thread for processing in Dart. | 
 |     /// | 
 |     ///             When the application indicates that frame times need to be | 
 |     ///             reported, it collects this information till a specified | 
 |     ///             number of data points are gathered. Then this information is | 
 |     ///             sent back to Dart code via `Engine::ReportTimings`. | 
 |     /// | 
 |     ///             This option is engine counterpart of the | 
 |     ///             `Window._setNeedsReportTimings` in `window.dart`. | 
 |     /// | 
 |     /// @param[in]  needs_reporting  If reporting information should be | 
 |     ///                              collected and send back to Dart. | 
 |     /// | 
 |     virtual void SetNeedsReportTimings(bool needs_reporting) = 0; | 
 |  | 
 |     //-------------------------------------------------------------------------- | 
 |     /// @brief      Directly invokes platform-specific APIs to compute the | 
 |     ///             locale the platform would have natively resolved to. | 
 |     /// | 
 |     /// @param[in]  supported_locale_data  The vector of strings that represents | 
 |     ///                                    the locales supported by the app. | 
 |     ///                                    Each locale consists of three | 
 |     ///                                    strings: languageCode, countryCode, | 
 |     ///                                    and scriptCode in that order. | 
 |     /// | 
 |     /// @return     A vector of 3 strings languageCode, countryCode, and | 
 |     ///             scriptCode that represents the locale selected by the | 
 |     ///             platform. Empty strings mean the value was unassigned. Empty | 
 |     ///             vector represents a null locale. | 
 |     /// | 
 |     virtual std::unique_ptr<std::vector<std::string>> | 
 |     ComputePlatformResolvedLocale( | 
 |         const std::vector<std::string>& supported_locale_data) = 0; | 
 |  | 
 |     //-------------------------------------------------------------------------- | 
 |     /// @brief      Invoked when the Dart VM requests that a deferred library | 
 |     ///             be loaded. Notifies the engine that the deferred library | 
 |     ///             identified by the specified loading unit id should be | 
 |     ///             downloaded and loaded into the Dart VM via | 
 |     ///             `LoadDartDeferredLibrary` | 
 |     /// | 
 |     ///             Upon encountering errors or otherwise failing to load a | 
 |     ///             loading unit with the specified id, the failure should be | 
 |     ///             directly reported to dart by calling | 
 |     ///             `LoadDartDeferredLibraryFailure` to ensure the waiting dart | 
 |     ///             future completes with an error. | 
 |     /// | 
 |     /// @param[in]  loading_unit_id  The unique id of the deferred library's | 
 |     ///                              loading unit. This id is to be passed | 
 |     ///                              back into LoadDartDeferredLibrary | 
 |     ///                              in order to identify which deferred | 
 |     ///                              library to load. | 
 |     /// | 
 |     virtual void RequestDartDeferredLibrary(intptr_t loading_unit_id) = 0; | 
 |  | 
 |     //-------------------------------------------------------------------------- | 
 |     /// @brief      Returns the current fml::TimePoint. | 
 |     ///             This method is primarily provided to allow tests to control | 
 |     ///             Any methods that rely on advancing the clock. | 
 |     virtual fml::TimePoint GetCurrentTimePoint() = 0; | 
 |  | 
 |     //---------------------------------------------------------------------------- | 
 |     /// @brief Returns the delegate object that handles PlatformMessage's from | 
 |     ///        Flutter to the host platform (and its responses). | 
 |     virtual const std::shared_ptr<PlatformMessageHandler>& | 
 |     GetPlatformMessageHandler() const = 0; | 
 |  | 
 |     //-------------------------------------------------------------------------- | 
 |     /// @brief      Invoked when a listener is registered on a platform channel. | 
 |     /// | 
 |     /// @param[in]  name             The name of the platform channel to which a | 
 |     ///                              listener has been registered or cleared. | 
 |     /// | 
 |     /// @param[in]  listening        Whether the listener has been set (true) or | 
 |     ///                              cleared (false). | 
 |     /// | 
 |     virtual void OnEngineChannelUpdate(std::string name, bool listening) = 0; | 
 |  | 
 |     //-------------------------------------------------------------------------- | 
 |     /// @brief      Synchronously invokes platform-specific APIs to apply the | 
 |     ///             system text scaling on the given unscaled font size. | 
 |     /// | 
 |     ///             Platforms that support this feature (currently it's only | 
 |     ///             implemented for Android SDK level 34+) will send a valid | 
 |     ///             configuration_id to potential callers, before this method | 
 |     ///             can be called. | 
 |     /// | 
 |     /// @param[in]  unscaled_font_size  The unscaled font size specified by the | 
 |     ///                                 app developer. The value is in logical | 
 |     ///                                 pixels, and is guaranteed to be finite | 
 |     ///                                 and non-negative. | 
 |     /// @param[in]  configuration_id    The unique id of the configuration to | 
 |     ///                                 use for computing the scaled font size. | 
 |     /// | 
 |     /// @return     The scaled font size in logical pixels, or -1 when the given | 
 |     ///             configuration_id did not match a valid configuration. | 
 |     /// | 
 |     virtual double GetScaledFontSize(double unscaled_font_size, | 
 |                                      int configuration_id) const = 0; | 
 |   }; | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Creates an instance of the engine with a supplied | 
 |   ///             `RuntimeController`.  Use the other constructor except for | 
 |   ///             tests. | 
 |   /// | 
 |   Engine(Delegate& delegate, | 
 |          const PointerDataDispatcherMaker& dispatcher_maker, | 
 |          const std::shared_ptr<fml::ConcurrentTaskRunner>& | 
 |              image_decoder_task_runner, | 
 |          const TaskRunners& task_runners, | 
 |          const Settings& settings, | 
 |          std::unique_ptr<Animator> animator, | 
 |          const fml::WeakPtr<IOManager>& io_manager, | 
 |          const std::shared_ptr<FontCollection>& font_collection, | 
 |          std::unique_ptr<RuntimeController> runtime_controller, | 
 |          const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Creates an instance of the engine. This is done by the Shell | 
 |   ///             on the UI task runner. | 
 |   /// | 
 |   /// @param      delegate           The object used by the engine to perform | 
 |   ///                                tasks that require access to components | 
 |   ///                                that cannot be safely accessed by the | 
 |   ///                                engine. This is the shell. | 
 |   /// @param      dispatcher_maker   The callback provided by `PlatformView` for | 
 |   ///                                engine to create the pointer data | 
 |   ///                                dispatcher. Similar to other engine | 
 |   ///                                resources, this dispatcher_maker and its | 
 |   ///                                returned dispatcher is only safe to be | 
 |   ///                                called from the UI thread. | 
 |   /// @param      vm                 An instance of the running Dart VM. | 
 |   /// @param[in]  isolate_snapshot   The snapshot used to create the root | 
 |   ///                                isolate. Even though the isolate is not | 
 |   ///                                `DartIsolate::Phase::Running` phase, it is | 
 |   ///                                created when the engine is created. This | 
 |   ///                                requires access to the isolate snapshot | 
 |   ///                                upfront. | 
 |   //  TODO(chinmaygarde): This is probably redundant now that the IO manager is | 
 |   //  it's own object. | 
 |   /// @param[in]  task_runners       The task runners used by the shell that | 
 |   ///                                hosts this engine. | 
 |   /// @param[in]  settings           The settings used to initialize the shell | 
 |   ///                                and the engine. | 
 |   /// @param[in]  animator           The animator used to schedule frames. | 
 |   //  TODO(chinmaygarde): Move this to `Engine::Delegate` | 
 |   /// @param[in]  snapshot_delegate  The delegate used to fulfill requests to | 
 |   ///                                snapshot a specified scene. The engine | 
 |   ///                                cannot snapshot a scene on the UI thread | 
 |   ///                                directly because the scene (described via | 
 |   ///                                a `DisplayList`) may reference resources on | 
 |   ///                                the GPU and there is no GPU context current | 
 |   ///                                on the UI thread. The delegate is a | 
 |   ///                                component that has access to all the | 
 |   ///                                requisite GPU resources. | 
 |   /// @param[in]  io_manager         The IO manager used by this root isolate to | 
 |   ///                                schedule tasks that manage resources on the | 
 |   ///                                GPU. | 
 |   /// | 
 |   Engine(Delegate& delegate, | 
 |          const PointerDataDispatcherMaker& dispatcher_maker, | 
 |          DartVM& vm, | 
 |          fml::RefPtr<const DartSnapshot> isolate_snapshot, | 
 |          const TaskRunners& task_runners, | 
 |          const PlatformData& platform_data, | 
 |          const Settings& settings, | 
 |          std::unique_ptr<Animator> animator, | 
 |          fml::WeakPtr<IOManager> io_manager, | 
 |          const fml::RefPtr<SkiaUnrefQueue>& unref_queue, | 
 |          fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate, | 
 |          std::shared_ptr<VolatilePathTracker> volatile_path_tracker, | 
 |          const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch, | 
 |          impeller::RuntimeStageBackend runtime_stage_type = | 
 |              impeller::RuntimeStageBackend::kSkSL); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Create a Engine that shares as many resources as | 
 |   ///             possible with the calling Engine such that together | 
 |   ///             they occupy less memory and be created faster. | 
 |   /// @details    This should only be called on running Engines. | 
 |   /// @return     A new Engine with a running isolate. | 
 |   /// @see        Engine::Engine | 
 |   /// @see        DartIsolate::SpawnIsolate | 
 |   /// | 
 |   std::unique_ptr<Engine> Spawn( | 
 |       Delegate& delegate, | 
 |       const PointerDataDispatcherMaker& dispatcher_maker, | 
 |       const Settings& settings, | 
 |       std::unique_ptr<Animator> animator, | 
 |       const std::string& initial_route, | 
 |       const fml::WeakPtr<IOManager>& io_manager, | 
 |       fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate, | 
 |       const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch) const; | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Destroys the engine engine. Called by the shell on the UI task | 
 |   ///             runner. The running root isolate is terminated and will no | 
 |   ///             longer access the task runner after this call returns. This | 
 |   ///             allows the embedder to tear down the thread immediately if | 
 |   ///             needed. | 
 |   /// | 
 |   ~Engine() override; | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @return     The pointer to this instance of the engine. The engine may | 
 |   ///             only be accessed safely on the UI task runner. | 
 |   /// | 
 |   fml::WeakPtr<Engine> GetWeakPtr() const; | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Moves the root isolate to the `DartIsolate::Phase::Running` | 
 |   ///             phase on a successful call to this method. | 
 |   /// | 
 |   ///             The isolate itself is created when the engine is created, but | 
 |   ///             it is not yet in the running phase. This is done to amortize | 
 |   ///             initial time taken to launch the root isolate. The isolate | 
 |   ///             snapshots used to run the isolate can be fetched on another | 
 |   ///             thread while the engine itself is launched on the UI task | 
 |   ///             runner. | 
 |   /// | 
 |   ///             Repeated calls to this method after a successful run will be | 
 |   ///             rejected even if the run configuration is valid (with the | 
 |   ///             appropriate error returned). | 
 |   /// | 
 |   /// @param[in]  configuration  The configuration used to run the root isolate. | 
 |   ///                            The configuration must be valid. | 
 |   /// | 
 |   /// @return     The result of the call to run the root isolate. | 
 |   /// | 
 |   [[nodiscard]] RunStatus Run(RunConfiguration configuration); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Tears down an existing root isolate, reuses the components of | 
 |   ///             that isolate and attempts to launch a new isolate using the | 
 |   ///             given the run configuration. This is only used in the | 
 |   ///             "debug" Flutter runtime mode in the cold-restart scenario. | 
 |   /// | 
 |   /// @attention  This operation must be performed with care as even a | 
 |   ///             non-successful restart will still tear down any existing root | 
 |   ///             isolate. In such cases, the engine and its shell must be | 
 |   ///             discarded. | 
 |   /// | 
 |   /// @param[in]  configuration  The configuration used to launch the new | 
 |   ///                            isolate. | 
 |   /// | 
 |   /// @return     Whether the restart was successful. If not, the engine and its | 
 |   ///             shell must be discarded. | 
 |   /// | 
 |   [[nodiscard]] bool Restart(RunConfiguration configuration); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Setup default font manager according to specific platform. | 
 |   /// | 
 |   void SetupDefaultFontManager(); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      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. | 
 |   /// | 
 |   /// @param[in]  asset_manager  The new asset manager to use for the running | 
 |   ///                            root isolate. | 
 |   /// | 
 |   /// @return     If the asset manager was successfully replaced. This may fail | 
 |   ///             if the new asset manager is invalid. | 
 |   /// | 
 |   bool UpdateAssetManager(const std::shared_ptr<AssetManager>& asset_manager); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Notifies the engine that it is time to begin working on a new | 
 |   ///             frame previously scheduled via a call to | 
 |   ///             `Engine::ScheduleFrame`. This call originates in the animator. | 
 |   /// | 
 |   ///             The frame time given as the argument indicates the point at | 
 |   ///             which the current frame interval began. It is very slightly | 
 |   ///             (because of scheduling overhead) in the past. If a new layer | 
 |   ///             tree is not produced and given to the raster task runner | 
 |   ///             within one frame interval from this point, the Flutter | 
 |   ///             application will jank. | 
 |   /// | 
 |   ///             If a root isolate is running, this method calls the | 
 |   ///             `::_beginFrame` method in `hooks.dart`. If a root isolate is | 
 |   ///             not running, this call does nothing. | 
 |   /// | 
 |   ///             This method encapsulates the entire UI thread frame workload. | 
 |   ///             The following (mis)behavior in the functioning of the method | 
 |   ///             will cause the jank in the Flutter application: | 
 |   ///             * The time taken by this method to create a layer-tree exceeds | 
 |   ///               one frame interval (for example, 16.66 ms on a 60Hz | 
 |   ///               display). | 
 |   ///             * The time take by this method to generate a new layer-tree | 
 |   ///               causes the current layer-tree pipeline depth to change. To | 
 |   ///               illustrate this point, note that maximum pipeline depth used | 
 |   ///               by layer tree in the engine is 2. If both the UI and GPU | 
 |   ///               task runner tasks finish within one frame interval, the | 
 |   ///               pipeline depth is one. If the UI thread happens to be | 
 |   ///               working on a frame when the raster thread is still not done | 
 |   ///               with the previous frame, the pipeline depth is 2. When the | 
 |   ///               pipeline depth changes from 1 to 2, animations and UI | 
 |   ///               interactions that cause the generation of the new layer tree | 
 |   ///               appropriate for (frame_time + one frame interval) will | 
 |   ///               actually end up at (frame_time + two frame intervals). This | 
 |   ///               is not what code running on the UI thread expected would | 
 |   ///               happen. This causes perceptible jank. | 
 |   /// | 
 |   /// @param[in]  frame_time  The point at which the current frame interval | 
 |   ///                         began. May be used by animation interpolators, | 
 |   ///                         physics simulations, etc.. | 
 |   /// | 
 |   /// @param[in]  frame_number The frame number recorded by the animator. Used | 
 |   ///                          by the framework to associate frame specific | 
 |   ///                          debug information with frame timings and timeline | 
 |   ///                          events. | 
 |   void BeginFrame(fml::TimePoint frame_time, uint64_t frame_number); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Notifies the engine that the UI task runner is not expected to | 
 |   ///             undertake a new frame workload till a specified timepoint. The | 
 |   ///             timepoint is measured in microseconds against the system's | 
 |   ///             monotonic clock. It is recommended that the clock be accessed | 
 |   ///             via `Dart_TimelineGetMicros` from `dart_api.h` for | 
 |   ///             consistency. In reality, the clocks used by Dart, FML and | 
 |   ///             std::steady_clock are all the same and the timepoints can be | 
 |   ///             converted from on clock type to another. | 
 |   /// | 
 |   ///             The Dart VM uses this notification to schedule book-keeping | 
 |   ///             tasks that may include a garbage collection. In this way, it | 
 |   ///             is less likely for the VM to perform such (potentially long | 
 |   ///             running) tasks in the middle of a frame workload. | 
 |   /// | 
 |   ///             This notification is advisory. That is, not providing this | 
 |   ///             notification does not mean garbage collection is postponed | 
 |   ///             till this call is made. If this notification is not provided, | 
 |   ///             garbage collection will happen based on the usual heuristics | 
 |   ///             used by the Dart VM. | 
 |   /// | 
 |   ///             Currently, this idle notification is delivered to the engine | 
 |   ///             at two points. Once, the deadline is calculated based on how | 
 |   ///             much time in the current frame interval is left on the UI task | 
 |   ///             runner. Since the next frame workload cannot begin till at | 
 |   ///             least the next callback from the vsync waiter, this period may | 
 |   ///             be used to used as a "small" idle notification. On the other | 
 |   ///             hand, if no more frames are scheduled, a large (but arbitrary) | 
 |   ///             idle notification deadline is chosen for a "big" idle | 
 |   ///             notification. Again, this notification does not guarantee | 
 |   ///             collection, just gives the Dart VM more hints about opportune | 
 |   ///             moments to perform collections. | 
 |   /// | 
 |   /// | 
 |   /// @param[in]  deadline  The deadline is used by the VM to determine if the | 
 |   ///                       corresponding sweep can be performed within the | 
 |   ///                       deadline. | 
 |   /// | 
 |   void NotifyIdle(fml::TimeDelta deadline); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Notifies the engine that the attached flutter view has been | 
 |   ///             destroyed. | 
 |   ///             This enables the engine to notify the Dart VM so it can do | 
 |   ///             some cleanp activities. | 
 |   void NotifyDestroyed(); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      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 raster 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 raster 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. | 
 |   /// | 
 |   /// @see        `FrameTiming` | 
 |   /// | 
 |   //  TODO(chinmaygarde): The use `int64_t` is added for ease of conversion to | 
 |   //  Dart but hurts readability. The phases and the units of the timepoints are | 
 |   //  not obvious without some sleuthing. The conversion can happen at the | 
 |   //  native interface boundary instead. | 
 |   /// | 
 |   /// @param[in]  timings  Collection of `FrameTiming::kCount` * `n` timestamps | 
 |   ///                      for `n` frames whose timings have not been reported | 
 |   ///                      yet. A collection of integers is reported here for | 
 |   ///                      easier conversions to Dart objects. The timestamps | 
 |   ///                      are measured against the system monotonic clock | 
 |   ///                      measured in microseconds. | 
 |   /// | 
 |   void ReportTimings(std::vector<int64_t> timings); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Gets the main port of the root isolate. Since the isolate is | 
 |   ///             created immediately in the constructor of the engine, it is | 
 |   ///             possible to get its main port immediately (even before a call | 
 |   ///             to `Run` can be made). This is useful in registering the port | 
 |   ///             in a race free manner with a port nameserver. | 
 |   /// | 
 |   /// @return     The main port of the root isolate. | 
 |   /// | 
 |   Dart_Port GetUIIsolateMainPort(); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Gets the debug name of the root isolate. By default, the | 
 |   ///             debug name of the isolate is derived from its advisory script | 
 |   ///             URI, advisory main entrypoint and its main port name. For | 
 |   ///             example, "main.dart$main-1234" where the script URI is | 
 |   ///             "main.dart", the entrypoint is "main" and the port name | 
 |   ///             "1234". Once launched, the isolate may re-christen itself | 
 |   ///             using a name it selects via `setIsolateDebugName` in | 
 |   ///             `platform_dispatcher.dart`. This name is purely advisory and | 
 |   ///             only used by instrumentation and reporting purposes. | 
 |   /// | 
 |   /// @return     The debug name of the root isolate. | 
 |   /// | 
 |   std::string GetUIIsolateName(); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      It is an unexpected challenge to determine when a Dart | 
 |   ///             application is "done". The application cannot simply terminate | 
 |   ///             the native process (and perhaps return an exit code) because | 
 |   ///             it does not have that power. After all, Flutter applications | 
 |   ///             reside within a host process that may have other | 
 |   ///             responsibilities besides just running Flutter applications. | 
 |   ///             Also, the `main` entry-points are run on an event loop and | 
 |   ///             returning from "main" (unlike in C/C++ applications) does not | 
 |   ///             mean termination of the process. Besides, the return value of | 
 |   ///             the main entrypoint is discarded. | 
 |   /// | 
 |   ///             One technique used by embedders to determine "liveness" is to | 
 |   ///             count the outstanding live ports dedicated to the application. | 
 |   ///             These ports may be live as a result of pending timers, | 
 |   ///             scheduled tasks, pending IO on sockets, channels open with | 
 |   ///             other isolates, etc.. At regular intervals (sometimes as often | 
 |   ///             as after the UI task runner processes any task), embedders may | 
 |   ///             check for the "liveness" of the application and perform | 
 |   ///             teardown of the embedder when no more ports are live. | 
 |   /// | 
 |   /// @return     Check if the root isolate has any live ports. | 
 |   /// | 
 |   bool UIIsolateHasLivePorts(); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Errors that are unhandled on the Dart message loop are kept | 
 |   ///             for further inspection till the next unhandled error comes | 
 |   ///             along. This accessor returns the last unhandled error | 
 |   ///             encountered by the root isolate. | 
 |   /// | 
 |   /// @return     The ui isolate last error. | 
 |   /// | 
 |   tonic::DartErrorHandleType GetUIIsolateLastError(); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      As described in the discussion for `UIIsolateHasLivePorts`, | 
 |   ///             the "done-ness" of a Dart application is tricky to ascertain | 
 |   ///             and the return value from the main entrypoint is discarded | 
 |   ///             (because the Dart isolate is still running after the main | 
 |   ///             entrypoint returns). But, the concept of an exit code akin to | 
 |   ///             those returned by native applications is still useful. Short | 
 |   ///             lived Dart applications (usually tests), emulate this by | 
 |   ///             setting a per isolate "return value" and then indicating their | 
 |   ///             "done-ness" (usually via closing all live ports). This | 
 |   ///             accessor returns that "return value" is present. | 
 |   /// | 
 |   /// @see        `UIIsolateHasLivePorts` | 
 |   /// | 
 |   /// @return     The return code (if specified) by the isolate. | 
 |   /// | 
 |   std::optional<uint32_t> GetUIIsolateReturnCode(); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Notify the Flutter application that a new view is available. | 
 |   /// | 
 |   ///             A view must be added before other methods can refer to it, | 
 |   ///             including the implicit view. Adding a view that already exists | 
 |   ///             triggers an assertion. | 
 |   /// | 
 |   /// @param[in]  view_id           The ID of the new view. | 
 |   /// @param[in]  viewport_metrics  The initial viewport metrics for the view. | 
 |   /// @param[in]  callback          Callback that will be invoked once | 
 |   ///                               the engine attempts to add the view. | 
 |   /// | 
 |   void AddView(int64_t view_id, | 
 |                const ViewportMetrics& view_metrics, | 
 |                std::function<void(bool added)> callback); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Notify the Flutter application that a view is no | 
 |   ///             longer available. | 
 |   /// | 
 |   ///             Removing a view that does not exist triggers an assertion. | 
 |   /// | 
 |   ///             The implicit view (kFlutterImplicitViewId) should never be | 
 |   ///             removed. Doing so triggers an assertion. | 
 |   /// | 
 |   /// @param[in]  view_id  The ID of the view. | 
 |   /// | 
 |   /// @return     Whether the view was removed. | 
 |   /// | 
 |   bool RemoveView(int64_t view_id); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Updates the viewport metrics for a view. The viewport metrics | 
 |   ///             detail the size of the rendering viewport in texels as well as | 
 |   ///             edge insets if present. | 
 |   /// | 
 |   /// @see        `ViewportMetrics` | 
 |   /// | 
 |   /// @param[in]  view_id  The ID for the view that `metrics` describes. | 
 |   /// @param[in]  metrics  The metrics. | 
 |   /// | 
 |   void SetViewportMetrics(int64_t view_id, const ViewportMetrics& metrics); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Updates the display metrics for the currently running Flutter | 
 |   ///             application. | 
 |   /// | 
 |   /// @param[in]  displays  A complete list of displays | 
 |   /// | 
 |   void SetDisplays(const std::vector<DisplayData>& displays); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Notifies the engine that the embedder has sent it a message. | 
 |   ///             This call originates in the platform view and has been | 
 |   ///             forwarded to the engine on the UI task runner here. | 
 |   /// | 
 |   /// @param[in]  message  The message sent from the embedder to the Dart | 
 |   ///                      application. | 
 |   /// | 
 |   void DispatchPlatformMessage(std::unique_ptr<PlatformMessage> message); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Notifies the engine that the embedder has sent it a pointer | 
 |   ///             data packet. A pointer data packet may contain multiple | 
 |   ///             input events. This call originates in the platform view and | 
 |   ///             the shell has forwarded the same to the engine on the UI task | 
 |   ///             runner here. | 
 |   /// | 
 |   /// @param[in]  packet         The pointer data packet containing multiple | 
 |   ///                            input events. | 
 |   /// @param[in]  trace_flow_id  The trace flow identifier associated with the | 
 |   ///                            pointer data packet. The engine uses this trace | 
 |   ///                            identifier to connect trace flows in the | 
 |   ///                            timeline from the input event to the | 
 |   ///                            frames generated due to those input events. | 
 |   ///                            These flows are tagged as "PointerEvent" in the | 
 |   ///                            timeline and allow grouping frames and input | 
 |   ///                            events into logical chunks. | 
 |   /// | 
 |   void DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet, | 
 |                                  uint64_t trace_flow_id); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Notifies the engine that the embedder encountered an | 
 |   ///             accessibility related action on the specified node. This call | 
 |   ///             originates on the platform view and has been forwarded to the | 
 |   ///             engine here on the UI task runner by the shell. | 
 |   /// | 
 |   /// @param[in]  node_id The identifier of the accessibility node. | 
 |   /// @param[in]  action  The accessibility related action performed on the | 
 |   ///                     node of the specified ID. | 
 |   /// @param[in]  args    Optional data that applies to the specified action. | 
 |   /// | 
 |   void DispatchSemanticsAction(int node_id, | 
 |                                SemanticsAction action, | 
 |                                fml::MallocMapping args); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Notifies the engine that the embedder has expressed an opinion | 
 |   ///             about whether the accessibility tree should be generated or | 
 |   ///             not. This call originates in the platform view and is | 
 |   ///             forwarded to the engine here on the UI task runner by the | 
 |   ///             shell. | 
 |   /// | 
 |   /// @param[in]  enabled  Whether the accessibility tree is enabled or | 
 |   ///                      disabled. | 
 |   /// | 
 |   void SetSemanticsEnabled(bool enabled); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Notifies the engine that the embedder has expressed an opinion | 
 |   ///             about where the flags to set on the accessibility tree. This | 
 |   ///             flag originates in the platform view and is forwarded to the | 
 |   ///             engine here on the UI task runner by the shell. | 
 |   /// | 
 |   ///             The engine does not care about the accessibility feature flags | 
 |   ///             as all it does is forward this information from the embedder | 
 |   ///             to the framework. However, curious readers may refer to | 
 |   ///             `AccessibilityFeatures` in `window.dart` for currently | 
 |   ///             supported accessibility feature flags. | 
 |   /// | 
 |   /// @param[in]  flags  The features to enable in the accessibility tree. | 
 |   /// | 
 |   void SetAccessibilityFeatures(int32_t flags); | 
 |  | 
 |   // |RuntimeDelegate| | 
 |   void ScheduleFrame(bool regenerate_layer_trees) override; | 
 |  | 
 |   /// Schedule a frame with the default parameter of regenerating the layer | 
 |   /// tree. | 
 |   void ScheduleFrame() { ScheduleFrame(true); } | 
 |  | 
 |   // |RuntimeDelegate| | 
 |   void OnAllViewsRendered() override; | 
 |  | 
 |   // |RuntimeDelegate| | 
 |   FontCollection& GetFontCollection() override; | 
 |  | 
 |   // |RuntimeDelegate| | 
 |   std::shared_ptr<AssetManager> GetAssetManager() override; | 
 |  | 
 |   // Return the weak_ptr of ImageDecoder. | 
 |   fml::WeakPtr<ImageDecoder> GetImageDecoderWeakPtr(); | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Get the `ImageGeneratorRegistry` associated with the current | 
 |   ///             engine. | 
 |   /// | 
 |   /// @return     The engine's `ImageGeneratorRegistry`. | 
 |   /// | 
 |   fml::WeakPtr<ImageGeneratorRegistry> GetImageGeneratorRegistry(); | 
 |  | 
 |   // |PointerDataDispatcher::Delegate| | 
 |   void DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet, | 
 |                         uint64_t trace_flow_id) override; | 
 |  | 
 |   // |PointerDataDispatcher::Delegate| | 
 |   void ScheduleSecondaryVsyncCallback(uintptr_t id, | 
 |                                       const fml::closure& callback) override; | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Get the last Entrypoint that was used in the RunConfiguration | 
 |   ///             when |Engine::Run| was called. | 
 |   /// | 
 |   const std::string& GetLastEntrypoint() const; | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Get the last Entrypoint Library that was used in the | 
 |   ///             RunConfiguration when |Engine::Run| was called. | 
 |   /// | 
 |   const std::string& GetLastEntrypointLibrary() const; | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Get the last Entrypoint Arguments that was used in the | 
 |   ///             RunConfiguration when |Engine::Run| was called.This is only | 
 |   ///             valid in debug mode. | 
 |   /// | 
 |   const std::vector<std::string>& GetLastEntrypointArgs() const; | 
 |  | 
 |   //---------------------------------------------------------------------------- | 
 |   /// @brief      Getter for the initial route.  This can be set with a platform | 
 |   ///             message. | 
 |   /// | 
 |   const std::string& InitialRoute() const { return initial_route_; } | 
 |  | 
 |   //-------------------------------------------------------------------------- | 
 |   /// @brief      Loads the Dart shared library into the Dart VM. When the | 
 |   ///             Dart library is loaded successfully, the Dart future | 
 |   ///             returned by the originating loadLibrary() call completes. | 
 |   /// | 
 |   ///             The Dart compiler may generate separate shared libraries | 
 |   ///             files called 'loading units' when libraries are imported | 
 |   ///             as deferred. Each of these shared libraries are identified | 
 |   ///             by a unique loading unit id. Callers should open and resolve | 
 |   ///             a SymbolMapping from the shared library. The Mappings should | 
 |   ///             be moved into this method, as ownership will be assumed by the | 
 |   ///             dart root isolate after successful loading and released after | 
 |   ///             shutdown of the root isolate. The loading unit may not be | 
 |   ///             used after isolate shutdown. If loading fails, the mappings | 
 |   ///             will be released. | 
 |   /// | 
 |   ///             This method is paired with a RequestDartDeferredLibrary | 
 |   ///             invocation that provides the embedder with the loading unit id | 
 |   ///             of the deferred library to load. | 
 |   /// | 
 |   /// | 
 |   /// @param[in]  loading_unit_id  The unique id of the deferred library's | 
 |   ///                              loading unit, as passed in by | 
 |   ///                              RequestDartDeferredLibrary. | 
 |   /// | 
 |   /// @param[in]  snapshot_data    Dart snapshot data of the loading unit's | 
 |   ///                              shared library. | 
 |   /// | 
 |   /// @param[in]  snapshot_data    Dart snapshot instructions of the loading | 
 |   ///                              unit's shared library. | 
 |   /// | 
 |   void LoadDartDeferredLibrary( | 
 |       intptr_t loading_unit_id, | 
 |       std::unique_ptr<const fml::Mapping> snapshot_data, | 
 |       std::unique_ptr<const fml::Mapping> snapshot_instructions); | 
 |  | 
 |   //-------------------------------------------------------------------------- | 
 |   /// @brief      Indicates to the dart VM that the request to load a deferred | 
 |   ///             library with the specified loading unit id has failed. | 
 |   /// | 
 |   ///             The dart future returned by the initiating loadLibrary() call | 
 |   ///             will complete with an error. | 
 |   /// | 
 |   /// @param[in]  loading_unit_id  The unique id of the deferred library's | 
 |   ///                              loading unit, as passed in by | 
 |   ///                              RequestDartDeferredLibrary. | 
 |   /// | 
 |   /// @param[in]  error_message    The error message that will appear in the | 
 |   ///                              dart Future. | 
 |   /// | 
 |   /// @param[in]  transient        A transient error is a failure due to | 
 |   ///                              temporary conditions such as no network. | 
 |   ///                              Transient errors allow the dart VM to | 
 |   ///                              re-request the same deferred library and | 
 |   ///                              loading_unit_id again. Non-transient | 
 |   ///                              errors are permanent and attempts to | 
 |   ///                              re-request the library will instantly | 
 |   ///                              complete with an error. | 
 |   void LoadDartDeferredLibraryError(intptr_t loading_unit_id, | 
 |                                     const std::string& error_message, | 
 |                                     bool transient); | 
 |  | 
 |   //-------------------------------------------------------------------------- | 
 |   /// @brief      Accessor for the RuntimeController. | 
 |   /// | 
 |   const RuntimeController* GetRuntimeController() const { | 
 |     return runtime_controller_.get(); | 
 |   } | 
 |  | 
 |   const std::weak_ptr<VsyncWaiter> GetVsyncWaiter() const; | 
 |  | 
 |   //-------------------------------------------------------------------------- | 
 |   /// @brief      Shuts down all registered platform isolates. Must be called | 
 |   ///             from the platform thread. | 
 |   /// | 
 |   void ShutdownPlatformIsolates(); | 
 |  | 
 |  private: | 
 |   // |RuntimeDelegate| | 
 |   std::string DefaultRouteName() override; | 
 |  | 
 |   // |RuntimeDelegate| | 
 |   void Render(int64_t view_id, | 
 |               std::unique_ptr<flutter::LayerTree> layer_tree, | 
 |               float device_pixel_ratio) override; | 
 |  | 
 |   // |RuntimeDelegate| | 
 |   void UpdateSemantics(SemanticsNodeUpdates update, | 
 |                        CustomAccessibilityActionUpdates actions) override; | 
 |  | 
 |   // |RuntimeDelegate| | 
 |   void HandlePlatformMessage(std::unique_ptr<PlatformMessage> message) override; | 
 |  | 
 |   // |RuntimeDelegate| | 
 |   void OnRootIsolateCreated() override; | 
 |  | 
 |   // |RuntimeDelegate| | 
 |   void UpdateIsolateDescription(const std::string isolate_name, | 
 |                                 int64_t isolate_port) override; | 
 |  | 
 |   // |RuntimeDelegate| | 
 |   std::unique_ptr<std::vector<std::string>> ComputePlatformResolvedLocale( | 
 |       const std::vector<std::string>& supported_locale_data) override; | 
 |  | 
 |   // |RuntimeDelegate| | 
 |   void RequestDartDeferredLibrary(intptr_t loading_unit_id) override; | 
 |  | 
 |   // |RuntimeDelegate| | 
 |   std::weak_ptr<PlatformMessageHandler> GetPlatformMessageHandler() | 
 |       const override; | 
 |  | 
 |   // |RuntimeDelegate| | 
 |   void SendChannelUpdate(std::string name, bool listening) override; | 
 |  | 
 |   // |RuntimeDelegate| | 
 |   double GetScaledFontSize(double unscaled_font_size, | 
 |                            int configuration_id) const override; | 
 |  | 
 |   void SetNeedsReportTimings(bool value) override; | 
 |  | 
 |   bool HandleLifecyclePlatformMessage(PlatformMessage* message); | 
 |  | 
 |   bool HandleNavigationPlatformMessage( | 
 |       std::unique_ptr<PlatformMessage> message); | 
 |  | 
 |   bool HandleLocalizationPlatformMessage(PlatformMessage* message); | 
 |  | 
 |   void HandleSettingsPlatformMessage(PlatformMessage* message); | 
 |  | 
 |   void HandleAssetPlatformMessage(std::unique_ptr<PlatformMessage> message); | 
 |  | 
 |   bool GetAssetAsBuffer(const std::string& name, std::vector<uint8_t>* data); | 
 |  | 
 |   friend class testing::ShellTest; | 
 |  | 
 |   Engine::Delegate& delegate_; | 
 |   const Settings settings_; | 
 |   std::unique_ptr<Animator> animator_; | 
 |   std::unique_ptr<RuntimeController> runtime_controller_; | 
 |  | 
 |   // The pointer_data_dispatcher_ depends on animator_ and runtime_controller_. | 
 |   // So it should be defined after them to ensure that pointer_data_dispatcher_ | 
 |   // is destructed first. | 
 |   std::unique_ptr<PointerDataDispatcher> pointer_data_dispatcher_; | 
 |  | 
 |   std::string last_entry_point_; | 
 |   std::string last_entry_point_library_; | 
 |   std::vector<std::string> last_entry_point_args_; | 
 |   std::string initial_route_; | 
 |   std::shared_ptr<AssetManager> asset_manager_; | 
 |   std::shared_ptr<FontCollection> font_collection_; | 
 |   const std::unique_ptr<ImageDecoder> image_decoder_; | 
 |   ImageGeneratorRegistry image_generator_registry_; | 
 |   TaskRunners task_runners_; | 
 |   fml::WeakPtrFactory<Engine> weak_factory_;  // Must be the last member. | 
 |   FML_DISALLOW_COPY_AND_ASSIGN(Engine); | 
 | }; | 
 |  | 
 | }  // namespace flutter | 
 |  | 
 | #endif  // FLUTTER_SHELL_COMMON_ENGINE_H_ |