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/shell/common/engine.h"
6
7#include <cstring>
8#include <memory>
9#include <string>
10#include <utility>
11#include <vector>
12
13#include "flutter/common/settings.h"
14#include "flutter/fml/make_copyable.h"
15#include "flutter/fml/trace_event.h"
16#include "flutter/lib/snapshot/snapshot.h"
17#include "flutter/lib/ui/text/font_collection.h"
18#include "flutter/shell/common/animator.h"
19#include "flutter/shell/common/platform_view.h"
20#include "flutter/shell/common/shell.h"
21#include "rapidjson/document.h"
22#include "third_party/dart/runtime/include/dart_tools_api.h"
23
24namespace flutter {
25
26static constexpr char kAssetChannel[] = "flutter/assets";
27static constexpr char kLifecycleChannel[] = "flutter/lifecycle";
28static constexpr char kNavigationChannel[] = "flutter/navigation";
29static constexpr char kLocalizationChannel[] = "flutter/localization";
30static constexpr char kSettingsChannel[] = "flutter/settings";
31static constexpr char kIsolateChannel[] = "flutter/isolate";
32
33namespace {
34fml::MallocMapping MakeMapping(const std::string& str) {
35 return fml::MallocMapping::Copy(begin: str.c_str(), length: str.length());
36}
37} // namespace
38
39Engine::Engine(
40 Delegate& delegate,
41 const PointerDataDispatcherMaker& dispatcher_maker,
42 std::shared_ptr<fml::ConcurrentTaskRunner> image_decoder_task_runner,
43 const TaskRunners& task_runners,
44 const Settings& settings,
45 std::unique_ptr<Animator> animator,
46 fml::WeakPtr<IOManager> io_manager,
47 const std::shared_ptr<FontCollection>& font_collection,
48 std::unique_ptr<RuntimeController> runtime_controller,
49 const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch)
50 : delegate_(delegate),
51 settings_(settings),
52 animator_(std::move(animator)),
53 runtime_controller_(std::move(runtime_controller)),
54 font_collection_(font_collection),
55 image_decoder_(ImageDecoder::Make(settings: settings_,
56 runners: task_runners,
57 concurrent_task_runner: std::move(image_decoder_task_runner),
58 io_manager: std::move(io_manager),
59 gpu_disabled_switch)),
60 task_runners_(task_runners),
61 weak_factory_(this) {
62 pointer_data_dispatcher_ = dispatcher_maker(*this);
63}
64
65Engine::Engine(Delegate& delegate,
66 const PointerDataDispatcherMaker& dispatcher_maker,
67 DartVM& vm,
68 fml::RefPtr<const DartSnapshot> isolate_snapshot,
69 const TaskRunners& task_runners,
70 const PlatformData& platform_data,
71 const Settings& settings,
72 std::unique_ptr<Animator> animator,
73 fml::WeakPtr<IOManager> io_manager,
74 fml::RefPtr<SkiaUnrefQueue> unref_queue,
75 fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
76 std::shared_ptr<VolatilePathTracker> volatile_path_tracker,
77 const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch)
78 : Engine(delegate,
79 dispatcher_maker,
80 vm.GetConcurrentWorkerTaskRunner(),
81 task_runners,
82 settings,
83 std::move(animator),
84 io_manager,
85 std::make_shared<FontCollection>(),
86 nullptr,
87 gpu_disabled_switch) {
88 runtime_controller_ = std::make_unique<RuntimeController>(
89 args&: *this, // runtime delegate
90 args: &vm, // VM
91 args: std::move(isolate_snapshot), // isolate snapshot
92 args: settings_.idle_notification_callback, // idle notification callback
93 args: platform_data, // platform data
94 args: settings_.isolate_create_callback, // isolate create callback
95 args: settings_.isolate_shutdown_callback, // isolate shutdown callback
96 args: settings_.persistent_isolate_data, // persistent isolate data
97 args: UIDartState::Context{
98 task_runners_, // task runners
99 std::move(snapshot_delegate), // snapshot delegate
100 std::move(io_manager), // io manager
101 std::move(unref_queue), // Skia unref queue
102 image_decoder_->GetWeakPtr(), // image decoder
103 image_generator_registry_.GetWeakPtr(), // image generator registry
104 settings_.advisory_script_uri, // advisory script uri
105 settings_.advisory_script_entrypoint, // advisory script entrypoint
106 std::move(volatile_path_tracker), // volatile path tracker
107 vm.GetConcurrentWorkerTaskRunner(), // concurrent task runner
108 settings_.enable_impeller, // enable impeller
109 });
110}
111
112std::unique_ptr<Engine> Engine::Spawn(
113 Delegate& delegate,
114 const PointerDataDispatcherMaker& dispatcher_maker,
115 const Settings& settings,
116 std::unique_ptr<Animator> animator,
117 const std::string& initial_route,
118 const fml::WeakPtr<IOManager>& io_manager,
119 fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
120 const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch) const {
121 auto result = std::make_unique<Engine>(
122 /*delegate=*/args&: delegate,
123 /*dispatcher_maker=*/args: dispatcher_maker,
124 /*image_decoder_task_runner=*/
125 args: runtime_controller_->GetDartVM()->GetConcurrentWorkerTaskRunner(),
126 /*task_runners=*/args: task_runners_,
127 /*settings=*/args: settings,
128 /*animator=*/args: std::move(animator),
129 /*io_manager=*/args: io_manager,
130 /*font_collection=*/args: font_collection_,
131 /*runtime_controller=*/args: nullptr,
132 /*gpu_disabled_switch=*/args: gpu_disabled_switch);
133 result->runtime_controller_ = runtime_controller_->Spawn(
134 /*p_client=*/*result,
135 /*advisory_script_uri=*/settings.advisory_script_uri,
136 /*advisory_script_entrypoint=*/settings.advisory_script_entrypoint,
137 /*idle_notification_callback=*/settings.idle_notification_callback,
138 /*isolate_create_callback=*/settings.isolate_create_callback,
139 /*isolate_shutdown_callback=*/settings.isolate_shutdown_callback,
140 /*persistent_isolate_data=*/settings.persistent_isolate_data,
141 /*io_manager=*/io_manager,
142 /*image_decoder=*/result->GetImageDecoderWeakPtr(),
143 /*image_generator_registry=*/result->GetImageGeneratorRegistry(),
144 /*snapshot_delegate=*/std::move(snapshot_delegate));
145 result->initial_route_ = initial_route;
146 return result;
147}
148
149Engine::~Engine() = default;
150
151fml::WeakPtr<Engine> Engine::GetWeakPtr() const {
152 return weak_factory_.GetWeakPtr();
153}
154
155void Engine::SetupDefaultFontManager() {
156 TRACE_EVENT0("flutter", "Engine::SetupDefaultFontManager");
157 font_collection_->SetupDefaultFontManager(settings_.font_initialization_data);
158}
159
160std::shared_ptr<AssetManager> Engine::GetAssetManager() {
161 return asset_manager_;
162}
163
164fml::WeakPtr<ImageDecoder> Engine::GetImageDecoderWeakPtr() {
165 return image_decoder_->GetWeakPtr();
166}
167
168fml::WeakPtr<ImageGeneratorRegistry> Engine::GetImageGeneratorRegistry() {
169 return image_generator_registry_.GetWeakPtr();
170}
171
172bool Engine::UpdateAssetManager(
173 const std::shared_ptr<AssetManager>& new_asset_manager) {
174 if (asset_manager_ == new_asset_manager) {
175 return false;
176 }
177
178 asset_manager_ = new_asset_manager;
179
180 if (!asset_manager_) {
181 return false;
182 }
183
184 // Using libTXT as the text engine.
185 if (settings_.use_asset_fonts) {
186 font_collection_->RegisterFonts(asset_manager: asset_manager_);
187 }
188
189 if (settings_.use_test_fonts) {
190 font_collection_->RegisterTestFonts();
191 }
192
193 return true;
194}
195
196bool Engine::Restart(RunConfiguration configuration) {
197 TRACE_EVENT0("flutter", "Engine::Restart");
198 if (!configuration.IsValid()) {
199 FML_LOG(ERROR) << "Engine run configuration was invalid.";
200 return false;
201 }
202 delegate_.OnPreEngineRestart();
203 runtime_controller_ = runtime_controller_->Clone();
204 UpdateAssetManager(new_asset_manager: nullptr);
205 return Run(configuration: std::move(configuration)) == Engine::RunStatus::Success;
206}
207
208Engine::RunStatus Engine::Run(RunConfiguration configuration) {
209 if (!configuration.IsValid()) {
210 FML_LOG(ERROR) << "Engine run configuration was invalid.";
211 return RunStatus::Failure;
212 }
213
214 last_entry_point_ = configuration.GetEntrypoint();
215 last_entry_point_library_ = configuration.GetEntrypointLibrary();
216#if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG)
217 // This is only used to support restart.
218 last_entry_point_args_ = configuration.GetEntrypointArgs();
219#endif
220
221 UpdateAssetManager(new_asset_manager: configuration.GetAssetManager());
222
223 if (runtime_controller_->IsRootIsolateRunning()) {
224 return RunStatus::FailureAlreadyRunning;
225 }
226
227 // If the embedding prefetched the default font manager, then set up the
228 // font manager later in the engine launch process. This makes it less
229 // likely that the setup will need to wait for the prefetch to complete.
230 auto root_isolate_create_callback = [&]() {
231 if (settings_.prefetched_default_font_manager) {
232 SetupDefaultFontManager();
233 }
234 };
235
236 if (!runtime_controller_->LaunchRootIsolate(
237 settings: settings_, //
238 root_isolate_create_callback, //
239 dart_entrypoint: configuration.GetEntrypoint(), //
240 dart_entrypoint_library: configuration.GetEntrypointLibrary(), //
241 dart_entrypoint_args: configuration.GetEntrypointArgs(), //
242 isolate_configuration: configuration.TakeIsolateConfiguration()) //
243 ) {
244 return RunStatus::Failure;
245 }
246
247 auto service_id = runtime_controller_->GetRootIsolateServiceID();
248 if (service_id.has_value()) {
249 std::unique_ptr<PlatformMessage> service_id_message =
250 std::make_unique<flutter::PlatformMessage>(
251 args: kIsolateChannel, args: MakeMapping(str: service_id.value()), args: nullptr);
252 HandlePlatformMessage(message: std::move(service_id_message));
253 }
254
255 return Engine::RunStatus::Success;
256}
257
258void Engine::BeginFrame(fml::TimePoint frame_time, uint64_t frame_number) {
259 runtime_controller_->BeginFrame(frame_time, frame_number);
260}
261
262void Engine::ReportTimings(std::vector<int64_t> timings) {
263 runtime_controller_->ReportTimings(timings: std::move(timings));
264}
265
266void Engine::NotifyIdle(fml::TimeDelta deadline) {
267 runtime_controller_->NotifyIdle(deadline);
268}
269
270void Engine::NotifyDestroyed() {
271 TRACE_EVENT0("flutter", "Engine::NotifyDestroyed");
272 runtime_controller_->NotifyDestroyed();
273}
274
275std::optional<uint32_t> Engine::GetUIIsolateReturnCode() {
276 return runtime_controller_->GetRootIsolateReturnCode();
277}
278
279Dart_Port Engine::GetUIIsolateMainPort() {
280 return runtime_controller_->GetMainPort();
281}
282
283std::string Engine::GetUIIsolateName() {
284 return runtime_controller_->GetIsolateName();
285}
286
287bool Engine::UIIsolateHasLivePorts() {
288 return runtime_controller_->HasLivePorts();
289}
290
291tonic::DartErrorHandleType Engine::GetUIIsolateLastError() {
292 return runtime_controller_->GetLastError();
293}
294
295void Engine::SetViewportMetrics(int64_t view_id,
296 const ViewportMetrics& metrics) {
297 runtime_controller_->SetViewportMetrics(view_id, metrics);
298 ScheduleFrame();
299}
300
301void Engine::DispatchPlatformMessage(std::unique_ptr<PlatformMessage> message) {
302 std::string channel = message->channel();
303 if (channel == kLifecycleChannel) {
304 if (HandleLifecyclePlatformMessage(message: message.get())) {
305 return;
306 }
307 } else if (channel == kLocalizationChannel) {
308 if (HandleLocalizationPlatformMessage(message: message.get())) {
309 return;
310 }
311 } else if (channel == kSettingsChannel) {
312 HandleSettingsPlatformMessage(message: message.get());
313 return;
314 } else if (!runtime_controller_->IsRootIsolateRunning() &&
315 channel == kNavigationChannel) {
316 // If there's no runtime_, we may still need to set the initial route.
317 HandleNavigationPlatformMessage(message: std::move(message));
318 return;
319 }
320
321 if (runtime_controller_->IsRootIsolateRunning() &&
322 runtime_controller_->DispatchPlatformMessage(message: std::move(message))) {
323 return;
324 }
325
326 FML_DLOG(WARNING) << "Dropping platform message on channel: " << channel;
327}
328
329bool Engine::HandleLifecyclePlatformMessage(PlatformMessage* message) {
330 const auto& data = message->data();
331 std::string state(reinterpret_cast<const char*>(data.GetMapping()),
332 data.GetSize());
333
334 // Always schedule a frame when the app does become active as per API
335 // recommendation
336 // https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622956-applicationdidbecomeactive?language=objc
337 if (state == "AppLifecycleState.resumed" ||
338 state == "AppLifecycleState.inactive") {
339 ScheduleFrame();
340 }
341 runtime_controller_->SetInitialLifecycleState(state);
342 // Always forward these messages to the framework by returning false.
343 return false;
344}
345
346bool Engine::HandleNavigationPlatformMessage(
347 std::unique_ptr<PlatformMessage> message) {
348 const auto& data = message->data();
349
350 rapidjson::Document document;
351 document.Parse(str: reinterpret_cast<const char*>(data.GetMapping()),
352 length: data.GetSize());
353 if (document.HasParseError() || !document.IsObject()) {
354 return false;
355 }
356 auto root = document.GetObject();
357 auto method = root.FindMember(name: "method");
358 if (method->value != "setInitialRoute") {
359 return false;
360 }
361 auto route = root.FindMember(name: "args");
362 initial_route_ = route->value.GetString();
363 return true;
364}
365
366bool Engine::HandleLocalizationPlatformMessage(PlatformMessage* message) {
367 const auto& data = message->data();
368
369 rapidjson::Document document;
370 document.Parse(str: reinterpret_cast<const char*>(data.GetMapping()),
371 length: data.GetSize());
372 if (document.HasParseError() || !document.IsObject()) {
373 return false;
374 }
375 auto root = document.GetObject();
376 auto method = root.FindMember(name: "method");
377 if (method == root.MemberEnd()) {
378 return false;
379 }
380 const size_t strings_per_locale = 4;
381 if (method->value == "setLocale") {
382 // Decode and pass the list of locale data onwards to dart.
383 auto args = root.FindMember(name: "args");
384 if (args == root.MemberEnd() || !args->value.IsArray()) {
385 return false;
386 }
387
388 if (args->value.Size() % strings_per_locale != 0) {
389 return false;
390 }
391 std::vector<std::string> locale_data;
392 for (size_t locale_index = 0; locale_index < args->value.Size();
393 locale_index += strings_per_locale) {
394 if (!args->value[locale_index].IsString() ||
395 !args->value[locale_index + 1].IsString()) {
396 return false;
397 }
398 locale_data.push_back(x: args->value[locale_index].GetString());
399 locale_data.push_back(x: args->value[locale_index + 1].GetString());
400 locale_data.push_back(x: args->value[locale_index + 2].GetString());
401 locale_data.push_back(x: args->value[locale_index + 3].GetString());
402 }
403
404 return runtime_controller_->SetLocales(locale_data);
405 }
406 return false;
407}
408
409void Engine::HandleSettingsPlatformMessage(PlatformMessage* message) {
410 const auto& data = message->data();
411 std::string jsonData(reinterpret_cast<const char*>(data.GetMapping()),
412 data.GetSize());
413 if (runtime_controller_->SetUserSettingsData(jsonData)) {
414 ScheduleFrame();
415 }
416}
417
418void Engine::DispatchPointerDataPacket(
419 std::unique_ptr<PointerDataPacket> packet,
420 uint64_t trace_flow_id) {
421 TRACE_EVENT0_WITH_FLOW_IDS("flutter", "Engine::DispatchPointerDataPacket",
422 /*flow_id_count=*/1,
423 /*flow_ids=*/&trace_flow_id);
424 TRACE_FLOW_STEP("flutter", "PointerEvent", trace_flow_id);
425 pointer_data_dispatcher_->DispatchPacket(packet: std::move(packet), trace_flow_id);
426}
427
428void Engine::DispatchSemanticsAction(int node_id,
429 SemanticsAction action,
430 fml::MallocMapping args) {
431 runtime_controller_->DispatchSemanticsAction(node_id, action,
432 args: std::move(args));
433}
434
435void Engine::SetSemanticsEnabled(bool enabled) {
436 runtime_controller_->SetSemanticsEnabled(enabled);
437}
438
439void Engine::SetAccessibilityFeatures(int32_t flags) {
440 runtime_controller_->SetAccessibilityFeatures(flags);
441}
442
443bool Engine::ImplicitViewEnabled() {
444 // TODO(loicsharma): This value should be provided by the embedder
445 // when it launches the engine. For now, assume the embedder always creates a
446 // view.
447 // See: https://github.com/flutter/flutter/issues/120306
448 return true;
449}
450
451std::string Engine::DefaultRouteName() {
452 if (!initial_route_.empty()) {
453 return initial_route_;
454 }
455 return "/";
456}
457
458void Engine::ScheduleFrame(bool regenerate_layer_tree) {
459 animator_->RequestFrame(regenerate_layer_tree);
460}
461
462void Engine::Render(std::unique_ptr<flutter::LayerTree> layer_tree,
463 float device_pixel_ratio) {
464 if (!layer_tree) {
465 return;
466 }
467
468 // Ensure frame dimensions are sane.
469 if (layer_tree->frame_size().isEmpty() || device_pixel_ratio <= 0.0f) {
470 return;
471 }
472
473 animator_->Render(layer_tree: std::move(layer_tree), device_pixel_ratio);
474}
475
476void Engine::UpdateSemantics(SemanticsNodeUpdates update,
477 CustomAccessibilityActionUpdates actions) {
478 delegate_.OnEngineUpdateSemantics(updates: std::move(update), actions: std::move(actions));
479}
480
481void Engine::HandlePlatformMessage(std::unique_ptr<PlatformMessage> message) {
482 if (message->channel() == kAssetChannel) {
483 HandleAssetPlatformMessage(message: std::move(message));
484 } else {
485 delegate_.OnEngineHandlePlatformMessage(message: std::move(message));
486 }
487}
488
489void Engine::OnRootIsolateCreated() {
490 delegate_.OnRootIsolateCreated();
491}
492
493void Engine::UpdateIsolateDescription(const std::string isolate_name,
494 int64_t isolate_port) {
495 delegate_.UpdateIsolateDescription(isolate_name, isolate_port);
496}
497
498std::unique_ptr<std::vector<std::string>> Engine::ComputePlatformResolvedLocale(
499 const std::vector<std::string>& supported_locale_data) {
500 return delegate_.ComputePlatformResolvedLocale(supported_locale_data);
501}
502
503void Engine::SetNeedsReportTimings(bool needs_reporting) {
504 delegate_.SetNeedsReportTimings(needs_reporting);
505}
506
507FontCollection& Engine::GetFontCollection() {
508 return *font_collection_;
509}
510
511void Engine::DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
512 uint64_t trace_flow_id) {
513 animator_->EnqueueTraceFlowId(trace_flow_id);
514 if (runtime_controller_) {
515 runtime_controller_->DispatchPointerDataPacket(packet: *packet);
516 }
517}
518
519void Engine::ScheduleSecondaryVsyncCallback(uintptr_t id,
520 const fml::closure& callback) {
521 animator_->ScheduleSecondaryVsyncCallback(id, callback);
522}
523
524void Engine::HandleAssetPlatformMessage(
525 std::unique_ptr<PlatformMessage> message) {
526 fml::RefPtr<PlatformMessageResponse> response = message->response();
527 if (!response) {
528 return;
529 }
530 const auto& data = message->data();
531 std::string asset_name(reinterpret_cast<const char*>(data.GetMapping()),
532 data.GetSize());
533
534 if (asset_manager_) {
535 std::unique_ptr<fml::Mapping> asset_mapping =
536 asset_manager_->GetAsMapping(asset_name);
537 if (asset_mapping) {
538 response->Complete(data: std::move(asset_mapping));
539 return;
540 }
541 }
542
543 response->CompleteEmpty();
544}
545
546const std::string& Engine::GetLastEntrypoint() const {
547 return last_entry_point_;
548}
549
550const std::string& Engine::GetLastEntrypointLibrary() const {
551 return last_entry_point_library_;
552}
553
554const std::vector<std::string>& Engine::GetLastEntrypointArgs() const {
555 return last_entry_point_args_;
556}
557
558// |RuntimeDelegate|
559void Engine::RequestDartDeferredLibrary(intptr_t loading_unit_id) {
560 return delegate_.RequestDartDeferredLibrary(loading_unit_id);
561}
562
563std::weak_ptr<PlatformMessageHandler> Engine::GetPlatformMessageHandler()
564 const {
565 return delegate_.GetPlatformMessageHandler();
566}
567
568void Engine::LoadDartDeferredLibrary(
569 intptr_t loading_unit_id,
570 std::unique_ptr<const fml::Mapping> snapshot_data,
571 std::unique_ptr<const fml::Mapping> snapshot_instructions) {
572 if (runtime_controller_->IsRootIsolateRunning()) {
573 runtime_controller_->LoadDartDeferredLibrary(
574 loading_unit_id, snapshot_data: std::move(snapshot_data),
575 snapshot_instructions: std::move(snapshot_instructions));
576 } else {
577 LoadDartDeferredLibraryError(loading_unit_id, error_message: "No running root isolate.",
578 transient: true);
579 }
580}
581
582void Engine::LoadDartDeferredLibraryError(intptr_t loading_unit_id,
583 const std::string& error_message,
584 bool transient) {
585 if (runtime_controller_->IsRootIsolateRunning()) {
586 runtime_controller_->LoadDartDeferredLibraryError(loading_unit_id,
587 error_message, transient);
588 }
589}
590
591const std::weak_ptr<VsyncWaiter> Engine::GetVsyncWaiter() const {
592 return animator_->GetVsyncWaiter();
593}
594
595void Engine::SetDisplays(const std::vector<DisplayData>& displays) {
596 runtime_controller_->SetDisplays(displays);
597 ScheduleFrame();
598}
599
600} // namespace flutter
601

source code of flutter_engine/flutter/shell/common/engine.cc