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