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/runtime_delegate.h"
15#include "third_party/tonic/dart_message_handler.h"
16
17namespace flutter {
18
19RuntimeController::RuntimeController(RuntimeDelegate& client,
20 TaskRunners p_task_runners)
21 : client_(client), vm_(nullptr), task_runners_(p_task_runners) {}
22
23RuntimeController::RuntimeController(
24 RuntimeDelegate& p_client,
25 DartVM* p_vm,
26 fml::RefPtr<const DartSnapshot> p_isolate_snapshot,
27 TaskRunners p_task_runners,
28 fml::WeakPtr<SnapshotDelegate> p_snapshot_delegate,
29 fml::WeakPtr<IOManager> p_io_manager,
30 fml::RefPtr<SkiaUnrefQueue> p_unref_queue,
31 fml::WeakPtr<ImageDecoder> p_image_decoder,
32 std::string p_advisory_script_uri,
33 std::string p_advisory_script_entrypoint,
34 const std::function<void(int64_t)>& idle_notification_callback,
35 const PlatformData& p_platform_data,
36 const fml::closure& p_isolate_create_callback,
37 const fml::closure& p_isolate_shutdown_callback,
38 std::shared_ptr<const fml::Mapping> p_persistent_isolate_data)
39 : client_(p_client),
40 vm_(p_vm),
41 isolate_snapshot_(std::move(p_isolate_snapshot)),
42 task_runners_(p_task_runners),
43 snapshot_delegate_(p_snapshot_delegate),
44 io_manager_(p_io_manager),
45 unref_queue_(p_unref_queue),
46 image_decoder_(p_image_decoder),
47 advisory_script_uri_(p_advisory_script_uri),
48 advisory_script_entrypoint_(p_advisory_script_entrypoint),
49 idle_notification_callback_(idle_notification_callback),
50 platform_data_(std::move(p_platform_data)),
51 isolate_create_callback_(p_isolate_create_callback),
52 isolate_shutdown_callback_(p_isolate_shutdown_callback),
53 persistent_isolate_data_(std::move(p_persistent_isolate_data)) {
54 // Create the root isolate as soon as the runtime controller is initialized.
55 // It will be run at a later point when the engine provides a run
56 // configuration and then runs the isolate.
57 auto strong_root_isolate =
58 DartIsolate::CreateRootIsolate(
59 vm_->GetVMData()->GetSettings(), //
60 isolate_snapshot_, //
61 task_runners_, //
62 std::make_unique<PlatformConfiguration>(this), //
63 snapshot_delegate_, //
64 io_manager_, //
65 unref_queue_, //
66 image_decoder_, //
67 p_advisory_script_uri, //
68 p_advisory_script_entrypoint, //
69 nullptr, //
70 isolate_create_callback_, //
71 isolate_shutdown_callback_ //
72 )
73 .lock();
74
75 FML_CHECK(strong_root_isolate) << "Could not create root isolate.";
76
77 // The root isolate ivar is weak.
78 root_isolate_ = strong_root_isolate;
79
80 strong_root_isolate->SetReturnCodeCallback([this](uint32_t code) {
81 root_isolate_return_code_ = {true, code};
82 });
83
84 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
85 tonic::DartState::Scope scope(strong_root_isolate);
86 platform_configuration->DidCreateIsolate();
87 if (!FlushRuntimeStateToIsolate()) {
88 FML_DLOG(ERROR) << "Could not setup initial isolate state.";
89 }
90 } else {
91 FML_DCHECK(false) << "RuntimeController created without window binding.";
92 }
93
94 FML_DCHECK(Dart_CurrentIsolate() == nullptr);
95}
96
97RuntimeController::~RuntimeController() {
98 FML_DCHECK(Dart_CurrentIsolate() == nullptr);
99 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
100 if (root_isolate) {
101 root_isolate->SetReturnCodeCallback(nullptr);
102 auto result = root_isolate->Shutdown();
103 if (!result) {
104 FML_DLOG(ERROR) << "Could not shutdown the root isolate.";
105 }
106 root_isolate_ = {};
107 }
108}
109
110bool RuntimeController::IsRootIsolateRunning() const {
111 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
112 if (root_isolate) {
113 return root_isolate->GetPhase() == DartIsolate::Phase::Running;
114 }
115 return false;
116}
117
118std::unique_ptr<RuntimeController> RuntimeController::Clone() const {
119 return std::unique_ptr<RuntimeController>(new RuntimeController(
120 client_, //
121 vm_, //
122 isolate_snapshot_, //
123 task_runners_, //
124 snapshot_delegate_, //
125 io_manager_, //
126 unref_queue_, //
127 image_decoder_, //
128 advisory_script_uri_, //
129 advisory_script_entrypoint_, //
130 idle_notification_callback_, //
131 platform_data_, //
132 isolate_create_callback_, //
133 isolate_shutdown_callback_, //
134 persistent_isolate_data_ //
135 ));
136}
137
138bool RuntimeController::FlushRuntimeStateToIsolate() {
139 return SetViewportMetrics(platform_data_.viewport_metrics) &&
140 SetLocales(platform_data_.locale_data) &&
141 SetSemanticsEnabled(platform_data_.semantics_enabled) &&
142 SetAccessibilityFeatures(
143 platform_data_.accessibility_feature_flags_) &&
144 SetUserSettingsData(platform_data_.user_settings_data) &&
145 SetLifecycleState(platform_data_.lifecycle_state);
146}
147
148bool RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) {
149 platform_data_.viewport_metrics = metrics;
150
151 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
152 platform_configuration->window()->UpdateWindowMetrics(metrics);
153 return true;
154 }
155
156 return false;
157}
158
159bool RuntimeController::SetLocales(
160 const std::vector<std::string>& locale_data) {
161 platform_data_.locale_data = locale_data;
162
163 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
164 platform_configuration->UpdateLocales(locale_data);
165 return true;
166 }
167
168 return false;
169}
170
171bool RuntimeController::SetUserSettingsData(const std::string& data) {
172 platform_data_.user_settings_data = data;
173
174 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
175 platform_configuration->UpdateUserSettingsData(
176 platform_data_.user_settings_data);
177 return true;
178 }
179
180 return false;
181}
182
183bool RuntimeController::SetLifecycleState(const std::string& data) {
184 platform_data_.lifecycle_state = data;
185
186 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
187 platform_configuration->UpdateLifecycleState(
188 platform_data_.lifecycle_state);
189 return true;
190 }
191
192 return false;
193}
194
195bool RuntimeController::SetSemanticsEnabled(bool enabled) {
196 platform_data_.semantics_enabled = enabled;
197
198 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
199 platform_configuration->UpdateSemanticsEnabled(
200 platform_data_.semantics_enabled);
201 return true;
202 }
203
204 return false;
205}
206
207bool RuntimeController::SetAccessibilityFeatures(int32_t flags) {
208 platform_data_.accessibility_feature_flags_ = flags;
209 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
210 platform_configuration->UpdateAccessibilityFeatures(
211 platform_data_.accessibility_feature_flags_);
212 return true;
213 }
214
215 return false;
216}
217
218bool RuntimeController::BeginFrame(fml::TimePoint frame_time) {
219 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
220 platform_configuration->BeginFrame(frame_time);
221 return true;
222 }
223
224 return false;
225}
226
227bool RuntimeController::ReportTimings(std::vector<int64_t> timings) {
228 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
229 platform_configuration->ReportTimings(std::move(timings));
230 return true;
231 }
232
233 return false;
234}
235
236bool RuntimeController::NotifyIdle(int64_t deadline) {
237 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
238 if (!root_isolate) {
239 return false;
240 }
241
242 tonic::DartState::Scope scope(root_isolate);
243
244 Dart_NotifyIdle(deadline);
245
246 // Idle notifications being in isolate scope are part of the contract.
247 if (idle_notification_callback_) {
248 TRACE_EVENT0("flutter", "EmbedderIdleNotification");
249 idle_notification_callback_(deadline);
250 }
251 return true;
252}
253
254bool RuntimeController::DispatchPlatformMessage(
255 fml::RefPtr<PlatformMessage> message) {
256 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
257 TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage",
258 "mode", "basic");
259 platform_configuration->DispatchPlatformMessage(std::move(message));
260 return true;
261 }
262
263 return false;
264}
265
266bool RuntimeController::DispatchPointerDataPacket(
267 const PointerDataPacket& packet) {
268 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
269 TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket",
270 "mode", "basic");
271 platform_configuration->window()->DispatchPointerDataPacket(packet);
272 return true;
273 }
274
275 return false;
276}
277
278bool RuntimeController::DispatchSemanticsAction(int32_t id,
279 SemanticsAction action,
280 std::vector<uint8_t> args) {
281 TRACE_EVENT1("flutter", "RuntimeController::DispatchSemanticsAction", "mode",
282 "basic");
283 if (auto* platform_configuration = GetPlatformConfigurationIfAvailable()) {
284 platform_configuration->DispatchSemanticsAction(id, action,
285 std::move(args));
286 return true;
287 }
288
289 return false;
290}
291
292PlatformConfiguration*
293RuntimeController::GetPlatformConfigurationIfAvailable() {
294 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
295 return root_isolate ? root_isolate->platform_configuration() : nullptr;
296}
297
298// |PlatformConfigurationClient|
299std::string RuntimeController::DefaultRouteName() {
300 return client_.DefaultRouteName();
301}
302
303// |PlatformConfigurationClient|
304void RuntimeController::ScheduleFrame() {
305 client_.ScheduleFrame();
306}
307
308// |PlatformConfigurationClient|
309void RuntimeController::Render(Scene* scene) {
310 client_.Render(scene->takeLayerTree());
311}
312
313// |PlatformConfigurationClient|
314void RuntimeController::UpdateSemantics(SemanticsUpdate* update) {
315 if (platform_data_.semantics_enabled) {
316 client_.UpdateSemantics(update->takeNodes(), update->takeActions());
317 }
318}
319
320// |PlatformConfigurationClient|
321void RuntimeController::HandlePlatformMessage(
322 fml::RefPtr<PlatformMessage> message) {
323 client_.HandlePlatformMessage(std::move(message));
324}
325
326// |PlatformConfigurationClient|
327FontCollection& RuntimeController::GetFontCollection() {
328 return client_.GetFontCollection();
329}
330
331// |PlatformConfigurationClient|
332void RuntimeController::UpdateIsolateDescription(const std::string isolate_name,
333 int64_t isolate_port) {
334 client_.UpdateIsolateDescription(isolate_name, isolate_port);
335}
336
337// |PlatformConfigurationClient|
338void RuntimeController::SetNeedsReportTimings(bool value) {
339 client_.SetNeedsReportTimings(value);
340}
341
342// |PlatformConfigurationClient|
343std::shared_ptr<const fml::Mapping>
344RuntimeController::GetPersistentIsolateData() {
345 return persistent_isolate_data_;
346}
347
348// |PlatformConfigurationClient|
349std::unique_ptr<std::vector<std::string>>
350RuntimeController::ComputePlatformResolvedLocale(
351 const std::vector<std::string>& supported_locale_data) {
352 return client_.ComputePlatformResolvedLocale(supported_locale_data);
353}
354
355Dart_Port RuntimeController::GetMainPort() {
356 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
357 return root_isolate ? root_isolate->main_port() : ILLEGAL_PORT;
358}
359
360std::string RuntimeController::GetIsolateName() {
361 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
362 return root_isolate ? root_isolate->debug_name() : "";
363}
364
365bool RuntimeController::HasLivePorts() {
366 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
367 if (!root_isolate) {
368 return false;
369 }
370 tonic::DartState::Scope scope(root_isolate);
371 return Dart_HasLivePorts();
372}
373
374tonic::DartErrorHandleType RuntimeController::GetLastError() {
375 std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
376 return root_isolate ? root_isolate->GetLastError() : tonic::kNoError;
377}
378
379std::weak_ptr<DartIsolate> RuntimeController::GetRootIsolate() {
380 return root_isolate_;
381}
382
383std::pair<bool, uint32_t> RuntimeController::GetRootIsolateReturnCode() {
384 return root_isolate_return_code_;
385}
386
387RuntimeController::Locale::Locale(std::string language_code_,
388 std::string country_code_,
389 std::string script_code_,
390 std::string variant_code_)
391 : language_code(language_code_),
392 country_code(country_code_),
393 script_code(script_code_),
394 variant_code(variant_code_) {}
395
396RuntimeController::Locale::~Locale() = default;
397
398} // namespace flutter
399