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