runtime_controller.h 24.7 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 <memory>
9
#include <vector>
10

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

24
namespace flutter {
25

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

31 32 33 34 35
//------------------------------------------------------------------------------
/// 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
36 37 38 39
/// 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.
40
///
41
class RuntimeController final : public WindowClient {
42
 public:
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
  //----------------------------------------------------------------------------
  /// @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.
  /// @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.
  /// @param[in]  window_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.
  ///
108 109 110 111 112
  RuntimeController(
      RuntimeDelegate& client,
      DartVM* vm,
      fml::RefPtr<const DartSnapshot> isolate_snapshot,
      TaskRunners task_runners,
113
      fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
114
      fml::WeakPtr<IOManager> io_manager,
115 116
      fml::RefPtr<SkiaUnrefQueue> unref_queue,
      fml::WeakPtr<ImageDecoder> image_decoder,
117 118
      std::string advisory_script_uri,
      std::string advisory_script_entrypoint,
119
      const std::function<void(int64_t)>& idle_notification_callback,
120
      const WindowData& window_data,
121 122
      const fml::closure& isolate_create_callback,
      const fml::closure& isolate_shutdown_callback,
123
      std::shared_ptr<const fml::Mapping> persistent_isolate_data);
124

125
  // |WindowClient|
126
  ~RuntimeController() override;
127

128 129 130 131 132 133 134 135
  //----------------------------------------------------------------------------
  /// @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.
  ///
136 137
  std::unique_ptr<RuntimeController> Clone() const;

138 139 140 141 142 143 144 145 146
  //----------------------------------------------------------------------------
  /// @brief      Forward the specified window 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]  metrics  The metrics.
  ///
  /// @return     If the window metrics were forwarded to the running isolate.
  ///
147
  bool SetViewportMetrics(const ViewportMetrics& metrics);
148

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

164
  //----------------------------------------------------------------------------
165 166 167 168 169 170 171 172 173 174 175 176
  /// @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.
  ///
177 178
  bool SetUserSettingsData(const std::string& data);

179 180 181 182 183 184 185 186 187 188 189 190 191
  //----------------------------------------------------------------------------
  /// @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.
  ///
192 193
  bool SetLifecycleState(const std::string& data);

194 195 196 197 198 199 200 201 202 203 204
  //----------------------------------------------------------------------------
  /// @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.
  ///
205 206
  bool SetSemanticsEnabled(bool enabled);

207 208 209 210 211 212 213 214 215 216 217 218
  //----------------------------------------------------------------------------
  /// @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.
  ///
219
  bool SetAccessibilityFeatures(int32_t flags);
220

221 222 223 224 225 226 227 228
  //----------------------------------------------------------------------------
  /// @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,
229
  ///                         physics simulations, etc.
230 231 232 233
  ///
  /// @return     If notification to begin frame rendering was delivered to the
  ///             running isolate.
  ///
234
  bool BeginFrame(fml::TimePoint frame_time);
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
  //----------------------------------------------------------------------------
  /// @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.
  ///
262 263
  bool ReportTimings(std::vector<int64_t> timings);

264 265 266 267 268 269 270
  //----------------------------------------------------------------------------
  /// @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.
  ///
271 272 273
  /// 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.
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
  ///
  /// 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`.
  ///
  /// @return     If the idle notification was forwarded to the running isolate.
  ///
334
  bool NotifyIdle(int64_t deadline);
335

336 337 338 339 340 341 342
  //----------------------------------------------------------------------------
  /// @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.
  ///
343 344
  bool IsRootIsolateRunning() const;

345 346 347 348 349 350 351 352 353
  //----------------------------------------------------------------------------
  /// @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.
  ///
354
  bool DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message);
355

356 357 358 359 360 361 362 363 364
  //----------------------------------------------------------------------------
  /// @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.
  ///
365 366
  bool DispatchPointerDataPacket(const PointerDataPacket& packet);

367 368 369 370 371 372 373 374 375 376 377 378
  //----------------------------------------------------------------------------
  /// @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.
  ///
379
  bool DispatchSemanticsAction(int32_t id,
380 381
                               SemanticsAction action,
                               std::vector<uint8_t> args);
382

383 384 385 386 387 388
  //----------------------------------------------------------------------------
  /// @brief      Gets the main port identifier of the root isolate.
  ///
  /// @return     The main port identifier. If no root isolate is running,
  ///             returns `ILLEGAL_PORT`.
  ///
389
  Dart_Port GetMainPort();
390

391 392 393 394 395 396 397 398 399 400 401 402 403
  //----------------------------------------------------------------------------
  /// @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.
  ///
404
  std::string GetIsolateName();
405

406 407 408 409
  //----------------------------------------------------------------------------
  /// @brief      Returns if the root isolate has any live receive ports.
  ///
  /// @return     True if there are live receive ports, False otherwise. Return
410
  ///             False if the root isolate is not running as well.
411
  ///
412
  bool HasLivePorts();
413

414 415 416 417 418
  //----------------------------------------------------------------------------
  /// @brief      Get the last error encountered by the microtask queue.
  ///
  /// @return     The last error encountered by the microtask queue.
  ///
419
  tonic::DartErrorHandleType GetLastError();
420

421 422 423 424 425 426 427 428
  //----------------------------------------------------------------------------
  /// @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
  ///             phase.
  ///
  /// @return     The root isolate reference.
  ///
429
  std::weak_ptr<DartIsolate> GetRootIsolate();
430

431 432 433 434 435 436 437 438 439 440
  //----------------------------------------------------------------------------
  /// @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.
  ///
441
  std::pair<bool, uint32_t> GetRootIsolateReturnCode();
442

443
 private:
444 445 446 447
  struct Locale {
    Locale(std::string language_code_,
           std::string country_code_,
           std::string script_code_,
448 449 450
           std::string variant_code_);

    ~Locale();
451 452 453 454 455 456 457

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

458
  RuntimeDelegate& client_;
B
Ben Konyi 已提交
459
  DartVM* const vm_;
460
  fml::RefPtr<const DartSnapshot> isolate_snapshot_;
461
  TaskRunners task_runners_;
462
  fml::WeakPtr<SnapshotDelegate> snapshot_delegate_;
463
  fml::WeakPtr<IOManager> io_manager_;
464
  fml::RefPtr<SkiaUnrefQueue> unref_queue_;
465
  fml::WeakPtr<ImageDecoder> image_decoder_;
466 467
  std::string advisory_script_uri_;
  std::string advisory_script_entrypoint_;
468
  std::function<void(int64_t)> idle_notification_callback_;
469
  WindowData window_data_;
470
  std::weak_ptr<DartIsolate> root_isolate_;
471
  std::pair<bool, uint32_t> root_isolate_return_code_ = {false, 0};
472 473
  const fml::closure isolate_create_callback_;
  const fml::closure isolate_shutdown_callback_;
474 475
  std::shared_ptr<const fml::Mapping> persistent_isolate_data_;

476 477 478 479
  Window* GetWindowIfAvailable();

  bool FlushRuntimeStateToIsolate();

480
  // |WindowClient|
481
  std::string DefaultRouteName() override;
482

483
  // |WindowClient|
484
  void ScheduleFrame() override;
485

486
  // |WindowClient|
487
  void Render(Scene* scene) override;
488

489
  // |WindowClient|
490
  void UpdateSemantics(SemanticsUpdate* update) override;
491

492
  // |WindowClient|
493
  void HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) override;
494

495
  // |WindowClient|
496
  FontCollection& GetFontCollection() override;
497

498
  // |WindowClient|
499 500
  void UpdateIsolateDescription(const std::string isolate_name,
                                int64_t isolate_port) override;
501

502 503 504
  // |WindowClient|
  void SetNeedsReportTimings(bool value) override;

505 506 507
  // |WindowClient|
  std::shared_ptr<const fml::Mapping> GetPersistentIsolateData() override;

508 509 510 511
  // |WindowClient|
  std::unique_ptr<std::vector<std::string>> ComputePlatformResolvedLocale(
      const std::vector<std::string>& supported_locale_data) override;

512
  FML_DISALLOW_COPY_AND_ASSIGN(RuntimeController);
513 514
};

515
}  // namespace flutter
516

517
#endif  // FLUTTER_RUNTIME_RUNTIME_CONTROLLER_H_