• 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 #define RAPIDJSON_HAS_STDSTRING 1
6 #include "flutter/shell/common/shell.h"
7 
8 #include <memory>
9 #include <sstream>
10 #include <vector>
11 
12 #include "flutter/assets/directory_asset_bundle.h"
13 #include "flutter/fml/file.h"
14 #include "flutter/fml/icu_util.h"
15 #include "flutter/fml/log_settings.h"
16 #include "flutter/fml/logging.h"
17 #include "flutter/fml/make_copyable.h"
18 #include "flutter/fml/message_loop.h"
19 #include "flutter/fml/paths.h"
20 #include "flutter/fml/trace_event.h"
21 #include "flutter/fml/unique_fd.h"
22 #include "flutter/runtime/dart_vm.h"
23 #include "flutter/runtime/start_up.h"
24 #include "flutter/shell/common/engine.h"
25 #include "flutter/shell/common/persistent_cache.h"
26 #include "flutter/shell/common/skia_event_tracer_impl.h"
27 #include "flutter/shell/common/switches.h"
28 #include "flutter/shell/common/vsync_waiter.h"
29 #include "third_party/skia/include/core/SkGraphics.h"
30 
31 namespace flutter {
32 
33 constexpr char kSkiaChannel[] = "flutter/skia";
34 
CreateShellOnPlatformThread(DartVMRef vm,TaskRunners task_runners,Settings settings,fml::RefPtr<const DartSnapshot> isolate_snapshot,fml::RefPtr<const DartSnapshot> shared_snapshot,Shell::CreateCallback<PlatformView> on_create_platform_view,Shell::CreateCallback<Rasterizer> on_create_rasterizer)35 std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
36     DartVMRef vm,
37     TaskRunners task_runners,
38     Settings settings,
39     fml::RefPtr<const DartSnapshot> isolate_snapshot,
40     fml::RefPtr<const DartSnapshot> shared_snapshot,
41     Shell::CreateCallback<PlatformView> on_create_platform_view,
42     Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
43   if (!task_runners.IsValid()) {
44     FML_LOG(ERROR) << "Task runners to run the shell were invalid.";
45     return nullptr;
46   }
47 
48   auto shell =
49       std::unique_ptr<Shell>(new Shell(std::move(vm), task_runners, settings));
50 
51   // Create the platform view on the platform thread (this thread).
52   auto platform_view = on_create_platform_view(*shell.get());
53   if (!platform_view || !platform_view->GetWeakPtr()) {
54     return nullptr;
55   }
56 
57   // Ask the platform view for the vsync waiter. This will be used by the engine
58   // to create the animator.
59   auto vsync_waiter = platform_view->CreateVSyncWaiter();
60   if (!vsync_waiter) {
61     return nullptr;
62   }
63 
64   // Create the IO manager on the IO thread. The IO manager must be initialized
65   // first because it has state that the other subsystems depend on. It must
66   // first be booted and the necessary references obtained to initialize the
67   // other subsystems.
68   fml::AutoResetWaitableEvent io_latch;
69   std::unique_ptr<ShellIOManager> io_manager;
70   auto io_task_runner = shell->GetTaskRunners().GetIOTaskRunner();
71   fml::TaskRunner::RunNowOrPostTask(
72       io_task_runner,
73       [&io_latch,       //
74        &io_manager,     //
75        &platform_view,  //
76        io_task_runner   //
77   ]() {
78         TRACE_EVENT0("flutter", "ShellSetupIOSubsystem");
79         io_manager = std::make_unique<ShellIOManager>(
80             platform_view->CreateResourceContext(), io_task_runner);
81         io_latch.Signal();
82       });
83   io_latch.Wait();
84 
85   // Create the rasterizer on the GPU thread.
86   fml::AutoResetWaitableEvent gpu_latch;
87   std::unique_ptr<Rasterizer> rasterizer;
88   fml::TaskRunner::RunNowOrPostTask(
89       task_runners.GetGPUTaskRunner(), [&gpu_latch,            //
90                                         &rasterizer,           //
91                                         on_create_rasterizer,  //
92                                         shell = shell.get()    //
93   ]() {
94         TRACE_EVENT0("flutter", "ShellSetupGPUSubsystem");
95         if (auto new_rasterizer = on_create_rasterizer(*shell)) {
96           rasterizer = std::move(new_rasterizer);
97         }
98         gpu_latch.Signal();
99       });
100 
101   gpu_latch.Wait();
102 
103   // Create the engine on the UI thread.
104   fml::AutoResetWaitableEvent ui_latch;
105   std::unique_ptr<Engine> engine;
106   fml::TaskRunner::RunNowOrPostTask(
107       shell->GetTaskRunners().GetUITaskRunner(),
108       fml::MakeCopyable([&ui_latch,                                       //
109                          &engine,                                         //
110                          shell = shell.get(),                             //
111                          isolate_snapshot = std::move(isolate_snapshot),  //
112                          shared_snapshot = std::move(shared_snapshot),    //
113                          vsync_waiter = std::move(vsync_waiter),          //
114                          io_manager = io_manager->GetWeakPtr()            //
115   ]() mutable {
116         TRACE_EVENT0("flutter", "ShellSetupUISubsystem");
117         const auto& task_runners = shell->GetTaskRunners();
118 
119         // The animator is owned by the UI thread but it gets its vsync pulses
120         // from the platform.
121         auto animator = std::make_unique<Animator>(*shell, task_runners,
122                                                    std::move(vsync_waiter));
123 
124         engine = std::make_unique<Engine>(*shell,                       //
125                                           *shell->GetDartVM(),          //
126                                           std::move(isolate_snapshot),  //
127                                           std::move(shared_snapshot),   //
128                                           task_runners,                 //
129                                           shell->GetSettings(),         //
130                                           std::move(animator),          //
131                                           std::move(io_manager)         //
132         );
133         ui_latch.Signal();
134       }));
135 
136   ui_latch.Wait();
137   // We are already on the platform thread. So there is no platform latch to
138   // wait on.
139 
140   if (!shell->Setup(std::move(platform_view),  //
141                     std::move(engine),         //
142                     std::move(rasterizer),     //
143                     std::move(io_manager))     //
144   ) {
145     return nullptr;
146   }
147 
148   return shell;
149 }
150 
RecordStartupTimestamp()151 static void RecordStartupTimestamp() {
152   if (engine_main_enter_ts == 0) {
153     engine_main_enter_ts = 0;
154   }
155 }
156 
157 // Though there can be multiple shells, some settings apply to all components in
158 // the process. These have to be setup before the shell or any of its
159 // sub-components can be initialized. In a perfect world, this would be empty.
160 // TODO(chinmaygarde): The unfortunate side effect of this call is that settings
161 // that cause shell initialization failures will still lead to some of their
162 // settings being applied.
PerformInitializationTasks(const Settings & settings)163 static void PerformInitializationTasks(const Settings& settings) {
164   {
165     fml::LogSettings log_settings;
166     log_settings.min_log_level =
167         settings.verbose_logging ? fml::LOG_INFO : fml::LOG_ERROR;
168     fml::SetLogSettings(log_settings);
169   }
170 
171   static std::once_flag gShellSettingsInitialization = {};
172   std::call_once(gShellSettingsInitialization, [&settings] {
173     RecordStartupTimestamp();
174 
175     tonic::SetLogHandler(
176         [](const char* message) { FML_LOG(ERROR) << message; });
177 
178     if (settings.trace_skia) {
179       InitSkiaEventTracer(settings.trace_skia);
180     }
181 
182     if (!settings.skia_deterministic_rendering_on_cpu) {
183       SkGraphics::Init();
184     } else {
185       FML_DLOG(INFO) << "Skia deterministic rendering is enabled.";
186     }
187 
188     if (settings.icu_initialization_required) {
189       if (settings.icu_data_path.size() != 0) {
190         fml::icu::InitializeICU(settings.icu_data_path);
191       } else if (settings.icu_mapper) {
192         fml::icu::InitializeICUFromMapping(settings.icu_mapper());
193       } else {
194         FML_DLOG(WARNING) << "Skipping ICU initialization in the shell.";
195       }
196     }
197   });
198 }
199 
Create(TaskRunners task_runners,Settings settings,Shell::CreateCallback<PlatformView> on_create_platform_view,Shell::CreateCallback<Rasterizer> on_create_rasterizer)200 std::unique_ptr<Shell> Shell::Create(
201     TaskRunners task_runners,
202     Settings settings,
203     Shell::CreateCallback<PlatformView> on_create_platform_view,
204     Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
205   PerformInitializationTasks(settings);
206 
207   TRACE_EVENT0("flutter", "Shell::Create");
208 
209   auto vm = DartVMRef::Create(settings);
210   FML_CHECK(vm) << "Must be able to initialize the VM.";
211 
212   auto vm_data = vm->GetVMData();
213 
214   return Shell::Create(std::move(task_runners),             //
215                        std::move(settings),                 //
216                        vm_data->GetIsolateSnapshot(),       // isolate snapshot
217                        DartSnapshot::Empty(),               // shared snapshot
218                        std::move(on_create_platform_view),  //
219                        std::move(on_create_rasterizer),     //
220                        std::move(vm)                        //
221   );
222 }
223 
Create(TaskRunners task_runners,Settings settings,fml::RefPtr<const DartSnapshot> isolate_snapshot,fml::RefPtr<const DartSnapshot> shared_snapshot,Shell::CreateCallback<PlatformView> on_create_platform_view,Shell::CreateCallback<Rasterizer> on_create_rasterizer,DartVMRef vm)224 std::unique_ptr<Shell> Shell::Create(
225     TaskRunners task_runners,
226     Settings settings,
227     fml::RefPtr<const DartSnapshot> isolate_snapshot,
228     fml::RefPtr<const DartSnapshot> shared_snapshot,
229     Shell::CreateCallback<PlatformView> on_create_platform_view,
230     Shell::CreateCallback<Rasterizer> on_create_rasterizer,
231     DartVMRef vm) {
232   PerformInitializationTasks(settings);
233 
234   TRACE_EVENT0("flutter", "Shell::CreateWithSnapshots");
235 
236   if (!task_runners.IsValid() || !on_create_platform_view ||
237       !on_create_rasterizer) {
238     return nullptr;
239   }
240 
241   fml::AutoResetWaitableEvent latch;
242   std::unique_ptr<Shell> shell;
243   fml::TaskRunner::RunNowOrPostTask(
244       task_runners.GetPlatformTaskRunner(),
245       fml::MakeCopyable([&latch,                                          //
246                          vm = std::move(vm),                              //
247                          &shell,                                          //
248                          task_runners = std::move(task_runners),          //
249                          settings,                                        //
250                          isolate_snapshot = std::move(isolate_snapshot),  //
251                          shared_snapshot = std::move(shared_snapshot),    //
252                          on_create_platform_view,                         //
253                          on_create_rasterizer                             //
254   ]() mutable {
255         shell = CreateShellOnPlatformThread(std::move(vm),
256                                             std::move(task_runners),      //
257                                             settings,                     //
258                                             std::move(isolate_snapshot),  //
259                                             std::move(shared_snapshot),   //
260                                             on_create_platform_view,      //
261                                             on_create_rasterizer          //
262         );
263         latch.Signal();
264       }));
265   latch.Wait();
266   return shell;
267 }
268 
Shell(DartVMRef vm,TaskRunners task_runners,Settings settings)269 Shell::Shell(DartVMRef vm, TaskRunners task_runners, Settings settings)
270     : task_runners_(std::move(task_runners)),
271       settings_(std::move(settings)),
272       vm_(std::move(vm)),
273       weak_factory_(this) {
274   FML_CHECK(vm_) << "Must have access to VM to create a shell.";
275   FML_DCHECK(task_runners_.IsValid());
276   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
277 
278   // Install service protocol handlers.
279 
280   service_protocol_handlers_[ServiceProtocol::kScreenshotExtensionName] = {
281       task_runners_.GetGPUTaskRunner(),
282       std::bind(&Shell::OnServiceProtocolScreenshot, this,
283                 std::placeholders::_1, std::placeholders::_2)};
284   service_protocol_handlers_[ServiceProtocol::kScreenshotSkpExtensionName] = {
285       task_runners_.GetGPUTaskRunner(),
286       std::bind(&Shell::OnServiceProtocolScreenshotSKP, this,
287                 std::placeholders::_1, std::placeholders::_2)};
288   service_protocol_handlers_[ServiceProtocol::kRunInViewExtensionName] = {
289       task_runners_.GetUITaskRunner(),
290       std::bind(&Shell::OnServiceProtocolRunInView, this, std::placeholders::_1,
291                 std::placeholders::_2)};
292   service_protocol_handlers_
293       [ServiceProtocol::kFlushUIThreadTasksExtensionName] = {
294           task_runners_.GetUITaskRunner(),
295           std::bind(&Shell::OnServiceProtocolFlushUIThreadTasks, this,
296                     std::placeholders::_1, std::placeholders::_2)};
297   service_protocol_handlers_
298       [ServiceProtocol::kSetAssetBundlePathExtensionName] = {
299           task_runners_.GetUITaskRunner(),
300           std::bind(&Shell::OnServiceProtocolSetAssetBundlePath, this,
301                     std::placeholders::_1, std::placeholders::_2)};
302   service_protocol_handlers_
303       [ServiceProtocol::kGetDisplayRefreshRateExtensionName] = {
304           task_runners_.GetUITaskRunner(),
305           std::bind(&Shell::OnServiceProtocolGetDisplayRefreshRate, this,
306                     std::placeholders::_1, std::placeholders::_2)};
307 }
308 
~Shell()309 Shell::~Shell() {
310   PersistentCache::GetCacheForProcess()->RemoveWorkerTaskRunner(
311       task_runners_.GetIOTaskRunner());
312 
313   vm_->GetServiceProtocol()->RemoveHandler(this);
314 
315   fml::AutoResetWaitableEvent ui_latch, gpu_latch, platform_latch, io_latch;
316 
317   fml::TaskRunner::RunNowOrPostTask(
318       task_runners_.GetUITaskRunner(),
319       fml::MakeCopyable([engine = std::move(engine_), &ui_latch]() mutable {
320         engine.reset();
321         ui_latch.Signal();
322       }));
323   ui_latch.Wait();
324 
325   fml::TaskRunner::RunNowOrPostTask(
326       task_runners_.GetGPUTaskRunner(),
327       fml::MakeCopyable(
328           [rasterizer = std::move(rasterizer_), &gpu_latch]() mutable {
329             rasterizer.reset();
330             gpu_latch.Signal();
331           }));
332   gpu_latch.Wait();
333 
334   fml::TaskRunner::RunNowOrPostTask(
335       task_runners_.GetIOTaskRunner(),
336       fml::MakeCopyable([io_manager = std::move(io_manager_),
337                          platform_view = platform_view_.get(),
338                          &io_latch]() mutable {
339         io_manager.reset();
340         if (platform_view) {
341           platform_view->ReleaseResourceContext();
342         }
343         io_latch.Signal();
344       }));
345 
346   io_latch.Wait();
347 
348   // The platform view must go last because it may be holding onto platform side
349   // counterparts to resources owned by subsystems running on other threads. For
350   // example, the NSOpenGLContext on the Mac.
351   fml::TaskRunner::RunNowOrPostTask(
352       task_runners_.GetPlatformTaskRunner(),
353       fml::MakeCopyable([platform_view = std::move(platform_view_),
354                          &platform_latch]() mutable {
355         platform_view.reset();
356         platform_latch.Signal();
357       }));
358   platform_latch.Wait();
359 }
360 
NotifyLowMemoryWarning() const361 void Shell::NotifyLowMemoryWarning() const {
362   task_runners_.GetGPUTaskRunner()->PostTask(
363       [rasterizer = rasterizer_->GetWeakPtr()]() {
364         if (rasterizer) {
365           rasterizer->NotifyLowMemoryWarning();
366         }
367       });
368   // The IO Manager uses resource cache limits of 0, so it is not necessary
369   // to purge them.
370 }
371 
RunEngine(RunConfiguration run_configuration)372 void Shell::RunEngine(RunConfiguration run_configuration) {
373   RunEngine(std::move(run_configuration), nullptr);
374 }
375 
RunEngine(RunConfiguration run_configuration,std::function<void (Engine::RunStatus)> result_callback)376 void Shell::RunEngine(RunConfiguration run_configuration,
377                       std::function<void(Engine::RunStatus)> result_callback) {
378   auto result = [platform_runner = task_runners_.GetPlatformTaskRunner(),
379                  result_callback](Engine::RunStatus run_result) {
380     if (!result_callback) {
381       return;
382     }
383     platform_runner->PostTask(
384         [result_callback, run_result]() { result_callback(run_result); });
385   };
386   FML_DCHECK(is_setup_);
387   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
388 
389   if (!weak_engine_) {
390     result(Engine::RunStatus::Failure);
391   }
392   fml::TaskRunner::RunNowOrPostTask(
393       task_runners_.GetUITaskRunner(),
394       fml::MakeCopyable(
395           [run_configuration = std::move(run_configuration),
396            weak_engine = weak_engine_, result]() mutable {
397             if (!weak_engine) {
398               FML_LOG(ERROR)
399                   << "Could not launch engine with configuration - no engine.";
400               result(Engine::RunStatus::Failure);
401               return;
402             }
403             auto run_result = weak_engine->Run(std::move(run_configuration));
404             if (run_result == flutter::Engine::RunStatus::Failure) {
405               FML_LOG(ERROR) << "Could not launch engine with configuration.";
406             }
407             result(run_result);
408           }));
409 }
410 
GetUIIsolateLastError() const411 std::optional<DartErrorCode> Shell::GetUIIsolateLastError() const {
412   FML_DCHECK(is_setup_);
413   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
414 
415   // We're using the unique_ptr here because we're sure we're on the Platform
416   // Thread and callers expect this to be synchronous.
417   if (!engine_) {
418     return std::nullopt;
419   }
420   switch (engine_->GetUIIsolateLastError()) {
421     case tonic::kCompilationErrorType:
422       return DartErrorCode::CompilationError;
423     case tonic::kApiErrorType:
424       return DartErrorCode::ApiError;
425     case tonic::kUnknownErrorType:
426       return DartErrorCode::UnknownError;
427     case tonic::kNoError:
428       return DartErrorCode::NoError;
429   }
430   return DartErrorCode::UnknownError;
431 }
432 
EngineHasLivePorts() const433 bool Shell::EngineHasLivePorts() const {
434   FML_DCHECK(is_setup_);
435   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
436 
437   // We're using the unique_ptr here because we're sure we're on the Platform
438   // Thread and callers expect this to be synchronous.
439   if (!engine_) {
440     return false;
441   }
442   return engine_->UIIsolateHasLivePorts();
443 }
444 
IsSetup() const445 bool Shell::IsSetup() const {
446   return is_setup_;
447 }
448 
Setup(std::unique_ptr<PlatformView> platform_view,std::unique_ptr<Engine> engine,std::unique_ptr<Rasterizer> rasterizer,std::unique_ptr<ShellIOManager> io_manager)449 bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
450                   std::unique_ptr<Engine> engine,
451                   std::unique_ptr<Rasterizer> rasterizer,
452                   std::unique_ptr<ShellIOManager> io_manager) {
453   if (is_setup_) {
454     return false;
455   }
456 
457   if (!platform_view || !engine || !rasterizer || !io_manager) {
458     return false;
459   }
460 
461   platform_view_ = std::move(platform_view);
462   engine_ = std::move(engine);
463   rasterizer_ = std::move(rasterizer);
464   io_manager_ = std::move(io_manager);
465 
466   // The weak ptr must be generated in the platform thread which owns the unique
467   // ptr.
468   weak_engine_ = engine_->GetWeakPtr();
469   weak_rasterizer_ = rasterizer_->GetWeakPtr();
470   weak_platform_view_ = platform_view_->GetWeakPtr();
471 
472   is_setup_ = true;
473 
474   vm_->GetServiceProtocol()->AddHandler(this, GetServiceProtocolDescription());
475 
476   PersistentCache::GetCacheForProcess()->AddWorkerTaskRunner(
477       task_runners_.GetIOTaskRunner());
478 
479   PersistentCache::GetCacheForProcess()->SetIsDumpingSkp(
480       settings_.dump_skp_on_shader_compilation);
481 
482   return true;
483 }
484 
GetSettings() const485 const Settings& Shell::GetSettings() const {
486   return settings_;
487 }
488 
GetTaskRunners() const489 const TaskRunners& Shell::GetTaskRunners() const {
490   return task_runners_;
491 }
492 
GetRasterizer()493 fml::WeakPtr<Rasterizer> Shell::GetRasterizer() {
494   FML_DCHECK(is_setup_);
495   return weak_rasterizer_;
496 }
497 
498 // TODO(dnfield): Remove this when either Topaz is up to date or flutter_runner
499 // is built out of this repo.
500 #ifdef OS_FUCHSIA
GetEngine()501 fml::WeakPtr<Engine> Shell::GetEngine() {
502   FML_DCHECK(is_setup_);
503   return weak_engine_;
504 }
505 #endif  // OS_FUCHSIA
506 
GetPlatformView()507 fml::WeakPtr<PlatformView> Shell::GetPlatformView() {
508   FML_DCHECK(is_setup_);
509   return weak_platform_view_;
510 }
511 
GetDartVM()512 DartVM* Shell::GetDartVM() {
513   return &vm_;
514 }
515 
516 // |PlatformView::Delegate|
OnPlatformViewCreated(std::unique_ptr<Surface> surface)517 void Shell::OnPlatformViewCreated(std::unique_ptr<Surface> surface) {
518   TRACE_EVENT0("flutter", "Shell::OnPlatformViewCreated");
519   FML_DCHECK(is_setup_);
520   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
521 
522   // Note:
523   // This is a synchronous operation because certain platforms depend on
524   // setup/suspension of all activities that may be interacting with the GPU in
525   // a synchronous fashion.
526   fml::AutoResetWaitableEvent latch;
527   auto gpu_task =
528       fml::MakeCopyable([& waiting_for_first_frame = waiting_for_first_frame_,
529                          rasterizer = rasterizer_->GetWeakPtr(),  //
530                          surface = std::move(surface),            //
531                          &latch]() mutable {
532         if (rasterizer) {
533           rasterizer->Setup(std::move(surface));
534         }
535 
536         waiting_for_first_frame.store(true);
537 
538         // Step 3: All done. Signal the latch that the platform thread is
539         // waiting on.
540         latch.Signal();
541       });
542 
543   // The normal flow executed by this method is that the platform thread is
544   // starting the sequence and waiting on the latch. Later the UI thread posts
545   // gpu_task to the GPU thread which signals the latch. If the GPU the and
546   // platform threads are the same this results in a deadlock as the gpu_task
547   // will never be posted to the plaform/gpu thread that is blocked on a latch.
548   // To avoid the described deadlock, if the gpu and the platform threads are
549   // the same, should_post_gpu_task will be false, and then instead of posting a
550   // task to the gpu thread, the ui thread just signals the latch and the
551   // platform/gpu thread follows with executing gpu_task.
552   bool should_post_gpu_task =
553       task_runners_.GetGPUTaskRunner() != task_runners_.GetPlatformTaskRunner();
554 
555   auto ui_task = [engine = engine_->GetWeakPtr(),                      //
556                   gpu_task_runner = task_runners_.GetGPUTaskRunner(),  //
557                   gpu_task, should_post_gpu_task,
558                   &latch  //
559   ] {
560     if (engine) {
561       engine->OnOutputSurfaceCreated();
562     }
563     // Step 2: Next, tell the GPU thread that it should create a surface for its
564     // rasterizer.
565     if (should_post_gpu_task) {
566       fml::TaskRunner::RunNowOrPostTask(gpu_task_runner, gpu_task);
567     } else {
568       // See comment on should_post_gpu_task, in this case we just unblock
569       // the platform thread.
570       latch.Signal();
571     }
572   };
573 
574   // Threading: Capture platform view by raw pointer and not the weak pointer.
575   // We are going to use the pointer on the IO thread which is not safe with a
576   // weak pointer. However, we are preventing the platform view from being
577   // collected by using a latch.
578   auto* platform_view = platform_view_.get();
579 
580   FML_DCHECK(platform_view);
581 
582   auto io_task = [io_manager = io_manager_->GetWeakPtr(), platform_view,
583                   ui_task_runner = task_runners_.GetUITaskRunner(), ui_task] {
584     if (io_manager && !io_manager->GetResourceContext()) {
585       io_manager->NotifyResourceContextAvailable(
586           platform_view->CreateResourceContext());
587     }
588     // Step 1: Next, post a task on the UI thread to tell the engine that it has
589     // an output surface.
590     fml::TaskRunner::RunNowOrPostTask(ui_task_runner, ui_task);
591   };
592 
593   fml::TaskRunner::RunNowOrPostTask(task_runners_.GetIOTaskRunner(), io_task);
594 
595   latch.Wait();
596   if (!should_post_gpu_task) {
597     // See comment on should_post_gpu_task, in this case the gpu_task
598     // wasn't executed, and we just run it here as the platform thread
599     // is the GPU thread.
600     gpu_task();
601   }
602 }
603 
604 // |PlatformView::Delegate|
OnPlatformViewDestroyed()605 void Shell::OnPlatformViewDestroyed() {
606   TRACE_EVENT0("flutter", "Shell::OnPlatformViewDestroyed");
607   FML_DCHECK(is_setup_);
608   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
609 
610   // Note:
611   // This is a synchronous operation because certain platforms depend on
612   // setup/suspension of all activities that may be interacting with the GPU in
613   // a synchronous fashion.
614 
615   fml::AutoResetWaitableEvent latch;
616 
617   auto io_task = [io_manager = io_manager_.get(), &latch]() {
618     // Execute any pending Skia object deletions while GPU access is still
619     // allowed.
620     io_manager->GetSkiaUnrefQueue()->Drain();
621     // Step 3: All done. Signal the latch that the platform thread is waiting
622     // on.
623     latch.Signal();
624   };
625 
626   auto gpu_task = [rasterizer = rasterizer_->GetWeakPtr(),
627                    io_task_runner = task_runners_.GetIOTaskRunner(),
628                    io_task]() {
629     if (rasterizer) {
630       rasterizer->Teardown();
631     }
632     // Step 2: Next, tell the IO thread to complete its remaining work.
633     fml::TaskRunner::RunNowOrPostTask(io_task_runner, io_task);
634   };
635 
636   // The normal flow executed by this method is that the platform thread is
637   // starting the sequence and waiting on the latch. Later the UI thread posts
638   // gpu_task to the GPU thread triggers signaling the latch(on the IO thread).
639   // If the GPU the and platform threads are the same this results in a deadlock
640   // as the gpu_task will never be posted to the plaform/gpu thread that is
641   // blocked on a latch.  To avoid the described deadlock, if the gpu and the
642   // platform threads are the same, should_post_gpu_task will be false, and then
643   // instead of posting a task to the gpu thread, the ui thread just signals the
644   // latch and the platform/gpu thread follows with executing gpu_task.
645   bool should_post_gpu_task =
646       task_runners_.GetGPUTaskRunner() != task_runners_.GetPlatformTaskRunner();
647 
648   auto ui_task = [engine = engine_->GetWeakPtr(),
649                   gpu_task_runner = task_runners_.GetGPUTaskRunner(), gpu_task,
650                   should_post_gpu_task, &latch]() {
651     if (engine) {
652       engine->OnOutputSurfaceDestroyed();
653     }
654     // Step 1: Next, tell the GPU thread that its rasterizer should suspend
655     // access to the underlying surface.
656     if (should_post_gpu_task) {
657       fml::TaskRunner::RunNowOrPostTask(gpu_task_runner, gpu_task);
658     } else {
659       // See comment on should_post_gpu_task, in this case we just unblock
660       // the platform thread.
661       latch.Signal();
662     }
663   };
664 
665   // Step 0: Post a task onto the UI thread to tell the engine that its output
666   // surface is about to go away.
667   fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(), ui_task);
668   latch.Wait();
669   if (!should_post_gpu_task) {
670     // See comment on should_post_gpu_task, in this case the gpu_task
671     // wasn't executed, and we just run it here as the platform thread
672     // is the GPU thread.
673     gpu_task();
674     latch.Wait();
675   }
676 }
677 
678 // |PlatformView::Delegate|
OnPlatformViewSetViewportMetrics(const ViewportMetrics & metrics)679 void Shell::OnPlatformViewSetViewportMetrics(const ViewportMetrics& metrics) {
680   FML_DCHECK(is_setup_);
681   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
682 
683   // This is the formula Android uses.
684   // https://android.googlesource.com/platform/frameworks/base/+/master/libs/hwui/renderthread/CacheManager.cpp#41
685   size_t max_bytes = metrics.physical_width * metrics.physical_height * 12 * 4;
686   task_runners_.GetGPUTaskRunner()->PostTask(
687       [rasterizer = rasterizer_->GetWeakPtr(), max_bytes] {
688         if (rasterizer) {
689           rasterizer->SetResourceCacheMaxBytes(max_bytes, false);
690         }
691       });
692 
693   task_runners_.GetUITaskRunner()->PostTask(
694       [engine = engine_->GetWeakPtr(), metrics]() {
695         if (engine) {
696           engine->SetViewportMetrics(metrics);
697         }
698       });
699 }
700 
701 // |PlatformView::Delegate|
OnPlatformViewDispatchPlatformMessage(fml::RefPtr<PlatformMessage> message)702 void Shell::OnPlatformViewDispatchPlatformMessage(
703     fml::RefPtr<PlatformMessage> message) {
704   FML_DCHECK(is_setup_);
705   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
706 
707   task_runners_.GetUITaskRunner()->PostTask(
708       [engine = engine_->GetWeakPtr(), message = std::move(message)] {
709         if (engine) {
710           engine->DispatchPlatformMessage(std::move(message));
711         }
712       });
713 }
714 
715 // |PlatformView::Delegate|
OnPlatformViewDispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet)716 void Shell::OnPlatformViewDispatchPointerDataPacket(
717     std::unique_ptr<PointerDataPacket> packet) {
718   TRACE_EVENT0("flutter", "Shell::OnPlatformViewDispatchPointerDataPacket");
719   TRACE_FLOW_BEGIN("flutter", "PointerEvent", next_pointer_flow_id_);
720   FML_DCHECK(is_setup_);
721   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
722   task_runners_.GetUITaskRunner()->PostTask(fml::MakeCopyable(
723       [engine = engine_->GetWeakPtr(), packet = std::move(packet),
724        flow_id = next_pointer_flow_id_] {
725         if (engine) {
726           engine->DispatchPointerDataPacket(*packet, flow_id);
727         }
728       }));
729   next_pointer_flow_id_++;
730 }
731 
732 // |PlatformView::Delegate|
OnPlatformViewDispatchSemanticsAction(int32_t id,SemanticsAction action,std::vector<uint8_t> args)733 void Shell::OnPlatformViewDispatchSemanticsAction(int32_t id,
734                                                   SemanticsAction action,
735                                                   std::vector<uint8_t> args) {
736   FML_DCHECK(is_setup_);
737   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
738 
739   task_runners_.GetUITaskRunner()->PostTask(
740       [engine = engine_->GetWeakPtr(), id, action, args = std::move(args)] {
741         if (engine) {
742           engine->DispatchSemanticsAction(id, action, std::move(args));
743         }
744       });
745 }
746 
747 // |PlatformView::Delegate|
OnPlatformViewSetSemanticsEnabled(bool enabled)748 void Shell::OnPlatformViewSetSemanticsEnabled(bool enabled) {
749   FML_DCHECK(is_setup_);
750   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
751 
752   task_runners_.GetUITaskRunner()->PostTask(
753       [engine = engine_->GetWeakPtr(), enabled] {
754         if (engine) {
755           engine->SetSemanticsEnabled(enabled);
756         }
757       });
758 }
759 
760 // |PlatformView::Delegate|
OnPlatformViewSetAccessibilityFeatures(int32_t flags)761 void Shell::OnPlatformViewSetAccessibilityFeatures(int32_t flags) {
762   FML_DCHECK(is_setup_);
763   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
764 
765   task_runners_.GetUITaskRunner()->PostTask(
766       [engine = engine_->GetWeakPtr(), flags] {
767         if (engine) {
768           engine->SetAccessibilityFeatures(flags);
769         }
770       });
771 }
772 
773 // |PlatformView::Delegate|
OnPlatformViewRegisterTexture(std::shared_ptr<flutter::Texture> texture)774 void Shell::OnPlatformViewRegisterTexture(
775     std::shared_ptr<flutter::Texture> texture) {
776   FML_DCHECK(is_setup_);
777   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
778 
779   task_runners_.GetGPUTaskRunner()->PostTask(
780       [rasterizer = rasterizer_->GetWeakPtr(), texture] {
781         if (rasterizer) {
782           if (auto* registry = rasterizer->GetTextureRegistry()) {
783             registry->RegisterTexture(texture);
784           }
785         }
786       });
787 }
788 
789 // |PlatformView::Delegate|
OnPlatformViewUnregisterTexture(int64_t texture_id)790 void Shell::OnPlatformViewUnregisterTexture(int64_t texture_id) {
791   FML_DCHECK(is_setup_);
792   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
793 
794   task_runners_.GetGPUTaskRunner()->PostTask(
795       [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() {
796         if (rasterizer) {
797           if (auto* registry = rasterizer->GetTextureRegistry()) {
798             registry->UnregisterTexture(texture_id);
799           }
800         }
801       });
802 }
803 
804 // |PlatformView::Delegate|
OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id)805 void Shell::OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id) {
806   FML_DCHECK(is_setup_);
807   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
808 
809   // Tell the rasterizer that one of its textures has a new frame available.
810   task_runners_.GetGPUTaskRunner()->PostTask(
811       [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() {
812         auto* registry = rasterizer->GetTextureRegistry();
813 
814         if (!registry) {
815           return;
816         }
817 
818         auto texture = registry->GetTexture(texture_id);
819 
820         if (!texture) {
821           return;
822         }
823 
824         texture->MarkNewFrameAvailable();
825       });
826 
827   // Schedule a new frame without having to rebuild the layer tree.
828   task_runners_.GetUITaskRunner()->PostTask([engine = engine_->GetWeakPtr()]() {
829     if (engine) {
830       engine->ScheduleFrame(false);
831     }
832   });
833 }
834 
835 // |PlatformView::Delegate|
OnPlatformViewSetNextFrameCallback(fml::closure closure)836 void Shell::OnPlatformViewSetNextFrameCallback(fml::closure closure) {
837   FML_DCHECK(is_setup_);
838   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
839 
840   task_runners_.GetGPUTaskRunner()->PostTask(
841       [rasterizer = rasterizer_->GetWeakPtr(), closure = std::move(closure)]() {
842         if (rasterizer) {
843           rasterizer->SetNextFrameCallback(std::move(closure));
844         }
845       });
846 }
847 
848 // |Animator::Delegate|
OnAnimatorBeginFrame(fml::TimePoint frame_time)849 void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_time) {
850   FML_DCHECK(is_setup_);
851   FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
852 
853   if (engine_) {
854     engine_->BeginFrame(frame_time);
855   }
856 }
857 
858 // |Animator::Delegate|
OnAnimatorNotifyIdle(int64_t deadline)859 void Shell::OnAnimatorNotifyIdle(int64_t deadline) {
860   FML_DCHECK(is_setup_);
861   FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
862 
863   if (engine_) {
864     engine_->NotifyIdle(deadline);
865   }
866 }
867 
868 // |Animator::Delegate|
OnAnimatorDraw(fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline)869 void Shell::OnAnimatorDraw(fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline) {
870   FML_DCHECK(is_setup_);
871 
872   task_runners_.GetGPUTaskRunner()->PostTask(
873       [& waiting_for_first_frame = waiting_for_first_frame_,
874        &waiting_for_first_frame_condition = waiting_for_first_frame_condition_,
875        rasterizer = rasterizer_->GetWeakPtr(),
876        pipeline = std::move(pipeline)]() {
877         if (rasterizer) {
878           rasterizer->Draw(pipeline);
879 
880           if (waiting_for_first_frame.load()) {
881             waiting_for_first_frame.store(false);
882             waiting_for_first_frame_condition.notify_all();
883           }
884         }
885       });
886 }
887 
888 // |Animator::Delegate|
OnAnimatorDrawLastLayerTree()889 void Shell::OnAnimatorDrawLastLayerTree() {
890   FML_DCHECK(is_setup_);
891 
892   task_runners_.GetGPUTaskRunner()->PostTask(
893       [rasterizer = rasterizer_->GetWeakPtr()]() {
894         if (rasterizer) {
895           rasterizer->DrawLastLayerTree();
896         }
897       });
898 }
899 
900 // |Engine::Delegate|
OnEngineUpdateSemantics(SemanticsNodeUpdates update,CustomAccessibilityActionUpdates actions)901 void Shell::OnEngineUpdateSemantics(SemanticsNodeUpdates update,
902                                     CustomAccessibilityActionUpdates actions) {
903   FML_DCHECK(is_setup_);
904   FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
905 
906   task_runners_.GetPlatformTaskRunner()->PostTask(
907       [view = platform_view_->GetWeakPtr(), update = std::move(update),
908        actions = std::move(actions)] {
909         if (view) {
910           view->UpdateSemantics(std::move(update), std::move(actions));
911         }
912       });
913 }
914 
915 // |Engine::Delegate|
OnEngineHandlePlatformMessage(fml::RefPtr<PlatformMessage> message)916 void Shell::OnEngineHandlePlatformMessage(
917     fml::RefPtr<PlatformMessage> message) {
918   FML_DCHECK(is_setup_);
919   FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
920 
921   if (message->channel() == kSkiaChannel) {
922     HandleEngineSkiaMessage(std::move(message));
923     return;
924   }
925 
926   task_runners_.GetPlatformTaskRunner()->PostTask(
927       [view = platform_view_->GetWeakPtr(), message = std::move(message)]() {
928         if (view) {
929           view->HandlePlatformMessage(std::move(message));
930         }
931       });
932 }
933 
HandleEngineSkiaMessage(fml::RefPtr<PlatformMessage> message)934 void Shell::HandleEngineSkiaMessage(fml::RefPtr<PlatformMessage> message) {
935   const auto& data = message->data();
936 
937   rapidjson::Document document;
938   document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
939   if (document.HasParseError() || !document.IsObject())
940     return;
941   auto root = document.GetObject();
942   auto method = root.FindMember("method");
943   if (method->value != "Skia.setResourceCacheMaxBytes")
944     return;
945   auto args = root.FindMember("args");
946   if (args == root.MemberEnd() || !args->value.IsInt())
947     return;
948 
949   task_runners_.GetGPUTaskRunner()->PostTask(
950       [rasterizer = rasterizer_->GetWeakPtr(), max_bytes = args->value.GetInt(),
951        response = std::move(message->response())] {
952         if (rasterizer) {
953           rasterizer->SetResourceCacheMaxBytes(static_cast<size_t>(max_bytes),
954                                                true);
955         }
956         if (response) {
957           response->CompleteEmpty();
958         }
959       });
960 }
961 
962 // |Engine::Delegate|
OnPreEngineRestart()963 void Shell::OnPreEngineRestart() {
964   FML_DCHECK(is_setup_);
965   FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
966 
967   fml::AutoResetWaitableEvent latch;
968   fml::TaskRunner::RunNowOrPostTask(
969       task_runners_.GetPlatformTaskRunner(),
970       [view = platform_view_->GetWeakPtr(), &latch]() {
971         if (view) {
972           view->OnPreEngineRestart();
973         }
974         latch.Signal();
975       });
976   // This is blocking as any embedded platform views has to be flushed before
977   // we re-run the Dart code.
978   latch.Wait();
979 }
980 
981 // |Engine::Delegate|
UpdateIsolateDescription(const std::string isolate_name,int64_t isolate_port)982 void Shell::UpdateIsolateDescription(const std::string isolate_name,
983                                      int64_t isolate_port) {
984   Handler::Description description(isolate_port, isolate_name);
985   vm_->GetServiceProtocol()->SetHandlerDescription(this, description);
986 }
987 
SetNeedsReportTimings(bool value)988 void Shell::SetNeedsReportTimings(bool value) {
989   needs_report_timings_ = value;
990 }
991 
ReportTimings()992 void Shell::ReportTimings() {
993   FML_DCHECK(is_setup_);
994   FML_DCHECK(task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread());
995 
996   auto timings = std::move(unreported_timings_);
997   unreported_timings_ = {};
998   task_runners_.GetUITaskRunner()->PostTask([timings, engine = weak_engine_] {
999     if (engine) {
1000       engine->ReportTimings(std::move(timings));
1001     }
1002   });
1003 }
1004 
UnreportedFramesCount() const1005 size_t Shell::UnreportedFramesCount() const {
1006   // Check that this is running on the GPU thread to avoid race conditions.
1007   FML_DCHECK(task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread());
1008   FML_DCHECK(unreported_timings_.size() % FrameTiming::kCount == 0);
1009   return unreported_timings_.size() / FrameTiming::kCount;
1010 }
1011 
OnFrameRasterized(const FrameTiming & timing)1012 void Shell::OnFrameRasterized(const FrameTiming& timing) {
1013   FML_DCHECK(is_setup_);
1014   FML_DCHECK(task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread());
1015 
1016   // The C++ callback defined in settings.h and set by Flutter runner. This is
1017   // independent of the timings report to the Dart side.
1018   if (settings_.frame_rasterized_callback) {
1019     settings_.frame_rasterized_callback(timing);
1020   }
1021 
1022   if (!needs_report_timings_) {
1023     return;
1024   }
1025 
1026   for (auto phase : FrameTiming::kPhases) {
1027     unreported_timings_.push_back(
1028         timing.Get(phase).ToEpochDelta().ToMicroseconds());
1029   }
1030 
1031   // In tests using iPhone 6S with profile mode, sending a batch of 1 frame or a
1032   // batch of 100 frames have roughly the same cost of less than 0.1ms. Sending
1033   // a batch of 500 frames costs about 0.2ms. The 1 second threshold usually
1034   // kicks in before we reaching the following 100 frames threshold. The 100
1035   // threshold here is mainly for unit tests (so we don't have to write a
1036   // 1-second unit test), and make sure that our vector won't grow too big with
1037   // future 120fps, 240fps, or 1000fps displays.
1038   //
1039   // In the profile/debug mode, the timings are used by development tools which
1040   // require a latency of no more than 100ms. Hence we lower that 1-second
1041   // threshold to 100ms because performance overhead isn't that critical in
1042   // those cases.
1043   if (!first_frame_rasterized_ || UnreportedFramesCount() >= 100) {
1044     first_frame_rasterized_ = true;
1045     ReportTimings();
1046   } else if (!frame_timings_report_scheduled_) {
1047 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE
1048     constexpr int kBatchTimeInMilliseconds = 1000;
1049 #else
1050     constexpr int kBatchTimeInMilliseconds = 100;
1051 #endif
1052 
1053     // Also make sure that frame times get reported with a max latency of 1
1054     // second. Otherwise, the timings of last few frames of an animation may
1055     // never be reported until the next animation starts.
1056     frame_timings_report_scheduled_ = true;
1057     task_runners_.GetGPUTaskRunner()->PostDelayedTask(
1058         [self = weak_factory_.GetWeakPtr()]() {
1059           if (!self.get()) {
1060             return;
1061           }
1062           self->frame_timings_report_scheduled_ = false;
1063           if (self->UnreportedFramesCount() > 0) {
1064             self->ReportTimings();
1065           }
1066         },
1067         fml::TimeDelta::FromMilliseconds(kBatchTimeInMilliseconds));
1068   }
1069 }
1070 
1071 // |ServiceProtocol::Handler|
GetServiceProtocolHandlerTaskRunner(std::string_view method) const1072 fml::RefPtr<fml::TaskRunner> Shell::GetServiceProtocolHandlerTaskRunner(
1073     std::string_view method) const {
1074   FML_DCHECK(is_setup_);
1075   auto found = service_protocol_handlers_.find(method);
1076   if (found != service_protocol_handlers_.end()) {
1077     return found->second.first;
1078   }
1079   return task_runners_.GetUITaskRunner();
1080 }
1081 
1082 // |ServiceProtocol::Handler|
HandleServiceProtocolMessage(std::string_view method,const ServiceProtocolMap & params,rapidjson::Document & response)1083 bool Shell::HandleServiceProtocolMessage(
1084     std::string_view method,  // one if the extension names specified above.
1085     const ServiceProtocolMap& params,
1086     rapidjson::Document& response) {
1087   auto found = service_protocol_handlers_.find(method);
1088   if (found != service_protocol_handlers_.end()) {
1089     return found->second.second(params, response);
1090   }
1091   return false;
1092 }
1093 
1094 // |ServiceProtocol::Handler|
GetServiceProtocolDescription() const1095 ServiceProtocol::Handler::Description Shell::GetServiceProtocolDescription()
1096     const {
1097   return {
1098       engine_->GetUIIsolateMainPort(),
1099       engine_->GetUIIsolateName(),
1100   };
1101 }
1102 
ServiceProtocolParameterError(rapidjson::Document & response,std::string error_details)1103 static void ServiceProtocolParameterError(rapidjson::Document& response,
1104                                           std::string error_details) {
1105   auto& allocator = response.GetAllocator();
1106   response.SetObject();
1107   const int64_t kInvalidParams = -32602;
1108   response.AddMember("code", kInvalidParams, allocator);
1109   response.AddMember("message", "Invalid params", allocator);
1110   {
1111     rapidjson::Value details(rapidjson::kObjectType);
1112     details.AddMember("details", error_details, allocator);
1113     response.AddMember("data", details, allocator);
1114   }
1115 }
1116 
ServiceProtocolFailureError(rapidjson::Document & response,std::string message)1117 static void ServiceProtocolFailureError(rapidjson::Document& response,
1118                                         std::string message) {
1119   auto& allocator = response.GetAllocator();
1120   response.SetObject();
1121   const int64_t kJsonServerError = -32000;
1122   response.AddMember("code", kJsonServerError, allocator);
1123   response.AddMember("message", message, allocator);
1124 }
1125 
1126 // Service protocol handler
OnServiceProtocolScreenshot(const ServiceProtocol::Handler::ServiceProtocolMap & params,rapidjson::Document & response)1127 bool Shell::OnServiceProtocolScreenshot(
1128     const ServiceProtocol::Handler::ServiceProtocolMap& params,
1129     rapidjson::Document& response) {
1130   FML_DCHECK(task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread());
1131   auto screenshot = rasterizer_->ScreenshotLastLayerTree(
1132       Rasterizer::ScreenshotType::CompressedImage, true);
1133   if (screenshot.data) {
1134     response.SetObject();
1135     auto& allocator = response.GetAllocator();
1136     response.AddMember("type", "Screenshot", allocator);
1137     rapidjson::Value image;
1138     image.SetString(static_cast<const char*>(screenshot.data->data()),
1139                     screenshot.data->size(), allocator);
1140     response.AddMember("screenshot", image, allocator);
1141     return true;
1142   }
1143   ServiceProtocolFailureError(response, "Could not capture image screenshot.");
1144   return false;
1145 }
1146 
1147 // Service protocol handler
OnServiceProtocolScreenshotSKP(const ServiceProtocol::Handler::ServiceProtocolMap & params,rapidjson::Document & response)1148 bool Shell::OnServiceProtocolScreenshotSKP(
1149     const ServiceProtocol::Handler::ServiceProtocolMap& params,
1150     rapidjson::Document& response) {
1151   FML_DCHECK(task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread());
1152   auto screenshot = rasterizer_->ScreenshotLastLayerTree(
1153       Rasterizer::ScreenshotType::SkiaPicture, true);
1154   if (screenshot.data) {
1155     response.SetObject();
1156     auto& allocator = response.GetAllocator();
1157     response.AddMember("type", "ScreenshotSkp", allocator);
1158     rapidjson::Value skp;
1159     skp.SetString(static_cast<const char*>(screenshot.data->data()),
1160                   screenshot.data->size(), allocator);
1161     response.AddMember("skp", skp, allocator);
1162     return true;
1163   }
1164   ServiceProtocolFailureError(response, "Could not capture SKP screenshot.");
1165   return false;
1166 }
1167 
1168 // Service protocol handler
OnServiceProtocolRunInView(const ServiceProtocol::Handler::ServiceProtocolMap & params,rapidjson::Document & response)1169 bool Shell::OnServiceProtocolRunInView(
1170     const ServiceProtocol::Handler::ServiceProtocolMap& params,
1171     rapidjson::Document& response) {
1172   FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
1173 
1174   if (params.count("mainScript") == 0) {
1175     ServiceProtocolParameterError(response,
1176                                   "'mainScript' parameter is missing.");
1177     return false;
1178   }
1179 
1180   // TODO(chinmaygarde): In case of hot-reload from .dill files, the packages
1181   // file is ignored. Currently, the tool is passing a junk packages file to
1182   // pass this check. Update the service protocol interface and remove this
1183   // workaround.
1184   if (params.count("packagesFile") == 0) {
1185     ServiceProtocolParameterError(response,
1186                                   "'packagesFile' parameter is missing.");
1187     return false;
1188   }
1189 
1190   if (params.count("assetDirectory") == 0) {
1191     ServiceProtocolParameterError(response,
1192                                   "'assetDirectory' parameter is missing.");
1193     return false;
1194   }
1195 
1196   std::string main_script_path =
1197       fml::paths::FromURI(params.at("mainScript").data());
1198   std::string packages_path =
1199       fml::paths::FromURI(params.at("packagesFile").data());
1200   std::string asset_directory_path =
1201       fml::paths::FromURI(params.at("assetDirectory").data());
1202 
1203   auto main_script_file_mapping =
1204       std::make_unique<fml::FileMapping>(fml::OpenFile(
1205           main_script_path.c_str(), false, fml::FilePermission::kRead));
1206 
1207   auto isolate_configuration = IsolateConfiguration::CreateForKernel(
1208       std::move(main_script_file_mapping));
1209 
1210   RunConfiguration configuration(std::move(isolate_configuration));
1211 
1212   configuration.AddAssetResolver(
1213       std::make_unique<DirectoryAssetBundle>(fml::OpenDirectory(
1214           asset_directory_path.c_str(), false, fml::FilePermission::kRead)));
1215 
1216   auto& allocator = response.GetAllocator();
1217   response.SetObject();
1218   if (engine_->Restart(std::move(configuration))) {
1219     response.AddMember("type", "Success", allocator);
1220     auto new_description = GetServiceProtocolDescription();
1221     rapidjson::Value view(rapidjson::kObjectType);
1222     new_description.Write(this, view, allocator);
1223     response.AddMember("view", view, allocator);
1224     return true;
1225   } else {
1226     FML_DLOG(ERROR) << "Could not run configuration in engine.";
1227     ServiceProtocolFailureError(response,
1228                                 "Could not run configuration in engine.");
1229     return false;
1230   }
1231 
1232   FML_DCHECK(false);
1233   return false;
1234 }
1235 
1236 // Service protocol handler
OnServiceProtocolFlushUIThreadTasks(const ServiceProtocol::Handler::ServiceProtocolMap & params,rapidjson::Document & response)1237 bool Shell::OnServiceProtocolFlushUIThreadTasks(
1238     const ServiceProtocol::Handler::ServiceProtocolMap& params,
1239     rapidjson::Document& response) {
1240   FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
1241   // This API should not be invoked by production code.
1242   // It can potentially starve the service isolate if the main isolate pauses
1243   // at a breakpoint or is in an infinite loop.
1244   //
1245   // It should be invoked from the VM Service and and blocks it until UI thread
1246   // tasks are processed.
1247   response.SetObject();
1248   response.AddMember("type", "Success", response.GetAllocator());
1249   return true;
1250 }
1251 
OnServiceProtocolGetDisplayRefreshRate(const ServiceProtocol::Handler::ServiceProtocolMap & params,rapidjson::Document & response)1252 bool Shell::OnServiceProtocolGetDisplayRefreshRate(
1253     const ServiceProtocol::Handler::ServiceProtocolMap& params,
1254     rapidjson::Document& response) {
1255   FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
1256   response.SetObject();
1257   response.AddMember("fps", engine_->GetDisplayRefreshRate(),
1258                      response.GetAllocator());
1259   return true;
1260 }
1261 
1262 // Service protocol handler
OnServiceProtocolSetAssetBundlePath(const ServiceProtocol::Handler::ServiceProtocolMap & params,rapidjson::Document & response)1263 bool Shell::OnServiceProtocolSetAssetBundlePath(
1264     const ServiceProtocol::Handler::ServiceProtocolMap& params,
1265     rapidjson::Document& response) {
1266   FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
1267 
1268   if (params.count("assetDirectory") == 0) {
1269     ServiceProtocolParameterError(response,
1270                                   "'assetDirectory' parameter is missing.");
1271     return false;
1272   }
1273 
1274   auto& allocator = response.GetAllocator();
1275   response.SetObject();
1276 
1277   auto asset_manager = std::make_shared<AssetManager>();
1278 
1279   asset_manager->PushFront(std::make_unique<DirectoryAssetBundle>(
1280       fml::OpenDirectory(params.at("assetDirectory").data(), false,
1281                          fml::FilePermission::kRead)));
1282 
1283   if (engine_->UpdateAssetManager(std::move(asset_manager))) {
1284     response.AddMember("type", "Success", allocator);
1285     auto new_description = GetServiceProtocolDescription();
1286     rapidjson::Value view(rapidjson::kObjectType);
1287     new_description.Write(this, view, allocator);
1288     response.AddMember("view", view, allocator);
1289     return true;
1290   } else {
1291     FML_DLOG(ERROR) << "Could not update asset directory.";
1292     ServiceProtocolFailureError(response, "Could not update asset directory.");
1293     return false;
1294   }
1295 
1296   FML_DCHECK(false);
1297   return false;
1298 }
1299 
Screenshot(Rasterizer::ScreenshotType screenshot_type,bool base64_encode)1300 Rasterizer::Screenshot Shell::Screenshot(
1301     Rasterizer::ScreenshotType screenshot_type,
1302     bool base64_encode) {
1303   TRACE_EVENT0("flutter", "Shell::Screenshot");
1304   fml::AutoResetWaitableEvent latch;
1305   Rasterizer::Screenshot screenshot;
1306   fml::TaskRunner::RunNowOrPostTask(
1307       task_runners_.GetGPUTaskRunner(), [&latch,                        //
1308                                          rasterizer = GetRasterizer(),  //
1309                                          &screenshot,                   //
1310                                          screenshot_type,               //
1311                                          base64_encode                  //
1312   ]() {
1313         if (rasterizer) {
1314           screenshot = rasterizer->ScreenshotLastLayerTree(screenshot_type,
1315                                                            base64_encode);
1316         }
1317         latch.Signal();
1318       });
1319   latch.Wait();
1320   return screenshot;
1321 }
1322 
WaitForFirstFrame(fml::TimeDelta timeout)1323 fml::Status Shell::WaitForFirstFrame(fml::TimeDelta timeout) {
1324   FML_DCHECK(is_setup_);
1325   if (task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread() ||
1326       task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread()) {
1327     return fml::Status(fml::StatusCode::kFailedPrecondition,
1328                        "WaitForFirstFrame called from thread that can't wait "
1329                        "because it is responsible for generating the frame.");
1330   }
1331 
1332   std::unique_lock<std::mutex> lock(waiting_for_first_frame_mutex_);
1333   bool success = waiting_for_first_frame_condition_.wait_for(
1334       lock, std::chrono::milliseconds(timeout.ToMilliseconds()),
1335       [& waiting_for_first_frame = waiting_for_first_frame_] {
1336         return !waiting_for_first_frame.load();
1337       });
1338   if (success) {
1339     return fml::Status();
1340   } else {
1341     return fml::Status(fml::StatusCode::kDeadlineExceeded, "timeout");
1342   }
1343 }
1344 
1345 }  // namespace flutter
1346