runtime_controller.h 26.2 KB
Newer Older
M
Michael Goderbauer 已提交
1
// Copyright 2013 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
#ifndef FLUTTER_RUNTIME_RUNTIME_CONTROLLER_H_
#define FLUTTER_RUNTIME_RUNTIME_CONTROLLER_H_
7

8
#include <future>
9
#include <memory>
10
#include <vector>
11

12
#include "flutter/common/task_runners.h"
13
#include "flutter/flow/layers/layer_tree.h"
14
#include "flutter/fml/macros.h"
15
#include "flutter/lib/ui/io_manager.h"
16
#include "flutter/lib/ui/text/font_collection.h"
17
#include "flutter/lib/ui/ui_dart_state.h"
18
#include "flutter/lib/ui/window/platform_configuration.h"
19
#include "flutter/lib/ui/window/pointer_data_packet.h"
20
#include "flutter/runtime/dart_vm.h"
21
#include "flutter/runtime/platform_data.h"
22 23
#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
24

25
namespace flutter {
26

27
class Scene;
28
class RuntimeDelegate;
29
class View;
30
class Window;
31

32 33 34 35 36
//------------------------------------------------------------------------------
/// 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
37 38 39 40
/// 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.
41
///
42
class RuntimeController : public PlatformConfigurationClient {
43
 public:
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
  //----------------------------------------------------------------------------
  /// @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]  isolate_snapshot            The isolate snapshot used to start
  ///                                         the root isolate managed by this
  ///                                         runtime controller. The isolate
  ///                                         must be transitioned into the
  ///                                         running phase manually by the
  ///                                         caller.
  /// @param[in]  task_runners                The task runners used by the shell
  ///                                         hosting this runtime controller.
  ///                                         This may be used by the isolate to
  ///                                         scheduled asynchronous texture
  ///                                         uploads or post tasks to the
  ///                                         platform task runner.
  /// @param[in]  snapshot_delegate           The snapshot delegate used by the
  ///                                         isolate to gather raster snapshots
  ///                                         of Flutter view hierarchies.
71 72 73 74 75
  /// @param[in]  hint_freed_delegate         The delegate used by the isolate
  ///                                         to hint the Dart VM when
  ///                                         additional memory may be freed
  ///                                         if a GC ran at the next
  ///                                         NotifyIdle.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
  /// @param[in]  io_manager                  The IO manager used by the isolate
  ///                                         for asynchronous texture uploads.
  /// @param[in]  unref_queue                 The unref queue used by the
  ///                                         isolate to collect resources that
  ///                                         may reference resources on the
  ///                                         GPU.
  /// @param[in]  image_decoder               The image decoder
  /// @param[in]  advisory_script_uri         The advisory script URI (only used
  ///                                         for debugging). This does not
  ///                                         affect the code being run in the
  ///                                         isolate in any way.
  /// @param[in]  advisory_script_entrypoint  The advisory script entrypoint
  ///                                         (only used for debugging). This
  ///                                         does not affect the code being run
  ///                                         in the isolate in any way. The
  ///                                         isolate must be transitioned to
  ///                                         the running state explicitly by
  ///                                         the caller.
  /// @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.
99
  /// @param[in]  platform_data                 The window data (if exists).
100 101 102 103 104 105 106 107 108 109 110 111 112 113
  /// @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.
  ///
114 115 116 117 118
  RuntimeController(
      RuntimeDelegate& client,
      DartVM* vm,
      fml::RefPtr<const DartSnapshot> isolate_snapshot,
      TaskRunners task_runners,
119
      fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
120
      fml::WeakPtr<HintFreedDelegate> hint_freed_delegate,
121
      fml::WeakPtr<IOManager> io_manager,
122 123
      fml::RefPtr<SkiaUnrefQueue> unref_queue,
      fml::WeakPtr<ImageDecoder> image_decoder,
124 125
      std::string advisory_script_uri,
      std::string advisory_script_entrypoint,
126
      const std::function<void(int64_t)>& idle_notification_callback,
127
      const PlatformData& platform_data,
128 129
      const fml::closure& isolate_create_callback,
      const fml::closure& isolate_shutdown_callback,
130
      std::shared_ptr<const fml::Mapping> persistent_isolate_data);
131

132
  // |PlatformConfigurationClient|
133
  ~RuntimeController() override;
134

135 136 137 138 139 140 141 142
  //----------------------------------------------------------------------------
  /// @brief      Clone the the runtime controller. This re-creates the root
  ///             isolate with 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.
  ///
143 144
  std::unique_ptr<RuntimeController> Clone() const;

145
  //----------------------------------------------------------------------------
146
  /// @brief      Forward the specified viewport metrics to the running isolate.
147 148 149
  ///             If the isolate is not running, these metrics will be saved and
  ///             flushed to the isolate when it starts.
  ///
150
  /// @param[in]  metrics  The viewport metrics.
151 152 153
  ///
  /// @return     If the window metrics were forwarded to the running isolate.
  ///
154
  bool SetViewportMetrics(const ViewportMetrics& metrics);
155

156 157 158 159 160 161 162 163
  //----------------------------------------------------------------------------
  /// @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.
  ///
164 165
  /// @param[in]  locale_data  The locale data. This should consist of groups of
  ///             4 strings, each group representing a single locale.
166 167 168
  ///
  /// @return     If the locale data was forwarded to the running isolate.
  ///
169
  bool SetLocales(const std::vector<std::string>& locale_data);
170

171
  //----------------------------------------------------------------------------
172 173 174 175 176 177 178 179 180 181 182 183
  /// @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.
  ///
184 185
  bool SetUserSettingsData(const std::string& data);

186 187 188 189 190 191 192 193 194 195 196 197 198
  //----------------------------------------------------------------------------
  /// @brief      Forward the 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.
  ///
  /// @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.
  ///
199 200
  bool SetLifecycleState(const std::string& data);

201 202 203 204 205 206 207 208 209 210 211
  //----------------------------------------------------------------------------
  /// @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.
  ///
212 213
  bool SetSemanticsEnabled(bool enabled);

214 215 216 217 218 219 220 221 222 223 224 225
  //----------------------------------------------------------------------------
  /// @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.
  ///
226
  bool SetAccessibilityFeatures(int32_t flags);
227

228 229 230 231 232 233 234 235
  //----------------------------------------------------------------------------
  /// @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,
236
  ///                         physics simulations, etc.
237 238 239 240
  ///
  /// @return     If notification to begin frame rendering was delivered to the
  ///             running isolate.
  ///
241
  bool BeginFrame(fml::TimePoint frame_time);
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
  //----------------------------------------------------------------------------
  /// @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 GPU 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 GPU 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.
  ///
269 270
  bool ReportTimings(std::vector<int64_t> timings);

271 272 273 274 275 276 277
  //----------------------------------------------------------------------------
  /// @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.
  ///
278 279 280
  /// 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.
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
  ///
  /// 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 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 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 measures in microseconds against the
  ///             system's monotonic time. The clock can be accessed via
  ///             `Dart_TimelineGetMicros`.
338 339
  /// @param[in] freed_hint  A hint of the number of bytes potentially freed
  ///                        since the last call to NotifyIdle if a GC were run.
340 341 342
  ///
  /// @return     If the idle notification was forwarded to the running isolate.
  ///
343
  bool NotifyIdle(int64_t deadline, size_t freed_hint);
344

345 346 347 348 349 350 351
  //----------------------------------------------------------------------------
  /// @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.
  ///
352
  virtual bool IsRootIsolateRunning();
353

354 355 356 357 358 359 360 361 362
  //----------------------------------------------------------------------------
  /// @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.
  ///
363
  virtual bool DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message);
364

365 366 367 368 369 370 371 372 373
  //----------------------------------------------------------------------------
  /// @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.
  ///
374 375
  bool DispatchPointerDataPacket(const PointerDataPacket& packet);

376 377 378 379 380 381 382 383 384 385 386 387
  //----------------------------------------------------------------------------
  /// @brief      Dispatch the semantics action to the specified accessibility
  ///             node.
  ///
  /// @param[in]  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.
  ///
388
  bool DispatchSemanticsAction(int32_t id,
389 390
                               SemanticsAction action,
                               std::vector<uint8_t> args);
391

392 393 394 395 396 397
  //----------------------------------------------------------------------------
  /// @brief      Gets the main port identifier of the root isolate.
  ///
  /// @return     The main port identifier. If no root isolate is running,
  ///             returns `ILLEGAL_PORT`.
  ///
398
  Dart_Port GetMainPort();
399

400 401 402 403 404 405 406 407 408 409 410 411 412
  //----------------------------------------------------------------------------
  /// @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.
  ///
413
  std::string GetIsolateName();
414

415 416 417 418
  //----------------------------------------------------------------------------
  /// @brief      Returns if the root isolate has any live receive ports.
  ///
  /// @return     True if there are live receive ports, False otherwise. Return
419
  ///             False if the root isolate is not running as well.
420
  ///
421
  bool HasLivePorts();
422

423 424 425 426 427
  //----------------------------------------------------------------------------
  /// @brief      Get the last error encountered by the microtask queue.
  ///
  /// @return     The last error encountered by the microtask queue.
  ///
428
  tonic::DartErrorHandleType GetLastError();
429

430 431 432 433
  //----------------------------------------------------------------------------
  /// @brief      Get a weak pointer to the root Dart isolate. This isolate may
  ///             only be locked on the UI task runner. Callers use this
  ///             accessor to transition to the root isolate to the running
434 435 436 437
  ///             phase. Note that it might take times if the isolate is not yet
  ///             created, which should be done in a subsequence task after
  ///             constructing `RuntimeController`, or it should get a quick
  ///             return otherwise.
438 439 440
  ///
  /// @return     The root isolate reference.
  ///
441
  std::weak_ptr<DartIsolate> GetRootIsolate();
442

443 444 445 446 447 448 449 450 451 452
  //----------------------------------------------------------------------------
  /// @brief      Get the return code specified by the root isolate (if one is
  ///             present).
  ///
  /// @bug        Change this method to return `std::optional<uint32_t>`
  ///             instead.
  ///
  /// @return     The root isolate return code. The first argument in the pair
  ///             indicates if one is specified by the root isolate.
  ///
453
  std::pair<bool, uint32_t> GetRootIsolateReturnCode();
454

455 456 457 458
 protected:
  /// Constructor for Mocks.
  RuntimeController(RuntimeDelegate& client, TaskRunners p_task_runners);

459
 private:
460 461 462 463
  struct Locale {
    Locale(std::string language_code_,
           std::string country_code_,
           std::string script_code_,
464 465 466
           std::string variant_code_);

    ~Locale();
467 468 469 470 471 472 473

    std::string language_code;
    std::string country_code;
    std::string script_code;
    std::string variant_code;
  };

474
  RuntimeDelegate& client_;
B
Ben Konyi 已提交
475
  DartVM* const vm_;
476
  fml::RefPtr<const DartSnapshot> isolate_snapshot_;
477
  TaskRunners task_runners_;
478
  fml::WeakPtr<SnapshotDelegate> snapshot_delegate_;
479
  fml::WeakPtr<HintFreedDelegate> hint_freed_delegate_;
480
  fml::WeakPtr<IOManager> io_manager_;
481
  fml::RefPtr<SkiaUnrefQueue> unref_queue_;
482
  fml::WeakPtr<ImageDecoder> image_decoder_;
483 484
  std::string advisory_script_uri_;
  std::string advisory_script_entrypoint_;
485
  std::function<void(int64_t)> idle_notification_callback_;
486
  PlatformData platform_data_;
487 488 489 490
  std::future<void> create_and_config_root_isolate_;
  // Note that `root_isolate_` is created asynchronously from the constructor of
  // `RuntimeController`, be careful to use it directly while it might have not
  // been created yet. Call `GetRootIsolate()` instead which guarantees that.
491
  std::weak_ptr<DartIsolate> root_isolate_;
492
  std::pair<bool, uint32_t> root_isolate_return_code_ = {false, 0};
493 494
  const fml::closure isolate_create_callback_;
  const fml::closure isolate_shutdown_callback_;
495
  std::shared_ptr<const fml::Mapping> persistent_isolate_data_;
496
  fml::WeakPtrFactory<RuntimeController> weak_factory_;
497

498
  PlatformConfiguration* GetPlatformConfigurationIfAvailable();
499 500 501

  bool FlushRuntimeStateToIsolate();

502
  // |PlatformConfigurationClient|
503
  std::string DefaultRouteName() override;
504

505
  // |PlatformConfigurationClient|
506
  void ScheduleFrame() override;
507

508
  // |PlatformConfigurationClient|
509
  void Render(Scene* scene) override;
510

511
  // |PlatformConfigurationClient|
512
  void UpdateSemantics(SemanticsUpdate* update) override;
513

514
  // |PlatformConfigurationClient|
515
  void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) override;
516

517
  // |PlatformConfigurationClient|
518
  FontCollection& GetFontCollection() override;
519

520
  // |PlatformConfigurationClient|
521 522
  void UpdateIsolateDescription(const std::string isolate_name,
                                int64_t isolate_port) override;
523

524
  // |PlatformConfigurationClient|
525 526
  void SetNeedsReportTimings(bool value) override;

527
  // |PlatformConfigurationClient|
528 529
  std::shared_ptr<const fml::Mapping> GetPersistentIsolateData() override;

530
  // |PlatformConfigurationClient|
531 532 533
  std::unique_ptr<std::vector<std::string>> ComputePlatformResolvedLocale(
      const std::vector<std::string>& supported_locale_data) override;

534
  FML_DISALLOW_COPY_AND_ASSIGN(RuntimeController);
535 536
};

537
}  // namespace flutter
538

539
#endif  // FLUTTER_RUNTIME_RUNTIME_CONTROLLER_H_