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 <utility>
8
9#include "flutter/fml/message_loop.h"
10#include "flutter/fml/trace_event.h"
11#include "flutter/lib/ui/compositing/scene.h"
12#include "flutter/lib/ui/ui_dart_state.h"
13#include "flutter/lib/ui/window/platform_configuration.h"
14#include "flutter/lib/ui/window/viewport_metrics.h"
15#include "flutter/lib/ui/window/window.h"
16#include "flutter/runtime/dart_isolate_group_data.h"
17#include "flutter/runtime/isolate_configuration.h"
18#include "flutter/runtime/runtime_delegate.h"
19#include "third_party/tonic/dart_message_handler.h"
20
21namespace flutter {
22
23constexpr uint64_t kFlutterImplicitViewId = 0ll;
24
25RuntimeController::RuntimeController(RuntimeDelegate& p_client,
26 const TaskRunners& task_runners)
27 : client_(p_client), vm_(nullptr), context_(task_runners) {}
28
29RuntimeController::RuntimeController(
30 RuntimeDelegate& p_client,
31 DartVM* p_vm,
32 fml::RefPtr<const DartSnapshot> p_isolate_snapshot,
33 const std::function<void(int64_t)>& p_idle_notification_callback,
34 const PlatformData& p_platform_data,
35 const fml::closure& p_isolate_create_callback,
36 const fml::closure& p_isolate_shutdown_callback,
37 std::shared_ptr<const fml::Mapping> p_persistent_isolate_data,
38 const UIDartState::Context& p_context)
39 : client_(p_client),
40 vm_(p_vm),
41 isolate_snapshot_(std::move(p_isolate_snapshot)),
42 idle_notification_callback_(p_idle_notification_callback),
43 platform_data_(p_platform_data),
44 isolate_create_callback_(p_isolate_create_callback),
45 isolate_shutdown_callback_(p_isolate_shutdown_callback),
46 persistent_isolate_data_(std::move(p_persistent_isolate_data)),
47 context_(p_context) {}
48
49std::unique_ptr<RuntimeController> RuntimeController::Spawn(
50 RuntimeDelegate& p_client,
51 std::string advisory_script_uri,
52 std::string advisory_script_entrypoint,
53 const std::function<void(int64_t)>& p_idle_notification_callback,
54 const fml::closure& p_isolate_create_callback,
55 const fml::closure& p_isolate_shutdown_callback,
56 const std::shared_ptr<const fml::Mapping>& p_persistent_isolate_data,
57 fml::WeakPtr<IOManager> io_manager,
58 fml::WeakPtr<ImageDecoder> image_decoder,
59 fml::WeakPtr<ImageGeneratorRegistry> image_generator_registry,
60 fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate) const {
61 UIDartState::Context spawned_context{
62 context_.task_runners, std::move(snapshot_delegate),
63 std::move(io_manager), context_.unref_queue,
64 std::move(image_decoder), std::move(image_generator_registry),
65 std::move(advisory_script_uri), std::move(advisory_script_entrypoint),
66 context_.volatile_path_tracker, context_.concurrent_task_runner,
67 context_.enable_impeller};
68 auto result =
69 std::make_unique<RuntimeController>(args&: p_client, //
70 args: vm_, //
71 args: isolate_snapshot_, //
72 args: p_idle_notification_callback, //
73 args: platform_data_, //
74 args: p_isolate_create_callback, //
75 args: p_isolate_shutdown_callback, //
76 args: p_persistent_isolate_data, //
77 args&: spawned_context); //
78 result->spawning_isolate_ = root_isolate_;
79 result->platform_data_.viewport_metrics = ViewportMetrics();
80 return result;
81}
82
83RuntimeController::~RuntimeController() {
84 FML_DCHECK(Dart_CurrentIsolate() == nullptr);
85 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
86 if (root_isolate) {
87 root_isolate->SetReturnCodeCallback(nullptr);
88 auto result = root_isolate->Shutdown();
89 if (!result) {
90 FML_DLOG(ERROR) << "Could not shutdown the root isolate.";
91 }
92 root_isolate_ = {};
93 }
94}
95
96bool RuntimeController::IsRootIsolateRunning() {
97 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
98 if (root_isolate) {
99 return root_isolate->GetPhase() == DartIsolate::Phase::Running;
100 }
101 return false;
102}
103
104std::unique_ptr<RuntimeController> RuntimeController::Clone() const {
105 return std::make_unique<RuntimeController>(args&: client_, //
106 args: vm_, //
107 args: isolate_snapshot_, //
108 args: idle_notification_callback_, //
109 args: platform_data_, //
110 args: isolate_create_callback_, //
111 args: isolate_shutdown_callback_, //
112 args: persistent_isolate_data_, //
113 args: context_ //
114 );
115}
116
117bool RuntimeController::FlushRuntimeStateToIsolate() {
118 // TODO(dkwingsmt): Needs a view ID here (or platform_data should probably
119 // have multiple view metrics).
120 return SetViewportMetrics(view_id: kFlutterImplicitViewId,
121 metrics: platform_data_.viewport_metrics) &&
122 SetLocales(platform_data_.locale_data) &&
123 SetSemanticsEnabled(platform_data_.semantics_enabled) &&
124 SetAccessibilityFeatures(
125 platform_data_.accessibility_feature_flags_) &&
126 SetUserSettingsData(platform_data_.user_settings_data) &&
127 SetInitialLifecycleState(platform_data_.lifecycle_state) &&
128 SetDisplays(platform_data_.displays);
129}
130
131bool RuntimeController::SetViewportMetrics(int64_t view_id,
132 const ViewportMetrics& metrics) {
133 TRACE_EVENT0("flutter", "SetViewportMetrics");
134 platform_data_.viewport_metrics = metrics;
135
136 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
137 Window* window = platform_configuration->get_window(window_id: view_id);
138 if (window) {
139 window->UpdateWindowMetrics(metrics);
140 return true;
141 } else {
142 FML_LOG(WARNING) << "View ID " << view_id << " does not exist.";
143 }
144 }
145
146 return false;
147}
148
149bool RuntimeController::SetLocales(
150 const std::vector<std::string>& locale_data) {
151 platform_data_.locale_data = locale_data;
152
153 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
154 platform_configuration->UpdateLocales(locales: locale_data);
155 return true;
156 }
157
158 return false;
159}
160
161bool RuntimeController::SetUserSettingsData(const std::string& data) {
162 platform_data_.user_settings_data = data;
163
164 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
165 platform_configuration->UpdateUserSettingsData(
166 data: platform_data_.user_settings_data);
167 return true;
168 }
169
170 return false;
171}
172
173bool RuntimeController::SetInitialLifecycleState(const std::string& data) {
174 platform_data_.lifecycle_state = data;
175
176 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
177 platform_configuration->UpdateInitialLifecycleState(
178 data: platform_data_.lifecycle_state);
179 return true;
180 }
181
182 return false;
183}
184
185bool RuntimeController::SetSemanticsEnabled(bool enabled) {
186 platform_data_.semantics_enabled = enabled;
187
188 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
189 platform_configuration->UpdateSemanticsEnabled(
190 enabled: platform_data_.semantics_enabled);
191 return true;
192 }
193
194 return false;
195}
196
197bool RuntimeController::SetAccessibilityFeatures(int32_t flags) {
198 platform_data_.accessibility_feature_flags_ = flags;
199 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
200 platform_configuration->UpdateAccessibilityFeatures(
201 flags: platform_data_.accessibility_feature_flags_);
202 return true;
203 }
204
205 return false;
206}
207
208bool RuntimeController::BeginFrame(fml::TimePoint frame_time,
209 uint64_t frame_number) {
210 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
211 platform_configuration->BeginFrame(frame_time, frame_number);
212 return true;
213 }
214
215 return false;
216}
217
218bool RuntimeController::ReportTimings(std::vector<int64_t> timings) {
219 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
220 platform_configuration->ReportTimings(timings: std::move(timings));
221 return true;
222 }
223
224 return false;
225}
226
227bool RuntimeController::NotifyIdle(fml::TimeDelta deadline) {
228 if (deadline - fml::TimeDelta::FromMicroseconds(micros: Dart_TimelineGetMicros()) <
229 fml::TimeDelta::FromMilliseconds(millis: 1)) {
230 // There's less than 1ms left before the deadline. Upstream callers do not
231 // check to see if the deadline is in the past, and work after this point
232 // will be in vain.
233 return false;
234 }
235
236 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
237 if (!root_isolate) {
238 return false;
239 }
240
241 tonic::DartState::Scope scope(root_isolate);
242
243 Dart_PerformanceMode performance_mode =
244 PlatformConfigurationNativeApi::GetDartPerformanceMode();
245 if (performance_mode == Dart_PerformanceMode::Dart_PerformanceMode_Latency) {
246 return false;
247 }
248
249 Dart_NotifyIdle(deadline: deadline.ToMicroseconds());
250
251 // Idle notifications being in isolate scope are part of the contract.
252 if (idle_notification_callback_) {
253 TRACE_EVENT0("flutter", "EmbedderIdleNotification");
254 idle_notification_callback_(deadline.ToMicroseconds());
255 }
256 return true;
257}
258
259bool RuntimeController::NotifyDestroyed() {
260 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
261 if (!root_isolate) {
262 return false;
263 }
264
265 tonic::DartState::Scope scope(root_isolate);
266
267 Dart_NotifyDestroyed();
268
269 return true;
270}
271
272bool RuntimeController::DispatchPlatformMessage(
273 std::unique_ptr<PlatformMessage> message) {
274 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
275 TRACE_EVENT0("flutter", "RuntimeController::DispatchPlatformMessage");
276 platform_configuration->DispatchPlatformMessage(message: std::move(message));
277 return true;
278 }
279
280 return false;
281}
282
283bool RuntimeController::DispatchPointerDataPacket(
284 const PointerDataPacket& packet) {
285 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
286 TRACE_EVENT0("flutter", "RuntimeController::DispatchPointerDataPacket");
287 platform_configuration->DispatchPointerDataPacket(packet);
288 return true;
289 }
290
291 return false;
292}
293
294bool RuntimeController::DispatchSemanticsAction(int32_t node_id,
295 SemanticsAction action,
296 fml::MallocMapping args) {
297 TRACE_EVENT1("flutter", "RuntimeController::DispatchSemanticsAction", "mode",
298 "basic");
299 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
300 platform_configuration->DispatchSemanticsAction(node_id, action,
301 args: std::move(args));
302 return true;
303 }
304
305 return false;
306}
307
308PlatformConfiguration*
309RuntimeController::GetPlatformConfigurationIfAvailable() {
310 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
311 return root_isolate ? root_isolate->platform_configuration() : nullptr;
312}
313
314// |PlatformConfigurationClient|
315bool RuntimeController::ImplicitViewEnabled() {
316 return client_.ImplicitViewEnabled();
317}
318
319// |PlatformConfigurationClient|
320std::string RuntimeController::DefaultRouteName() {
321 return client_.DefaultRouteName();
322}
323
324// |PlatformConfigurationClient|
325void RuntimeController::ScheduleFrame() {
326 client_.ScheduleFrame();
327}
328
329// |PlatformConfigurationClient|
330void RuntimeController::Render(Scene* scene) {
331 // TODO(dkwingsmt): Currently only supports a single window.
332 int64_t view_id = kFlutterImplicitViewId;
333 auto window =
334 UIDartState::Current()->platform_configuration()->get_window(window_id: view_id);
335 if (window == nullptr) {
336 return;
337 }
338 const auto& viewport_metrics = window->viewport_metrics();
339 client_.Render(layer_tree: scene->takeLayerTree(width: viewport_metrics.physical_width,
340 height: viewport_metrics.physical_height),
341 device_pixel_ratio: viewport_metrics.device_pixel_ratio);
342}
343
344// |PlatformConfigurationClient|
345void RuntimeController::UpdateSemantics(SemanticsUpdate* update) {
346 if (platform_data_.semantics_enabled) {
347 client_.UpdateSemantics(update: update->takeNodes(), actions: update->takeActions());
348 }
349}
350
351// |PlatformConfigurationClient|
352void RuntimeController::HandlePlatformMessage(
353 std::unique_ptr<PlatformMessage> message) {
354 client_.HandlePlatformMessage(message: std::move(message));
355}
356
357// |PlatformConfigurationClient|
358FontCollection& RuntimeController::GetFontCollection() {
359 return client_.GetFontCollection();
360}
361
362// |PlatfromConfigurationClient|
363std::shared_ptr<AssetManager> RuntimeController::GetAssetManager() {
364 return client_.GetAssetManager();
365}
366
367// |PlatformConfigurationClient|
368void RuntimeController::UpdateIsolateDescription(const std::string isolate_name,
369 int64_t isolate_port) {
370 client_.UpdateIsolateDescription(isolate_name, isolate_port);
371}
372
373// |PlatformConfigurationClient|
374void RuntimeController::SetNeedsReportTimings(bool value) {
375 client_.SetNeedsReportTimings(value);
376}
377
378// |PlatformConfigurationClient|
379std::shared_ptr<const fml::Mapping>
380RuntimeController::GetPersistentIsolateData() {
381 return persistent_isolate_data_;
382}
383
384// |PlatformConfigurationClient|
385std::unique_ptr<std::vector<std::string>>
386RuntimeController::ComputePlatformResolvedLocale(
387 const std::vector<std::string>& supported_locale_data) {
388 return client_.ComputePlatformResolvedLocale(supported_locale_data);
389}
390
391Dart_Port RuntimeController::GetMainPort() {
392 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
393 return root_isolate ? root_isolate->main_port() : ILLEGAL_PORT;
394}
395
396std::string RuntimeController::GetIsolateName() {
397 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
398 return root_isolate ? root_isolate->debug_name() : "";
399}
400
401bool RuntimeController::HasLivePorts() {
402 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
403 if (!root_isolate) {
404 return false;
405 }
406 tonic::DartState::Scope scope(root_isolate);
407 return Dart_HasLivePorts();
408}
409
410tonic::DartErrorHandleType RuntimeController::GetLastError() {
411 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
412 return root_isolate ? root_isolate->GetLastError() : tonic::kNoError;
413}
414
415bool RuntimeController::LaunchRootIsolate(
416 const Settings& settings,
417 const fml::closure& root_isolate_create_callback,
418 std::optional<std::string> dart_entrypoint,
419 std::optional<std::string> dart_entrypoint_library,
420 const std::vector<std::string>& dart_entrypoint_args,
421 std::unique_ptr<IsolateConfiguration> isolate_configuration) {
422 if (root_isolate_.lock()) {
423 FML_LOG(ERROR) << "Root isolate was already running.";
424 return false;
425 }
426
427 auto strong_root_isolate =
428 DartIsolate::CreateRunningRootIsolate(
429 settings, //
430 isolate_snapshot: isolate_snapshot_, //
431 platform_configuration: std::make_unique<PlatformConfiguration>(args: this), //
432 flags: DartIsolate::Flags{}, //
433 root_isolate_create_callback, //
434 isolate_create_callback: isolate_create_callback_, //
435 isolate_shutdown_callback: isolate_shutdown_callback_, //
436 dart_entrypoint: std::move(dart_entrypoint), //
437 dart_entrypoint_library: std::move(dart_entrypoint_library), //
438 dart_entrypoint_args, //
439 isolate_configuration: std::move(isolate_configuration), //
440 context: context_, //
441 spawning_isolate: spawning_isolate_.lock().get()) //
442 .lock();
443
444 if (!strong_root_isolate) {
445 FML_LOG(ERROR) << "Could not create root isolate.";
446 return false;
447 }
448
449 // Enable platform channels for background isolates.
450 strong_root_isolate->GetIsolateGroupData().SetPlatformMessageHandler(
451 root_isolate_token: strong_root_isolate->GetRootIsolateToken(),
452 handler: client_.GetPlatformMessageHandler());
453
454 // The root isolate ivar is weak.
455 root_isolate_ = strong_root_isolate;
456
457 // Capture by `this` here is safe because the callback is made by the dart
458 // state itself. The isolate (and its Dart state) is owned by this object and
459 // it will be collected before this object.
460 strong_root_isolate->SetReturnCodeCallback(
461 [this](uint32_t code) { root_isolate_return_code_ = code; });
462
463 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
464 tonic::DartState::Scope scope(strong_root_isolate);
465 platform_configuration->DidCreateIsolate();
466 if (!FlushRuntimeStateToIsolate()) {
467 FML_DLOG(ERROR) << "Could not set up initial isolate state.";
468 }
469 } else {
470 FML_DCHECK(false) << "RuntimeController created without window binding.";
471 }
472
473 FML_DCHECK(Dart_CurrentIsolate() == nullptr);
474
475 client_.OnRootIsolateCreated();
476
477 return true;
478}
479
480std::optional<std::string> RuntimeController::GetRootIsolateServiceID() const {
481 if (auto isolate = root_isolate_.lock()) {
482 return isolate->GetServiceId();
483 }
484 return std::nullopt;
485}
486
487std::optional<uint32_t> RuntimeController::GetRootIsolateReturnCode() {
488 return root_isolate_return_code_;
489}
490
491uint64_t RuntimeController::GetRootIsolateGroup() const {
492 auto isolate = root_isolate_.lock();
493 if (isolate) {
494 auto isolate_scope = tonic::DartIsolateScope(isolate->isolate());
495 Dart_IsolateGroup isolate_group = Dart_CurrentIsolateGroup();
496 return reinterpret_cast<uint64_t>(isolate_group);
497 } else {
498 return 0;
499 }
500}
501
502void RuntimeController::LoadDartDeferredLibrary(
503 intptr_t loading_unit_id,
504 std::unique_ptr<const fml::Mapping> snapshot_data,
505 std::unique_ptr<const fml::Mapping> snapshot_instructions) {
506 root_isolate_.lock()->LoadLoadingUnit(loading_unit_id,
507 snapshot_data: std::move(snapshot_data),
508 snapshot_instructions: std::move(snapshot_instructions));
509}
510
511void RuntimeController::LoadDartDeferredLibraryError(
512 intptr_t loading_unit_id,
513 const std::string
514 error_message, // NOLINT(performance-unnecessary-value-param)
515 bool transient) {
516 root_isolate_.lock()->LoadLoadingUnitError(loading_unit_id, error_message,
517 transient);
518}
519
520void RuntimeController::RequestDartDeferredLibrary(intptr_t loading_unit_id) {
521 return client_.RequestDartDeferredLibrary(loading_unit_id);
522}
523
524bool RuntimeController::SetDisplays(const std::vector<DisplayData>& displays) {
525 TRACE_EVENT0("flutter", "SetDisplays");
526 platform_data_.displays = displays;
527
528 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
529 platform_configuration->UpdateDisplays(displays);
530 return true;
531 }
532 return false;
533}
534
535RuntimeController::Locale::Locale(std::string language_code_,
536 std::string country_code_,
537 std::string script_code_,
538 std::string variant_code_)
539 : language_code(std::move(language_code_)),
540 country_code(std::move(country_code_)),
541 script_code(std::move(script_code_)),
542 variant_code(std::move(variant_code_)) {}
543
544RuntimeController::Locale::~Locale() = default;
545
546} // namespace flutter
547

source code of flutter_engine/flutter/runtime/runtime_controller.cc