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/mapping.h"
15#include "flutter/fml/memory/weak_ptr.h"
16#include "flutter/lib/ui/painting/image_decoder.h"
17#include "flutter/lib/ui/painting/image_generator_registry.h"
18#include "flutter/lib/ui/semantics/custom_accessibility_action.h"
19#include "flutter/lib/ui/semantics/semantics_node.h"
20#include "flutter/lib/ui/snapshot_delegate.h"
21#include "flutter/lib/ui/text/font_collection.h"
22#include "flutter/lib/ui/volatile_path_tracker.h"
23#include "flutter/lib/ui/window/platform_message.h"
24#include "flutter/lib/ui/window/viewport_metrics.h"
25#include "flutter/runtime/dart_vm.h"
26#include "flutter/runtime/runtime_controller.h"
27#include "flutter/runtime/runtime_delegate.h"
28#include "flutter/shell/common/animator.h"
29#include "flutter/shell/common/display_manager.h"
30#include "flutter/shell/common/platform_view.h"
31#include "flutter/shell/common/pointer_data_dispatcher.h"
32#include "flutter/shell/common/rasterizer.h"
33#include "flutter/shell/common/run_configuration.h"
34#include "flutter/shell/common/shell_io_manager.h"
35
36namespace flutter {
37
38//------------------------------------------------------------------------------
39/// The engine is a component owned by the shell that resides on the UI task
40/// runner and is responsible for managing the needs of the root isolate and its
41/// runtime. The engine can only be created, accessed and collected on the UI
42/// task runner. Each shell owns exactly one instance of the engine.
43///
44/// The root isolate of Flutter application gets "window" bindings. Using these
45/// bindings, the application can schedule frames, post layer-trees for
46/// rendering, ask to decompress images and upload them to the GPU, etc..
47/// Non-root isolates of the VM do not get any of these capabilities and are run
48/// in a VM managed thread pool (so if they did have "window", the threading
49/// guarantees needed for engine operation would be violated).
50///
51/// The engine is responsible for the entire life-cycle of the root isolate.
52/// When the engine is collected, its owner assumes that the root isolate has
53/// been shutdown and appropriate resources collected. While each engine
54/// instance can only manage a single instance of a root isolate, it may restart
55/// that isolate on request. This is how the cold-restart development scenario
56/// is supported.
57///
58/// When the engine instance is initially created, the root isolate is created
59/// but it is not in the |DartIsolate::Phase::Running| phase yet. It only moves
60/// into that phase when a successful call to `Engine::Run` is made.
61///
62/// @see `Shell`
63///
64/// @note This name of this class is perhaps a bit unfortunate and has
65/// sometimes been the cause of confusion. For a class named "Engine"
66/// in the Flutter "Engine" repository, its responsibilities are
67/// decidedly unremarkable. But, it does happen to be the primary
68/// entry-point used by components higher up in the Flutter tech stack
69/// (usually in Dart code) to peer into the lower level functionality.
70/// Besides, the authors haven't been able to come up with a more apt
71/// name and it does happen to be one of the older classes in the
72/// repository.
73///
74class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
75 public:
76 //----------------------------------------------------------------------------
77 /// @brief Indicates the result of the call to `Engine::Run`.
78 ///
79 enum class RunStatus {
80 //--------------------------------------------------------------------------
81 /// The call to |Engine::Run| was successful and the root isolate is in the
82 /// `DartIsolate::Phase::Running` phase with its entry-point invocation
83 /// already pending in the task queue.
84 ///
85 Success,
86
87 //--------------------------------------------------------------------------
88 /// The engine can only manage a single instance of a root isolate. If a
89 /// previous call to run the root isolate was successful, subsequent calls
90 /// to run the isolate (even if the new run configuration is different) will
91 /// be rejected.
92 ///
93 /// It is up to the caller to decide to re-purpose the running isolate,
94 /// terminate it, or use another shell to host the new isolate. This is
95 /// mostly used by embedders which have a fire-and-forget strategy to root
96 /// isolate launch. For example, the application may try to "launch" an
97 /// isolate when the embedders launches or resumes from a paused state. That
98 /// the isolate is running is not necessarily a failure condition for them.
99 /// But from the engine's perspective, the run configuration was rejected.
100 ///
101 FailureAlreadyRunning,
102
103 //--------------------------------------------------------------------------
104 /// Used to indicate to the embedder that a root isolate was not already
105 /// running but the run configuration was not valid and root isolate could
106 /// not be moved into the `DartIsolate::Phase::Running` phase.
107 ///
108 /// The caller must attempt the run call again with a valid configuration.
109 /// The set of all failure modes is massive and can originate from a variety
110 /// of sub-components. The engine will attempt to log the same when
111 /// possible. With the aid of logs, the common causes of failure are:
112 ///
113 /// * AOT assets were given to JIT/DBC mode VM's and vice-versa.
114 /// * The assets could not be found in the asset manager. Callers must make
115 /// sure their run configuration asset managers have been correctly set
116 /// up.
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`, `SemanticsNodeUpdates`,
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,
163 CustomAccessibilityActionUpdates actions) = 0;
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 std::unique_ptr<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
206 /// `PlatformDispatcher.setIsolateDebugName` in
207 /// `platform_dispatcher.dart`). The name of the isolate is
208 /// meaningless to the engine but is used in instrumentation and
209 /// tooling. Currently, this information is to update the
210 /// service protocol list of available root isolates running in
211 /// the VM and their names so that the appropriate isolate can
212 /// be selected in the tools for debugging and instrumentation.
213 ///
214 /// @param[in] isolate_name The isolate name
215 /// @param[in] isolate_port The isolate port
216 ///
217 virtual void UpdateIsolateDescription(const std::string isolate_name,
218 int64_t isolate_port) = 0;
219
220 //--------------------------------------------------------------------------
221 /// @brief Notifies the shell that the application has an opinion about
222 /// whether its frame timings need to be reported backed to it.
223 /// Due to the asynchronous nature of rendering in Flutter, it
224 /// is not possible for the application to determine the total
225 /// time it took to render a specific frame. While the
226 /// layer-tree is constructed on the UI thread, it needs to be
227 /// rendering on the raster thread. Dart code cannot execute on
228 /// this thread. So any instrumentation about the frame times
229 /// gathered on this thread needs to be aggregated and sent back
230 /// to the UI thread for processing in Dart.
231 ///
232 /// When the application indicates that frame times need to be
233 /// reported, it collects this information till a specified
234 /// number of data points are gathered. Then this information is
235 /// sent back to Dart code via `Engine::ReportTimings`.
236 ///
237 /// This option is engine counterpart of the
238 /// `Window._setNeedsReportTimings` in `window.dart`.
239 ///
240 /// @param[in] needs_reporting If reporting information should be
241 /// collected and send back to Dart.
242 ///
243 virtual void SetNeedsReportTimings(bool needs_reporting) = 0;
244
245 //--------------------------------------------------------------------------
246 /// @brief Directly invokes platform-specific APIs to compute the
247 /// locale the platform would have natively resolved to.
248 ///
249 /// @param[in] supported_locale_data The vector of strings that represents
250 /// the locales supported by the app.
251 /// Each locale consists of three
252 /// strings: languageCode, countryCode,
253 /// and scriptCode in that order.
254 ///
255 /// @return A vector of 3 strings languageCode, countryCode, and
256 /// scriptCode that represents the locale selected by the
257 /// platform. Empty strings mean the value was unassigned. Empty
258 /// vector represents a null locale.
259 ///
260 virtual std::unique_ptr<std::vector<std::string>>
261 ComputePlatformResolvedLocale(
262 const std::vector<std::string>& supported_locale_data) = 0;
263
264 //--------------------------------------------------------------------------
265 /// @brief Invoked when the Dart VM requests that a deferred library
266 /// be loaded. Notifies the engine that the deferred library
267 /// identified by the specified loading unit id should be
268 /// downloaded and loaded into the Dart VM via
269 /// `LoadDartDeferredLibrary`
270 ///
271 /// Upon encountering errors or otherwise failing to load a
272 /// loading unit with the specified id, the failure should be
273 /// directly reported to dart by calling
274 /// `LoadDartDeferredLibraryFailure` to ensure the waiting dart
275 /// future completes with an error.
276 ///
277 /// @param[in] loading_unit_id The unique id of the deferred library's
278 /// loading unit. This id is to be passed
279 /// back into LoadDartDeferredLibrary
280 /// in order to identify which deferred
281 /// library to load.
282 ///
283 virtual void RequestDartDeferredLibrary(intptr_t loading_unit_id) = 0;
284
285 //--------------------------------------------------------------------------
286 /// @brief Returns the current fml::TimePoint.
287 /// This method is primarily provided to allow tests to control
288 /// Any methods that rely on advancing the clock.
289 virtual fml::TimePoint GetCurrentTimePoint() = 0;
290
291 //----------------------------------------------------------------------------
292 /// @brief Returns the delegate object that handles PlatformMessage's from
293 /// Flutter to the host platform (and its responses).
294 virtual const std::shared_ptr<PlatformMessageHandler>&
295 GetPlatformMessageHandler() const = 0;
296 };
297
298 //----------------------------------------------------------------------------
299 /// @brief Creates an instance of the engine with a supplied
300 /// `RuntimeController`. Use the other constructor except for
301 /// tests.
302 ///
303 Engine(Delegate& delegate,
304 const PointerDataDispatcherMaker& dispatcher_maker,
305 std::shared_ptr<fml::ConcurrentTaskRunner> image_decoder_task_runner,
306 const TaskRunners& task_runners,
307 const Settings& settings,
308 std::unique_ptr<Animator> animator,
309 fml::WeakPtr<IOManager> io_manager,
310 const std::shared_ptr<FontCollection>& font_collection,
311 std::unique_ptr<RuntimeController> runtime_controller,
312 const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch);
313
314 //----------------------------------------------------------------------------
315 /// @brief Creates an instance of the engine. This is done by the Shell
316 /// on the UI task runner.
317 ///
318 /// @param delegate The object used by the engine to perform
319 /// tasks that require access to components
320 /// that cannot be safely accessed by the
321 /// engine. This is the shell.
322 /// @param dispatcher_maker The callback provided by `PlatformView` for
323 /// engine to create the pointer data
324 /// dispatcher. Similar to other engine
325 /// resources, this dispatcher_maker and its
326 /// returned dispatcher is only safe to be
327 /// called from the UI thread.
328 /// @param vm An instance of the running Dart VM.
329 /// @param[in] isolate_snapshot The snapshot used to create the root
330 /// isolate. Even though the isolate is not
331 /// `DartIsolate::Phase::Running` phase, it is
332 /// created when the engine is created. This
333 /// requires access to the isolate snapshot
334 /// upfront.
335 // TODO(chinmaygarde): This is probably redundant now that the IO manager is
336 // it's own object.
337 /// @param[in] task_runners The task runners used by the shell that
338 /// hosts this engine.
339 /// @param[in] settings The settings used to initialize the shell
340 /// and the engine.
341 /// @param[in] animator The animator used to schedule frames.
342 // TODO(chinmaygarde): Move this to `Engine::Delegate`
343 /// @param[in] snapshot_delegate The delegate used to fulfill requests to
344 /// snapshot a specified scene. The engine
345 /// cannot snapshot a scene on the UI thread
346 /// directly because the scene (described via
347 /// a `DisplayList`) may reference resources on
348 /// the GPU and there is no GPU context current
349 /// on the UI thread. The delegate is a
350 /// component that has access to all the
351 /// requisite GPU resources.
352 /// @param[in] io_manager The IO manager used by this root isolate to
353 /// schedule tasks that manage resources on the
354 /// GPU.
355 ///
356 Engine(Delegate& delegate,
357 const PointerDataDispatcherMaker& dispatcher_maker,
358 DartVM& vm,
359 fml::RefPtr<const DartSnapshot> isolate_snapshot,
360 const TaskRunners& task_runners,
361 const PlatformData& platform_data,
362 const Settings& settings,
363 std::unique_ptr<Animator> animator,
364 fml::WeakPtr<IOManager> io_manager,
365 fml::RefPtr<SkiaUnrefQueue> unref_queue,
366 fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
367 std::shared_ptr<VolatilePathTracker> volatile_path_tracker,
368 const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch);
369
370 //----------------------------------------------------------------------------
371 /// @brief Create a Engine that shares as many resources as
372 /// possible with the calling Engine such that together
373 /// they occupy less memory and be created faster.
374 /// @details This should only be called on running Engines.
375 /// @return A new Engine with a running isolate.
376 /// @see Engine::Engine
377 /// @see DartIsolate::SpawnIsolate
378 ///
379 std::unique_ptr<Engine> Spawn(
380 Delegate& delegate,
381 const PointerDataDispatcherMaker& dispatcher_maker,
382 const Settings& settings,
383 std::unique_ptr<Animator> animator,
384 const std::string& initial_route,
385 const fml::WeakPtr<IOManager>& io_manager,
386 fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
387 const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch) const;
388
389 //----------------------------------------------------------------------------
390 /// @brief Destroys the engine engine. Called by the shell on the UI task
391 /// runner. The running root isolate is terminated and will no
392 /// longer access the task runner after this call returns. This
393 /// allows the embedder to tear down the thread immediately if
394 /// needed.
395 ///
396 ~Engine() override;
397
398 //----------------------------------------------------------------------------
399 /// @return The pointer to this instance of the engine. The engine may
400 /// only be accessed safely on the UI task runner.
401 ///
402 fml::WeakPtr<Engine> GetWeakPtr() const;
403
404 //----------------------------------------------------------------------------
405 /// @brief Moves the root isolate to the `DartIsolate::Phase::Running`
406 /// phase on a successful call to this method.
407 ///
408 /// The isolate itself is created when the engine is created, but
409 /// it is not yet in the running phase. This is done to amortize
410 /// initial time taken to launch the root isolate. The isolate
411 /// snapshots used to run the isolate can be fetched on another
412 /// thread while the engine itself is launched on the UI task
413 /// runner.
414 ///
415 /// Repeated calls to this method after a successful run will be
416 /// rejected even if the run configuration is valid (with the
417 /// appropriate error returned).
418 ///
419 /// @param[in] configuration The configuration used to run the root isolate.
420 /// The configuration must be valid.
421 ///
422 /// @return The result of the call to run the root isolate.
423 ///
424 [[nodiscard]] RunStatus Run(RunConfiguration configuration);
425
426 //----------------------------------------------------------------------------
427 /// @brief Tears down an existing root isolate, reuses the components of
428 /// that isolate and attempts to launch a new isolate using the
429 /// given the run configuration. This is only used in the
430 /// "debug" Flutter runtime mode in the cold-restart scenario.
431 ///
432 /// @attention This operation must be performed with care as even a
433 /// non-successful restart will still tear down any existing root
434 /// isolate. In such cases, the engine and its shell must be
435 /// discarded.
436 ///
437 /// @param[in] configuration The configuration used to launch the new
438 /// isolate.
439 ///
440 /// @return Whether the restart was successful. If not, the engine and its
441 /// shell must be discarded.
442 ///
443 [[nodiscard]] bool Restart(RunConfiguration configuration);
444
445 //----------------------------------------------------------------------------
446 /// @brief Setup default font manager according to specific platform.
447 ///
448 void SetupDefaultFontManager();
449
450 //----------------------------------------------------------------------------
451 /// @brief Updates the asset manager referenced by the root isolate of a
452 /// Flutter application. This happens implicitly in the call to
453 /// `Engine::Run` and `Engine::Restart` as the asset manager is
454 /// referenced from the run configuration provided to those calls.
455 /// In addition to the `Engine::Run` and `Engine::Restart`
456 /// calls, the tooling may need to update the assets available to
457 /// the application as the user adds them to their project. For
458 /// example, these assets may be referenced by code that is newly
459 /// patched in after a hot-reload. Neither the shell or the
460 /// isolate in relaunched in such cases. The tooling usually
461 /// patches in the new assets in a temporary location and updates
462 /// the asset manager to point to that location.
463 ///
464 /// @param[in] asset_manager The new asset manager to use for the running
465 /// root isolate.
466 ///
467 /// @return If the asset manager was successfully replaced. This may fail
468 /// if the new asset manager is invalid.
469 ///
470 bool UpdateAssetManager(const std::shared_ptr<AssetManager>& asset_manager);
471
472 //----------------------------------------------------------------------------
473 /// @brief Notifies the engine that it is time to begin working on a new
474 /// frame previously scheduled via a call to
475 /// `Engine::ScheduleFrame`. This call originates in the animator.
476 ///
477 /// The frame time given as the argument indicates the point at
478 /// which the current frame interval began. It is very slightly
479 /// (because of scheduling overhead) in the past. If a new layer
480 /// tree is not produced and given to the raster task runner
481 /// within one frame interval from this point, the Flutter
482 /// application will jank.
483 ///
484 /// If a root isolate is running, this method calls the
485 /// `::_beginFrame` method in `hooks.dart`. If a root isolate is
486 /// not running, this call does nothing.
487 ///
488 /// This method encapsulates the entire UI thread frame workload.
489 /// The following (mis)behavior in the functioning of the method
490 /// will cause the jank in the Flutter application:
491 /// * The time taken by this method to create a layer-tree exceeds
492 /// one frame interval (for example, 16.66 ms on a 60Hz
493 /// display).
494 /// * The time take by this method to generate a new layer-tree
495 /// causes the current layer-tree pipeline depth to change. To
496 /// illustrate this point, note that maximum pipeline depth used
497 /// by layer tree in the engine is 2. If both the UI and GPU
498 /// task runner tasks finish within one frame interval, the
499 /// pipeline depth is one. If the UI thread happens to be
500 /// working on a frame when the raster thread is still not done
501 /// with the previous frame, the pipeline depth is 2. When the
502 /// pipeline depth changes from 1 to 2, animations and UI
503 /// interactions that cause the generation of the new layer tree
504 /// appropriate for (frame_time + one frame interval) will
505 /// actually end up at (frame_time + two frame intervals). This
506 /// is not what code running on the UI thread expected would
507 /// happen. This causes perceptible jank.
508 ///
509 /// @param[in] frame_time The point at which the current frame interval
510 /// began. May be used by animation interpolators,
511 /// physics simulations, etc..
512 ///
513 /// @param[in] frame_number The frame number recorded by the animator. Used
514 /// by the framework to associate frame specific
515 /// debug information with frame timings and timeline
516 /// events.
517 void BeginFrame(fml::TimePoint frame_time, uint64_t frame_number);
518
519 //----------------------------------------------------------------------------
520 /// @brief Notifies the engine that the UI task runner is not expected to
521 /// undertake a new frame workload till a specified timepoint. The
522 /// timepoint is measured in microseconds against the system's
523 /// monotonic clock. It is recommended that the clock be accessed
524 /// via `Dart_TimelineGetMicros` from `dart_api.h` for
525 /// consistency. In reality, the clocks used by Dart, FML and
526 /// std::steady_clock are all the same and the timepoints can be
527 /// converted from on clock type to another.
528 ///
529 /// The Dart VM uses this notification to schedule book-keeping
530 /// tasks that may include a garbage collection. In this way, it
531 /// is less likely for the VM to perform such (potentially long
532 /// running) tasks in the middle of a frame workload.
533 ///
534 /// This notification is advisory. That is, not providing this
535 /// notification does not mean garbage collection is postponed
536 /// till this call is made. If this notification is not provided,
537 /// garbage collection will happen based on the usual heuristics
538 /// used by the Dart VM.
539 ///
540 /// Currently, this idle notification is delivered to the engine
541 /// at two points. Once, the deadline is calculated based on how
542 /// much time in the current frame interval is left on the UI task
543 /// runner. Since the next frame workload cannot begin till at
544 /// least the next callback from the vsync waiter, this period may
545 /// be used to used as a "small" idle notification. On the other
546 /// hand, if no more frames are scheduled, a large (but arbitrary)
547 /// idle notification deadline is chosen for a "big" idle
548 /// notification. Again, this notification does not guarantee
549 /// collection, just gives the Dart VM more hints about opportune
550 /// moments to perform collections.
551 ///
552 ///
553 /// @param[in] deadline The deadline is used by the VM to determine if the
554 /// corresponding sweep can be performed within the
555 /// deadline.
556 ///
557 void NotifyIdle(fml::TimeDelta deadline);
558
559 //----------------------------------------------------------------------------
560 /// @brief Notifies the engine that the attached flutter view has been
561 /// destroyed.
562 /// This enables the engine to notify the Dart VM so it can do
563 /// some cleanp activities.
564 void NotifyDestroyed();
565
566 //----------------------------------------------------------------------------
567 /// @brief Dart code cannot fully measure the time it takes for a
568 /// specific frame to be rendered. This is because Dart code only
569 /// runs on the UI task runner. That is only a small part of the
570 /// overall frame workload. The raster task runner frame workload
571 /// is executed on a thread where Dart code cannot run (and hence
572 /// instrument). Besides, due to the pipelined nature of rendering
573 /// in Flutter, there may be multiple frame workloads being
574 /// processed at any given time. However, for non-Timeline based
575 /// profiling, it is useful for trace collection and processing to
576 /// happen in Dart. To do this, the raster task runner frame
577 /// workloads need to be instrumented separately. After a set
578 /// number of these profiles have been gathered, they need to be
579 /// reported back to Dart code. The shell reports this extra
580 /// instrumentation information back to Dart code running on the
581 /// engine by invoking this method at predefined intervals.
582 ///
583 /// @see `FrameTiming`
584 ///
585 // TODO(chinmaygarde): The use `int64_t` is added for ease of conversion to
586 // Dart but hurts readability. The phases and the units of the timepoints are
587 // not obvious without some sleuthing. The conversion can happen at the
588 // native interface boundary instead.
589 ///
590 /// @param[in] timings Collection of `FrameTiming::kCount` * `n` timestamps
591 /// for `n` frames whose timings have not been reported
592 /// yet. A collection of integers is reported here for
593 /// easier conversions to Dart objects. The timestamps
594 /// are measured against the system monotonic clock
595 /// measured in microseconds.
596 ///
597 void ReportTimings(std::vector<int64_t> timings);
598
599 //----------------------------------------------------------------------------
600 /// @brief Gets the main port of the root isolate. Since the isolate is
601 /// created immediately in the constructor of the engine, it is
602 /// possible to get its main port immediately (even before a call
603 /// to `Run` can be made). This is useful in registering the port
604 /// in a race free manner with a port nameserver.
605 ///
606 /// @return The main port of the root isolate.
607 ///
608 Dart_Port GetUIIsolateMainPort();
609
610 //----------------------------------------------------------------------------
611 /// @brief Gets the debug name of the root isolate. By default, the
612 /// debug name of the isolate is derived from its advisory script
613 /// URI, advisory main entrypoint and its main port name. For
614 /// example, "main.dart$main-1234" where the script URI is
615 /// "main.dart", the entrypoint is "main" and the port name
616 /// "1234". Once launched, the isolate may re-christen itself
617 /// using a name it selects via `setIsolateDebugName` in
618 /// `platform_dispatcher.dart`. This name is purely advisory and
619 /// only used by instrumentation and reporting purposes.
620 ///
621 /// @return The debug name of the root isolate.
622 ///
623 std::string GetUIIsolateName();
624
625 //----------------------------------------------------------------------------
626 /// @brief It is an unexpected challenge to determine when a Dart
627 /// application is "done". The application cannot simply terminate
628 /// the native process (and perhaps return an exit code) because
629 /// it does not have that power. After all, Flutter applications
630 /// reside within a host process that may have other
631 /// responsibilities besides just running Flutter applications.
632 /// Also, the `main` entry-points are run on an event loop and
633 /// returning from "main" (unlike in C/C++ applications) does not
634 /// mean termination of the process. Besides, the return value of
635 /// the main entrypoint is discarded.
636 ///
637 /// One technique used by embedders to determine "liveness" is to
638 /// count the outstanding live ports dedicated to the application.
639 /// These ports may be live as a result of pending timers,
640 /// scheduled tasks, pending IO on sockets, channels open with
641 /// other isolates, etc.. At regular intervals (sometimes as often
642 /// as after the UI task runner processes any task), embedders may
643 /// check for the "liveness" of the application and perform
644 /// teardown of the embedder when no more ports are live.
645 ///
646 /// @return Check if the root isolate has any live ports.
647 ///
648 bool UIIsolateHasLivePorts();
649
650 //----------------------------------------------------------------------------
651 /// @brief Errors that are unhandled on the Dart message loop are kept
652 /// for further inspection till the next unhandled error comes
653 /// along. This accessor returns the last unhandled error
654 /// encountered by the root isolate.
655 ///
656 /// @return The ui isolate last error.
657 ///
658 tonic::DartErrorHandleType GetUIIsolateLastError();
659
660 //----------------------------------------------------------------------------
661 /// @brief As described in the discussion for `UIIsolateHasLivePorts`,
662 /// the "done-ness" of a Dart application is tricky to ascertain
663 /// and the return value from the main entrypoint is discarded
664 /// (because the Dart isolate is still running after the main
665 /// entrypoint returns). But, the concept of an exit code akin to
666 /// those returned by native applications is still useful. Short
667 /// lived Dart applications (usually tests), emulate this by
668 /// setting a per isolate "return value" and then indicating their
669 /// "done-ness" (usually via closing all live ports). This
670 /// accessor returns that "return value" is present.
671 ///
672 /// @see `UIIsolateHasLivePorts`
673 ///
674 /// @return The return code (if specified) by the isolate.
675 ///
676 std::optional<uint32_t> GetUIIsolateReturnCode();
677
678 //----------------------------------------------------------------------------
679 /// @brief Updates the viewport metrics for a view. The viewport metrics
680 /// detail the size of the rendering viewport in texels as well as
681 /// edge insets if present.
682 ///
683 /// @see `ViewportMetrics`
684 ///
685 /// @param[in] view_id The ID for the view that `metrics` describes.
686 /// @param[in] metrics The metrics.
687 ///
688 void SetViewportMetrics(int64_t view_id, const ViewportMetrics& metrics);
689
690 //----------------------------------------------------------------------------
691 /// @brief Updates the display metrics for the currently running Flutter
692 /// application.
693 ///
694 /// @param[in] displays A complete list of displays
695 ///
696 void SetDisplays(const std::vector<DisplayData>& displays);
697
698 //----------------------------------------------------------------------------
699 /// @brief Notifies the engine that the embedder has sent it a message.
700 /// This call originates in the platform view and has been
701 /// forwarded to the engine on the UI task runner here.
702 ///
703 /// @param[in] message The message sent from the embedder to the Dart
704 /// application.
705 ///
706 void DispatchPlatformMessage(std::unique_ptr<PlatformMessage> message);
707
708 //----------------------------------------------------------------------------
709 /// @brief Notifies the engine that the embedder has sent it a pointer
710 /// data packet. A pointer data packet may contain multiple
711 /// input events. This call originates in the platform view and
712 /// the shell has forwarded the same to the engine on the UI task
713 /// runner here.
714 ///
715 /// @param[in] packet The pointer data packet containing multiple
716 /// input events.
717 /// @param[in] trace_flow_id The trace flow identifier associated with the
718 /// pointer data packet. The engine uses this trace
719 /// identifier to connect trace flows in the
720 /// timeline from the input event to the
721 /// frames generated due to those input events.
722 /// These flows are tagged as "PointerEvent" in the
723 /// timeline and allow grouping frames and input
724 /// events into logical chunks.
725 ///
726 void DispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet,
727 uint64_t trace_flow_id);
728
729 //----------------------------------------------------------------------------
730 /// @brief Notifies the engine that the embedder encountered an
731 /// accessibility related action on the specified node. This call
732 /// originates on the platform view and has been forwarded to the
733 /// engine here on the UI task runner by the shell.
734 ///
735 /// @param[in] node_id The identifier of the accessibility node.
736 /// @param[in] action The accessibility related action performed on the
737 /// node of the specified ID.
738 /// @param[in] args Optional data that applies to the specified action.
739 ///
740 void DispatchSemanticsAction(int node_id,
741 SemanticsAction action,
742 fml::MallocMapping args);
743
744 //----------------------------------------------------------------------------
745 /// @brief Notifies the engine that the embedder has expressed an opinion
746 /// about whether the accessibility tree should be generated or
747 /// not. This call originates in the platform view and is
748 /// forwarded to the engine here on the UI task runner by the
749 /// shell.
750 ///
751 /// @param[in] enabled Whether the accessibility tree is enabled or
752 /// disabled.
753 ///
754 void SetSemanticsEnabled(bool enabled);
755
756 //----------------------------------------------------------------------------
757 /// @brief Notifies the engine that the embedder has expressed an opinion
758 /// about where the flags to set on the accessibility tree. This
759 /// flag originates in the platform view and is forwarded to the
760 /// engine here on the UI task runner by the shell.
761 ///
762 /// The engine does not care about the accessibility feature flags
763 /// as all it does is forward this information from the embedder
764 /// to the framework. However, curious readers may refer to
765 /// `AccessibilityFeatures` in `window.dart` for currently
766 /// supported accessibility feature flags.
767 ///
768 /// @param[in] flags The features to enable in the accessibility tree.
769 ///
770 void SetAccessibilityFeatures(int32_t flags);
771
772 // |RuntimeDelegate|
773 void ScheduleFrame(bool regenerate_layer_tree) override;
774
775 /// Schedule a frame with the default parameter of regenerating the layer
776 /// tree.
777 void ScheduleFrame() { ScheduleFrame(regenerate_layer_tree: true); }
778
779 // |RuntimeDelegate|
780 FontCollection& GetFontCollection() override;
781
782 // |RuntimeDelegate|
783 std::shared_ptr<AssetManager> GetAssetManager() override;
784
785 // Return the weak_ptr of ImageDecoder.
786 fml::WeakPtr<ImageDecoder> GetImageDecoderWeakPtr();
787
788 //----------------------------------------------------------------------------
789 /// @brief Get the `ImageGeneratorRegistry` associated with the current
790 /// engine.
791 ///
792 /// @return The engine's `ImageGeneratorRegistry`.
793 ///
794 fml::WeakPtr<ImageGeneratorRegistry> GetImageGeneratorRegistry();
795
796 // |PointerDataDispatcher::Delegate|
797 void DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
798 uint64_t trace_flow_id) override;
799
800 // |PointerDataDispatcher::Delegate|
801 void ScheduleSecondaryVsyncCallback(uintptr_t id,
802 const fml::closure& callback) override;
803
804 //----------------------------------------------------------------------------
805 /// @brief Get the last Entrypoint that was used in the RunConfiguration
806 /// when |Engine::Run| was called.
807 ///
808 const std::string& GetLastEntrypoint() const;
809
810 //----------------------------------------------------------------------------
811 /// @brief Get the last Entrypoint Library that was used in the
812 /// RunConfiguration when |Engine::Run| was called.
813 ///
814 const std::string& GetLastEntrypointLibrary() const;
815
816 //----------------------------------------------------------------------------
817 /// @brief Get the last Entrypoint Arguments that was used in the
818 /// RunConfiguration when |Engine::Run| was called.This is only
819 /// valid in debug mode.
820 ///
821 const std::vector<std::string>& GetLastEntrypointArgs() const;
822
823 //----------------------------------------------------------------------------
824 /// @brief Getter for the initial route. This can be set with a platform
825 /// message.
826 ///
827 const std::string& InitialRoute() const { return initial_route_; }
828
829 //--------------------------------------------------------------------------
830 /// @brief Loads the Dart shared library into the Dart VM. When the
831 /// Dart library is loaded successfully, the Dart future
832 /// returned by the originating loadLibrary() call completes.
833 ///
834 /// The Dart compiler may generate separate shared libraries
835 /// files called 'loading units' when libraries are imported
836 /// as deferred. Each of these shared libraries are identified
837 /// by a unique loading unit id. Callers should open and resolve
838 /// a SymbolMapping from the shared library. The Mappings should
839 /// be moved into this method, as ownership will be assumed by the
840 /// dart root isolate after successful loading and released after
841 /// shutdown of the root isolate. The loading unit may not be
842 /// used after isolate shutdown. If loading fails, the mappings
843 /// will be released.
844 ///
845 /// This method is paired with a RequestDartDeferredLibrary
846 /// invocation that provides the embedder with the loading unit id
847 /// of the deferred library to load.
848 ///
849 ///
850 /// @param[in] loading_unit_id The unique id of the deferred library's
851 /// loading unit, as passed in by
852 /// RequestDartDeferredLibrary.
853 ///
854 /// @param[in] snapshot_data Dart snapshot data of the loading unit's
855 /// shared library.
856 ///
857 /// @param[in] snapshot_data Dart snapshot instructions of the loading
858 /// unit's shared library.
859 ///
860 void LoadDartDeferredLibrary(
861 intptr_t loading_unit_id,
862 std::unique_ptr<const fml::Mapping> snapshot_data,
863 std::unique_ptr<const fml::Mapping> snapshot_instructions);
864
865 //--------------------------------------------------------------------------
866 /// @brief Indicates to the dart VM that the request to load a deferred
867 /// library with the specified loading unit id has failed.
868 ///
869 /// The dart future returned by the initiating loadLibrary() call
870 /// will complete with an error.
871 ///
872 /// @param[in] loading_unit_id The unique id of the deferred library's
873 /// loading unit, as passed in by
874 /// RequestDartDeferredLibrary.
875 ///
876 /// @param[in] error_message The error message that will appear in the
877 /// dart Future.
878 ///
879 /// @param[in] transient A transient error is a failure due to
880 /// temporary conditions such as no network.
881 /// Transient errors allow the dart VM to
882 /// re-request the same deferred library and
883 /// loading_unit_id again. Non-transient
884 /// errors are permanent and attempts to
885 /// re-request the library will instantly
886 /// complete with an error.
887 void LoadDartDeferredLibraryError(intptr_t loading_unit_id,
888 const std::string& error_message,
889 bool transient);
890
891 //--------------------------------------------------------------------------
892 /// @brief Accessor for the RuntimeController.
893 ///
894 const RuntimeController* GetRuntimeController() const {
895 return runtime_controller_.get();
896 }
897
898 const std::weak_ptr<VsyncWaiter> GetVsyncWaiter() const;
899
900 private:
901 // |RuntimeDelegate|
902 bool ImplicitViewEnabled() override;
903
904 // |RuntimeDelegate|
905 std::string DefaultRouteName() override;
906
907 // |RuntimeDelegate|
908 void Render(std::unique_ptr<flutter::LayerTree> layer_tree,
909 float device_pixel_ratio) override;
910
911 // |RuntimeDelegate|
912 void UpdateSemantics(SemanticsNodeUpdates update,
913 CustomAccessibilityActionUpdates actions) override;
914
915 // |RuntimeDelegate|
916 void HandlePlatformMessage(std::unique_ptr<PlatformMessage> message) override;
917
918 // |RuntimeDelegate|
919 void OnRootIsolateCreated() override;
920
921 // |RuntimeDelegate|
922 void UpdateIsolateDescription(const std::string isolate_name,
923 int64_t isolate_port) override;
924
925 // |RuntimeDelegate|
926 std::unique_ptr<std::vector<std::string>> ComputePlatformResolvedLocale(
927 const std::vector<std::string>& supported_locale_data) override;
928
929 // |RuntimeDelegate|
930 void RequestDartDeferredLibrary(intptr_t loading_unit_id) override;
931
932 // |RuntimeDelegate|
933 std::weak_ptr<PlatformMessageHandler> GetPlatformMessageHandler()
934 const override;
935
936 void SetNeedsReportTimings(bool value) override;
937
938 bool HandleLifecyclePlatformMessage(PlatformMessage* message);
939
940 bool HandleNavigationPlatformMessage(
941 std::unique_ptr<PlatformMessage> message);
942
943 bool HandleLocalizationPlatformMessage(PlatformMessage* message);
944
945 void HandleSettingsPlatformMessage(PlatformMessage* message);
946
947 void HandleAssetPlatformMessage(std::unique_ptr<PlatformMessage> message);
948
949 bool GetAssetAsBuffer(const std::string& name, std::vector<uint8_t>* data);
950
951 friend class testing::ShellTest;
952
953 Engine::Delegate& delegate_;
954 const Settings settings_;
955 std::unique_ptr<Animator> animator_;
956 std::unique_ptr<RuntimeController> runtime_controller_;
957
958 // The pointer_data_dispatcher_ depends on animator_ and runtime_controller_.
959 // So it should be defined after them to ensure that pointer_data_dispatcher_
960 // is destructed first.
961 std::unique_ptr<PointerDataDispatcher> pointer_data_dispatcher_;
962
963 std::string last_entry_point_;
964 std::string last_entry_point_library_;
965 std::vector<std::string> last_entry_point_args_;
966 std::string initial_route_;
967 std::shared_ptr<AssetManager> asset_manager_;
968 std::shared_ptr<FontCollection> font_collection_;
969 const std::unique_ptr<ImageDecoder> image_decoder_;
970 ImageGeneratorRegistry image_generator_registry_;
971 TaskRunners task_runners_;
972 fml::WeakPtrFactory<Engine> weak_factory_; // Must be the last member.
973 FML_DISALLOW_COPY_AND_ASSIGN(Engine);
974};
975
976} // namespace flutter
977
978#endif // SHELL_COMMON_ENGINE_H_
979

source code of flutter_engine/flutter/shell/common/engine.h