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 <memory>
8#include <string>
9#include <utility>
10#include <vector>
11
12#include "flutter/common/settings.h"
13#include "flutter/fml/eintr_wrapper.h"
14#include "flutter/fml/file.h"
15#include "flutter/fml/make_copyable.h"
16#include "flutter/fml/paths.h"
17#include "flutter/fml/trace_event.h"
18#include "flutter/fml/unique_fd.h"
19#include "flutter/lib/snapshot/snapshot.h"
20#include "flutter/lib/ui/text/font_collection.h"
21#include "flutter/shell/common/animator.h"
22#include "flutter/shell/common/platform_view.h"
23#include "flutter/shell/common/shell.h"
24#include "rapidjson/document.h"
25#include "third_party/dart/runtime/include/dart_tools_api.h"
26#include "third_party/skia/include/core/SkCanvas.h"
27#include "third_party/skia/include/core/SkPictureRecorder.h"
28
29namespace flutter {
30
31static constexpr char kAssetChannel[] = "flutter/assets";
32static constexpr char kLifecycleChannel[] = "flutter/lifecycle";
33static constexpr char kNavigationChannel[] = "flutter/navigation";
34static constexpr char kLocalizationChannel[] = "flutter/localization";
35static constexpr char kSettingsChannel[] = "flutter/settings";
36static constexpr char kIsolateChannel[] = "flutter/isolate";
37
38Engine::Engine(
39 Delegate& delegate,
40 const PointerDataDispatcherMaker& dispatcher_maker,
41 std::shared_ptr<fml::ConcurrentTaskRunner> image_decoder_task_runner,
42 TaskRunners task_runners,
43 Settings settings,
44 std::unique_ptr<Animator> animator,
45 fml::WeakPtr<IOManager> io_manager,
46 std::unique_ptr<RuntimeController> runtime_controller)
47 : delegate_(delegate),
48 settings_(std::move(settings)),
49 animator_(std::move(animator)),
50 runtime_controller_(std::move(runtime_controller)),
51 activity_running_(true),
52 have_surface_(false),
53 image_decoder_(task_runners, image_decoder_task_runner, io_manager),
54 task_runners_(std::move(task_runners)),
55 weak_factory_(this) {
56 pointer_data_dispatcher_ = dispatcher_maker(*this);
57}
58
59Engine::Engine(Delegate& delegate,
60 const PointerDataDispatcherMaker& dispatcher_maker,
61 DartVM& vm,
62 fml::RefPtr<const DartSnapshot> isolate_snapshot,
63 TaskRunners task_runners,
64 const PlatformData platform_data,
65 Settings settings,
66 std::unique_ptr<Animator> animator,
67 fml::WeakPtr<IOManager> io_manager,
68 fml::RefPtr<SkiaUnrefQueue> unref_queue,
69 fml::WeakPtr<SnapshotDelegate> snapshot_delegate)
70 : Engine(delegate,
71 dispatcher_maker,
72 vm.GetConcurrentWorkerTaskRunner(),
73 task_runners,
74 settings,
75 std::move(animator),
76 io_manager,
77 nullptr) {
78 runtime_controller_ = std::make_unique<RuntimeController>(
79 *this, // runtime delegate
80 &vm, // VM
81 std::move(isolate_snapshot), // isolate snapshot
82 task_runners_, // task runners
83 std::move(snapshot_delegate),
84 std::move(io_manager), // io manager
85 std::move(unref_queue), // Skia unref queue
86 image_decoder_.GetWeakPtr(), // image decoder
87 settings_.advisory_script_uri, // advisory script uri
88 settings_.advisory_script_entrypoint, // advisory script entrypoint
89 settings_.idle_notification_callback, // idle notification callback
90 platform_data, // platform data
91 settings_.isolate_create_callback, // isolate create callback
92 settings_.isolate_shutdown_callback, // isolate shutdown callback
93 settings_.persistent_isolate_data // persistent isolate data
94 );
95}
96
97Engine::~Engine() = default;
98
99float Engine::GetDisplayRefreshRate() const {
100 return animator_->GetDisplayRefreshRate();
101}
102
103fml::WeakPtr<Engine> Engine::GetWeakPtr() const {
104 return weak_factory_.GetWeakPtr();
105}
106
107void Engine::SetupDefaultFontManager() {
108 TRACE_EVENT0("flutter", "Engine::SetupDefaultFontManager");
109 font_collection_.SetupDefaultFontManager();
110}
111
112bool Engine::UpdateAssetManager(
113 std::shared_ptr<AssetManager> new_asset_manager) {
114 if (asset_manager_ == new_asset_manager) {
115 return false;
116 }
117
118 asset_manager_ = new_asset_manager;
119
120 if (!asset_manager_) {
121 return false;
122 }
123
124 // Using libTXT as the text engine.
125 font_collection_.RegisterFonts(asset_manager_);
126
127 if (settings_.use_test_fonts) {
128 font_collection_.RegisterTestFonts();
129 }
130
131 return true;
132}
133
134bool Engine::Restart(RunConfiguration configuration) {
135 TRACE_EVENT0("flutter", "Engine::Restart");
136 if (!configuration.IsValid()) {
137 FML_LOG(ERROR) << "Engine run configuration was invalid.";
138 return false;
139 }
140 delegate_.OnPreEngineRestart();
141 runtime_controller_ = runtime_controller_->Clone();
142 UpdateAssetManager(nullptr);
143 return Run(std::move(configuration)) == Engine::RunStatus::Success;
144}
145
146Engine::RunStatus Engine::Run(RunConfiguration configuration) {
147 if (!configuration.IsValid()) {
148 FML_LOG(ERROR) << "Engine run configuration was invalid.";
149 return RunStatus::Failure;
150 }
151
152 last_entry_point_ = configuration.GetEntrypoint();
153 last_entry_point_library_ = configuration.GetEntrypointLibrary();
154
155 auto isolate_launch_status =
156 PrepareAndLaunchIsolate(std::move(configuration));
157 if (isolate_launch_status == Engine::RunStatus::Failure) {
158 FML_LOG(ERROR) << "Engine not prepare and launch isolate.";
159 return isolate_launch_status;
160 } else if (isolate_launch_status ==
161 Engine::RunStatus::FailureAlreadyRunning) {
162 return isolate_launch_status;
163 }
164
165 std::shared_ptr<DartIsolate> isolate =
166 runtime_controller_->GetRootIsolate().lock();
167
168 bool isolate_running =
169 isolate && isolate->GetPhase() == DartIsolate::Phase::Running;
170
171 if (isolate_running) {
172 tonic::DartState::Scope scope(isolate.get());
173
174 if (settings_.root_isolate_create_callback) {
175 settings_.root_isolate_create_callback();
176 }
177
178 if (settings_.root_isolate_shutdown_callback) {
179 isolate->AddIsolateShutdownCallback(
180 settings_.root_isolate_shutdown_callback);
181 }
182
183 std::string service_id = isolate->GetServiceId();
184 fml::RefPtr<PlatformMessage> service_id_message =
185 fml::MakeRefCounted<flutter::PlatformMessage>(
186 kIsolateChannel,
187 std::vector<uint8_t>(service_id.begin(), service_id.end()),
188 nullptr);
189 HandlePlatformMessage(service_id_message);
190 }
191
192 return isolate_running ? Engine::RunStatus::Success
193 : Engine::RunStatus::Failure;
194}
195
196Engine::RunStatus Engine::PrepareAndLaunchIsolate(
197 RunConfiguration configuration) {
198 TRACE_EVENT0("flutter", "Engine::PrepareAndLaunchIsolate");
199
200 UpdateAssetManager(configuration.GetAssetManager());
201
202 auto isolate_configuration = configuration.TakeIsolateConfiguration();
203
204 std::shared_ptr<DartIsolate> isolate =
205 runtime_controller_->GetRootIsolate().lock();
206
207 if (!isolate) {
208 return RunStatus::Failure;
209 }
210
211 // This can happen on iOS after a plugin shows a native window and returns to
212 // the Flutter ViewController.
213 if (isolate->GetPhase() == DartIsolate::Phase::Running) {
214 FML_DLOG(WARNING) << "Isolate was already running!";
215 return RunStatus::FailureAlreadyRunning;
216 }
217
218 if (!isolate_configuration->PrepareIsolate(*isolate)) {
219 FML_LOG(ERROR) << "Could not prepare to run the isolate.";
220 return RunStatus::Failure;
221 }
222
223 if (configuration.GetEntrypointLibrary().empty()) {
224 if (!isolate->Run(configuration.GetEntrypoint(),
225 settings_.dart_entrypoint_args)) {
226 FML_LOG(ERROR) << "Could not run the isolate.";
227 return RunStatus::Failure;
228 }
229 } else {
230 if (!isolate->RunFromLibrary(configuration.GetEntrypointLibrary(),
231 configuration.GetEntrypoint(),
232 settings_.dart_entrypoint_args)) {
233 FML_LOG(ERROR) << "Could not run the isolate.";
234 return RunStatus::Failure;
235 }
236 }
237
238 return RunStatus::Success;
239}
240
241void Engine::BeginFrame(fml::TimePoint frame_time) {
242 TRACE_EVENT0("flutter", "Engine::BeginFrame");
243 runtime_controller_->BeginFrame(frame_time);
244}
245
246void Engine::ReportTimings(std::vector<int64_t> timings) {
247 TRACE_EVENT0("flutter", "Engine::ReportTimings");
248 runtime_controller_->ReportTimings(std::move(timings));
249}
250
251void Engine::NotifyIdle(int64_t deadline) {
252 auto trace_event = std::to_string(deadline - Dart_TimelineGetMicros());
253 TRACE_EVENT1("flutter", "Engine::NotifyIdle", "deadline_now_delta",
254 trace_event.c_str());
255 runtime_controller_->NotifyIdle(deadline);
256}
257
258std::pair<bool, uint32_t> Engine::GetUIIsolateReturnCode() {
259 return runtime_controller_->GetRootIsolateReturnCode();
260}
261
262Dart_Port Engine::GetUIIsolateMainPort() {
263 return runtime_controller_->GetMainPort();
264}
265
266std::string Engine::GetUIIsolateName() {
267 return runtime_controller_->GetIsolateName();
268}
269
270bool Engine::UIIsolateHasLivePorts() {
271 return runtime_controller_->HasLivePorts();
272}
273
274tonic::DartErrorHandleType Engine::GetUIIsolateLastError() {
275 return runtime_controller_->GetLastError();
276}
277
278void Engine::OnOutputSurfaceCreated() {
279 have_surface_ = true;
280 StartAnimatorIfPossible();
281 ScheduleFrame();
282}
283
284void Engine::OnOutputSurfaceDestroyed() {
285 have_surface_ = false;
286 StopAnimator();
287}
288
289void Engine::SetViewportMetrics(const ViewportMetrics& metrics) {
290 bool dimensions_changed =
291 viewport_metrics_.physical_height != metrics.physical_height ||
292 viewport_metrics_.physical_width != metrics.physical_width ||
293 viewport_metrics_.device_pixel_ratio != metrics.device_pixel_ratio;
294 viewport_metrics_ = metrics;
295 runtime_controller_->SetViewportMetrics(viewport_metrics_);
296 if (animator_) {
297 if (dimensions_changed) {
298 animator_->SetDimensionChangePending();
299 }
300 if (have_surface_) {
301 ScheduleFrame();
302 }
303 }
304}
305
306void Engine::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message) {
307 std::string channel = message->channel();
308 if (channel == kLifecycleChannel) {
309 if (HandleLifecyclePlatformMessage(message.get())) {
310 return;
311 }
312 } else if (channel == kLocalizationChannel) {
313 if (HandleLocalizationPlatformMessage(message.get())) {
314 return;
315 }
316 } else if (channel == kSettingsChannel) {
317 HandleSettingsPlatformMessage(message.get());
318 return;
319 } else if (!runtime_controller_->IsRootIsolateRunning() &&
320 channel == kNavigationChannel) {
321 // If there's no runtime_, we may still need to set the initial route.
322 HandleNavigationPlatformMessage(std::move(message));
323 return;
324 }
325
326 if (runtime_controller_->IsRootIsolateRunning() &&
327 runtime_controller_->DispatchPlatformMessage(std::move(message))) {
328 return;
329 }
330
331 FML_DLOG(WARNING) << "Dropping platform message on channel: " << channel;
332}
333
334bool Engine::HandleLifecyclePlatformMessage(PlatformMessage* message) {
335 const auto& data = message->data();
336 std::string state(reinterpret_cast<const char*>(data.data()), data.size());
337 if (state == "AppLifecycleState.paused" ||
338 state == "AppLifecycleState.detached") {
339 activity_running_ = false;
340 StopAnimator();
341 } else if (state == "AppLifecycleState.resumed" ||
342 state == "AppLifecycleState.inactive") {
343 activity_running_ = true;
344 StartAnimatorIfPossible();
345 }
346
347 // Always schedule a frame when the app does become active as per API
348 // recommendation
349 // https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622956-applicationdidbecomeactive?language=objc
350 if (state == "AppLifecycleState.resumed" && have_surface_) {
351 ScheduleFrame();
352 }
353 runtime_controller_->SetLifecycleState(state);
354 // Always forward these messages to the framework by returning false.
355 return false;
356}
357
358bool Engine::HandleNavigationPlatformMessage(
359 fml::RefPtr<PlatformMessage> message) {
360 const auto& data = message->data();
361
362 rapidjson::Document document;
363 document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
364 if (document.HasParseError() || !document.IsObject()) {
365 return false;
366 }
367 auto root = document.GetObject();
368 auto method = root.FindMember("method");
369 if (method->value != "setInitialRoute") {
370 return false;
371 }
372 auto route = root.FindMember("args");
373 initial_route_ = std::move(route->value.GetString());
374 return true;
375}
376
377bool Engine::HandleLocalizationPlatformMessage(PlatformMessage* message) {
378 const auto& data = message->data();
379
380 rapidjson::Document document;
381 document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
382 if (document.HasParseError() || !document.IsObject()) {
383 return false;
384 }
385 auto root = document.GetObject();
386 auto method = root.FindMember("method");
387 if (method == root.MemberEnd()) {
388 return false;
389 }
390 const size_t strings_per_locale = 4;
391 if (method->value == "setLocale") {
392 // Decode and pass the list of locale data onwards to dart.
393 auto args = root.FindMember("args");
394 if (args == root.MemberEnd() || !args->value.IsArray()) {
395 return false;
396 }
397
398 if (args->value.Size() % strings_per_locale != 0) {
399 return false;
400 }
401 std::vector<std::string> locale_data;
402 for (size_t locale_index = 0; locale_index < args->value.Size();
403 locale_index += strings_per_locale) {
404 if (!args->value[locale_index].IsString() ||
405 !args->value[locale_index + 1].IsString()) {
406 return false;
407 }
408 locale_data.push_back(args->value[locale_index].GetString());
409 locale_data.push_back(args->value[locale_index + 1].GetString());
410 locale_data.push_back(args->value[locale_index + 2].GetString());
411 locale_data.push_back(args->value[locale_index + 3].GetString());
412 }
413
414 return runtime_controller_->SetLocales(locale_data);
415 }
416 return false;
417}
418
419void Engine::HandleSettingsPlatformMessage(PlatformMessage* message) {
420 const auto& data = message->data();
421 std::string jsonData(reinterpret_cast<const char*>(data.data()), data.size());
422 if (runtime_controller_->SetUserSettingsData(std::move(jsonData)) &&
423 have_surface_) {
424 ScheduleFrame();
425 }
426}
427
428void Engine::DispatchPointerDataPacket(
429 std::unique_ptr<PointerDataPacket> packet,
430 uint64_t trace_flow_id) {
431 TRACE_EVENT0("flutter", "Engine::DispatchPointerDataPacket");
432 TRACE_FLOW_STEP("flutter", "PointerEvent", trace_flow_id);
433 pointer_data_dispatcher_->DispatchPacket(std::move(packet), trace_flow_id);
434}
435
436void Engine::DispatchSemanticsAction(int id,
437 SemanticsAction action,
438 std::vector<uint8_t> args) {
439 runtime_controller_->DispatchSemanticsAction(id, action, std::move(args));
440}
441
442void Engine::SetSemanticsEnabled(bool enabled) {
443 runtime_controller_->SetSemanticsEnabled(enabled);
444}
445
446void Engine::SetAccessibilityFeatures(int32_t flags) {
447 runtime_controller_->SetAccessibilityFeatures(flags);
448}
449
450void Engine::StopAnimator() {
451 animator_->Stop();
452}
453
454void Engine::StartAnimatorIfPossible() {
455 if (activity_running_ && have_surface_) {
456 animator_->Start();
457 }
458}
459
460std::string Engine::DefaultRouteName() {
461 if (!initial_route_.empty()) {
462 return initial_route_;
463 }
464 return "/";
465}
466
467void Engine::ScheduleFrame(bool regenerate_layer_tree) {
468 animator_->RequestFrame(regenerate_layer_tree);
469}
470
471void Engine::Render(std::unique_ptr<flutter::LayerTree> layer_tree) {
472 if (!layer_tree) {
473 return;
474 }
475
476 // Ensure frame dimensions are sane.
477 if (layer_tree->frame_size().isEmpty() ||
478 layer_tree->device_pixel_ratio() <= 0.0f) {
479 return;
480 }
481
482 animator_->Render(std::move(layer_tree));
483}
484
485void Engine::UpdateSemantics(SemanticsNodeUpdates update,
486 CustomAccessibilityActionUpdates actions) {
487 delegate_.OnEngineUpdateSemantics(std::move(update), std::move(actions));
488}
489
490void Engine::HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) {
491 if (message->channel() == kAssetChannel) {
492 HandleAssetPlatformMessage(std::move(message));
493 } else {
494 delegate_.OnEngineHandlePlatformMessage(std::move(message));
495 }
496}
497
498void Engine::UpdateIsolateDescription(const std::string isolate_name,
499 int64_t isolate_port) {
500 delegate_.UpdateIsolateDescription(isolate_name, isolate_port);
501}
502
503std::unique_ptr<std::vector<std::string>> Engine::ComputePlatformResolvedLocale(
504 const std::vector<std::string>& supported_locale_data) {
505 return delegate_.ComputePlatformResolvedLocale(supported_locale_data);
506}
507
508void Engine::SetNeedsReportTimings(bool needs_reporting) {
509 delegate_.SetNeedsReportTimings(needs_reporting);
510}
511
512FontCollection& Engine::GetFontCollection() {
513 return font_collection_;
514}
515
516void Engine::DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
517 uint64_t trace_flow_id) {
518 animator_->EnqueueTraceFlowId(trace_flow_id);
519 if (runtime_controller_) {
520 runtime_controller_->DispatchPointerDataPacket(*packet);
521 }
522}
523
524void Engine::ScheduleSecondaryVsyncCallback(const fml::closure& callback) {
525 animator_->ScheduleSecondaryVsyncCallback(callback);
526}
527
528void Engine::HandleAssetPlatformMessage(fml::RefPtr<PlatformMessage> message) {
529 fml::RefPtr<PlatformMessageResponse> response = message->response();
530 if (!response) {
531 return;
532 }
533 const auto& data = message->data();
534 std::string asset_name(reinterpret_cast<const char*>(data.data()),
535 data.size());
536
537 if (asset_manager_) {
538 std::unique_ptr<fml::Mapping> asset_mapping =
539 asset_manager_->GetAsMapping(asset_name);
540 if (asset_mapping) {
541 response->Complete(std::move(asset_mapping));
542 return;
543 }
544 }
545
546 response->CompleteEmpty();
547}
548
549const std::string& Engine::GetLastEntrypoint() const {
550 return last_entry_point_;
551}
552
553const std::string& Engine::GetLastEntrypointLibrary() const {
554 return last_entry_point_library_;
555}
556
557} // namespace flutter
558