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