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