Flutter Engine
runtime_controller.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "flutter/runtime/runtime_controller.h"
6 
7 #include "flutter/fml/message_loop.h"
8 #include "flutter/fml/trace_event.h"
9 #include "flutter/lib/ui/compositing/scene.h"
10 #include "flutter/lib/ui/ui_dart_state.h"
11 #include "flutter/lib/ui/window/platform_configuration.h"
12 #include "flutter/lib/ui/window/viewport_metrics.h"
13 #include "flutter/lib/ui/window/window.h"
14 #include "flutter/runtime/isolate_configuration.h"
15 #include "flutter/runtime/runtime_delegate.h"
17 
18 namespace flutter {
19 
21  TaskRunners task_runners)
22  : client_(p_client), vm_(nullptr), context_(task_runners) {}
23 
25  RuntimeDelegate& p_client,
26  DartVM* p_vm,
27  fml::RefPtr<const DartSnapshot> p_isolate_snapshot,
28  const std::function<void(int64_t)>& p_idle_notification_callback,
29  const PlatformData& p_platform_data,
30  const fml::closure& p_isolate_create_callback,
31  const fml::closure& p_isolate_shutdown_callback,
32  std::shared_ptr<const fml::Mapping> p_persistent_isolate_data,
33  const UIDartState::Context& p_context)
34  : client_(p_client),
35  vm_(p_vm),
36  isolate_snapshot_(p_isolate_snapshot),
37  idle_notification_callback_(p_idle_notification_callback),
38  platform_data_(std::move(p_platform_data)),
39  isolate_create_callback_(p_isolate_create_callback),
40  isolate_shutdown_callback_(p_isolate_shutdown_callback),
41  persistent_isolate_data_(std::move(p_persistent_isolate_data)),
42  context_(p_context) {}
43 
44 std::unique_ptr<RuntimeController> RuntimeController::Spawn(
45  RuntimeDelegate& p_client,
46  std::string advisory_script_uri,
47  std::string advisory_script_entrypoint,
48  const std::function<void(int64_t)>& p_idle_notification_callback,
49  const fml::closure& p_isolate_create_callback,
50  const fml::closure& p_isolate_shutdown_callback,
51  std::shared_ptr<const fml::Mapping> p_persistent_isolate_data) const {
52  auto result =
53  std::make_unique<RuntimeController>(p_client, //
54  vm_, //
55  isolate_snapshot_, //
56  p_idle_notification_callback, //
57  platform_data_, //
58  p_isolate_create_callback, //
59  p_isolate_shutdown_callback, //
60  p_persistent_isolate_data, //
61  context_); //
62  result->spawning_isolate_ = root_isolate_;
63  return result;
64 }
65 
67  FML_DCHECK(Dart_CurrentIsolate() == nullptr);
68  std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
69  if (root_isolate) {
70  root_isolate->SetReturnCodeCallback(nullptr);
71  auto result = root_isolate->Shutdown();
72  if (!result) {
73  FML_DLOG(ERROR) << "Could not shutdown the root isolate.";
74  }
75  root_isolate_ = {};
76  }
77 }
78 
80  std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
81  if (root_isolate) {
82  return root_isolate->GetPhase() == DartIsolate::Phase::Running;
83  }
84  return false;
85 }
86 
87 std::unique_ptr<RuntimeController> RuntimeController::Clone() const {
88  return std::make_unique<RuntimeController>(client_, //
89  vm_, //
90  isolate_snapshot_, //
91  idle_notification_callback_, //
92  platform_data_, //
93  isolate_create_callback_, //
94  isolate_shutdown_callback_, //
95  persistent_isolate_data_, //
96  context_ //
97  );
98 }
99 
100 bool RuntimeController::FlushRuntimeStateToIsolate() {
101  return SetViewportMetrics(platform_data_.viewport_metrics) &&
102  SetLocales(platform_data_.locale_data) &&
103  SetSemanticsEnabled(platform_data_.semantics_enabled) &&
105  platform_data_.accessibility_feature_flags_) &&
106  SetUserSettingsData(platform_data_.user_settings_data) &&
107  SetLifecycleState(platform_data_.lifecycle_state);
108 }
109 
111  platform_data_.viewport_metrics = metrics;
112 
113  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
114  platform_configuration->get_window(0)->UpdateWindowMetrics(metrics);
115  return true;
116  }
117 
118  return false;
119 }
120 
122  const std::vector<std::string>& locale_data) {
123  platform_data_.locale_data = locale_data;
124 
125  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
126  platform_configuration->UpdateLocales(locale_data);
127  return true;
128  }
129 
130  return false;
131 }
132 
133 bool RuntimeController::SetUserSettingsData(const std::string& data) {
134  platform_data_.user_settings_data = data;
135 
136  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
137  platform_configuration->UpdateUserSettingsData(
138  platform_data_.user_settings_data);
139  return true;
140  }
141 
142  return false;
143 }
144 
145 bool RuntimeController::SetLifecycleState(const std::string& data) {
146  platform_data_.lifecycle_state = data;
147 
148  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
149  platform_configuration->UpdateLifecycleState(
150  platform_data_.lifecycle_state);
151  return true;
152  }
153 
154  return false;
155 }
156 
158  platform_data_.semantics_enabled = enabled;
159 
160  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
161  platform_configuration->UpdateSemanticsEnabled(
162  platform_data_.semantics_enabled);
163  return true;
164  }
165 
166  return false;
167 }
168 
170  platform_data_.accessibility_feature_flags_ = flags;
171  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
172  platform_configuration->UpdateAccessibilityFeatures(
173  platform_data_.accessibility_feature_flags_);
174  return true;
175  }
176 
177  return false;
178 }
179 
181  uint64_t frame_number) {
182  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
183  platform_configuration->BeginFrame(frame_time, frame_number);
184  return true;
185  }
186 
187  return false;
188 }
189 
190 bool RuntimeController::ReportTimings(std::vector<int64_t> timings) {
191  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
192  platform_configuration->ReportTimings(std::move(timings));
193  return true;
194  }
195 
196  return false;
197 }
198 
199 bool RuntimeController::NotifyIdle(int64_t deadline) {
200  std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
201  if (!root_isolate) {
202  return false;
203  }
204 
205  tonic::DartState::Scope scope(root_isolate);
206 
207  Dart_NotifyIdle(deadline);
208 
209  // Idle notifications being in isolate scope are part of the contract.
210  if (idle_notification_callback_) {
211  TRACE_EVENT0("flutter", "EmbedderIdleNotification");
212  idle_notification_callback_(deadline);
213  }
214  return true;
215 }
216 
218  std::unique_ptr<PlatformMessage> message) {
219  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
220  TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage",
221  "mode", "basic");
222  platform_configuration->DispatchPlatformMessage(std::move(message));
223  return true;
224  }
225 
226  return false;
227 }
228 
230  const PointerDataPacket& packet) {
231  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
232  TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket",
233  "mode", "basic");
234  platform_configuration->get_window(0)->DispatchPointerDataPacket(packet);
235  return true;
236  }
237 
238  return false;
239 }
240 
243  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
244  TRACE_EVENT1("flutter", "RuntimeController::DispatchKeyDataPacket", "mode",
245  "basic");
246  uint64_t response_id =
247  platform_configuration->RegisterKeyDataResponse(std::move(callback));
248  platform_configuration->get_window(0)->DispatchKeyDataPacket(packet,
249  response_id);
250  return true;
251  }
252  return false;
253 }
254 
258  TRACE_EVENT1("flutter", "RuntimeController::DispatchSemanticsAction", "mode",
259  "basic");
260  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
261  platform_configuration->DispatchSemanticsAction(id, action,
262  std::move(args));
263  return true;
264  }
265 
266  return false;
267 }
268 
270 RuntimeController::GetPlatformConfigurationIfAvailable() {
271  std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
272  return root_isolate ? root_isolate->platform_configuration() : nullptr;
273 }
274 
275 // |PlatformConfigurationClient|
276 std::string RuntimeController::DefaultRouteName() {
277  return client_.DefaultRouteName();
278 }
279 
280 // |PlatformConfigurationClient|
281 void RuntimeController::ScheduleFrame() {
282  client_.ScheduleFrame();
283 }
284 
285 // |PlatformConfigurationClient|
286 void RuntimeController::Render(Scene* scene) {
287  client_.Render(scene->takeLayerTree());
288 }
289 
290 // |PlatformConfigurationClient|
291 void RuntimeController::UpdateSemantics(SemanticsUpdate* update) {
292  if (platform_data_.semantics_enabled) {
293  client_.UpdateSemantics(update->takeNodes(), update->takeActions());
294  }
295 }
296 
297 // |PlatformConfigurationClient|
298 void RuntimeController::HandlePlatformMessage(
299  std::unique_ptr<PlatformMessage> message) {
300  client_.HandlePlatformMessage(std::move(message));
301 }
302 
303 // |PlatformConfigurationClient|
304 FontCollection& RuntimeController::GetFontCollection() {
305  return client_.GetFontCollection();
306 }
307 
308 // |PlatformConfigurationClient|
309 void RuntimeController::UpdateIsolateDescription(const std::string isolate_name,
310  int64_t isolate_port) {
311  client_.UpdateIsolateDescription(isolate_name, isolate_port);
312 }
313 
314 // |PlatformConfigurationClient|
315 void RuntimeController::SetNeedsReportTimings(bool value) {
316  client_.SetNeedsReportTimings(value);
317 }
318 
319 // |PlatformConfigurationClient|
320 std::shared_ptr<const fml::Mapping>
321 RuntimeController::GetPersistentIsolateData() {
322  return persistent_isolate_data_;
323 }
324 
325 // |PlatformConfigurationClient|
326 std::unique_ptr<std::vector<std::string>>
327 RuntimeController::ComputePlatformResolvedLocale(
328  const std::vector<std::string>& supported_locale_data) {
329  return client_.ComputePlatformResolvedLocale(supported_locale_data);
330 }
331 
333  std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
334  return root_isolate ? root_isolate->main_port() : ILLEGAL_PORT;
335 }
336 
338  std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
339  return root_isolate ? root_isolate->debug_name() : "";
340 }
341 
343  std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
344  if (!root_isolate) {
345  return false;
346  }
347  tonic::DartState::Scope scope(root_isolate);
348  return Dart_HasLivePorts();
349 }
350 
352  std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
353  return root_isolate ? root_isolate->GetLastError() : tonic::kNoError;
354 }
355 
357  const Settings& settings,
358  std::optional<std::string> dart_entrypoint,
359  std::optional<std::string> dart_entrypoint_library,
360  std::unique_ptr<IsolateConfiguration> isolate_configuration) {
361  if (root_isolate_.lock()) {
362  FML_LOG(ERROR) << "Root isolate was already running.";
363  return false;
364  }
365 
366  auto strong_root_isolate =
368  settings, //
369  isolate_snapshot_, //
370  std::make_unique<PlatformConfiguration>(this), //
371  DartIsolate::Flags{}, //
372  isolate_create_callback_, //
373  isolate_shutdown_callback_, //
374  dart_entrypoint, //
375  dart_entrypoint_library, //
376  std::move(isolate_configuration), //
377  context_, //
378  spawning_isolate_.lock().get()) //
379  .lock();
380 
381  if (!strong_root_isolate) {
382  FML_LOG(ERROR) << "Could not create root isolate.";
383  return false;
384  }
385 
386  // The root isolate ivar is weak.
387  root_isolate_ = strong_root_isolate;
388 
389  // Capture by `this` here is safe because the callback is made by the dart
390  // state itself. The isolate (and its Dart state) is owned by this object and
391  // it will be collected before this object.
392  strong_root_isolate->SetReturnCodeCallback(
393  [this](uint32_t code) { root_isolate_return_code_ = code; });
394 
395  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
396  tonic::DartState::Scope scope(strong_root_isolate);
397  platform_configuration->DidCreateIsolate();
398  if (!FlushRuntimeStateToIsolate()) {
399  FML_DLOG(ERROR) << "Could not set up initial isolate state.";
400  }
401  } else {
402  FML_DCHECK(false) << "RuntimeController created without window binding.";
403  }
404 
405  FML_DCHECK(Dart_CurrentIsolate() == nullptr);
406 
407  client_.OnRootIsolateCreated();
408 
409  return true;
410 }
411 
412 std::optional<std::string> RuntimeController::GetRootIsolateServiceID() const {
413  if (auto isolate = root_isolate_.lock()) {
414  return isolate->GetServiceId();
415  }
416  return std::nullopt;
417 }
418 
420  return root_isolate_return_code_;
421 }
422 
424  auto isolate = root_isolate_.lock();
425  if (isolate) {
426  auto isolate_scope = tonic::DartIsolateScope(isolate->isolate());
427  Dart_IsolateGroup isolate_group = Dart_CurrentIsolateGroup();
428  return reinterpret_cast<uint64_t>(isolate_group);
429  } else {
430  return 0;
431  }
432 }
433 
435  intptr_t loading_unit_id,
436  std::unique_ptr<const fml::Mapping> snapshot_data,
437  std::unique_ptr<const fml::Mapping> snapshot_instructions) {
438  root_isolate_.lock()->LoadLoadingUnit(loading_unit_id,
439  std::move(snapshot_data),
440  std::move(snapshot_instructions));
441 }
442 
444  intptr_t loading_unit_id,
445  const std::string error_message,
446  bool transient) {
447  root_isolate_.lock()->LoadLoadingUnitError(loading_unit_id, error_message,
448  transient);
449 }
450 
451 void RuntimeController::RequestDartDeferredLibrary(intptr_t loading_unit_id) {
452  return client_.RequestDartDeferredLibrary(loading_unit_id);
453 }
454 
455 RuntimeController::Locale::Locale(std::string language_code_,
456  std::string country_code_,
457  std::string script_code_,
458  std::string variant_code_)
459  : language_code(language_code_),
460  country_code(country_code_),
461  script_code(script_code_),
462  variant_code(variant_code_) {}
463 
464 RuntimeController::Locale::~Locale() = default;
465 
466 } // namespace flutter
bool DispatchSemanticsAction(int32_t id, SemanticsAction action, fml::MallocMapping args)
Dispatch the semantics action to the specified accessibility node.
virtual void SetNeedsReportTimings(bool value)=0
G_BEGIN_DECLS FlValue * args
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:90
#define FML_DCHECK(condition)
Definition: logging.h:86
bool SetSemanticsEnabled(bool enabled)
Notifies the running isolate about whether the semantics tree should be generated or not...
virtual bool IsRootIsolateRunning()
Returns if the root isolate is running. The isolate must be transitioned to the running phase manuall...
std::vector< std::string > locale_data
Definition: platform_data.h:38
bool SetAccessibilityFeatures(int32_t flags)
Forward the preference of accessibility features that must be enabled in the semantics tree to the ru...
Definition: ref_ptr.h:252
Dart_NativeFunction function
Definition: fuchsia.cc:51
virtual void UpdateSemantics(SemanticsNodeUpdates update, CustomAccessibilityActionUpdates actions)=0
std::unique_ptr< RuntimeController > Spawn(RuntimeDelegate &p_client, std::string advisory_script_uri, 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, std::shared_ptr< const fml::Mapping > persistent_isolate_data) const
Create a RuntimeController that shares as many resources as possible with the calling RuntimeControll...
std::unique_ptr< RuntimeController > Clone() const
Clone the the runtime controller. Launching an isolate with a cloned runtime controller will use the ...
GAsyncResult * result
virtual bool NotifyIdle(int64_t deadline)
Notify the Dart VM that no frame workloads are expected on the UI task runner till the specified dead...
bool SetUserSettingsData(const std::string &data)
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.
virtual void OnRootIsolateCreated()=0
#define FML_LOG(severity)
Definition: logging.h:65
RuntimeController(RuntimeDelegate &p_client, DartVM *vm, fml::RefPtr< const DartSnapshot > p_isolate_snapshot, const std::function< void(int64_t)> &idle_notification_callback, const PlatformData &platform_data, const fml::closure &isolate_create_callback, const fml::closure &isolate_shutdown_callback, std::shared_ptr< const fml::Mapping > p_persistent_isolate_data, const UIDartState::Context &context)
Creates a new instance of a runtime controller. This is usually only done by the engine instance asso...
bool SetLifecycleState(const std::string &data)
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.
FlKeyEvent FlKeyResponderAsyncCallback callback
bool BeginFrame(fml::TimePoint frame_time, uint64_t frame_number)
Notifies the running isolate that it should start generating a new frame.
DartErrorHandleType
Definition: dart_error.h:18
uint64_t GetRootIsolateGroup() const
Get an identifier that represents the Dart isolate group the root isolate is in.
virtual void UpdateIsolateDescription(const std::string isolate_name, int64_t isolate_port)=0
bool HasLivePorts()
Returns if the root isolate has any live receive ports.
bool LaunchRootIsolate(const Settings &settings, std::optional< std::string > dart_entrypoint, std::optional< std::string > dart_entrypoint_library, std::unique_ptr< IsolateConfiguration > isolate_configuration)
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.
std::function< void()> closure
Definition: closure.h:14
std::string user_settings_data
Definition: platform_data.h:39
uint8_t value
virtual void RequestDartDeferredLibrary(intptr_t loading_unit_id)=0
std::string GetIsolateName()
Gets the debug name of the root isolate. But default, the debug name of the isolate is derived from i...
bool SetLocales(const std::vector< std::string > &locale_data)
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.
virtual bool DispatchPlatformMessage(std::unique_ptr< PlatformMessage > message)
Dispatch the specified platform message to running root isolate.
SemanticsAction action
Dart_Port GetMainPort()
Gets the main port identifier of the root isolate.
The subset of state which is owned by the shell or engine and passed through the RuntimeController in...
Definition: ui_dart_state.h:43
std::optional< uint32_t > GetRootIsolateReturnCode()
Get the return code specified by the root isolate (if one is present).
virtual std::unique_ptr< std::vector< std::string > > ComputePlatformResolvedLocale(const std::vector< std::string > &supported_locale_data)=0
SemanticsNodeUpdates takeNodes()
int32_t accessibility_feature_flags_
Definition: platform_data.h:43
virtual std::string DefaultRouteName()=0
tonic::DartErrorHandleType GetLastError()
Get the last error encountered by the microtask queue.
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
Definition: trace_event.h:94
virtual void ScheduleFrame(bool regenerate_layer_tree=true)=0
static std::weak_ptr< DartIsolate > CreateRunningRootIsolate(const Settings &settings, fml::RefPtr< const DartSnapshot > isolate_snapshot, std::unique_ptr< PlatformConfiguration > platform_configuration, Flags flags, const fml::closure &isolate_create_callback, const fml::closure &isolate_shutdown_callback, std::optional< std::string > dart_entrypoint, std::optional< std::string > dart_entrypoint_library, std::unique_ptr< IsolateConfiguration > isolate_configration, const UIDartState::Context &context, const DartIsolate *spawning_isolate=nullptr)
Creates an instance of a root isolate and returns a weak pointer to the same. The isolate instance ma...
Describes a running instance of the Dart VM. There may only be one running instance of the Dart VM in...
Definition: dart_vm.h:61
bool DispatchKeyDataPacket(const KeyDataPacket &packet, KeyDataResponse callback)
Dispatch the specified pointer data message to the running root isolate.
CustomAccessibilityActionUpdates takeActions()
A Mapping like NonOwnedMapping, but uses Free as its release proc.
Definition: mapping.h:129
A class for holding and distributing platform-level information to and from the Dart code in Flutter&#39;...
bool ReportTimings(std::vector< int64_t > timings)
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.
std::unique_ptr< flutter::LayerTree > takeLayerTree()
Definition: scene.cc:86
virtual void HandlePlatformMessage(std::unique_ptr< PlatformMessage > message)=0
ViewportMetrics viewport_metrics
Definition: platform_data.h:33
std::function< void(bool)> KeyDataResponse
bool SetViewportMetrics(const ViewportMetrics &metrics)
Forward the specified viewport metrics to the running isolate. If the isolate is not running...
std::optional< std::string > GetRootIsolateServiceID() const
Get the service ID of the root isolate if the root isolate is running.
#define FML_DLOG(severity)
Definition: logging.h:85
virtual void Render(std::unique_ptr< flutter::LayerTree > layer_tree)=0
void LoadDartDeferredLibrary(intptr_t loading_unit_id, std::unique_ptr< const fml::Mapping > snapshot_data, std::unique_ptr< const fml::Mapping > snapshot_instructions)
Loads the Dart shared library into the Dart VM. When the Dart library is loaded successfully, the Dart future returned by the originating loadLibrary() call completes.
bool DispatchPointerDataPacket(const PointerDataPacket &packet)
Dispatch the specified pointer data message to the running root isolate.
virtual void LoadDartDeferredLibraryError(intptr_t loading_unit_id, const std::string error_message, bool transient)
Indicates to the dart VM that the request to load a deferred library with the specified loading unit ...
DEF_SWITCHES_START snapshot asset Path to the directory containing the four files specified by VmSnapshotInstructions and IsolateSnapshotInstructions vm snapshot The VM instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present isolate snapshot The isolate instructions snapshot that will be memory mapped as read and executable SnapshotAssetPath must be present icu symbol Prefix for the symbols representing ICU data linked into the Flutter library dart flags
Definition: switches.h:66
void RequestDartDeferredLibrary(intptr_t loading_unit_id) override
Invoked when the Dart VM requests that a deferred library be loaded. Notifies the engine that the def...
virtual FontCollection & GetFontCollection()=0
std::string lifecycle_state
Definition: platform_data.h:40