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 p_task_runners)
22  : client_(client), vm_(nullptr), task_runners_(p_task_runners) {}
23 
25  RuntimeDelegate& p_client,
26  DartVM* p_vm,
27  fml::RefPtr<const DartSnapshot> p_isolate_snapshot,
28  TaskRunners p_task_runners,
29  fml::WeakPtr<SnapshotDelegate> p_snapshot_delegate,
30  fml::WeakPtr<HintFreedDelegate> p_hint_freed_delegate,
31  fml::WeakPtr<IOManager> p_io_manager,
32  fml::RefPtr<SkiaUnrefQueue> p_unref_queue,
33  fml::WeakPtr<ImageDecoder> p_image_decoder,
34  std::string p_advisory_script_uri,
35  std::string p_advisory_script_entrypoint,
36  const std::function<void(int64_t)>& idle_notification_callback,
37  const PlatformData& p_platform_data,
38  const fml::closure& p_isolate_create_callback,
39  const fml::closure& p_isolate_shutdown_callback,
40  std::shared_ptr<const fml::Mapping> p_persistent_isolate_data)
41  : client_(p_client),
42  vm_(p_vm),
43  isolate_snapshot_(std::move(p_isolate_snapshot)),
44  task_runners_(p_task_runners),
45  snapshot_delegate_(p_snapshot_delegate),
46  hint_freed_delegate_(p_hint_freed_delegate),
47  io_manager_(p_io_manager),
48  unref_queue_(p_unref_queue),
49  image_decoder_(p_image_decoder),
50  advisory_script_uri_(p_advisory_script_uri),
51  advisory_script_entrypoint_(p_advisory_script_entrypoint),
52  idle_notification_callback_(idle_notification_callback),
53  platform_data_(std::move(p_platform_data)),
54  isolate_create_callback_(p_isolate_create_callback),
55  isolate_shutdown_callback_(p_isolate_shutdown_callback),
56  persistent_isolate_data_(std::move(p_persistent_isolate_data)) {}
57 
59  FML_DCHECK(Dart_CurrentIsolate() == nullptr);
60  std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
61  if (root_isolate) {
62  root_isolate->SetReturnCodeCallback(nullptr);
63  auto result = root_isolate->Shutdown();
64  if (!result) {
65  FML_DLOG(ERROR) << "Could not shutdown the root isolate.";
66  }
67  root_isolate_ = {};
68  }
69 }
70 
72  std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock();
73  if (root_isolate) {
74  return root_isolate->GetPhase() == DartIsolate::Phase::Running;
75  }
76  return false;
77 }
78 
79 std::unique_ptr<RuntimeController> RuntimeController::Clone() const {
80  return std::unique_ptr<RuntimeController>(new RuntimeController(
81  client_, //
82  vm_, //
83  isolate_snapshot_, //
84  task_runners_, //
85  snapshot_delegate_, //
86  hint_freed_delegate_, //
87  io_manager_, //
88  unref_queue_, //
89  image_decoder_, //
90  advisory_script_uri_, //
91  advisory_script_entrypoint_, //
92  idle_notification_callback_, //
93  platform_data_, //
94  isolate_create_callback_, //
95  isolate_shutdown_callback_, //
96  persistent_isolate_data_ //
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->window()->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  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
182  platform_configuration->BeginFrame(frame_time);
183  return true;
184  }
185 
186  return false;
187 }
188 
189 bool RuntimeController::ReportTimings(std::vector<int64_t> timings) {
190  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
191  platform_configuration->ReportTimings(std::move(timings));
192  return true;
193  }
194 
195  return false;
196 }
197 
198 bool RuntimeController::NotifyIdle(int64_t deadline, size_t freed_hint) {
199  std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock();
200  if (!root_isolate) {
201  return false;
202  }
203 
204  tonic::DartState::Scope scope(root_isolate);
205 
206  // Dart will use the freed hint at the next idle notification. Make sure to
207  // Update it with our latest value before calling NotifyIdle.
208  Dart_HintFreed(freed_hint);
209  Dart_NotifyIdle(deadline);
210 
211  // Idle notifications being in isolate scope are part of the contract.
212  if (idle_notification_callback_) {
213  TRACE_EVENT0("flutter", "EmbedderIdleNotification");
214  idle_notification_callback_(deadline);
215  }
216  return true;
217 }
218 
221  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
222  TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage",
223  "mode", "basic");
224  platform_configuration->DispatchPlatformMessage(std::move(message));
225  return true;
226  }
227 
228  return false;
229 }
230 
232  const PointerDataPacket& packet) {
233  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
234  TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket",
235  "mode", "basic");
236  platform_configuration->window()->DispatchPointerDataPacket(packet);
237  return true;
238  }
239 
240  return false;
241 }
242 
245  std::vector<uint8_t> args) {
246  TRACE_EVENT1("flutter", "RuntimeController::DispatchSemanticsAction", "mode",
247  "basic");
248  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
249  platform_configuration->DispatchSemanticsAction(id, action,
250  std::move(args));
251  return true;
252  }
253 
254  return false;
255 }
256 
258 RuntimeController::GetPlatformConfigurationIfAvailable() {
259  std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock();
260  return root_isolate ? root_isolate->platform_configuration() : nullptr;
261 }
262 
263 // |PlatformConfigurationClient|
264 std::string RuntimeController::DefaultRouteName() {
265  return client_.DefaultRouteName();
266 }
267 
268 // |PlatformConfigurationClient|
269 void RuntimeController::ScheduleFrame() {
270  client_.ScheduleFrame();
271 }
272 
273 // |PlatformConfigurationClient|
274 void RuntimeController::Render(Scene* scene) {
275  client_.Render(scene->takeLayerTree());
276 }
277 
278 // |PlatformConfigurationClient|
279 void RuntimeController::UpdateSemantics(SemanticsUpdate* update) {
280  if (platform_data_.semantics_enabled) {
281  client_.UpdateSemantics(update->takeNodes(), update->takeActions());
282  }
283 }
284 
285 // |PlatformConfigurationClient|
286 void RuntimeController::HandlePlatformMessage(
288  client_.HandlePlatformMessage(std::move(message));
289 }
290 
291 // |PlatformConfigurationClient|
292 FontCollection& RuntimeController::GetFontCollection() {
293  return client_.GetFontCollection();
294 }
295 
296 // |PlatformConfigurationClient|
297 void RuntimeController::UpdateIsolateDescription(const std::string isolate_name,
298  int64_t isolate_port) {
299  client_.UpdateIsolateDescription(isolate_name, isolate_port);
300 }
301 
302 // |PlatformConfigurationClient|
303 void RuntimeController::SetNeedsReportTimings(bool value) {
304  client_.SetNeedsReportTimings(value);
305 }
306 
307 // |PlatformConfigurationClient|
308 std::shared_ptr<const fml::Mapping>
309 RuntimeController::GetPersistentIsolateData() {
310  return persistent_isolate_data_;
311 }
312 
313 // |PlatformConfigurationClient|
314 std::unique_ptr<std::vector<std::string>>
315 RuntimeController::ComputePlatformResolvedLocale(
316  const std::vector<std::string>& supported_locale_data) {
317  return client_.ComputePlatformResolvedLocale(supported_locale_data);
318 }
319 
321  std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock();
322  return root_isolate ? root_isolate->main_port() : ILLEGAL_PORT;
323 }
324 
326  std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock();
327  return root_isolate ? root_isolate->debug_name() : "";
328 }
329 
331  std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock();
332  if (!root_isolate) {
333  return false;
334  }
335  tonic::DartState::Scope scope(root_isolate);
336  return Dart_HasLivePorts();
337 }
338 
340  std::shared_ptr<DartIsolate> root_isolate = GetRootIsolate().lock();
341  return root_isolate ? root_isolate->GetLastError() : tonic::kNoError;
342 }
343 
345  const Settings& settings,
346  std::optional<std::string> dart_entrypoint,
347  std::optional<std::string> dart_entrypoint_library,
348  std::unique_ptr<IsolateConfiguration> isolate_configuration) {
349  if (root_isolate_.lock()) {
350  FML_LOG(ERROR) << "Root isolate was already running.";
351  return false;
352  }
353 
354  auto strong_root_isolate =
356  settings, //
357  isolate_snapshot_, //
358  task_runners_, //
359  std::make_unique<PlatformConfiguration>(this), //
360  snapshot_delegate_, //
361  hint_freed_delegate_, //
362  io_manager_, //
363  unref_queue_, //
364  image_decoder_, //
365  advisory_script_uri_, //
366  advisory_script_entrypoint_, //
367  DartIsolate::Flags{}, //
368  isolate_create_callback_, //
369  isolate_shutdown_callback_, //
370  dart_entrypoint, //
371  dart_entrypoint_library, //
372  std::move(isolate_configuration) //
373  )
374  .lock();
375 
376  if (!strong_root_isolate) {
377  FML_LOG(ERROR) << "Could not create root isolate.";
378  return false;
379  }
380 
381  // The root isolate ivar is weak.
382  root_isolate_ = strong_root_isolate;
383 
384  // Capture by `this` here is safe because the callback is made by the dart
385  // state itself. The isolate (and its Dart state) is owned by this object and
386  // it will be collected before this object.
387  strong_root_isolate->SetReturnCodeCallback(
388  [this](uint32_t code) { root_isolate_return_code_ = code; });
389 
390  if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
391  tonic::DartState::Scope scope(strong_root_isolate);
392  platform_configuration->DidCreateIsolate();
393  if (!FlushRuntimeStateToIsolate()) {
394  FML_DLOG(ERROR) << "Could not setup initial isolate state.";
395  }
396  } else {
397  FML_DCHECK(false) << "RuntimeController created without window binding.";
398  }
399 
400  FML_DCHECK(Dart_CurrentIsolate() == nullptr);
401 
402  client_.OnRootIsolateCreated();
403 
404  return true;
405 }
406 
407 std::optional<std::string> RuntimeController::GetRootIsolateServiceID() const {
408  if (auto isolate = root_isolate_.lock()) {
409  return isolate->GetServiceId();
410  }
411  return std::nullopt;
412 }
413 
414 std::weak_ptr<DartIsolate> RuntimeController::GetRootIsolate() {
415  std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
416  if (root_isolate) {
417  return root_isolate_;
418  }
419 
420  return root_isolate_;
421 }
422 
424  return root_isolate_return_code_;
425 }
426 
427 RuntimeController::Locale::Locale(std::string language_code_,
428  std::string country_code_,
429  std::string script_code_,
430  std::string variant_code_)
431  : language_code(language_code_),
432  country_code(country_code_),
433  script_code(script_code_),
434  variant_code(variant_code_) {}
435 
436 RuntimeController::Locale::~Locale() = default;
437 
438 } // namespace flutter
virtual void SetNeedsReportTimings(bool value)=0
bool BeginFrame(fml::TimePoint frame_time)
Notifies the running isolate that it should start generating a new frame.
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:75
#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
static std::weak_ptr< DartIsolate > CreateRunningRootIsolate(const Settings &settings, fml::RefPtr< const DartSnapshot > isolate_snapshot, TaskRunners task_runners, std::unique_ptr< PlatformConfiguration > platform_configuration, fml::WeakPtr< SnapshotDelegate > snapshot_delegate, fml::WeakPtr< HintFreedDelegate > hint_freed_delegate, fml::WeakPtr< IOManager > io_manager, fml::RefPtr< SkiaUnrefQueue > skia_unref_queue, fml::WeakPtr< ImageDecoder > image_decoder, std::string advisory_script_uri, std::string advisory_script_entrypoint, 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)
Creates an instance of a root isolate and returns a weak pointer to the same. The isolate instance ma...
Definition: dart_isolate.cc:76
std::unique_ptr< RuntimeController > Clone() const
Clone the the runtime controller. Launching an isolate with a cloned runtime controller will use the ...
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
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.
bool DispatchSemanticsAction(int32_t id, SemanticsAction action, std::vector< uint8_t > args)
Dispatch the semantics action to the specified accessibility node.
DartErrorHandleType
Definition: dart_error.h:18
TaskRunners task_runners_
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.
virtual void HandlePlatformMessage(fml::RefPtr< PlatformMessage > message)=0
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
RuntimeController(RuntimeDelegate &client, DartVM *vm, fml::RefPtr< const DartSnapshot > isolate_snapshot, TaskRunners task_runners, fml::WeakPtr< SnapshotDelegate > snapshot_delegate, fml::WeakPtr< HintFreedDelegate > hint_freed_delegate, fml::WeakPtr< IOManager > io_manager, fml::RefPtr< SkiaUnrefQueue > unref_queue, fml::WeakPtr< ImageDecoder > image_decoder, std::string advisory_script_uri, std::string advisory_script_entrypoint, 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 > persistent_isolate_data)
Creates a new instance of a runtime controller. This is usually only done by the engine instance asso...
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.
SemanticsAction action
Dart_Port GetMainPort()
Gets the main port identifier of the root isolate.
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:79
virtual void ScheduleFrame(bool regenerate_layer_tree=true)=0
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
CustomAccessibilityActionUpdates takeActions()
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 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.
std::unique_ptr< flutter::LayerTree > takeLayerTree()
Definition: scene.cc:84
ViewportMetrics viewport_metrics
Definition: platform_data.h:33
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 bool DispatchPlatformMessage(fml::RefPtr< PlatformMessage > message)
Dispatch the specified platform message to running root isolate.
virtual void Render(std::unique_ptr< flutter::LayerTree > layer_tree)=0
bool NotifyIdle(int64_t deadline, size_t freed_hint)
Notify the Dart VM that no frame workloads are expected on the UI task runner till the specified dead...
bool DispatchPointerDataPacket(const PointerDataPacket &packet)
Dispatch the specified pointer data message to the running root isolate.
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
virtual FontCollection & GetFontCollection()=0
std::string lifecycle_state
Definition: platform_data.h:40