Flutter Engine
The Flutter Engine
runtime_controller.h
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef FLUTTER_RUNTIME_RUNTIME_CONTROLLER_H_
6#define FLUTTER_RUNTIME_RUNTIME_CONTROLLER_H_
7
8#include <memory>
9#include <vector>
10
11#include "flutter/assets/asset_manager.h"
12#include "flutter/common/task_runners.h"
13#include "flutter/flow/layers/layer_tree.h"
14#include "flutter/fml/macros.h"
15#include "flutter/fml/mapping.h"
16#include "flutter/lib/ui/io_manager.h"
17#include "flutter/lib/ui/painting/image_generator_registry.h"
18#include "flutter/lib/ui/text/font_collection.h"
19#include "flutter/lib/ui/ui_dart_state.h"
20#include "flutter/lib/ui/volatile_path_tracker.h"
21#include "flutter/lib/ui/window/platform_configuration.h"
22#include "flutter/lib/ui/window/pointer_data_packet.h"
23#include "flutter/lib/ui/window/pointer_data_packet_converter.h"
24#include "flutter/runtime/dart_vm.h"
25#include "flutter/runtime/platform_data.h"
26#include "flutter/runtime/platform_isolate_manager.h"
27#include "rapidjson/document.h"
28#include "rapidjson/stringbuffer.h"
29
30namespace flutter {
31
32class Scene;
33class RuntimeDelegate;
34class View;
35class Window;
36
37//------------------------------------------------------------------------------
38/// Represents an instance of a running root isolate with window bindings. In
39/// normal operation, a single instance of this object is owned by the engine
40/// per shell. This object may only be created, used, and collected on the UI
41/// task runner. Window state queried by the root isolate is stored by this
42/// object. In cold-restart scenarios, the engine may collect this before
43/// installing a new runtime controller in its place. The Clone method may be
44/// used by the engine to copy the currently accumulated window state so it can
45/// be referenced by the new runtime controller.
46///
47/// When `RuntimeController` is created, it takes some time before the root
48/// isolate becomes ready. Operation during this gap is stored by
49/// `RuntimeController` and flushed to the Dart VM when the isolate becomes
50/// ready before the entrypoint function. See `PlatformData`.
51///
54 public:
55 /// A callback that's invoked after this `RuntimeController` attempts to
56 /// add a view to the Dart isolate.
57 ///
58 /// If the Dart isolate is not launched yet, this callback will be stored
59 /// and invoked after the isolate is launched.
60 ///
61 /// The `added` parameter is false if the add operation fails or was
62 /// cancelled while pending using `RemoveView`.
63 using AddViewCallback = std::function<void(bool added)>;
64
65 //----------------------------------------------------------------------------
66 /// @brief Creates a new instance of a runtime controller. This is
67 /// usually only done by the engine instance associated with the
68 /// shell.
69 ///
70 /// @param client The runtime delegate. This is
71 /// usually the `Engine` instance.
72 /// @param vm A reference to a running Dart VM.
73 /// The runtime controller must be
74 /// collected before the VM is
75 /// destroyed (this order is
76 /// guaranteed by the shell).
77 /// @param[in] idle_notification_callback The idle notification callback.
78 /// This allows callers to run native
79 /// code in isolate scope when the VM
80 /// is about to be notified that the
81 /// engine is going to be idle.
82 /// @param[in] platform_data The window data (if exists).
83 /// @param[in] isolate_create_callback The isolate create callback. This
84 /// allows callers to run native code
85 /// in isolate scope on the UI task
86 /// runner as soon as the root isolate
87 /// has been created.
88 /// @param[in] isolate_shutdown_callback The isolate shutdown callback.
89 /// This allows callers to run native
90 /// code in isolate scoped on the UI
91 /// task runner just as the root
92 /// isolate is about to be torn down.
93 /// @param[in] persistent_isolate_data Unstructured persistent read-only
94 /// data that the root isolate can
95 /// access in a synchronous manner.
96 /// @param[in] context Engine-owned state which is
97 /// accessed by the root dart isolate.
98 ///
100 RuntimeDelegate& p_client,
101 DartVM* vm,
102 fml::RefPtr<const DartSnapshot> p_isolate_snapshot,
103 const std::function<void(int64_t)>& idle_notification_callback,
104 const PlatformData& platform_data,
105 const fml::closure& isolate_create_callback,
106 const fml::closure& isolate_shutdown_callback,
107 std::shared_ptr<const fml::Mapping> p_persistent_isolate_data,
108 const UIDartState::Context& context);
109
110 //----------------------------------------------------------------------------
111 /// @brief Create a RuntimeController that shares as many resources as
112 /// possible with the calling RuntimeController such that together
113 /// they occupy less memory.
114 /// @return A RuntimeController with a running isolate.
115 /// @see RuntimeController::RuntimeController
116 ///
117 std::unique_ptr<RuntimeController> Spawn(
118 RuntimeDelegate& p_client,
119 const std::string& advisory_script_uri,
120 const std::string& advisory_script_entrypoint,
121 const std::function<void(int64_t)>& idle_notification_callback,
122 const fml::closure& isolate_create_callback,
123 const fml::closure& isolate_shutdown_callback,
124 const std::shared_ptr<const fml::Mapping>& persistent_isolate_data,
125 fml::WeakPtr<IOManager> io_manager,
126 fml::WeakPtr<ImageDecoder> image_decoder,
127 fml::WeakPtr<ImageGeneratorRegistry> image_generator_registry,
128 fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate) const;
129
130 // |PlatformConfigurationClient|
131 ~RuntimeController() override;
132
133 //----------------------------------------------------------------------------
134 /// @brief Launches the isolate using the window data associated with
135 /// this runtime controller. Before this call, the Dart isolate
136 /// has not been initialized. On successful return, the caller can
137 /// assume that the isolate is in the
138 /// `DartIsolate::Phase::Running` phase.
139 ///
140 /// This call will fail if a root isolate is already running. To
141 /// re-create an isolate with the window data associated with this
142 /// runtime controller, `Clone` this runtime controller and
143 /// Launch an isolate in that runtime controller instead.
144 ///
145 /// @param[in] settings The per engine instance settings.
146 /// @param[in] root_isolate_create_callback A callback invoked before the
147 /// root isolate has launched the Dart
148 /// program, but after it has been
149 /// created. This is called without
150 /// isolate scope, and after any root
151 /// isolate callback in the settings.
152 /// @param[in] dart_entrypoint The dart entrypoint. If
153 /// `std::nullopt` or empty, `main` will
154 /// be attempted.
155 /// @param[in] dart_entrypoint_library The dart entrypoint library. If
156 /// `std::nullopt` or empty, the core
157 /// library will be attempted.
158 /// @param[in] dart_entrypoint_args Arguments passed as a List<String>
159 /// to Dart's entrypoint function.
160 /// @param[in] isolate_configuration The isolate configuration
161 ///
162 /// @return If the isolate could be launched and guided to the
163 /// `DartIsolate::Phase::Running` phase.
164 ///
165 [[nodiscard]] bool LaunchRootIsolate(
166 const Settings& settings,
167 const fml::closure& root_isolate_create_callback,
168 std::optional<std::string> dart_entrypoint,
169 std::optional<std::string> dart_entrypoint_library,
170 const std::vector<std::string>& dart_entrypoint_args,
171 std::unique_ptr<IsolateConfiguration> isolate_configuration);
172
173 //----------------------------------------------------------------------------
174 /// @brief Clone the runtime controller. Launching an isolate with a
175 /// cloned runtime controller will use the same snapshots and
176 /// copies all window data to the new instance. This is usually
177 /// only used in the debug runtime mode to support the
178 /// cold-restart scenario.
179 ///
180 /// @return A clone of the existing runtime controller.
181 ///
182 std::unique_ptr<RuntimeController> Clone() const;
183
184 //----------------------------------------------------------------------------
185 /// @brief Notify the isolate that a new view is available.
186 ///
187 /// A view must be added before other methods can refer to it,
188 /// including the implicit view. Adding a view that already exists
189 /// is an error.
190 ///
191 /// The `callback` is invoked when the add operation is attempted,
192 /// failed, or is cancelled.
193 ///
194 /// If the isolate is not running, the view add will be queued and
195 /// flushed to the isolate when it starts. Calling `RemoveView`
196 /// before the isolate is launched cancels the add operation.
197 ///
198 /// If the isolate is running, a frame will be scheduled.
199 ///
200 /// @param[in] view_id The ID of the new view.
201 /// @param[in] viewport_metrics The initial viewport metrics for the view.
202 /// @param[in] callback Callback that will be invoked after the add
203 /// operation is attempted or cancelled.
204 ///
205 void AddView(int64_t view_id,
206 const ViewportMetrics& view_metrics,
208
209 //----------------------------------------------------------------------------
210 /// @brief Notify the isolate that a view is no longer available.
211 ///
212 /// Views that are added before the isolate is started are
213 /// queued until the isolate is launched. If one of these
214 /// "pending" views are removed, the view add is cancelled:
215 /// the `AddViewCallback` will be invoked with an `added` of
216 /// false and `RemoveView` will return false.
217 ///
218 /// The implicit view (kFlutterImplicitViewId) should never be
219 /// removed. Doing so triggers an assertion.
220 ///
221 /// @param[in] view_id The ID of the view.
222 ///
223 /// @return If the remove view operation was forwarded to the running
224 /// isolate. False if the view does not exist. If the Dart isolate
225 /// is not running, then the pending view creation (if any) is
226 /// cancelled and the return value is always false.
227 bool RemoveView(int64_t view_id);
228
229 //----------------------------------------------------------------------------
230 /// @brief Forward the specified viewport metrics to the running isolate.
231 /// If the isolate is not running, these metrics will be saved and
232 /// flushed to the isolate when it starts.
233 ///
234 /// @param[in] view_id The ID for the view that `metrics` describes.
235 /// @param[in] metrics The window's viewport metrics.
236 ///
237 /// @return If the window metrics were forwarded to the running isolate.
238 ///
239 bool SetViewportMetrics(int64_t view_id, const ViewportMetrics& metrics);
240
241 //----------------------------------------------------------------------------
242 /// @brief Forward the specified display metrics to the running isolate.
243 /// If the isolate is not running, these metrics will be saved and
244 /// flushed to the isolate when it starts.
245 ///
246 /// @param[in] displays The available displays.
247 bool SetDisplays(const std::vector<DisplayData>& displays);
248
249 //----------------------------------------------------------------------------
250 /// @brief Forward the specified locale data to the running isolate. If
251 /// the isolate is not running, this data will be saved and
252 /// flushed to the isolate when it starts running.
253 ///
254 /// @deprecated The persistent isolate data must be used for this purpose
255 /// instead.
256 ///
257 /// @param[in] locale_data The locale data. This should consist of groups of
258 /// 4 strings, each group representing a single locale.
259 ///
260 /// @return If the locale data was forwarded to the running isolate.
261 ///
262 bool SetLocales(const std::vector<std::string>& locale_data);
263
264 //----------------------------------------------------------------------------
265 /// @brief Forward the user settings data to the running isolate. If the
266 /// isolate is not running, this data will be saved and flushed to
267 /// the isolate when it starts running.
268 ///
269 /// @deprecated The persistent isolate data must be used for this purpose
270 /// instead.
271 ///
272 /// @param[in] data The user settings data.
273 ///
274 /// @return If the user settings data was forwarded to the running
275 /// isolate.
276 ///
277 bool SetUserSettingsData(const std::string& data);
278
279 //----------------------------------------------------------------------------
280 /// @brief Forward the initial lifecycle state data to the running
281 /// isolate. If the isolate is not running, this data will be
282 /// saved and flushed to the isolate when it starts running.
283 /// After the isolate starts running, the current lifecycle
284 /// state is pushed to it via the "flutter/lifecycle" channel.
285 ///
286 /// @deprecated The persistent isolate data must be used for this purpose
287 /// instead.
288 ///
289 /// @param[in] data The lifecycle state data.
290 ///
291 /// @return If the lifecycle state data was forwarded to the running
292 /// isolate.
293 ///
294 bool SetInitialLifecycleState(const std::string& data);
295
296 //----------------------------------------------------------------------------
297 /// @brief Notifies the running isolate about whether the semantics tree
298 /// should be generated or not. If the isolate is not running,
299 /// this preference will be saved and flushed to the isolate when
300 /// it starts running.
301 ///
302 /// @param[in] enabled Indicates whether to generate the semantics tree.
303 ///
304 /// @return If the semantics tree generation preference was forwarded to
305 /// the running isolate.
306 ///
307 bool SetSemanticsEnabled(bool enabled);
308
309 //----------------------------------------------------------------------------
310 /// @brief Forward the preference of accessibility features that must be
311 /// enabled in the semantics tree to the running isolate. If the
312 /// isolate is not running, this data will be saved and flushed to
313 /// the isolate when it starts running.
314 ///
315 /// @param[in] flags The accessibility features that must be generated in
316 /// the semantics tree.
317 ///
318 /// @return If the preference of accessibility features was forwarded to
319 /// the running isolate.
320 ///
321 bool SetAccessibilityFeatures(int32_t flags);
322
323 //----------------------------------------------------------------------------
324 /// @brief Notifies the running isolate that it should start generating a
325 /// new frame.
326 ///
327 /// @see `Engine::BeginFrame` for more context.
328 ///
329 /// @param[in] frame_time The point at which the current frame interval
330 /// began. May be used by animation interpolators,
331 /// physics simulations, etc.
332 ///
333 /// @return If notification to begin frame rendering was delivered to the
334 /// running isolate.
335 ///
336 bool BeginFrame(fml::TimePoint frame_time, uint64_t frame_number);
337
338 //----------------------------------------------------------------------------
339 /// @brief Dart code cannot fully measure the time it takes for a
340 /// specific frame to be rendered. This is because Dart code only
341 /// runs on the UI task runner. That is only a small part of the
342 /// overall frame workload. The raster task runner frame workload
343 /// is executed on a thread where Dart code cannot run (and hence
344 /// instrument). Besides, due to the pipelined nature of rendering
345 /// in Flutter, there may be multiple frame workloads being
346 /// processed at any given time. However, for non-Timeline based
347 /// profiling, it is useful for trace collection and processing to
348 /// happen in Dart. To do this, the raster task runner frame
349 /// workloads need to be instrumented separately. After a set
350 /// number of these profiles have been gathered, they need to be
351 /// reported back to Dart code. The engine reports this extra
352 /// instrumentation information back to Dart code running on the
353 /// engine by invoking this method at predefined intervals.
354 ///
355 /// @see `Engine::ReportTimings`, `FrameTiming`
356 ///
357 /// @param[in] timings Collection of `FrameTiming::kCount` * `n` timestamps
358 /// for `n` frames whose timings have not been reported
359 /// yet. A collection of integers is reported here for
360 /// easier conversions to Dart objects. The timestamps
361 /// are measured against the system monotonic clock
362 /// measured in microseconds.
363 ///
364 bool ReportTimings(std::vector<int64_t> timings);
365
366 //----------------------------------------------------------------------------
367 /// @brief Notify the Dart VM that no frame workloads are expected on the
368 /// UI task runner till the specified deadline. The VM uses this
369 /// opportunity to perform garbage collection operations is a
370 /// manner that interferes as little as possible with frame
371 /// rendering.
372 ///
373 /// NotifyIdle is advisory. The VM may or may not run a garbage collection
374 /// when this is called, and will eventually perform garbage collections even
375 /// if it is not called or it is called with insufficient deadlines.
376 ///
377 /// The garbage collection mechanism and its thresholds are internal
378 /// implementation details and absolutely no guarantees are made about the
379 /// threshold discussed below. This discussion is also an oversimplification
380 /// but hopefully serves to calibrate expectations about GC behavior:
381 /// * When the Dart VM and its root isolate are initialized, the memory
382 /// consumed upto that point are treated as a baseline.
383 /// * A fixed percentage of the memory consumed (~20%) over the baseline is
384 /// treated as the hard threshold.
385 /// * The memory in play is divided into old space and new space. The new
386 /// space is typically very small and fills up rapidly.
387 /// * The baseline plus the threshold is considered the old space while the
388 /// small new space is a separate region (typically a few pages).
389 /// * The total old space size minus the max new space size is treated as the
390 /// soft threshold.
391 /// * In a world where there is no call to NotifyIdle, when the total
392 /// allocation exceeds the soft threshold, a concurrent mark is initiated in
393 /// the VM. There is a “small” pause that occurs when the concurrent mark is
394 /// initiated and another pause when the mark concludes and a sweep is
395 /// initiated.
396 /// * If the total allocations exceeds the hard threshold, a “big”
397 /// stop-the-world pause is initiated.
398 /// * If after either the sweep after the concurrent mark, or, the
399 /// stop-the-world pause, the consumption returns to be below the soft
400 /// threshold, the dance begins anew.
401 /// * If after both the “small” and “big” pauses, memory usage is still over
402 /// the hard threshold, i.e, the objects are still reachable, that amount of
403 /// memory is treated as the new baseline and a fixed percentage of the new
404 /// baseline over the new baseline is now the new hard threshold.
405 /// * Updating the baseline will continue till memory for the updated old
406 /// space can be allocated from the operating system. These allocations will
407 /// typically fail due to address space exhaustion on 32-bit systems and
408 /// page table exhaustion on 64-bit systems.
409 /// * NotifyIdle initiates the concurrent mark preemptively. The deadline is
410 /// used by the VM to determine if the corresponding sweep can be performed
411 /// within the deadline. This way, jank due to “small” pauses can be
412 /// ameliorated.
413 /// * There is no ability to stop a “big” pause on reaching the hard threshold
414 /// in the old space. The best you can do is release (by making them
415 /// unreachable) objects eagerly so that the are marked as unreachable in
416 /// the concurrent mark initiated by either reaching the soft threshold or
417 /// an explicit NotifyIdle.
418 /// * If you are running out of memory, its because too many large objects
419 /// were allocation and remained reachable such that the old space kept
420 /// growing till it could grow no more.
421 /// * At the edges of allocation thresholds, failures can occur gracefully if
422 /// the instigating allocation was made in the Dart VM or rather gracelessly
423 /// if the allocation is made by some native component.
424 ///
425 /// @see `Dart_TimelineGetMicros`
426 ///
427 /// @bug The `deadline` argument must be converted to `std::chrono`
428 /// instead of a raw integer.
429 ///
430 /// @param[in] deadline The deadline is used by the VM to determine if the
431 /// corresponding sweep can be performed within the deadline.
432 ///
433 /// @return If the idle notification was forwarded to the running isolate.
434 ///
435 virtual bool NotifyIdle(fml::TimeDelta deadline);
436
437 //----------------------------------------------------------------------------
438 /// @brief Notify the Dart VM that the attached flutter view has been
439 /// destroyed. This gives the Dart VM to perform some cleanup
440 /// activities e.g: perform garbage collection to free up any
441 /// unused memory.
442 ///
443 /// NotifyDestroyed is advisory. The VM may or may not perform any clean up
444 /// activities.
445 ///
446 virtual bool NotifyDestroyed();
447
448 //----------------------------------------------------------------------------
449 /// @brief Returns if the root isolate is running. The isolate must be
450 /// transitioned to the running phase manually. The isolate can
451 /// stop running if it terminates execution on its own.
452 ///
453 /// @return True if root isolate running, False otherwise.
454 ///
455 virtual bool IsRootIsolateRunning();
456
457 //----------------------------------------------------------------------------
458 /// @brief Dispatch the specified platform message to running root
459 /// isolate.
460 ///
461 /// @param[in] message The message to dispatch to the isolate.
462 ///
463 /// @return If the message was dispatched to the running root isolate.
464 /// This may fail is an isolate is not running.
465 ///
466 virtual bool DispatchPlatformMessage(
467 std::unique_ptr<PlatformMessage> message);
468
469 //----------------------------------------------------------------------------
470 /// @brief Dispatch the specified pointer data message to the running
471 /// root isolate.
472 ///
473 /// @param[in] packet The pointer data message to dispatch to the isolate.
474 ///
475 /// @return If the pointer data message was dispatched. This may fail is
476 /// an isolate is not running.
477 ///
479
480 //----------------------------------------------------------------------------
481 /// @brief Dispatch the semantics action to the specified accessibility
482 /// node.
483 ///
484 /// @param[in] node_id The identified of the accessibility node.
485 /// @param[in] action The semantics action to perform on the specified
486 /// accessibility node.
487 /// @param[in] args Optional data that applies to the specified action.
488 ///
489 /// @return If the semantics action was dispatched. This may fail if an
490 /// isolate is not running.
491 ///
492 bool DispatchSemanticsAction(int32_t node_id,
495
496 //----------------------------------------------------------------------------
497 /// @brief Gets the main port identifier of the root isolate.
498 ///
499 /// @return The main port identifier. If no root isolate is running,
500 /// returns `ILLEGAL_PORT`.
501 ///
503
504 //----------------------------------------------------------------------------
505 /// @brief Gets the debug name of the root isolate. But default, the
506 /// debug name of the isolate is derived from its advisory script
507 /// URI, advisory main entrypoint and its main port name. For
508 /// example, "main.dart$main-1234" where the script URI is
509 /// "main.dart", the entrypoint is "main" and the port name
510 /// "1234". Once launched, the isolate may re-christen itself
511 /// using a name it selects via `setIsolateDebugName` in
512 /// `window.dart`. This name is purely advisory and only used by
513 /// instrumentation and reporting purposes.
514 ///
515 /// @return The debug name of the root isolate.
516 ///
517 std::string GetIsolateName();
518
519 //----------------------------------------------------------------------------
520 /// @brief Returns if the root isolate has any live receive ports.
521 ///
522 /// @return True if there are live receive ports, False otherwise. Return
523 /// False if the root isolate is not running as well.
524 ///
525 bool HasLivePorts();
526
527 //----------------------------------------------------------------------------
528 /// @brief Get the last error encountered by the microtask queue.
529 ///
530 /// @return The last error encountered by the microtask queue.
531 ///
533
534 //----------------------------------------------------------------------------
535 /// @brief Get the service ID of the root isolate if the root isolate is
536 /// running.
537 ///
538 /// @return The root isolate service id.
539 ///
540 std::optional<std::string> GetRootIsolateServiceID() const;
541
542 //----------------------------------------------------------------------------
543 /// @brief Get the return code specified by the root isolate (if one is
544 /// present).
545 ///
546 /// @return The root isolate return code if the isolate has specified one.
547 ///
548 std::optional<uint32_t> GetRootIsolateReturnCode();
549
550 //----------------------------------------------------------------------------
551 /// @brief Get an identifier that represents the Dart isolate group the
552 /// root isolate is in.
553 ///
554 /// @return The root isolate group identifier, zero if one can't
555 /// be established.
556 uint64_t GetRootIsolateGroup() const;
557
558 //--------------------------------------------------------------------------
559 /// @brief Loads the Dart shared library into the Dart VM. When the
560 /// Dart library is loaded successfully, the Dart future
561 /// returned by the originating loadLibrary() call completes.
562 ///
563 /// The Dart compiler may generate separate shared libraries
564 /// files called 'loading units' when libraries are imported
565 /// as deferred. Each of these shared libraries are identified
566 /// by a unique loading unit id. Callers should open and resolve
567 /// a SymbolMapping from the shared library. The Mappings should
568 /// be moved into this method, as ownership will be assumed by the
569 /// dart root isolate after successful loading and released after
570 /// shutdown of the root isolate. The loading unit may not be
571 /// used after isolate shutdown. If loading fails, the mappings
572 /// will be released.
573 ///
574 /// This method is paired with a RequestDartDeferredLibrary
575 /// invocation that provides the embedder with the loading unit id
576 /// of the deferred library to load.
577 ///
578 ///
579 /// @param[in] loading_unit_id The unique id of the deferred library's
580 /// loading unit, as passed in by
581 /// RequestDartDeferredLibrary.
582 ///
583 /// @param[in] snapshot_data Dart snapshot data of the loading unit's
584 /// shared library.
585 ///
586 /// @param[in] snapshot_data Dart snapshot instructions of the loading
587 /// unit's shared library.
588 ///
590 intptr_t loading_unit_id,
591 std::unique_ptr<const fml::Mapping> snapshot_data,
592 std::unique_ptr<const fml::Mapping> snapshot_instructions);
593
594 //--------------------------------------------------------------------------
595 /// @brief Indicates to the dart VM that the request to load a deferred
596 /// library with the specified loading unit id has failed.
597 ///
598 /// The dart future returned by the initiating loadLibrary() call
599 /// will complete with an error.
600 ///
601 /// @param[in] loading_unit_id The unique id of the deferred library's
602 /// loading unit, as passed in by
603 /// RequestDartDeferredLibrary.
604 ///
605 /// @param[in] error_message The error message that will appear in the
606 /// dart Future.
607 ///
608 /// @param[in] transient A transient error is a failure due to
609 /// temporary conditions such as no network.
610 /// Transient errors allow the dart VM to
611 /// re-request the same deferred library and
612 /// loading_unit_id again. Non-transient
613 /// errors are permanent and attempts to
614 /// re-request the library will instantly
615 /// complete with an error.
616 virtual void LoadDartDeferredLibraryError(intptr_t loading_unit_id,
617 const std::string error_message,
618 bool transient);
619
620 // |PlatformConfigurationClient|
621 void RequestDartDeferredLibrary(intptr_t loading_unit_id) override;
622
623 // |PlatformConfigurationClient|
624 std::shared_ptr<const fml::Mapping> GetPersistentIsolateData() override;
625
627 return context_.io_manager;
628 }
629
630 virtual DartVM* GetDartVM() const { return vm_; }
631
633 return isolate_snapshot_;
634 }
635
636 const PlatformData& GetPlatformData() const { return platform_data_; }
637
639 return context_.unref_queue;
640 }
641
643 const {
644 return context_.snapshot_delegate;
645 }
646
647 std::weak_ptr<const DartIsolate> GetRootIsolate() const {
648 return root_isolate_;
649 }
650
651 std::shared_ptr<PlatformIsolateManager> GetPlatformIsolateManager() override {
652 return platform_isolate_manager_;
653 }
654
655 //--------------------------------------------------------------------------
656 /// @brief Shuts down all registered platform isolates. Must be called
657 /// from the platform thread.
658 ///
660
661 protected:
662 /// Constructor for Mocks.
663 RuntimeController(RuntimeDelegate& p_client, const TaskRunners& task_runners);
664
665 private:
666 struct Locale {
667 Locale(std::string language_code_,
668 std::string country_code_,
669 std::string script_code_,
670 std::string variant_code_);
671
672 ~Locale();
673
674 std::string language_code;
675 std::string country_code;
676 std::string script_code;
677 std::string variant_code;
678 };
679
680 RuntimeDelegate& client_;
681 DartVM* const vm_;
682 fml::RefPtr<const DartSnapshot> isolate_snapshot_;
683 std::function<void(int64_t)> idle_notification_callback_;
684 PlatformData platform_data_;
685 std::weak_ptr<DartIsolate> root_isolate_;
686 std::weak_ptr<DartIsolate> spawning_isolate_;
687 std::optional<uint32_t> root_isolate_return_code_;
688 const fml::closure isolate_create_callback_;
689 const fml::closure isolate_shutdown_callback_;
690 std::shared_ptr<const fml::Mapping> persistent_isolate_data_;
691 UIDartState::Context context_;
692 PointerDataPacketConverter pointer_data_packet_converter_;
693 std::shared_ptr<PlatformIsolateManager> platform_isolate_manager_ =
694 std::shared_ptr<PlatformIsolateManager>(new PlatformIsolateManager());
695 bool has_flushed_runtime_state_ = false;
696
697 // Callbacks when `AddView` was called before the Dart isolate is launched.
698 //
699 // These views will be added when `FlushRuntimeStateToIsolate` is called.
700 // This is no longer used once the Dart isolate starts.
701 std::unordered_map<int64_t, AddViewCallback> pending_add_view_callbacks_;
702
703 // Tracks the views that have been called `Render` during a frame.
704 //
705 // If all views that have been registered by `AddView` have been called
706 // `Render`, then the runtime controller notifies the client of the end of
707 // frame immediately, allowing the client to submit the views to the pipeline
708 // a bit earlier than having to wait for the end of `BeginFrame`. See also
709 // `Animator::OnAllViewsRendered`.
710 //
711 // This mechanism fixes https://github.com/flutter/flutter/issues/144584 with
712 // option 2 and
713 // https://github.com/flutter/engine/pull/51186#issuecomment-1977820525 with
714 // option a in most cases, except if there are multiple views and only part of
715 // them are rendered.
716 // TODO(dkwingsmt): Fix these problems for all cases.
717 std::unordered_set<uint64_t> rendered_views_during_frame_;
718
719 void MarkAsFrameBorder();
720
721 void CheckIfAllViewsRendered();
722
723 PlatformConfiguration* GetPlatformConfigurationIfAvailable();
724
725 bool FlushRuntimeStateToIsolate();
726
727 // |PointerDataPacketConverter::Delegate|
728 bool ViewExists(int64_t view_id) const override;
729
730 // |PlatformConfigurationClient|
731 std::string DefaultRouteName() override;
732
733 // |PlatformConfigurationClient|
734 void ScheduleFrame() override;
735
736 // |PlatformConfigurationClient|
737 void EndWarmUpFrame() override;
738
739 // |PlatformConfigurationClient|
740 void Render(int64_t view_id,
741 Scene* scene,
742 double width,
743 double height) override;
744
745 // |PlatformConfigurationClient|
746 void UpdateSemantics(SemanticsUpdate* update) override;
747
748 // |PlatformConfigurationClient|
749 void HandlePlatformMessage(std::unique_ptr<PlatformMessage> message) override;
750
751 // |PlatformConfigurationClient|
752 FontCollection& GetFontCollection() override;
753
754 // |PlatformConfigurationClient|
755 std::shared_ptr<AssetManager> GetAssetManager() override;
756
757 // |PlatformConfigurationClient|
758 void UpdateIsolateDescription(const std::string isolate_name,
759 int64_t isolate_port) override;
760
761 // |PlatformConfigurationClient|
762 void SetNeedsReportTimings(bool value) override;
763
764 // |PlatformConfigurationClient|
765 std::unique_ptr<std::vector<std::string>> ComputePlatformResolvedLocale(
766 const std::vector<std::string>& supported_locale_data) override;
767
768 // |PlatformConfigurationClient|
769 void SendChannelUpdate(std::string name, bool listening) override;
770
771 // |PlatformConfigurationClient|
772 double GetScaledFontSize(double unscaled_font_size,
773 int configuration_id) const override;
774
775 FML_DISALLOW_COPY_AND_ASSIGN(RuntimeController);
776};
777
778} // namespace flutter
779
780#endif // FLUTTER_RUNTIME_RUNTIME_CONTROLLER_H_
Describes a running instance of the Dart VM. There may only be one running instance of the Dart VM in...
Definition: dart_vm.h:61
A client interface that the RuntimeController uses to define handlers for PlatformConfiguration reque...
void AddView(int64_t view_id, const ViewportMetrics &view_metrics, AddViewCallback callback)
Notify the isolate that a new view is available.
bool SetAccessibilityFeatures(int32_t flags)
Forward the preference of accessibility features that must be enabled in the semantics tree to the ru...
virtual bool IsRootIsolateRunning()
Returns if the root isolate is running. The isolate must be transitioned to the running phase manuall...
Dart_Port GetMainPort()
Gets the main port identifier of the root isolate.
bool SetSemanticsEnabled(bool enabled)
Notifies the running isolate about whether the semantics tree should be generated or not....
bool SetViewportMetrics(int64_t view_id, const ViewportMetrics &metrics)
Forward the specified viewport metrics to the running isolate. If the isolate is not running,...
uint64_t GetRootIsolateGroup() const
Get an identifier that represents the Dart isolate group the root isolate is in.
RuntimeController(RuntimeDelegate &p_client, DartVM *vm, fml::RefPtr< const DartSnapshot > p_isolate_snapshot, const std::function< void(int64_t)> &idle_notification_callback, const PlatformData &platform_data, const fml::closure &isolate_create_callback, const fml::closure &isolate_shutdown_callback, std::shared_ptr< const fml::Mapping > p_persistent_isolate_data, const UIDartState::Context &context)
Creates a new instance of a runtime controller. This is usually only done by the engine instance asso...
bool DispatchSemanticsAction(int32_t node_id, SemanticsAction action, fml::MallocMapping args)
Dispatch the semantics action to the specified accessibility node.
virtual bool NotifyIdle(fml::TimeDelta deadline)
Notify the Dart VM that no frame workloads are expected on the UI task runner till the specified dead...
std::weak_ptr< const DartIsolate > GetRootIsolate() const
bool DispatchPointerDataPacket(const PointerDataPacket &packet)
Dispatch the specified pointer data message to the running root isolate.
bool SetInitialLifecycleState(const std::string &data)
Forward the initial lifecycle state data to the running isolate. If the isolate is not running,...
std::function< void(bool added)> AddViewCallback
std::shared_ptr< PlatformIsolateManager > GetPlatformIsolateManager() override
bool SetLocales(const std::vector< std::string > &locale_data)
Forward the specified locale data to the running isolate. If the isolate is not running,...
void RequestDartDeferredLibrary(intptr_t loading_unit_id) override
Invoked when the Dart VM requests that a deferred library be loaded. Notifies the engine that the def...
bool SetDisplays(const std::vector< DisplayData > &displays)
Forward the specified display metrics to the running isolate. If the isolate is not running,...
bool HasLivePorts()
Returns if the root isolate has any live receive ports.
bool RemoveView(int64_t view_id)
Notify the isolate that a view is no longer available.
std::optional< std::string > GetRootIsolateServiceID() const
Get the service ID of the root isolate if the root isolate is running.
const fml::RefPtr< const DartSnapshot > & GetIsolateSnapshot() const
const PlatformData & GetPlatformData() const
std::unique_ptr< RuntimeController > Spawn(RuntimeDelegate &p_client, const std::string &advisory_script_uri, const std::string &advisory_script_entrypoint, const std::function< void(int64_t)> &idle_notification_callback, const fml::closure &isolate_create_callback, const fml::closure &isolate_shutdown_callback, const std::shared_ptr< const fml::Mapping > &persistent_isolate_data, fml::WeakPtr< IOManager > io_manager, fml::WeakPtr< ImageDecoder > image_decoder, fml::WeakPtr< ImageGeneratorRegistry > image_generator_registry, fml::TaskRunnerAffineWeakPtr< SnapshotDelegate > snapshot_delegate) const
Create a RuntimeController that shares as many resources as possible with the calling RuntimeControll...
bool ReportTimings(std::vector< int64_t > timings)
Dart code cannot fully measure the time it takes for a specific frame to be rendered....
virtual bool NotifyDestroyed()
Notify the Dart VM that the attached flutter view has been destroyed. This gives the Dart VM to perfo...
const fml::RefPtr< SkiaUnrefQueue > & GetSkiaUnrefQueue() const
bool LaunchRootIsolate(const Settings &settings, const fml::closure &root_isolate_create_callback, std::optional< std::string > dart_entrypoint, std::optional< std::string > dart_entrypoint_library, const std::vector< std::string > &dart_entrypoint_args, std::unique_ptr< IsolateConfiguration > isolate_configuration)
Launches the isolate using the window data associated with this runtime controller....
const fml::TaskRunnerAffineWeakPtr< SnapshotDelegate > & GetSnapshotDelegate() const
virtual bool DispatchPlatformMessage(std::unique_ptr< PlatformMessage > message)
Dispatch the specified platform message to running root isolate.
tonic::DartErrorHandleType GetLastError()
Get the last error encountered by the microtask queue.
bool SetUserSettingsData(const std::string &data)
Forward the user settings data to the running isolate. If the isolate is not running,...
void LoadDartDeferredLibrary(intptr_t loading_unit_id, std::unique_ptr< const fml::Mapping > snapshot_data, std::unique_ptr< const fml::Mapping > snapshot_instructions)
Loads the Dart shared library into the Dart VM. When the Dart library is loaded successfully,...
std::unique_ptr< RuntimeController > Clone() const
Clone the runtime controller. Launching an isolate with a cloned runtime controller will use the same...
void ShutdownPlatformIsolates()
Shuts down all registered platform isolates. Must be called from the platform thread.
virtual DartVM * GetDartVM() const
bool BeginFrame(fml::TimePoint frame_time, uint64_t frame_number)
Notifies the running isolate that it should start generating a new frame.
std::optional< uint32_t > GetRootIsolateReturnCode()
Get the return code specified by the root isolate (if one is present).
std::shared_ptr< const fml::Mapping > GetPersistentIsolateData() override
The embedder can specify data that the isolate can request synchronously on launch....
const fml::WeakPtr< IOManager > & GetIOManager() const
virtual void LoadDartDeferredLibraryError(intptr_t loading_unit_id, const std::string error_message, bool transient)
Indicates to the dart VM that the request to load a deferred library with the specified loading unit ...
std::string GetIsolateName()
Gets the debug name of the root isolate. But default, the debug name of the isolate is derived from i...
A Mapping like NonOwnedMapping, but uses Free as its release proc.
Definition: mapping.h:144
int64_t Dart_Port
Definition: dart_api.h:1525
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
uint8_t value
Dart_NativeFunction function
Definition: fuchsia.cc:51
Definition: dart.idl:411
Win32Message message
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition: switches.h:41
std::function< void()> closure
Definition: closure.h:14
DartErrorHandleType
Definition: dart_error.h:67
Definition: update.py:1
int32_t height
int32_t width
The subset of state which is owned by the shell or engine and passed through the RuntimeController in...
Definition: ui_dart_state.h:45
fml::RefPtr< SkiaUnrefQueue > unref_queue
Definition: ui_dart_state.h:76
fml::WeakPtr< IOManager > io_manager
The IO manager used by the isolate for asynchronous texture uploads.
Definition: ui_dart_state.h:72
fml::TaskRunnerAffineWeakPtr< SnapshotDelegate > snapshot_delegate
Definition: ui_dart_state.h:69