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 | |
17 | namespace flutter { |
18 | |
19 | RuntimeController::RuntimeController(RuntimeDelegate& client, |
20 | TaskRunners p_task_runners) |
21 | : client_(client), vm_(nullptr), task_runners_(p_task_runners) {} |
22 | |
23 | RuntimeController::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 | |
97 | RuntimeController::~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 | |
110 | bool 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 | |
118 | std::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 | |
138 | bool 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 | |
148 | bool 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 | |
159 | bool 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 | |
171 | bool 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 | |
183 | bool 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 | |
195 | bool 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 | |
207 | bool 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 | |
218 | bool 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 | |
227 | bool 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 | |
236 | bool 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 | |
254 | bool 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 | |
266 | bool 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 | |
278 | bool 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 | |
292 | PlatformConfiguration* |
293 | RuntimeController::GetPlatformConfigurationIfAvailable() { |
294 | std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock(); |
295 | return root_isolate ? root_isolate->platform_configuration() : nullptr; |
296 | } |
297 | |
298 | // |PlatformConfigurationClient| |
299 | std::string RuntimeController::DefaultRouteName() { |
300 | return client_.DefaultRouteName(); |
301 | } |
302 | |
303 | // |PlatformConfigurationClient| |
304 | void RuntimeController::ScheduleFrame() { |
305 | client_.ScheduleFrame(); |
306 | } |
307 | |
308 | // |PlatformConfigurationClient| |
309 | void RuntimeController::Render(Scene* scene) { |
310 | client_.Render(scene->takeLayerTree()); |
311 | } |
312 | |
313 | // |PlatformConfigurationClient| |
314 | void RuntimeController::UpdateSemantics(SemanticsUpdate* update) { |
315 | if (platform_data_.semantics_enabled) { |
316 | client_.UpdateSemantics(update->takeNodes(), update->takeActions()); |
317 | } |
318 | } |
319 | |
320 | // |PlatformConfigurationClient| |
321 | void RuntimeController::HandlePlatformMessage( |
322 | fml::RefPtr<PlatformMessage> message) { |
323 | client_.HandlePlatformMessage(std::move(message)); |
324 | } |
325 | |
326 | // |PlatformConfigurationClient| |
327 | FontCollection& RuntimeController::GetFontCollection() { |
328 | return client_.GetFontCollection(); |
329 | } |
330 | |
331 | // |PlatformConfigurationClient| |
332 | void RuntimeController::UpdateIsolateDescription(const std::string isolate_name, |
333 | int64_t isolate_port) { |
334 | client_.UpdateIsolateDescription(isolate_name, isolate_port); |
335 | } |
336 | |
337 | // |PlatformConfigurationClient| |
338 | void RuntimeController::SetNeedsReportTimings(bool value) { |
339 | client_.SetNeedsReportTimings(value); |
340 | } |
341 | |
342 | // |PlatformConfigurationClient| |
343 | std::shared_ptr<const fml::Mapping> |
344 | RuntimeController::GetPersistentIsolateData() { |
345 | return persistent_isolate_data_; |
346 | } |
347 | |
348 | // |PlatformConfigurationClient| |
349 | std::unique_ptr<std::vector<std::string>> |
350 | RuntimeController::ComputePlatformResolvedLocale( |
351 | const std::vector<std::string>& supported_locale_data) { |
352 | return client_.ComputePlatformResolvedLocale(supported_locale_data); |
353 | } |
354 | |
355 | Dart_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 | |
360 | std::string RuntimeController::GetIsolateName() { |
361 | std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock(); |
362 | return root_isolate ? root_isolate->debug_name() : "" ; |
363 | } |
364 | |
365 | bool 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 | |
374 | tonic::DartErrorHandleType RuntimeController::GetLastError() { |
375 | std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock(); |
376 | return root_isolate ? root_isolate->GetLastError() : tonic::kNoError; |
377 | } |
378 | |
379 | std::weak_ptr<DartIsolate> RuntimeController::GetRootIsolate() { |
380 | return root_isolate_; |
381 | } |
382 | |
383 | std::pair<bool, uint32_t> RuntimeController::GetRootIsolateReturnCode() { |
384 | return root_isolate_return_code_; |
385 | } |
386 | |
387 | RuntimeController::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 | |
396 | RuntimeController::Locale::~Locale() = default; |
397 | |
398 | } // namespace flutter |
399 | |