• 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 // 2021.2.10 Framework adapted to ACE.
5 //           Copyright (c) 2021 Huawei Device Co., Ltd. All rights reserved.
6 
7 #define RAPIDJSON_HAS_STDSTRING 1
8 #include "flutter/shell/common/shell.h"
9 
10 #include <memory>
11 #include <sstream>
12 #include <vector>
13 
14 #include "flutter/assets/directory_asset_bundle.h"
15 #include "flutter/fml/file.h"
16 #include "flutter/fml/icu_util.h"
17 #include "flutter/fml/log_settings.h"
18 #include "flutter/fml/logging.h"
19 #include "flutter/fml/make_copyable.h"
20 #include "flutter/fml/message_loop.h"
21 #include "flutter/fml/paths.h"
22 #include "flutter/fml/trace_event.h"
23 #include "flutter/fml/unique_fd.h"
24 #include "flutter/lib/ui/text/font_collection.h"
25 #include "flutter/lib/ui/ui_dart_state.h"
26 #include "flutter/lib/ui/window/window.h"
27 #include "flutter/runtime/start_up.h"
28 #include "flutter/shell/common/engine.h"
29 #include "flutter/shell/common/persistent_cache.h"
30 #include "flutter/shell/common/skia_event_tracer_impl.h"
31 #include "flutter/shell/common/switches.h"
32 #include "flutter/shell/common/vsync_waiter.h"
33 #include "third_party/skia/include/core/SkGraphics.h"
34 
35 namespace {
36 
37 /**
38  * Preload font collection for accelerate text layout.
39  *
40  * txt::FontCollection uses font_collections_cache_ to cache minikin::FontCollection.
41  * ParagraphTxt::Layout will calling `getFamilyForChar` for every character. While first encountering
42  * characters like Chinese, a fallback will occured. So manually fallback.
43  */
FontCollectionPreload(flutter::Window * window)44 void FontCollectionPreload(flutter::Window* window) {
45   if (window && window->client()) {
46     window->client()->GetFontCollection().GetFontCollection();
47   }
48 }
49 
50 }  // namespace
51 
52 namespace flutter {
53 
54 constexpr char kSkiaChannel[] = "flutter/skia";
55 
CreateShellOnPlatformThread(TaskRunners task_runners,Settings settings,Shell::CreateCallback<PlatformView> on_create_platform_view,Shell::CreateCallback<Rasterizer> on_create_rasterizer)56 std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
57     TaskRunners task_runners,
58     Settings settings,
59     Shell::CreateCallback<PlatformView> on_create_platform_view,
60     Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
61   if (!task_runners.IsValid()) {
62     FML_LOG(ERROR) << "Task runners to run the shell were invalid.";
63     return nullptr;
64   }
65 
66   auto shell =
67       std::unique_ptr<Shell>(new Shell(task_runners, settings));
68 
69   // Create the platform view on the platform thread (this thread).
70   auto platform_view = on_create_platform_view(*shell.get());
71   if (!platform_view || !platform_view->GetWeakPtr()) {
72     return nullptr;
73   }
74 
75   // Ask the platform view for the vsync waiter. This will be used by the engine
76   // to create the animator.
77   auto vsync_waiter = platform_view->CreateVSyncWaiter(static_cast<int32_t>(settings.platform));
78   if (!vsync_waiter) {
79     return nullptr;
80   }
81 
82   // Create the IO manager on the IO thread. The IO manager must be initialized
83   // first because it has state that the other subsystems depend on. It must
84   // first be booted and the necessary references obtained to initialize the
85   // other subsystems.
86   fml::AutoResetWaitableEvent io_latch;
87   std::unique_ptr<ShellIOManager> io_manager;
88   auto io_task_runner = shell->GetTaskRunners().GetIOTaskRunner();
89   fml::TaskRunner::RunNowOrPostTask(
90       io_task_runner,
91       [&io_latch,       //
92        &io_manager,     //
93        &platform_view,  //
94        io_task_runner   //
95   ]() {
96         TRACE_EVENT0("flutter", "ShellSetupIOSubsystem");
97         io_manager = std::make_unique<ShellIOManager>(
98             platform_view->CreateResourceContext(), io_task_runner);
99         io_latch.Signal();
100       });
101   io_latch.Wait();
102 
103   // Create the rasterizer on the GPU thread.
104   fml::AutoResetWaitableEvent gpu_latch;
105   std::unique_ptr<Rasterizer> rasterizer;
106   fml::TaskRunner::RunNowOrPostTask(
107       task_runners.GetGPUTaskRunner(), [&gpu_latch,            //
108                                         &rasterizer,           //
109                                         on_create_rasterizer,  //
110                                         shell = shell.get()    //
111   ]() {
112         TRACE_EVENT0("flutter", "ShellSetupGPUSubsystem");
113         if (auto new_rasterizer = on_create_rasterizer(*shell)) {
114           rasterizer = std::move(new_rasterizer);
115         }
116         gpu_latch.Signal();
117       });
118 
119   gpu_latch.Wait();
120 
121   // Create the engine on the UI thread.
122   fml::AutoResetWaitableEvent ui_latch;
123   std::unique_ptr<Engine> engine;
124 
125   Window* window = nullptr;
126   fml::TaskRunner::RunNowOrPostTask(
127       shell->GetTaskRunners().GetUITaskRunner(),
128       fml::MakeCopyable([&ui_latch,                                       //
129                          &engine,                                         //
130                          shell = shell.get(),                             //
131                          vsync_waiter = std::move(vsync_waiter),          //
132                          io_manager = io_manager->GetWeakPtr(),           //
133                          &window
134   ]() mutable {
135         TRACE_EVENT0("flutter", "ShellSetupUISubsystem");
136         const auto& task_runners = shell->GetTaskRunners();
137 
138         // The animator is owned by the UI thread but it gets its vsync pulses
139         // from the platform.
140         auto animator = std::make_unique<Animator>(*shell, task_runners,
141                                                    std::move(vsync_waiter));
142 
143         engine = std::make_unique<Engine>(*shell,                       //
144                                           task_runners,                 //
145                                           shell->GetSettings(),         //
146                                           std::move(animator),          //
147                                           std::move(io_manager)         //
148         );
149         // Window is inited in Engine construction.
150         window = flutter::UIDartState::Current()->window();
151         ui_latch.Signal();
152       }));
153 
154   ui_latch.Wait();
155 
156   fml::TaskRunner::RunNowOrPostTask(
157         io_task_runner,
158         [window]() {
159           TRACE_EVENT0("flutter", "FontCollectionPreload");
160           // Window mustn't be dangling because Engine must be destroyed after this task. See Shell~Shell().
161           FontCollectionPreload(window);
162         });
163 
164   // We are already on the platform thread. So there is no platform latch to
165   // wait on.
166 
167   if (!shell->Setup(std::move(platform_view),  //
168                     std::move(engine),         //
169                     std::move(rasterizer),     //
170                     std::move(io_manager))     //
171   ) {
172     return nullptr;
173   }
174 
175   return shell;
176 }
177 
RecordStartupTimestamp()178 static void RecordStartupTimestamp() {
179 }
180 
181 // Though there can be multiple shells, some settings apply to all components in
182 // the process. These have to be setup before the shell or any of its
183 // sub-components can be initialized. In a perfect world, this would be empty.
184 // TODO(chinmaygarde): The unfortunate side effect of this call is that settings
185 // that cause shell initialization failures will still lead to some of their
186 // settings being applied.
PerformInitializationTasks(const Settings & settings)187 static void PerformInitializationTasks(const Settings& settings) {
188   {
189     fml::LogSettings log_settings;
190     log_settings.min_log_level =
191         settings.verbose_logging ? fml::LOG_INFO : fml::LOG_ERROR;
192     fml::SetLogSettings(log_settings);
193   }
194 
195   static std::once_flag gShellSettingsInitialization = {};
196   std::call_once(gShellSettingsInitialization, [&settings] {
197     RecordStartupTimestamp();
198 
199     if (!settings.skia_deterministic_rendering_on_cpu) {
200       SkGraphics::Init();
201     } else {
202       FML_DLOG(INFO) << "Skia deterministic rendering is enabled.";
203     }
204 #ifdef ACE_MISSING
205     if (settings.icu_initialization_required) {
206       if (settings.icu_data_path.size() != 0) {
207         fml::icu::InitializeICU(settings.icu_data_path);
208       } else if (settings.icu_mapper) {
209         fml::icu::InitializeICUFromMapping(settings.icu_mapper());
210       } else {
211         FML_DLOG(WARNING) << "Skipping ICU initialization in the shell.";
212       }
213     }
214 #endif
215   });
216 }
217 
Create(TaskRunners task_runners,Settings settings,Shell::CreateCallback<PlatformView> on_create_platform_view,Shell::CreateCallback<Rasterizer> on_create_rasterizer)218 std::unique_ptr<Shell> Shell::Create(
219     TaskRunners task_runners,
220     Settings settings,
221     Shell::CreateCallback<PlatformView> on_create_platform_view,
222     Shell::CreateCallback<Rasterizer> on_create_rasterizer) {
223   PerformInitializationTasks(settings);
224 
225   TRACE_EVENT0("flutter", "Shell::CreateWithSnapshots");
226 
227   if (!task_runners.IsValid() || !on_create_platform_view ||
228       !on_create_rasterizer) {
229     return nullptr;
230   }
231 
232   fml::AutoResetWaitableEvent latch;
233   std::unique_ptr<Shell> shell;
234   fml::TaskRunner::RunNowOrPostTask(
235       task_runners.GetPlatformTaskRunner(),
236       fml::MakeCopyable([&latch,                                          //
237                          &shell,                                          //
238                          task_runners = std::move(task_runners),          //
239                          settings,                                        //
240                          on_create_platform_view,                         //
241                          on_create_rasterizer                             //
242   ]() mutable {
243         shell = CreateShellOnPlatformThread(std::move(task_runners),      //
244                                             settings,                     //
245                                             on_create_platform_view,      //
246                                             on_create_rasterizer          //
247         );
248         latch.Signal();
249       }));
250   latch.Wait();
251   return shell;
252 }
253 
Shell(TaskRunners task_runners,Settings settings)254 Shell::Shell(TaskRunners task_runners, Settings settings)
255     : task_runners_(std::move(task_runners)),
256       settings_(std::move(settings)),
257       weak_factory_(this) {
258   FML_DCHECK(task_runners_.IsValid());
259   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
260   // Install service protocol handlers.
261 }
262 
~Shell()263 Shell::~Shell() {
264   fml::AutoResetWaitableEvent ui_latch, gpu_latch, platform_latch, io_latch;
265 
266   // Wait for IO thread finishing all works before UI thread destroy because we preload FontCollection on IO.
267   fml::AutoResetWaitableEvent wait_io_latch;
268   fml::TaskRunner::RunNowOrPostTask(
269       task_runners_.GetIOTaskRunner(), [&wait_io_latch]() {
270         wait_io_latch.Signal();
271       });
272   wait_io_latch.Wait();
273 
274   fml::TaskRunner::RunNowOrPostTask(
275       task_runners_.GetUITaskRunner(),
276       fml::MakeCopyable([engine = std::move(engine_), &ui_latch]() mutable {
277         engine.reset();
278         ui_latch.Signal();
279       }));
280   ui_latch.Wait();
281 
282   fml::TaskRunner::RunNowOrPostTask(
283       task_runners_.GetGPUTaskRunner(),
284       fml::MakeCopyable(
285           [rasterizer = std::move(rasterizer_), &gpu_latch]() mutable {
286             rasterizer.reset();
287             gpu_latch.Signal();
288           }));
289   gpu_latch.Wait();
290 
291   fml::TaskRunner::RunNowOrPostTask(
292       task_runners_.GetIOTaskRunner(),
293       fml::MakeCopyable([io_manager = std::move(io_manager_),
294                          platform_view = platform_view_.get(),
295                          &io_latch]() mutable {
296         io_manager.reset();
297         if (platform_view) {
298           platform_view->ReleaseResourceContext();
299         }
300         io_latch.Signal();
301       }));
302 
303   io_latch.Wait();
304 
305   // The platform view must go last because it may be holding onto platform side
306   // counterparts to resources owned by subsystems running on other threads. For
307   // example, the NSOpenGLContext on the Mac.
308   fml::TaskRunner::RunNowOrPostTask(
309       task_runners_.GetPlatformTaskRunner(),
310       fml::MakeCopyable([platform_view = std::move(platform_view_),
311                          &platform_latch]() mutable {
312         platform_view.reset();
313         platform_latch.Signal();
314       }));
315   platform_latch.Wait();
316 }
317 
NotifyLowMemoryWarning() const318 void Shell::NotifyLowMemoryWarning() const {
319   task_runners_.GetGPUTaskRunner()->PostTask(
320       [rasterizer = rasterizer_->GetWeakPtr()]() {
321         if (rasterizer) {
322           rasterizer->NotifyLowMemoryWarning();
323         }
324       });
325   // The IO Manager uses resource cache limits of 0, so it is not necessary
326   // to purge them.
327 }
328 
RunEngine(RunConfiguration run_configuration)329 void Shell::RunEngine(RunConfiguration run_configuration) {
330   RunEngine(std::move(run_configuration), nullptr);
331 }
332 
RunEngine(RunConfiguration run_configuration,std::function<void (Engine::RunStatus)> result_callback)333 void Shell::RunEngine(RunConfiguration run_configuration,
334                       std::function<void(Engine::RunStatus)> result_callback) {
335   auto result = [platform_runner = task_runners_.GetPlatformTaskRunner(),
336                  result_callback](Engine::RunStatus run_result) {
337     if (!result_callback) {
338       return;
339     }
340     platform_runner->PostTask(
341         [result_callback, run_result]() { result_callback(run_result); });
342   };
343   FML_DCHECK(is_setup_);
344   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
345 
346   if (!weak_engine_) {
347     result(Engine::RunStatus::Failure);
348   }
349   fml::TaskRunner::RunNowOrPostTask(
350       task_runners_.GetUITaskRunner(),
351       fml::MakeCopyable(
352           [run_configuration = std::move(run_configuration),
353            weak_engine = weak_engine_, result]() mutable {
354             if (!weak_engine) {
355               FML_LOG(ERROR)
356                   << "Could not launch engine with configuration - no engine.";
357               result(Engine::RunStatus::Failure);
358               return;
359             }
360             auto run_result = weak_engine->Run(std::move(run_configuration));
361             if (run_result == flutter::Engine::RunStatus::Failure) {
362               FML_LOG(ERROR) << "Could not launch engine with configuration.";
363             }
364             result(run_result);
365           }));
366 }
367 
IsSetup() const368 bool Shell::IsSetup() const {
369   return is_setup_;
370 }
371 
Setup(std::unique_ptr<PlatformView> platform_view,std::unique_ptr<Engine> engine,std::unique_ptr<Rasterizer> rasterizer,std::unique_ptr<ShellIOManager> io_manager)372 bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
373                   std::unique_ptr<Engine> engine,
374                   std::unique_ptr<Rasterizer> rasterizer,
375                   std::unique_ptr<ShellIOManager> io_manager) {
376   if (is_setup_) {
377     return false;
378   }
379 
380   if (!platform_view || !engine || !rasterizer || !io_manager) {
381     return false;
382   }
383 
384   platform_view_ = std::move(platform_view);
385   engine_ = std::move(engine);
386   rasterizer_ = std::move(rasterizer);
387   io_manager_ = std::move(io_manager);
388 
389   // The weak ptr must be generated in the platform thread which owns the unique
390   // ptr.
391   weak_engine_ = engine_->GetWeakPtr();
392   weak_rasterizer_ = rasterizer_->GetWeakPtr();
393   weak_platform_view_ = platform_view_->GetWeakPtr();
394 
395   is_setup_ = true;
396 
397   return true;
398 }
399 
GetSettings() const400 const Settings& Shell::GetSettings() const {
401   return settings_;
402 }
403 
GetTaskRunners() const404 const TaskRunners& Shell::GetTaskRunners() const {
405   return task_runners_;
406 }
407 
GetRasterizer()408 fml::WeakPtr<Rasterizer> Shell::GetRasterizer() {
409   FML_DCHECK(is_setup_);
410   return weak_rasterizer_;
411 }
412 
413 // TODO(dnfield): Remove this when either Topaz is up to date or flutter_runner
414 // is built out of this repo.
415 #ifdef OS_FUCHSIA
GetEngine()416 fml::WeakPtr<Engine> Shell::GetEngine() {
417   FML_DCHECK(is_setup_);
418   return weak_engine_;
419 }
420 #endif  // OS_FUCHSIA
421 
GetPlatformView()422 fml::WeakPtr<PlatformView> Shell::GetPlatformView() {
423   FML_DCHECK(is_setup_);
424   return weak_platform_view_;
425 }
426 
427 // |PlatformView::Delegate|
OnPlatformViewCreated(std::unique_ptr<Surface> surface)428 void Shell::OnPlatformViewCreated(std::unique_ptr<Surface> surface) {
429   TRACE_EVENT0("flutter", "Shell::OnPlatformViewCreated");
430   FML_DCHECK(is_setup_);
431   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
432 
433   // Note:
434   // This is a synchronous operation because certain platforms depend on
435   // setup/suspension of all activities that may be interacting with the GPU in
436   // a synchronous fashion.
437   fml::AutoResetWaitableEvent latch;
438   auto gpu_task =
439       fml::MakeCopyable([& waiting_for_first_frame = waiting_for_first_frame_,
440                          rasterizer = rasterizer_->GetWeakPtr(),  //
441                          surface = std::move(surface),            //
442                          &latch]() mutable {
443         if (rasterizer) {
444           rasterizer->Setup(std::move(surface));
445         }
446 
447         waiting_for_first_frame.store(true);
448 
449         // Step 3: All done. Signal the latch that the platform thread is
450         // waiting on.
451         latch.Signal();
452       });
453 
454   // The normal flow executed by this method is that the platform thread is
455   // starting the sequence and waiting on the latch. Later the UI thread posts
456   // gpu_task to the GPU thread which signals the latch. If the GPU the and
457   // platform threads are the same this results in a deadlock as the gpu_task
458   // will never be posted to the plaform/gpu thread that is blocked on a latch.
459   // To avoid the described deadlock, if the gpu and the platform threads are
460   // the same, should_post_gpu_task will be false, and then instead of posting a
461   // task to the gpu thread, the ui thread just signals the latch and the
462   // platform/gpu thread follows with executing gpu_task.
463   bool should_post_gpu_task =
464       task_runners_.GetGPUTaskRunner() != task_runners_.GetPlatformTaskRunner();
465 
466   auto ui_task = [engine = engine_->GetWeakPtr()] {
467     if (engine) {
468       engine->OnOutputSurfaceCreated();
469     }
470   };
471 
472   // Threading: Capture platform view by raw pointer and not the weak pointer.
473   // We are going to use the pointer on the IO thread which is not safe with a
474   // weak pointer. However, we are preventing the platform view from being
475   // collected by using a latch.
476   auto* platform_view = platform_view_.get();
477 
478   FML_DCHECK(platform_view);
479 
480   auto io_task = [io_manager = io_manager_->GetWeakPtr(), platform_view,
481                   ui_task_runner = task_runners_.GetUITaskRunner(), ui_task,
482                   should_post_gpu_task, gpu_task_runner = task_runners_.GetGPUTaskRunner(),
483                   gpu_task, &latch] {
484     if (io_manager && !io_manager->GetResourceContext()) {
485       io_manager->NotifyResourceContextAvailable(
486           platform_view->CreateResourceContext());
487     }
488     // Step 1: Next, post a task on the UI thread to tell the engine that it has
489     // an output surface.
490     fml::TaskRunner::RunNowOrPostTask(ui_task_runner, ui_task);
491     // Step 2: Next, tell the GPU thread that it should create a surface for its
492     // rasterizer.
493     if (should_post_gpu_task) {
494       fml::TaskRunner::RunNowOrPostTask(gpu_task_runner, gpu_task);
495     } else {
496       // See comment on should_post_gpu_task, in this case we just unblock
497       // the platform thread.
498       latch.Signal();
499     }
500   };
501 
502   fml::TaskRunner::RunNowOrPostTask(task_runners_.GetIOTaskRunner(), io_task);
503 
504   latch.Wait();
505   if (!should_post_gpu_task) {
506     // See comment on should_post_gpu_task, in this case the gpu_task
507     // wasn't executed, and we just run it here as the platform thread
508     // is the GPU thread.
509     gpu_task();
510   }
511 }
512 
513 // |PlatformView::Delegate|
OnPlatformViewDestroyed()514 void Shell::OnPlatformViewDestroyed() {
515   TRACE_EVENT0("flutter", "Shell::OnPlatformViewDestroyed");
516   FML_DCHECK(is_setup_);
517   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
518 
519   // Note:
520   // This is a synchronous operation because certain platforms depend on
521   // setup/suspension of all activities that may be interacting with the GPU in
522   // a synchronous fashion.
523 
524   fml::AutoResetWaitableEvent latch;
525 
526   auto io_task = [io_manager = io_manager_.get(), &latch]() {
527     // Execute any pending Skia object deletions while GPU access is still
528     // allowed.
529     io_manager->GetSkiaUnrefQueue()->Drain();
530     // Step 3: All done. Signal the latch that the platform thread is waiting
531     // on.
532     latch.Signal();
533   };
534 
535   auto gpu_task = [rasterizer = rasterizer_->GetWeakPtr(),
536                    io_task_runner = task_runners_.GetIOTaskRunner(),
537                    io_task]() {
538     if (rasterizer) {
539       rasterizer->Teardown();
540     }
541     // Step 2: Next, tell the IO thread to complete its remaining work.
542     fml::TaskRunner::RunNowOrPostTask(io_task_runner, io_task);
543   };
544 
545   // The normal flow executed by this method is that the platform thread is
546   // starting the sequence and waiting on the latch. Later the UI thread posts
547   // gpu_task to the GPU thread triggers signaling the latch(on the IO thread).
548   // If the GPU the and platform threads are the same this results in a deadlock
549   // as the gpu_task will never be posted to the plaform/gpu thread that is
550   // blocked on a latch.  To avoid the described deadlock, if the gpu and the
551   // platform threads are the same, should_post_gpu_task will be false, and then
552   // instead of posting a task to the gpu thread, the ui thread just signals the
553   // latch and the platform/gpu thread follows with executing gpu_task.
554   bool should_post_gpu_task =
555       task_runners_.GetGPUTaskRunner() != task_runners_.GetPlatformTaskRunner();
556 
557   auto ui_task = [engine = engine_->GetWeakPtr(),
558                   gpu_task_runner = task_runners_.GetGPUTaskRunner(), gpu_task,
559                   should_post_gpu_task, &latch]() {
560     if (engine) {
561       engine->OnOutputSurfaceDestroyed();
562     }
563     // Step 1: Next, tell the GPU thread that its rasterizer should suspend
564     // access to the underlying surface.
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   // Step 0: Post a task onto the UI thread to tell the engine that its output
575   // surface is about to go away.
576   fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(), ui_task);
577   latch.Wait();
578   if (!should_post_gpu_task) {
579     // See comment on should_post_gpu_task, in this case the gpu_task
580     // wasn't executed, and we just run it here as the platform thread
581     // is the GPU thread.
582     gpu_task();
583     latch.Wait();
584   }
585 }
586 
587 // |PlatformView::Delegate|
OnSetIdleNotificationCallback(const Engine::IdleCallback & idleCallback)588 void Shell::OnSetIdleNotificationCallback(const Engine::IdleCallback& idleCallback) {
589     task_runners_.GetUITaskRunner()->PostTask(
590         [engine = engine_->GetWeakPtr(), idleCallback]() {
591           if (engine) {
592             engine->SetIdleNotificationCallback(idleCallback);
593           }
594         });
595 }
596 
597 // |PlatformView::Delegate|
OnPlatformViewSetViewportMetrics(const ViewportMetrics & metrics)598 void Shell::OnPlatformViewSetViewportMetrics(const ViewportMetrics& metrics) {
599   FML_DCHECK(is_setup_);
600   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
601 
602   // This is the formula Android uses.
603   // https://android.googlesource.com/platform/frameworks/base/+/master/libs/hwui/renderthread/CacheManager.cpp#41
604   size_t max_bytes = metrics.physical_width * metrics.physical_height * 12 * 4;
605   task_runners_.GetGPUTaskRunner()->PostTask(
606       [rasterizer = rasterizer_->GetWeakPtr(), max_bytes] {
607         if (rasterizer) {
608           rasterizer->SetResourceCacheMaxBytes(max_bytes, false);
609         }
610       });
611 
612   task_runners_.GetUITaskRunner()->PostTask(
613       [engine = engine_->GetWeakPtr(), metrics]() {
614         if (engine) {
615           engine->SetViewportMetrics(metrics);
616         }
617       });
618 }
619 
620 // |PlatformView::Delegate|
OnPlatformViewDispatchPlatformMessage(fml::RefPtr<PlatformMessage> message)621 void Shell::OnPlatformViewDispatchPlatformMessage(
622     fml::RefPtr<PlatformMessage> message) {
623   FML_DCHECK(is_setup_);
624   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
625 
626   task_runners_.GetUITaskRunner()->PostTask(
627       [engine = engine_->GetWeakPtr(), message = std::move(message)] {
628         if (engine) {
629           engine->DispatchPlatformMessage(std::move(message));
630         }
631       });
632 }
633 
634 // |PlatformView::Delegate|
OnPlatformViewDispatchPointerDataPacket(std::unique_ptr<PointerDataPacket> packet)635 void Shell::OnPlatformViewDispatchPointerDataPacket(
636     std::unique_ptr<PointerDataPacket> packet) {
637   TRACE_EVENT0("flutter", "Shell::OnPlatformViewDispatchPointerDataPacket");
638   TRACE_FLOW_BEGIN("flutter", "PointerEvent", next_pointer_flow_id_);
639   FML_DCHECK(is_setup_);
640   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
641   task_runners_.GetUITaskRunner()->PostTask(fml::MakeCopyable(
642       [engine = engine_->GetWeakPtr(), packet = std::move(packet),
643        flow_id = next_pointer_flow_id_] {
644         if (engine) {
645           engine->DispatchPointerDataPacket(*packet, flow_id);
646         }
647       }));
648   next_pointer_flow_id_++;
649 }
650 
651 // |PlatformView::Delegate|
OnPlatformViewRegisterTexture(std::shared_ptr<flutter::Texture> texture)652 void Shell::OnPlatformViewRegisterTexture(
653     std::shared_ptr<flutter::Texture> texture) {
654   FML_DCHECK(is_setup_);
655   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
656 
657   task_runners_.GetGPUTaskRunner()->PostTask(
658       [rasterizer = rasterizer_->GetWeakPtr(), texture] {
659         if (rasterizer) {
660           if (auto* registry = rasterizer->GetTextureRegistry()) {
661             registry->RegisterTexture(texture);
662           }
663         }
664       });
665 }
666 
667 // |PlatformView::Delegate|
OnPlatformViewUnregisterTexture(int64_t texture_id)668 void Shell::OnPlatformViewUnregisterTexture(int64_t texture_id) {
669   FML_DCHECK(is_setup_);
670   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
671 
672   task_runners_.GetGPUTaskRunner()->PostTask(
673       [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() {
674         if (rasterizer) {
675           if (auto* registry = rasterizer->GetTextureRegistry()) {
676             registry->UnregisterTexture(texture_id);
677           }
678         }
679       });
680 }
681 
682 // |PlatformView::Delegate|
OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id)683 void Shell::OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id) {
684   FML_DCHECK(is_setup_);
685   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
686 
687   // Tell the rasterizer that one of its textures has a new frame available.
688   task_runners_.GetGPUTaskRunner()->PostTask(
689       [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() {
690         auto* registry = rasterizer->GetTextureRegistry();
691 
692         if (!registry) {
693           return;
694         }
695 
696         auto texture = registry->GetTexture(texture_id);
697 
698         if (!texture) {
699           return;
700         }
701 
702         texture->MarkNewFrameAvailable();
703       });
704 
705   // Schedule a new frame without having to rebuild the layer tree.
706   task_runners_.GetUITaskRunner()->PostTask([engine = engine_->GetWeakPtr()]() {
707     if (engine) {
708       engine->ScheduleFrame(false);
709     }
710   });
711 }
712 
713 // |PlatformView::Delegate|
OnPlatformViewSetNextFrameCallback(fml::closure closure)714 void Shell::OnPlatformViewSetNextFrameCallback(fml::closure closure) {
715   FML_DCHECK(is_setup_);
716   FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
717 
718   task_runners_.GetGPUTaskRunner()->PostTask(
719       [rasterizer = rasterizer_->GetWeakPtr(), closure = std::move(closure)]() {
720         if (rasterizer) {
721           rasterizer->SetNextFrameCallback(std::move(closure));
722         }
723       });
724 }
725 
726 // |Animator::Delegate|
OnAnimatorBeginFrame(fml::TimePoint frame_time)727 void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_time) {
728   FML_DCHECK(is_setup_);
729   FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
730 
731   if (engine_) {
732     engine_->BeginFrame(frame_time);
733   }
734 }
735 
736 // |Animator::Delegate|
OnAnimatorNotifyIdle(int64_t deadline)737 void Shell::OnAnimatorNotifyIdle(int64_t deadline) {
738   FML_DCHECK(is_setup_);
739   FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
740 
741   if (engine_) {
742     engine_->NotifyIdle(deadline);
743   }
744 }
745 
746 // |Animator::Delegate|
OnAnimatorDraw(fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline)747 void Shell::OnAnimatorDraw(fml::RefPtr<Pipeline<flutter::LayerTree>> pipeline) {
748   FML_DCHECK(is_setup_);
749 
750   task_runners_.GetGPUTaskRunner()->PostTask(
751       [& waiting_for_first_frame = waiting_for_first_frame_,
752        &waiting_for_first_frame_condition = waiting_for_first_frame_condition_,
753        rasterizer = rasterizer_->GetWeakPtr(),
754        pipeline = std::move(pipeline)]() {
755         if (rasterizer) {
756           rasterizer->Draw(pipeline);
757 
758           if (waiting_for_first_frame.load()) {
759             waiting_for_first_frame.store(false);
760             waiting_for_first_frame_condition.notify_all();
761           }
762         }
763       });
764 }
765 
766 // |Animator::Delegate|
OnAnimatorDrawLastLayerTree()767 void Shell::OnAnimatorDrawLastLayerTree() {
768   FML_DCHECK(is_setup_);
769 
770   task_runners_.GetGPUTaskRunner()->PostTask(
771       [rasterizer = rasterizer_->GetWeakPtr()]() {
772         if (rasterizer) {
773           rasterizer->DrawLastLayerTree();
774         }
775       });
776 }
777 
778 // |Engine::Delegate|
OnEngineHandlePlatformMessage(fml::RefPtr<PlatformMessage> message)779 void Shell::OnEngineHandlePlatformMessage(
780     fml::RefPtr<PlatformMessage> message) {
781   FML_DCHECK(is_setup_);
782   FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
783 
784   if (message->channel() == kSkiaChannel) {
785     HandleEngineSkiaMessage(std::move(message));
786     return;
787   }
788 
789   task_runners_.GetPlatformTaskRunner()->PostTask(
790       [view = platform_view_->GetWeakPtr(), message = std::move(message)]() {
791         if (view) {
792           view->HandlePlatformMessage(std::move(message));
793         }
794       });
795 }
796 
HandleEngineSkiaMessage(fml::RefPtr<PlatformMessage> message)797 void Shell::HandleEngineSkiaMessage(fml::RefPtr<PlatformMessage> message) {
798 }
799 
800 // |Engine::Delegate|
OnPreEngineRestart()801 void Shell::OnPreEngineRestart() {
802   FML_DCHECK(is_setup_);
803   FML_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
804 
805   fml::AutoResetWaitableEvent latch;
806   fml::TaskRunner::RunNowOrPostTask(
807       task_runners_.GetPlatformTaskRunner(),
808       [view = platform_view_->GetWeakPtr(), &latch]() {
809         if (view) {
810           view->OnPreEngineRestart();
811         }
812         latch.Signal();
813       });
814   // This is blocking as any embedded platform views has to be flushed before
815   // we re-run the Dart code.
816   latch.Wait();
817 }
818 
SetNeedsReportTimings(bool value)819 void Shell::SetNeedsReportTimings(bool value) {
820   needs_report_timings_ = value;
821 }
822 
ReportTimings()823 void Shell::ReportTimings() {
824   FML_DCHECK(is_setup_);
825   FML_DCHECK(task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread());
826 
827   auto timings = std::move(unreported_timings_);
828   unreported_timings_ = {};
829   task_runners_.GetUITaskRunner()->PostTask([timings, engine = weak_engine_] {
830     if (engine) {
831       engine->ReportTimings(std::move(timings));
832     }
833   });
834 }
835 
UnreportedFramesCount() const836 size_t Shell::UnreportedFramesCount() const {
837   // Check that this is running on the GPU thread to avoid race conditions.
838   FML_DCHECK(task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread());
839   FML_DCHECK(unreported_timings_.size() % FrameTiming::kCount == 0);
840   return unreported_timings_.size() / FrameTiming::kCount;
841 }
842 
OnFrameRasterized(const FrameTiming & timing)843 void Shell::OnFrameRasterized(const FrameTiming& timing) {
844   FML_DCHECK(is_setup_);
845   FML_DCHECK(task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread());
846 
847   // The C++ callback defined in settings.h and set by Flutter runner. This is
848   // independent of the timings report to the Dart side.
849   if (settings_.frame_rasterized_callback) {
850     settings_.frame_rasterized_callback(timing);
851   }
852 
853   if (!needs_report_timings_) {
854     return;
855   }
856 
857   for (auto phase : FrameTiming::kPhases) {
858     unreported_timings_.push_back(
859         timing.Get(phase).ToEpochDelta().ToMicroseconds());
860   }
861 
862   // In tests using iPhone 6S with profile mode, sending a batch of 1 frame or a
863   // batch of 100 frames have roughly the same cost of less than 0.1ms. Sending
864   // a batch of 500 frames costs about 0.2ms. The 1 second threshold usually
865   // kicks in before we reaching the following 100 frames threshold. The 100
866   // threshold here is mainly for unit tests (so we don't have to write a
867   // 1-second unit test), and make sure that our vector won't grow too big with
868   // future 120fps, 240fps, or 1000fps displays.
869   //
870   // In the profile/debug mode, the timings are used by development tools which
871   // require a latency of no more than 100ms. Hence we lower that 1-second
872   // threshold to 100ms because performance overhead isn't that critical in
873   // those cases.
874   if (!first_frame_rasterized_ || UnreportedFramesCount() >= 100) {
875     first_frame_rasterized_ = true;
876     ReportTimings();
877   } else if (!frame_timings_report_scheduled_) {
878 #if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE
879     constexpr int kBatchTimeInMilliseconds = 1000;
880 #else
881     constexpr int kBatchTimeInMilliseconds = 100;
882 #endif
883 
884     // Also make sure that frame times get reported with a max latency of 1
885     // second. Otherwise, the timings of last few frames of an animation may
886     // never be reported until the next animation starts.
887     frame_timings_report_scheduled_ = true;
888     task_runners_.GetGPUTaskRunner()->PostDelayedTask(
889         [self = weak_factory_.GetWeakPtr()]() {
890           if (!self.get()) {
891             return;
892           }
893           self->frame_timings_report_scheduled_ = false;
894           if (self->UnreportedFramesCount() > 0) {
895             self->ReportTimings();
896           }
897         },
898         fml::TimeDelta::FromMilliseconds(kBatchTimeInMilliseconds));
899   }
900 }
901 
Screenshot(Rasterizer::ScreenshotType screenshot_type,bool base64_encode)902 Rasterizer::Screenshot Shell::Screenshot(
903     Rasterizer::ScreenshotType screenshot_type,
904     bool base64_encode) {
905     TRACE_EVENT0("flutter", "Shell::Screenshot");
906     fml::AutoResetWaitableEvent latch;
907     Rasterizer::Screenshot screenshot;
908     fml::TaskRunner::RunNowOrPostTask(
909         task_runners_.GetGPUTaskRunner(), [&latch,                        //
910             rasterizer = GetRasterizer(),  //
911             &screenshot,                   //
912             screenshot_type,               //
913             base64_encode                  //
914         ]() {
915           if (rasterizer) {
916               screenshot = rasterizer->ScreenshotLastLayerTree(screenshot_type,
917                                                                base64_encode);
918           }
919           latch.Signal();
920         });
921     latch.Wait();
922     return screenshot;
923 }
924 
WaitForFirstFrame(fml::TimeDelta timeout)925 fml::Status Shell::WaitForFirstFrame(fml::TimeDelta timeout) {
926   FML_DCHECK(is_setup_);
927   if (task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread() ||
928       task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread()) {
929     return fml::Status(fml::StatusCode::kFailedPrecondition,
930                        "WaitForFirstFrame called from thread that can't wait "
931                        "because it is responsible for generating the frame.");
932   }
933 
934   std::unique_lock<std::mutex> lock(waiting_for_first_frame_mutex_);
935   bool success = waiting_for_first_frame_condition_.wait_for(
936       lock, std::chrono::milliseconds(timeout.ToMilliseconds()),
937       [& waiting_for_first_frame = waiting_for_first_frame_] {
938         return !waiting_for_first_frame.load();
939       });
940   if (success) {
941     return fml::Status();
942   } else {
943     return fml::Status(fml::StatusCode::kDeadlineExceeded, "timeout");
944   }
945 }
946 
947 }
948