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