Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
shell.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <future>
6#include "fml/task_runner.h"
9#define RAPIDJSON_HAS_STDSTRING 1
11
12#include <memory>
13#include <sstream>
14#include <utility>
15#include <vector>
16
20#include "flutter/fml/base32.h"
21#include "flutter/fml/file.h"
24#include "flutter/fml/logging.h"
27#include "flutter/fml/paths.h"
37#include "rapidjson/stringbuffer.h"
38#include "rapidjson/writer.h"
39#include "third_party/dart/runtime/include/dart_tools_api.h"
40#include "third_party/skia/include/codec/SkBmpDecoder.h"
41#include "third_party/skia/include/codec/SkCodec.h"
42#include "third_party/skia/include/codec/SkGifDecoder.h"
43#include "third_party/skia/include/codec/SkIcoDecoder.h"
44#include "third_party/skia/include/codec/SkJpegDecoder.h"
45#include "third_party/skia/include/codec/SkPngDecoder.h"
46#include "third_party/skia/include/codec/SkWbmpDecoder.h"
47#include "third_party/skia/include/codec/SkWebpDecoder.h"
48#include "third_party/skia/include/core/SkGraphics.h"
50
51namespace flutter {
52
53constexpr char kSkiaChannel[] = "flutter/skia";
54constexpr char kSystemChannel[] = "flutter/system";
55constexpr char kTypeKey[] = "type";
56constexpr char kFontChange[] = "fontsChange";
57
58namespace {
59
60std::unique_ptr<Engine> CreateEngine(
61 Engine::Delegate& delegate,
62 const PointerDataDispatcherMaker& dispatcher_maker,
63 DartVM& vm,
64 const fml::RefPtr<const DartSnapshot>& isolate_snapshot,
65 const TaskRunners& task_runners,
66 const PlatformData& platform_data,
67 const Settings& settings,
68 std::unique_ptr<Animator> animator,
69 const fml::WeakPtr<IOManager>& io_manager,
70 const fml::RefPtr<SkiaUnrefQueue>& unref_queue,
72 const std::shared_ptr<fml::SyncSwitch>& gpu_disabled_switch,
73 const std::shared_future<impeller::RuntimeStageBackend>&
74 runtime_stage_backend) {
75 return std::make_unique<Engine>(delegate, //
76 dispatcher_maker, //
77 vm, //
78 isolate_snapshot, //
79 task_runners, //
80 platform_data, //
81 settings, //
82 std::move(animator), //
83 io_manager, //
84 unref_queue, //
85 snapshot_delegate, //
86 gpu_disabled_switch, //
87 runtime_stage_backend);
88}
89
90void RegisterCodecsWithSkia() {
91 // These are in the order they will be attempted to be decoded from.
92 // If we have data to back it up, we can order these by "frequency used in
93 // the wild" for a very small performance bump, but for now we mirror the
94 // order Skia had them in.
95 SkCodecs::Register(SkPngDecoder::Decoder());
96 SkCodecs::Register(SkJpegDecoder::Decoder());
97 SkCodecs::Register(SkWebpDecoder::Decoder());
98 SkCodecs::Register(SkGifDecoder::Decoder());
99 SkCodecs::Register(SkBmpDecoder::Decoder());
100 SkCodecs::Register(SkWbmpDecoder::Decoder());
101 SkCodecs::Register(SkIcoDecoder::Decoder());
102}
103
104// Though there can be multiple shells, some settings apply to all components in
105// the process. These have to be set up before the shell or any of its
106// sub-components can be initialized. In a perfect world, this would be empty.
107// TODO(chinmaygarde): The unfortunate side effect of this call is that settings
108// that cause shell initialization failures will still lead to some of their
109// settings being applied.
110void PerformInitializationTasks(Settings& settings) {
111 {
112 fml::LogSettings log_settings;
113 log_settings.min_log_level =
115 fml::SetLogSettings(log_settings);
116 }
117
118 static std::once_flag gShellSettingsInitialization = {};
119 std::call_once(gShellSettingsInitialization, [&settings] {
121 [](const char* message) { FML_LOG(ERROR) << message; });
122
123 if (settings.trace_skia) {
125 }
126
127 if (!settings.trace_allowlist.empty()) {
129 }
130
132 SkGraphics::Init();
133 } else {
134 FML_DLOG(INFO) << "Skia deterministic rendering is enabled.";
135 }
136 RegisterCodecsWithSkia();
137
138 if (settings.icu_initialization_required) {
139 if (!settings.icu_data_path.empty()) {
141 } else if (settings.icu_mapper) {
143 } else {
144 FML_DLOG(WARNING) << "Skipping ICU initialization in the shell.";
145 }
146 }
147 });
148
149#if !SLIMPELLER
151#endif // !SLIMPELLER
152}
153
154bool ValidateViewportMetrics(const ViewportMetrics& metrics) {
155 // Pixel ratio cannot be zero.
156 if (metrics.device_pixel_ratio <= 0) {
157 return false;
158 }
159
160 // If negative values are passed in.
161 if (metrics.physical_width < 0 || metrics.physical_height < 0 ||
162 metrics.physical_min_width_constraint < 0 ||
163 metrics.physical_max_width_constraint < 0 ||
164 metrics.physical_min_height_constraint < 0 ||
165 metrics.physical_max_height_constraint < 0) {
166 return false;
167 }
168
169 // If width is zero and the constraints are tight.
170 if (metrics.physical_width == 0 &&
173 return false;
174 }
175
176 // If not tight constraints, check the width fits in the constraints.
177 if (metrics.physical_min_width_constraint !=
179 if (metrics.physical_min_width_constraint > metrics.physical_width ||
181 return false;
182 }
183 }
184
185 // If height is zero and the constraints are tight.
186 if (metrics.physical_height == 0 &&
189 return false;
190 }
191
192 // If not tight constraints, check the height fits in the constraints.
193 if (metrics.physical_min_height_constraint !=
195 if (metrics.physical_min_height_constraint > metrics.physical_height ||
197 return false;
198 }
199 }
200
201 return true;
202}
203
204} // namespace
205
206std::pair<DartVMRef, fml::RefPtr<const DartSnapshot>>
208 // Always use the `vm_snapshot` and `isolate_snapshot` provided by the
209 // settings to launch the VM. If the VM is already running, the snapshot
210 // arguments are ignored.
211 auto vm_snapshot = DartSnapshot::VMSnapshotFromSettings(settings);
212 auto isolate_snapshot = DartSnapshot::IsolateSnapshotFromSettings(settings);
213 auto vm = DartVMRef::Create(settings, vm_snapshot, isolate_snapshot);
214
215 // If the settings did not specify an `isolate_snapshot`, fall back to the
216 // one the VM was launched with.
217 if (!isolate_snapshot) {
218 isolate_snapshot = vm->GetVMData()->GetIsolateSnapshot();
219 }
220 return {std::move(vm), isolate_snapshot};
221}
222
223std::unique_ptr<Shell> Shell::Create(
224 const PlatformData& platform_data,
225 const TaskRunners& task_runners,
226 Settings settings,
227 const Shell::CreateCallback<PlatformView>& on_create_platform_view,
228 const Shell::CreateCallback<Rasterizer>& on_create_rasterizer,
229 bool is_gpu_disabled) {
230 // This must come first as it initializes tracing.
231 PerformInitializationTasks(settings);
232
233 TRACE_EVENT0("flutter", "Shell::Create");
234
235 auto [vm, isolate_snapshot] = InferVmInitDataFromSettings(settings);
236 auto resource_cache_limit_calculator =
237 std::make_shared<ResourceCacheLimitCalculator>(
239
240 return CreateWithSnapshot(platform_data, //
241 task_runners, //
242 /*parent_thread_merger=*/nullptr, //
243 /*parent_io_manager=*/nullptr, //
244 resource_cache_limit_calculator, //
245 settings, //
246 std::move(vm), //
247 std::move(isolate_snapshot), //
248 on_create_platform_view, //
249 on_create_rasterizer, //
250 CreateEngine, is_gpu_disabled);
251}
252
253std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
254 DartVMRef vm,
256 std::shared_ptr<ShellIOManager> parent_io_manager,
257 const std::shared_ptr<ResourceCacheLimitCalculator>&
258 resource_cache_limit_calculator,
259 const TaskRunners& task_runners,
260 const PlatformData& platform_data,
261 const Settings& settings,
262 fml::RefPtr<const DartSnapshot> isolate_snapshot,
263 const Shell::CreateCallback<PlatformView>& on_create_platform_view,
264 const Shell::CreateCallback<Rasterizer>& on_create_rasterizer,
265 const Shell::EngineCreateCallback& on_create_engine,
266 bool is_gpu_disabled) {
267 if (!task_runners.IsValid()) {
268 FML_LOG(ERROR) << "Task runners to run the shell were invalid.";
269 return nullptr;
270 }
271
272 auto shell = std::unique_ptr<Shell>(
273 new Shell(std::move(vm), task_runners, std::move(parent_merger),
274 resource_cache_limit_calculator, settings, is_gpu_disabled));
275
276 // Create the platform view on the platform thread (this thread).
277 auto platform_view = on_create_platform_view(*shell.get());
278 if (!platform_view || !platform_view->GetWeakPtr()) {
279 return nullptr;
280 }
281
282 PlatformView* platform_view_ptr = platform_view.get();
283 // Create the rasterizer on the raster thread.
284 std::promise<std::unique_ptr<Rasterizer>> rasterizer_promise;
285 auto rasterizer_future = rasterizer_promise.get_future();
286 std::promise<fml::TaskRunnerAffineWeakPtr<SnapshotDelegate>>
287 snapshot_delegate_promise;
288 auto snapshot_delegate_future = snapshot_delegate_promise.get_future();
289
290 std::promise<std::shared_ptr<impeller::Context>> impeller_context_promise;
291 auto impeller_context_future =
292 std::make_shared<impeller::ImpellerContextFuture>(
293 impeller_context_promise.get_future());
294
296 task_runners.GetRasterTaskRunner(),
297 [&rasterizer_promise, //
298 &snapshot_delegate_promise, impeller_context_future,
299 on_create_rasterizer, //
300 shell = shell.get()]() {
301 TRACE_EVENT0("flutter", "ShellSetupGPUSubsystem");
302 std::unique_ptr<Rasterizer> rasterizer(on_create_rasterizer(*shell));
303 rasterizer->SetImpellerContext(impeller_context_future);
304 snapshot_delegate_promise.set_value(rasterizer->GetSnapshotDelegate());
305 rasterizer_promise.set_value(std::move(rasterizer));
306 });
307
308 // Defer setting up the impeller context until after the startup blocking
309 // futures have completed. Context creation may be slow (100+ ms) when using
310 // the Vulkan backend on certain Android devices, so we intentionally try
311 // to move it off the critical path for startup.
312 std::promise<impeller::RuntimeStageBackend> runtime_stage_backend;
313 std::shared_future<impeller::RuntimeStageBackend> runtime_stage_future =
314 runtime_stage_backend.get_future();
315
317 task_runners.GetRasterTaskRunner(),
319 [impeller_context_promise = std::move(impeller_context_promise), //
320 runtime_stage_backend = std::move(runtime_stage_backend), //
321 platform_view_ptr]() mutable {
322 TRACE_EVENT0("flutter", "CreateImpellerContext");
323 platform_view_ptr->SetupImpellerContext();
324 std::shared_ptr<impeller::Context> impeller_context =
325 platform_view_ptr->GetImpellerContext();
326 if (impeller_context) {
327 runtime_stage_backend.set_value(
328 impeller_context->GetRuntimeStageBackend());
329 impeller_context_promise.set_value(impeller_context);
330 } else {
331 runtime_stage_backend.set_value(
332 impeller::RuntimeStageBackend::kSkSL);
333 impeller_context_promise.set_value(nullptr);
334 }
335 }));
336
337 // Ask the platform view for the vsync waiter. This will be used by the engine
338 // to create the animator.
339 auto vsync_waiter = platform_view->CreateVSyncWaiter();
340 if (!vsync_waiter) {
341 return nullptr;
342 }
343
344 // Create the IO manager on the IO thread. The IO manager must be initialized
345 // first because it has state that the other subsystems depend on. It must
346 // first be booted and the necessary references obtained to initialize the
347 // other subsystems.
348 std::promise<std::shared_ptr<ShellIOManager>> io_manager_promise;
349 auto io_manager_future = io_manager_promise.get_future();
350 std::promise<fml::WeakPtr<ShellIOManager>> weak_io_manager_promise;
351 auto weak_io_manager_future = weak_io_manager_promise.get_future();
352 std::promise<fml::RefPtr<SkiaUnrefQueue>> unref_queue_promise;
353 auto unref_queue_future = unref_queue_promise.get_future();
354 auto io_task_runner = shell->GetTaskRunners().GetIOTaskRunner();
355
356 // The platform_view will be stored into shell's platform_view_ in
357 // shell->Setup(std::move(platform_view), ...) at the end.
359 io_task_runner,
360 [&io_manager_promise, //
361 &weak_io_manager_promise, //
362 &parent_io_manager, //
363 &unref_queue_promise, //
364 platform_view_ptr, //
365 io_task_runner, //
366 is_backgrounded_sync_switch = shell->GetIsGpuDisabledSyncSwitch(), //
367 impeller_enabled = settings.enable_impeller, //
368 impeller_context_future]() {
369 TRACE_EVENT0("flutter", "ShellSetupIOSubsystem");
370 std::shared_ptr<ShellIOManager> io_manager;
371 if (parent_io_manager) {
372 io_manager = parent_io_manager;
373 } else {
374 io_manager = std::make_shared<ShellIOManager>(
375 nullptr, // resource context
376 is_backgrounded_sync_switch, // sync switch
377 io_task_runner, // unref queue task runner
378 impeller_context_future, // impeller context
379 impeller_enabled //
380 );
381 }
382 weak_io_manager_promise.set_value(io_manager->GetWeakPtr());
383 unref_queue_promise.set_value(io_manager->GetSkiaUnrefQueue());
384 io_manager_promise.set_value(io_manager);
385
386 // Wait until Impeller context setup is complete before creating the
387 // resource context.
388 io_manager->GetImpellerContext();
389 sk_sp<GrDirectContext> resource_context =
390 platform_view_ptr->CreateResourceContext();
391 io_manager->NotifyResourceContextAvailable(resource_context);
392 });
393
394 // Send dispatcher_maker to the engine constructor because shell won't have
395 // platform_view set until Shell::Setup is called later.
396 auto dispatcher_maker = platform_view->GetDispatcherMaker();
397
398 // Create the engine on the UI thread.
399 std::promise<std::unique_ptr<Engine>> engine_promise;
400 auto engine_future = engine_promise.get_future();
402 shell->GetTaskRunners().GetUITaskRunner(),
403 fml::MakeCopyable([&engine_promise, //
404 shell = shell.get(), //
405 &dispatcher_maker, //
406 &platform_data, //
407 isolate_snapshot = std::move(isolate_snapshot), //
408 vsync_waiter = std::move(vsync_waiter), //
409 &weak_io_manager_future, //
410 &snapshot_delegate_future, //
411 &runtime_stage_future, //
412 &unref_queue_future, //
413 &on_create_engine]() mutable {
414 TRACE_EVENT0("flutter", "ShellSetupUISubsystem");
415 const auto& task_runners = shell->GetTaskRunners();
416
417 // The animator is owned by the UI thread but it gets its vsync pulses
418 // from the platform.
419 auto animator = std::make_unique<Animator>(*shell, task_runners,
420 std::move(vsync_waiter));
421
422 engine_promise.set_value(
423 on_create_engine(*shell, //
424 dispatcher_maker, //
425 *shell->GetDartVM(), //
426 std::move(isolate_snapshot), //
427 task_runners, //
428 platform_data, //
429 shell->GetSettings(), //
430 std::move(animator), //
431 weak_io_manager_future.get(), //
432 unref_queue_future.get(), //
433 snapshot_delegate_future.get(), //
434 shell->is_gpu_disabled_sync_switch_, //
435 runtime_stage_future));
436 }));
437
438 if (!shell->Setup(std::move(platform_view), //
439 engine_future.get(), //
440 rasterizer_future.get(), //
441 io_manager_future.get()) //
442 ) {
443 return nullptr;
444 }
445
446 return shell;
447}
448
449std::unique_ptr<Shell> Shell::CreateWithSnapshot(
450 const PlatformData& platform_data,
451 const TaskRunners& task_runners,
452 const fml::RefPtr<fml::RasterThreadMerger>& parent_thread_merger,
453 const std::shared_ptr<ShellIOManager>& parent_io_manager,
454 const std::shared_ptr<ResourceCacheLimitCalculator>&
455 resource_cache_limit_calculator,
456 Settings settings,
457 DartVMRef vm,
458 fml::RefPtr<const DartSnapshot> isolate_snapshot,
459 const Shell::CreateCallback<PlatformView>& on_create_platform_view,
460 const Shell::CreateCallback<Rasterizer>& on_create_rasterizer,
461 const Shell::EngineCreateCallback& on_create_engine,
462 bool is_gpu_disabled) {
463 // This must come first as it initializes tracing.
464 PerformInitializationTasks(settings);
465
466 TRACE_EVENT0("flutter", "Shell::CreateWithSnapshot");
467
468 const bool callbacks_valid =
469 on_create_platform_view && on_create_rasterizer && on_create_engine;
470 if (!task_runners.IsValid() || !callbacks_valid) {
471 return nullptr;
472 }
473
475 std::unique_ptr<Shell> shell;
476 auto platform_task_runner = task_runners.GetPlatformTaskRunner();
478 platform_task_runner,
479 fml::MakeCopyable([&latch, //
480 &shell, //
481 parent_thread_merger, //
482 parent_io_manager, //
483 resource_cache_limit_calculator, //
484 task_runners = task_runners, //
485 platform_data = platform_data, //
486 settings = settings, //
487 vm = std::move(vm), //
488 isolate_snapshot = std::move(isolate_snapshot), //
489 on_create_platform_view = on_create_platform_view, //
490 on_create_rasterizer = on_create_rasterizer, //
491 on_create_engine = on_create_engine,
492 is_gpu_disabled]() mutable {
493 shell = CreateShellOnPlatformThread(std::move(vm), //
494 parent_thread_merger, //
495 parent_io_manager, //
496 resource_cache_limit_calculator, //
497 task_runners, //
498 platform_data, //
499 settings, //
500 std::move(isolate_snapshot), //
501 on_create_platform_view, //
502 on_create_rasterizer, //
503 on_create_engine, //
504 is_gpu_disabled);
505 latch.Signal();
506 }));
507 latch.Wait();
508 return shell;
509}
510
511Shell::Shell(DartVMRef vm,
512 const TaskRunners& task_runners,
514 const std::shared_ptr<ResourceCacheLimitCalculator>&
515 resource_cache_limit_calculator,
516 const Settings& settings,
517 bool is_gpu_disabled)
518 : task_runners_(task_runners),
519 parent_raster_thread_merger_(std::move(parent_merger)),
520 resource_cache_limit_calculator_(resource_cache_limit_calculator),
521 settings_(settings),
522 vm_(std::move(vm)),
523 is_gpu_disabled_sync_switch_(new fml::SyncSwitch(is_gpu_disabled)),
524 weak_factory_gpu_(nullptr),
525 weak_factory_(this) {
526 FML_CHECK(!settings.enable_software_rendering || !settings.enable_impeller)
527 << "Software rendering is incompatible with Impeller.";
528 if (!settings.enable_impeller && settings.warn_on_impeller_opt_out) {
529 FML_LOG(IMPORTANT) << //
530 R"warn([Action Required]: Impeller opt-out deprecated.
531 The application opted out of Impeller by either using the
532 `--no-enable-impeller` flag or the
533 `io.flutter.embedding.android.EnableImpeller` `AndroidManifest.xml` entry.
534 These options are going to go away in an upcoming Flutter release. Remove
535 the explicit opt-out. If you need to opt-out, please report a bug describing
536 the issue.
537
538 https://github.com/flutter/flutter/issues/new?template=02_bug.yml
539)warn";
540 }
541 FML_CHECK(vm_) << "Must have access to VM to create a shell.";
542 FML_DCHECK(task_runners_.IsValid());
544
545 display_manager_ = std::make_unique<DisplayManager>();
546 resource_cache_limit_calculator->AddResourceCacheLimitItem(
547 weak_factory_.GetWeakPtr());
548
549 std::shared_future<fml::WeakPtr<ShellIOManager>> weak_io_manager_future(
550 weak_io_manager_promise_.get_future());
551 shutdown_safe_io_task_runner_ =
552 std::make_shared<fml::ConditionalBasicTaskRunner>(
553 task_runners_.GetIOTaskRunner(),
554 [weak_io_manager_future = std::move(weak_io_manager_future)] {
555 return static_cast<bool>(weak_io_manager_future.get());
556 });
557
558 // Generate a WeakPtrFactory for use with the raster thread. This does not
559 // need to wait on a latch because it can only ever be used from the raster
560 // thread from this class, so we have ordering guarantees.
562 task_runners_.GetRasterTaskRunner(), fml::MakeCopyable([this]() mutable {
563 this->weak_factory_gpu_ =
564 std::make_unique<fml::TaskRunnerAffineWeakPtrFactory<Shell>>(this);
565 }));
566
567 // Install service protocol handlers.
568
569 service_protocol_handlers_[ServiceProtocol::kScreenshotExtensionName] = {
570 task_runners_.GetRasterTaskRunner(),
571 std::bind(&Shell::OnServiceProtocolScreenshot, this,
572 std::placeholders::_1, std::placeholders::_2)};
573 service_protocol_handlers_[ServiceProtocol::kScreenshotSkpExtensionName] = {
574 task_runners_.GetRasterTaskRunner(),
575 std::bind(&Shell::OnServiceProtocolScreenshotSKP, this,
576 std::placeholders::_1, std::placeholders::_2)};
577 service_protocol_handlers_[ServiceProtocol::kRunInViewExtensionName] = {
578 task_runners_.GetUITaskRunner(),
579 std::bind(&Shell::OnServiceProtocolRunInView, this, std::placeholders::_1,
580 std::placeholders::_2)};
581 service_protocol_handlers_
583 task_runners_.GetUITaskRunner(),
584 std::bind(&Shell::OnServiceProtocolFlushUIThreadTasks, this,
585 std::placeholders::_1, std::placeholders::_2)};
586 service_protocol_handlers_
588 task_runners_.GetUITaskRunner(),
589 std::bind(&Shell::OnServiceProtocolSetAssetBundlePath, this,
590 std::placeholders::_1, std::placeholders::_2)};
591 service_protocol_handlers_
593 task_runners_.GetUITaskRunner(),
594 std::bind(&Shell::OnServiceProtocolGetDisplayRefreshRate, this,
595 std::placeholders::_1, std::placeholders::_2)};
596 service_protocol_handlers_[ServiceProtocol::kGetSkSLsExtensionName] = {
597 task_runners_.GetIOTaskRunner(),
598 std::bind(&Shell::OnServiceProtocolGetSkSLs, this, std::placeholders::_1,
599 std::placeholders::_2)};
600 service_protocol_handlers_
602 task_runners_.GetRasterTaskRunner(),
603 std::bind(&Shell::OnServiceProtocolEstimateRasterCacheMemory, this,
604 std::placeholders::_1, std::placeholders::_2)};
605 service_protocol_handlers_[ServiceProtocol::kReloadAssetFonts] = {
606 task_runners_.GetPlatformTaskRunner(),
607 std::bind(&Shell::OnServiceProtocolReloadAssetFonts, this,
608 std::placeholders::_1, std::placeholders::_2)};
609 service_protocol_handlers_[ServiceProtocol::kGetPipelineUsageExtensionName] =
610 {task_runners_.GetIOTaskRunner(),
611 std::bind(&Shell::OnServiceProtocolGetPipelineUsage, this,
612 std::placeholders::_1, std::placeholders::_2)};
613}
614
616#if !SLIMPELLER
618 task_runners_.GetIOTaskRunner());
619#endif // !SLIMPELLER
620
621 vm_->GetServiceProtocol()->RemoveHandler(this);
622
623 fml::AutoResetWaitableEvent platiso_latch, ui_latch, gpu_latch,
624 platform_latch, io_latch;
625
627 task_runners_.GetPlatformTaskRunner(),
628 fml::MakeCopyable([this, &platiso_latch]() mutable {
629 engine_->ShutdownPlatformIsolates();
630 platiso_latch.Signal();
631 }));
632 platiso_latch.Wait();
633
635 task_runners_.GetUITaskRunner(),
636 fml::MakeCopyable([this, &ui_latch]() mutable {
637 engine_.reset();
638 ui_latch.Signal();
639 }));
640 ui_latch.Wait();
641
643 task_runners_.GetRasterTaskRunner(),
645 [this, rasterizer = std::move(rasterizer_), &gpu_latch]() mutable {
646 rasterizer.reset();
647 this->weak_factory_gpu_.reset();
648 gpu_latch.Signal();
649 }));
650 gpu_latch.Wait();
651
653 task_runners_.GetIOTaskRunner(),
654 fml::MakeCopyable([io_manager = std::move(io_manager_),
655 platform_view = platform_view_.get(),
656 &io_latch]() mutable {
657 std::weak_ptr<ShellIOManager> weak_io_manager(io_manager);
658 io_manager.reset();
659
660 // If the IO manager is not being used by any other spawned shells,
661 // then detach the resource context from the IO thread.
662 if (platform_view && weak_io_manager.expired()) {
663 platform_view->ReleaseResourceContext();
664 }
665 io_latch.Signal();
666 }));
667
668 io_latch.Wait();
669
670 // The platform view must go last because it may be holding onto platform side
671 // counterparts to resources owned by subsystems running on other threads. For
672 // example, the NSOpenGLContext on the Mac.
675 fml::MakeCopyable([platform_view = std::move(platform_view_),
676 &platform_latch]() mutable {
677 platform_view.reset();
678 platform_latch.Signal();
679 }));
680 platform_latch.Wait();
681
684 // Move the UI task runner back to its original thread to enable shutdown of
685 // that thread.
686 auto task_queues = fml::MessageLoopTaskQueues::GetInstance();
687 auto platform_queue_id =
689 auto ui_queue_id = task_runners_.GetUITaskRunner()->GetTaskQueueId();
690 if (task_queues->Owns(platform_queue_id, ui_queue_id)) {
691 task_queues->Unmerge(platform_queue_id, ui_queue_id);
692 }
693 }
694}
695
696std::unique_ptr<Shell> Shell::Spawn(
697 RunConfiguration run_configuration,
698 const std::string& initial_route,
699 const CreateCallback<PlatformView>& on_create_platform_view,
700 const CreateCallback<Rasterizer>& on_create_rasterizer) const {
701 FML_DCHECK(task_runners_.IsValid());
702
703 if (settings_.merged_platform_ui_thread ==
705 // Spawning engines that share the same task runners can result in
706 // deadlocks when the UI task runner is moved to the platform thread.
707 FML_LOG(ERROR) << "MergedPlatformUIThread::kMergeAfterLaunch does not "
708 "support spawning";
709 return nullptr;
710 }
711
712 // It's safe to store this value since it is set on the platform thread.
713 bool is_gpu_disabled = false;
716 .SetIfFalse([&is_gpu_disabled] { is_gpu_disabled = false; })
717 .SetIfTrue([&is_gpu_disabled] { is_gpu_disabled = true; }));
718 std::unique_ptr<Shell> result = CreateWithSnapshot(
719 PlatformData{}, task_runners_, rasterizer_->GetRasterThreadMerger(),
720 io_manager_, resource_cache_limit_calculator_, GetSettings(), vm_,
721 vm_->GetVMData()->GetIsolateSnapshot(), on_create_platform_view,
722 on_create_rasterizer,
723 [engine = this->engine_.get(), initial_route](
724 Engine::Delegate& delegate,
725 const PointerDataDispatcherMaker& dispatcher_maker, DartVM& vm,
726 const fml::RefPtr<const DartSnapshot>& isolate_snapshot,
727 const TaskRunners& task_runners, const PlatformData& platform_data,
728 const Settings& settings, std::unique_ptr<Animator> animator,
729 const fml::WeakPtr<IOManager>& io_manager,
730 const fml::RefPtr<SkiaUnrefQueue>& unref_queue,
732 const std::shared_ptr<fml::SyncSwitch>& is_gpu_disabled_sync_switch,
733 const std::shared_future<impeller::RuntimeStageBackend>&
734 runtime_stage_backend) {
735 return engine->Spawn(
736 /*delegate=*/delegate,
737 /*dispatcher_maker=*/dispatcher_maker,
738 /*settings=*/settings,
739 /*animator=*/std::move(animator),
740 /*initial_route=*/initial_route,
741 /*io_manager=*/io_manager,
742 /*snapshot_delegate=*/std::move(snapshot_delegate),
743 /*gpu_disabled_switch=*/is_gpu_disabled_sync_switch);
744 },
745 is_gpu_disabled);
746 result->RunEngine(std::move(run_configuration));
747 return result;
748}
749
751 auto trace_id = fml::tracing::TraceNonce();
752 TRACE_EVENT_ASYNC_BEGIN0("flutter", "Shell::NotifyLowMemoryWarning",
753 trace_id);
754 // This does not require a current isolate but does require a running VM.
755 // Since a valid shell will not be returned to the embedder without a valid
756 // DartVMRef, we can be certain that this is a safe spot to assume a VM is
757 // running.
758 ::Dart_NotifyLowMemory();
759
760 task_runners_.GetRasterTaskRunner()->PostTask(
761 [rasterizer = rasterizer_->GetWeakPtr(), trace_id = trace_id]() {
762 if (rasterizer) {
763 rasterizer->NotifyLowMemoryWarning();
764 }
765 TRACE_EVENT_ASYNC_END0("flutter", "Shell::NotifyLowMemoryWarning",
766 trace_id);
767 });
768 // The IO Manager uses resource cache limits of 0, so it is not necessary
769 // to purge them.
770}
771
772void Shell::FlushMicrotaskQueue() const {
773 if (engine_) {
774 engine_->FlushMicrotaskQueue();
775 }
776}
777
778void Shell::RunEngine(RunConfiguration run_configuration) {
779 RunEngine(std::move(run_configuration), nullptr);
780}
781
783 RunConfiguration run_configuration,
784 const std::function<void(Engine::RunStatus)>& result_callback) {
785 auto result = [platform_runner = task_runners_.GetPlatformTaskRunner(),
786 result_callback](Engine::RunStatus run_result) {
787 if (!result_callback) {
788 return;
789 }
790 platform_runner->PostTask(
791 [result_callback, run_result]() { result_callback(run_result); });
792 };
793 FML_DCHECK(is_set_up_);
795
797 task_runners_.GetUITaskRunner(),
799 [run_configuration = std::move(run_configuration),
800 weak_engine = weak_engine_, result]() mutable {
801 if (!weak_engine) {
802 FML_LOG(ERROR)
803 << "Could not launch engine with configuration - no engine.";
804 result(Engine::RunStatus::Failure);
805 return;
806 }
807 auto run_result = weak_engine->Run(std::move(run_configuration));
808 if (run_result == flutter::Engine::RunStatus::Failure) {
809 FML_LOG(ERROR) << "Could not launch engine with configuration.";
810 }
811
812 result(run_result);
813 }));
814}
815
816std::optional<DartErrorCode> Shell::GetUIIsolateLastError() const {
817 FML_DCHECK(is_set_up_);
819
820 if (!weak_engine_) {
821 return std::nullopt;
822 }
823 switch (weak_engine_->GetUIIsolateLastError()) {
837 FML_DCHECK(is_set_up_);
839
840 if (!weak_engine_) {
841 return false;
842 }
843
844 return weak_engine_->UIIsolateHasLivePorts();
845}
846
848 FML_DCHECK(is_set_up_);
850
851 if (!weak_engine_) {
852 return false;
853 }
854
855 return weak_engine_->UIIsolateHasPendingMicrotasks();
856}
857
858bool Shell::IsSetup() const {
859 return is_set_up_;
860}
861
862bool Shell::Setup(std::unique_ptr<PlatformView> platform_view,
863 std::unique_ptr<Engine> engine,
864 std::unique_ptr<Rasterizer> rasterizer,
865 const std::shared_ptr<ShellIOManager>& io_manager) {
866 if (is_set_up_) {
867 return false;
868 }
869
870 if (!platform_view || !engine || !rasterizer || !io_manager) {
871 return false;
872 }
873
874 platform_view_ = std::move(platform_view);
875 platform_message_handler_ = platform_view_->GetPlatformMessageHandler();
876 route_messages_through_platform_thread_.store(true);
877 task_runners_.GetPlatformTaskRunner()->PostTask(
878 [self = weak_factory_.GetWeakPtr()] {
879 if (self) {
880 self->route_messages_through_platform_thread_.store(false);
881 }
882 });
883 engine_ = std::move(engine);
884 rasterizer_ = std::move(rasterizer);
885 io_manager_ = io_manager;
886 weak_io_manager_promise_.set_value(io_manager_->GetWeakPtr());
887
888 // Set the external view embedder for the rasterizer.
889 auto view_embedder = platform_view_->CreateExternalViewEmbedder();
890 rasterizer_->SetExternalViewEmbedder(view_embedder);
891 rasterizer_->SetSnapshotSurfaceProducer(
892 platform_view_->CreateSnapshotSurfaceProducer());
893
894 // The weak ptr must be generated in the platform thread which owns the unique
895 // ptr.
896 weak_engine_ = engine_->GetWeakPtr();
897 weak_rasterizer_ = rasterizer_->GetWeakPtr();
898 weak_platform_view_ = platform_view_->GetWeakPtr();
899
900 // Add the implicit view with empty metrics.
901 engine_->AddView(kFlutterImplicitViewId, ViewportMetrics{}, [](bool added) {
902 FML_DCHECK(added) << "Failed to add the implicit view";
903 });
904
905 // Setup the time-consuming default font manager right after engine created.
908 [engine = weak_engine_] {
909 if (engine) {
910 engine->SetupDefaultFontManager();
911 }
912 });
913 }
914
915 is_set_up_ = true;
916
917#if !SLIMPELLER
920
926 }
927#endif // !SLIMPELLER
928
929 return true;
930}
932const Settings& Shell::GetSettings() const {
933 return settings_;
934}
935
937 return task_runners_;
938}
939
941 const {
942 return parent_raster_thread_merger_;
943}
944
946 FML_DCHECK(is_set_up_);
947 return weak_rasterizer_;
948}
949
951 FML_DCHECK(is_set_up_);
952 return weak_engine_;
953}
954
956 FML_DCHECK(is_set_up_);
957 return weak_platform_view_;
958}
959
961 FML_DCHECK(is_set_up_);
962 return io_manager_->GetWeakPtr();
963}
964
965std::shared_ptr<fml::BasicTaskRunner> Shell::GetShutdownSafeIOTaskRunner() {
966 return shutdown_safe_io_task_runner_;
967}
968
969DartVM* Shell::GetDartVM() {
970 return &vm_;
971}
972
973// |PlatformView::Delegate|
974void Shell::OnPlatformViewCreated(std::unique_ptr<Surface> surface) {
975 TRACE_EVENT0("flutter", "Shell::OnPlatformViewCreated");
976 FML_DCHECK(is_set_up_);
978
979 // Prevent any request to change the thread configuration for raster and
980 // platform queues while the platform view is being created.
981 //
982 // This prevents false positives such as this method starts assuming that the
983 // raster and platform queues have a given thread configuration, but then the
984 // configuration is changed by a task, and the assumption is no longer true.
985 //
986 // This incorrect assumption can lead to deadlock.
987 // See `should_post_raster_task` for more.
988 rasterizer_->DisableThreadMergerIfNeeded();
989
990 // The normal flow executed by this method is that the platform thread is
991 // starting the sequence and waiting on the latch. Later the UI thread posts
992 // raster_task to the raster thread which signals the latch. If the raster and
993 // the platform threads are the same this results in a deadlock as the
994 // raster_task will never be posted to the platform/raster thread that is
995 // blocked on a latch. To avoid the described deadlock, if the raster and the
996 // platform threads are the same, should_post_raster_task will be false, and
997 // then instead of posting a task to the raster thread, the ui thread just
998 // signals the latch and the platform/raster thread follows with executing
999 // raster_task.
1000 const bool should_post_raster_task =
1002
1003 auto raster_task = fml::MakeCopyable(
1004 [&waiting_for_first_frame = waiting_for_first_frame_, //
1005 rasterizer = rasterizer_->GetWeakPtr(), //
1006 surface = std::move(surface) //
1007 ]() mutable {
1008 if (rasterizer) {
1009 // Enables the thread merger which may be used by the external view
1010 // embedder.
1011 rasterizer->EnableThreadMergerIfNeeded();
1012 rasterizer->Setup(std::move(surface));
1013 }
1014
1015 waiting_for_first_frame.store(true);
1016 });
1017
1018 auto ui_task = [engine = engine_->GetWeakPtr()] {
1019 if (engine) {
1020 engine->ScheduleFrame();
1021 }
1022 };
1023
1024 // Threading: Capture platform view by raw pointer and not the weak pointer.
1025 // We are going to use the pointer on the IO thread which is not safe with a
1026 // weak pointer. However, we are preventing the platform view from being
1027 // collected by using a latch.
1028 auto* platform_view = platform_view_.get();
1031
1032 auto io_task = [io_manager = io_manager_->GetWeakPtr(), platform_view,
1033 ui_task_runner = task_runners_.GetUITaskRunner(), ui_task,
1034 raster_task_runner = task_runners_.GetRasterTaskRunner(),
1035 raster_task, should_post_raster_task, &latch] {
1036 if (io_manager && !io_manager->GetResourceContext()) {
1037 sk_sp<GrDirectContext> resource_context =
1038 platform_view->CreateResourceContext();
1039 io_manager->NotifyResourceContextAvailable(resource_context);
1040 }
1041 // Step 1: Post a task on the UI thread to tell the engine that it has
1042 // an output surface.
1043 fml::TaskRunner::RunNowOrPostTask(ui_task_runner, ui_task);
1044
1045 // Step 2: Tell the raster thread that it should create a surface for
1046 // its rasterizer.
1047 if (should_post_raster_task) {
1048 fml::TaskRunner::RunNowOrPostTask(raster_task_runner, raster_task);
1049 }
1050 latch.Signal();
1051 };
1052
1054
1055 latch.Wait();
1056 if (!should_post_raster_task) {
1057 // See comment on should_post_raster_task, in this case the raster_task
1058 // wasn't executed, and we just run it here as the platform thread
1059 // is the raster thread.
1060 raster_task();
1061 }
1062 // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
1063}
1064
1065// |PlatformView::Delegate|
1066void Shell::OnPlatformViewDestroyed() {
1067 TRACE_EVENT0("flutter", "Shell::OnPlatformViewDestroyed");
1068 FML_DCHECK(is_set_up_);
1070
1071 // Prevent any request to change the thread configuration for raster and
1072 // platform queues while the platform view is being destroyed.
1073 //
1074 // This prevents false positives such as this method starts assuming that the
1075 // raster and platform queues have a given thread configuration, but then the
1076 // configuration is changed by a task, and the assumption is no longer true.
1077 //
1078 // This incorrect assumption can lead to deadlock.
1079 rasterizer_->DisableThreadMergerIfNeeded();
1080
1081 // Note:
1082 // This is a synchronous operation because certain platforms depend on
1083 // setup/suspension of all activities that may be interacting with the GPU in
1084 // a synchronous fashion.
1085 // The UI thread does not need to be serialized here - there is sufficient
1086 // guardrailing in the rasterizer to allow the UI thread to post work to it
1087 // even after the surface has been torn down.
1088
1090
1091 auto io_task = [io_manager = io_manager_.get(), &latch]() {
1092 // Execute any pending Skia object deletions while GPU access is still
1093 // allowed.
1094 io_manager->GetIsGpuDisabledSyncSwitch()->Execute(
1096 [&] { io_manager->GetSkiaUnrefQueue()->Drain(); }));
1097 // Step 4: All done. Signal the latch that the platform thread is waiting
1098 // on.
1099 latch.Signal();
1100 };
1101
1102 auto raster_task = [rasterizer = rasterizer_->GetWeakPtr(),
1103 io_task_runner = task_runners_.GetIOTaskRunner(),
1104 io_task]() {
1105 if (rasterizer) {
1106 // Enables the thread merger which is required prior tearing down the
1107 // rasterizer. If the raster and platform threads are merged, tearing down
1108 // the rasterizer unmerges the threads.
1109 rasterizer->EnableThreadMergerIfNeeded();
1110 rasterizer->Teardown();
1111 }
1112 // Step 2: Tell the IO thread to complete its remaining work.
1113 fml::TaskRunner::RunNowOrPostTask(io_task_runner, io_task);
1114 };
1115
1116 // Step 1: Post a task to the Raster thread (possibly this thread) to tell the
1117 // rasterizer the output surface is going away.
1119 raster_task);
1120 latch.Wait();
1121 // On Android, the external view embedder may post a task to the platform
1122 // thread, and wait until it completes if overlay surfaces must be released.
1123 // However, the platform thread might be blocked when Dart is initializing.
1124 // In this situation, calling TeardownExternalViewEmbedder is safe because no
1125 // platform views have been created before Flutter renders the first frame.
1126 // Overall, the longer term plan is to remove this implementation once
1127 // https://github.com/flutter/flutter/issues/96679 is fixed.
1128 rasterizer_->TeardownExternalViewEmbedder();
1129}
1130
1131// |PlatformView::Delegate|
1132void Shell::OnPlatformViewScheduleFrame() {
1133 TRACE_EVENT0("flutter", "Shell::OnPlatformViewScheduleFrame");
1134 FML_DCHECK(is_set_up_);
1136
1138 [engine = engine_->GetWeakPtr()]() {
1139 if (engine) {
1140 engine->ScheduleFrame();
1141 }
1142 });
1143}
1144
1145// |PlatformView::Delegate|
1146void Shell::OnPlatformViewSetViewportMetrics(int64_t view_id,
1147 const ViewportMetrics& metrics) {
1148 FML_DCHECK(is_set_up_);
1150
1151 if (!ValidateViewportMetrics(metrics)) {
1152 // Ignore invalid view-port metrics.
1153 return;
1154 }
1155
1156 // This is the formula Android uses.
1157 // https://android.googlesource.com/platform/frameworks/base/+/39ae5bac216757bc201490f4c7b8c0f63006c6cd/libs/hwui/renderthread/CacheManager.cpp#45
1158 resource_cache_limit_ =
1159 metrics.physical_width * metrics.physical_height * 12 * 4;
1160 size_t resource_cache_max_bytes =
1161 resource_cache_limit_calculator_->GetResourceCacheMaxBytes();
1162 task_runners_.GetRasterTaskRunner()->PostTask(
1163 [rasterizer = rasterizer_->GetWeakPtr(), resource_cache_max_bytes] {
1164 if (rasterizer) {
1165 rasterizer->SetResourceCacheMaxBytes(resource_cache_max_bytes, false);
1166 }
1167 });
1168
1171 [engine = engine_->GetWeakPtr(), view_id, metrics]() {
1172 if (engine) {
1173 engine->SetViewportMetrics(view_id, metrics);
1174 }
1175 });
1176
1177 {
1178 std::scoped_lock<std::mutex> lock(resize_mutex_);
1179
1180 expected_frame_constraints_[view_id] =
1181 BoxConstraints(Size(metrics.physical_min_width_constraint,
1182 metrics.physical_min_height_constraint),
1183 Size(metrics.physical_max_width_constraint,
1184 metrics.physical_max_height_constraint));
1185 device_pixel_ratio_ = metrics.device_pixel_ratio;
1186 }
1187}
1188
1189// |PlatformView::Delegate|
1190void Shell::OnPlatformViewDispatchPlatformMessage(
1191 std::unique_ptr<PlatformMessage> message) {
1192 FML_DCHECK(is_set_up_);
1193#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
1194 if (!task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()) {
1195 std::scoped_lock lock(misbehaving_message_channels_mutex_);
1196 auto inserted = misbehaving_message_channels_.insert(message->channel());
1197 if (inserted.second) {
1198 FML_LOG(ERROR)
1199 << "The '" << message->channel()
1200 << "' channel sent a message from native to Flutter on a "
1201 "non-platform thread. Platform channel messages must be sent on "
1202 "the platform thread. Failure to do so may result in data loss or "
1203 "crashes, and must be fixed in the plugin or application code "
1204 "creating that channel.\n"
1205 "See https://docs.flutter.dev/platform-integration/"
1206 "platform-channels#channels-and-platform-threading for more "
1207 "information.";
1208 }
1209 }
1210#endif // FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG
1211
1212 // The static leak checker gets confused by the use of fml::MakeCopyable.
1213 // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
1215 task_runners_.GetUITaskRunner(),
1217 [engine = weak_engine_, message = std::move(message)]() mutable {
1218 if (engine) {
1219 engine->DispatchPlatformMessage(std::move(message));
1220 }
1221 }));
1222}
1223
1224// |PlatformView::Delegate|
1225void Shell::OnPlatformViewDispatchPointerDataPacket(
1226 std::unique_ptr<PointerDataPacket> packet) {
1228 "flutter", "Shell::OnPlatformViewDispatchPointerDataPacket",
1229 /*flow_id_count=*/1, /*flow_ids=*/&next_pointer_flow_id_);
1230 TRACE_FLOW_BEGIN("flutter", "PointerEvent", next_pointer_flow_id_);
1231 FML_DCHECK(is_set_up_);
1233
1234 task_runners_.GetUITaskRunner()->PostTask(
1235 fml::MakeCopyable([engine = weak_engine_, packet = std::move(packet),
1236 flow_id = next_pointer_flow_id_]() mutable {
1237 if (engine) {
1238 engine->DispatchPointerDataPacket(std::move(packet), flow_id);
1239 }
1240 }));
1241 next_pointer_flow_id_++;
1242}
1243
1244HitTestResponse Shell::OnPlatformViewHitTest(int64_t view_id,
1245 const flutter::PointData offset) {
1246 // hit test should be performed only when UI & platform threads are merged.
1249 if (engine_) {
1250 return engine_->HitTest(view_id, offset);
1251 }
1252 return {.has_platform_view = false};
1253}
1254
1255// |PlatformView::Delegate|
1256void Shell::OnPlatformViewDispatchSemanticsAction(int64_t view_id,
1257 int32_t node_id,
1260 FML_DCHECK(is_set_up_);
1262
1264 task_runners_.GetUITaskRunner(),
1265 fml::MakeCopyable([engine = engine_->GetWeakPtr(), view_id, node_id,
1266 action, args = std::move(args)]() mutable {
1267 if (engine) {
1268 engine->DispatchSemanticsAction(view_id, node_id, action,
1269 std::move(args));
1270 }
1271 }));
1272}
1273
1274// |PlatformView::Delegate|
1275void Shell::OnPlatformViewSetSemanticsEnabled(bool enabled) {
1276 FML_DCHECK(is_set_up_);
1278
1280 task_runners_.GetUITaskRunner(),
1281 [engine = engine_->GetWeakPtr(), enabled] {
1282 if (engine) {
1283 engine->SetSemanticsEnabled(enabled);
1284 }
1285 });
1286}
1287
1288// |PlatformView::Delegate|
1289void Shell::OnPlatformViewSetAccessibilityFeatures(int32_t flags) {
1290 FML_DCHECK(is_set_up_);
1292
1294 task_runners_.GetUITaskRunner(), [engine = engine_->GetWeakPtr(), flags] {
1295 if (engine) {
1296 engine->SetAccessibilityFeatures(flags);
1297 }
1298 });
1299}
1300
1301// |PlatformView::Delegate|
1302void Shell::OnPlatformViewRegisterTexture(
1303 std::shared_ptr<flutter::Texture> texture) {
1304 FML_DCHECK(is_set_up_);
1306
1307 task_runners_.GetRasterTaskRunner()->PostTask(
1308 [rasterizer = rasterizer_->GetWeakPtr(), texture] {
1309 if (rasterizer) {
1310 if (auto registry = rasterizer->GetTextureRegistry()) {
1311 registry->RegisterTexture(texture);
1312 }
1313 }
1314 });
1315}
1316
1317// |PlatformView::Delegate|
1318void Shell::OnPlatformViewUnregisterTexture(int64_t texture_id) {
1319 FML_DCHECK(is_set_up_);
1321
1322 task_runners_.GetRasterTaskRunner()->PostTask(
1323 [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() {
1324 if (rasterizer) {
1325 if (auto registry = rasterizer->GetTextureRegistry()) {
1326 registry->UnregisterTexture(texture_id);
1327 }
1328 }
1329 });
1330}
1331
1332// |PlatformView::Delegate|
1333void Shell::OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id) {
1334 FML_DCHECK(is_set_up_);
1336
1337 // Tell the rasterizer that one of its textures has a new frame available.
1338 task_runners_.GetRasterTaskRunner()->PostTask(
1339 [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() {
1340 if (!rasterizer) {
1341 return;
1342 }
1343 auto registry = rasterizer->GetTextureRegistry();
1344
1345 if (!registry) {
1346 return;
1347 }
1348
1349 auto texture = registry->GetTexture(texture_id);
1350
1351 if (!texture) {
1352 return;
1353 }
1354
1355 texture->MarkNewFrameAvailable();
1356 });
1357
1358 // Schedule a new frame without having to rebuild the layer tree.
1360 [engine = engine_->GetWeakPtr()]() {
1361 if (engine) {
1362 engine->ScheduleFrame(false);
1363 }
1364 });
1365}
1366
1367// |PlatformView::Delegate|
1368void Shell::OnPlatformViewSetNextFrameCallback(const fml::closure& closure) {
1369 FML_DCHECK(is_set_up_);
1371
1372 task_runners_.GetRasterTaskRunner()->PostTask(
1373 [rasterizer = rasterizer_->GetWeakPtr(), closure = closure]() {
1374 if (rasterizer) {
1375 rasterizer->SetNextFrameCallback(closure);
1376 }
1377 });
1378}
1379
1380// |PlatformView::Delegate|
1381const Settings& Shell::OnPlatformViewGetSettings() const {
1382 return settings_;
1383}
1384
1385// |PlatformView::Delegate|
1386std::shared_ptr<fml::BasicTaskRunner>
1387Shell::OnPlatformViewGetShutdownSafeIOTaskRunner() const {
1388 return shutdown_safe_io_task_runner_;
1389}
1390
1391// |Animator::Delegate|
1392void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_target_time,
1393 uint64_t frame_number) {
1394 FML_DCHECK(is_set_up_);
1396
1397 // record the target time for use by rasterizer.
1398 {
1399 std::scoped_lock time_recorder_lock(time_recorder_mutex_);
1400 latest_frame_target_time_.emplace(frame_target_time);
1401 }
1402 if (engine_) {
1403 engine_->BeginFrame(frame_target_time, frame_number);
1404 }
1405}
1406
1407// |Animator::Delegate|
1408void Shell::OnAnimatorNotifyIdle(fml::TimeDelta deadline) {
1409 FML_DCHECK(is_set_up_);
1411
1412 if (engine_) {
1413 engine_->NotifyIdle(deadline);
1414 }
1415}
1416
1417void Shell::OnAnimatorUpdateLatestFrameTargetTime(
1418 fml::TimePoint frame_target_time) {
1419 FML_DCHECK(is_set_up_);
1420
1421 // record the target time for use by rasterizer.
1422 {
1423 std::scoped_lock time_recorder_lock(time_recorder_mutex_);
1424 if (!latest_frame_target_time_) {
1425 latest_frame_target_time_ = frame_target_time;
1426 } else if (latest_frame_target_time_ < frame_target_time) {
1427 latest_frame_target_time_ = frame_target_time;
1428 }
1429 }
1430}
1431
1432// |Animator::Delegate|
1433void Shell::OnAnimatorDraw(std::shared_ptr<FramePipeline> pipeline) {
1434 FML_DCHECK(is_set_up_);
1435
1437 [&waiting_for_first_frame = waiting_for_first_frame_,
1438 &waiting_for_first_frame_condition = waiting_for_first_frame_condition_,
1439 rasterizer = rasterizer_->GetWeakPtr(),
1440 weak_pipeline = std::weak_ptr<FramePipeline>(pipeline)]() mutable {
1441 if (rasterizer) {
1442 std::shared_ptr<FramePipeline> pipeline = weak_pipeline.lock();
1443 if (pipeline) {
1444 rasterizer->Draw(pipeline);
1445 }
1446
1447 if (waiting_for_first_frame.load()) {
1448 waiting_for_first_frame.store(false);
1449 waiting_for_first_frame_condition.notify_all();
1450 }
1451 }
1452 }));
1453}
1454
1455// |Animator::Delegate|
1456void Shell::OnAnimatorDrawLastLayerTrees(
1457 std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
1458 FML_DCHECK(is_set_up_);
1459
1460 auto task = fml::MakeCopyable(
1461 [rasterizer = rasterizer_->GetWeakPtr(),
1462 frame_timings_recorder = std::move(frame_timings_recorder)]() mutable {
1463 if (rasterizer) {
1464 rasterizer->DrawLastLayerTrees(std::move(frame_timings_recorder));
1465 }
1466 });
1467
1469}
1470
1471// |Engine::Delegate|
1472void Shell::OnEngineUpdateSemantics(int64_t view_id,
1473 SemanticsNodeUpdates update,
1475 FML_DCHECK(is_set_up_);
1477
1478 task_runners_.GetPlatformTaskRunner()->RunNowOrPostTask(
1479 task_runners_.GetPlatformTaskRunner(),
1480 [view = platform_view_->GetWeakPtr(), update = std::move(update),
1481 actions = std::move(actions), view_id = view_id] {
1482 if (view) {
1483 view->UpdateSemantics(view_id, update, actions);
1484 }
1485 });
1486}
1487
1488// |Engine::Delegate|
1489void Shell::OnEngineSetApplicationLocale(std::string locale) {
1490 FML_DCHECK(is_set_up_);
1492
1493 task_runners_.GetPlatformTaskRunner()->RunNowOrPostTask(
1494 task_runners_.GetPlatformTaskRunner(),
1495 [view = platform_view_->GetWeakPtr(), locale_holder = std::move(locale)] {
1496 if (view) {
1497 view->SetApplicationLocale(locale_holder);
1498 }
1499 });
1500}
1501
1502// |Engine::Delegate|
1503void Shell::OnEngineSetSemanticsTreeEnabled(bool enabled) {
1504 FML_DCHECK(is_set_up_);
1506
1507 task_runners_.GetPlatformTaskRunner()->RunNowOrPostTask(
1508 task_runners_.GetPlatformTaskRunner(),
1509 [view = platform_view_->GetWeakPtr(), enabled] {
1510 if (view) {
1511 view->SetSemanticsTreeEnabled(enabled);
1512 }
1513 });
1514}
1515
1516// |Engine::Delegate|
1517void Shell::OnEngineHandlePlatformMessage(
1518 std::unique_ptr<PlatformMessage> message) {
1519 FML_DCHECK(is_set_up_);
1521
1522 if (message->channel() == kSkiaChannel) {
1523 HandleEngineSkiaMessage(std::move(message));
1524 return;
1525 }
1526
1527 if (platform_message_handler_) {
1528 if (route_messages_through_platform_thread_ &&
1529 !platform_message_handler_
1530 ->DoesHandlePlatformMessageOnPlatformThread()) {
1531#if _WIN32
1532 // On Windows capturing a TaskRunner with a TaskRunner will cause an
1533 // uncaught exception in process shutdown because of the deletion order of
1534 // global variables. See also
1535 // https://github.com/flutter/flutter/issues/111575.
1536 // This won't be an issue until Windows supports background platform
1537 // channels (https://github.com/flutter/flutter/issues/93945). Then this
1538 // can potentially be addressed by capturing a weak_ptr to an object that
1539 // retains the ui TaskRunner, instead of the TaskRunner directly.
1540 FML_DCHECK(false);
1541#endif
1542 // We route messages through the platform thread temporarily when the
1543 // shell is being initialized to be backwards compatible with setting
1544 // message handlers in the same event as starting the isolate, but after
1545 // it is started.
1546 auto ui_task_runner = task_runners_.GetUITaskRunner();
1548 [weak_platform_message_handler =
1549 std::weak_ptr<PlatformMessageHandler>(platform_message_handler_),
1550 message = std::move(message), ui_task_runner]() mutable {
1551 ui_task_runner->PostTask(
1552 fml::MakeCopyable([weak_platform_message_handler,
1553 message = std::move(message)]() mutable {
1554 auto platform_message_handler =
1555 weak_platform_message_handler.lock();
1556 if (platform_message_handler) {
1557 platform_message_handler->HandlePlatformMessage(
1558 std::move(message));
1559 }
1560 }));
1561 }));
1562 } else {
1563 platform_message_handler_->HandlePlatformMessage(std::move(message));
1564 }
1565 } else {
1566 task_runners_.GetPlatformTaskRunner()->PostTask(
1567 fml::MakeCopyable([view = platform_view_->GetWeakPtr(),
1568 message = std::move(message)]() mutable {
1569 if (view) {
1570 view->HandlePlatformMessage(std::move(message));
1571 }
1572 }));
1573 }
1574}
1575
1576void Shell::OnEngineChannelUpdate(std::string name, bool listening) {
1577 FML_DCHECK(is_set_up_);
1578
1579 task_runners_.GetPlatformTaskRunner()->PostTask(
1580 [view = platform_view_->GetWeakPtr(), name = std::move(name), listening] {
1581 if (view) {
1582 view->SendChannelUpdate(name, listening);
1583 }
1584 });
1585}
1586
1587void Shell::HandleEngineSkiaMessage(std::unique_ptr<PlatformMessage> message) {
1588 const auto& data = message->data();
1589
1590 rapidjson::Document document;
1591 document.Parse(reinterpret_cast<const char*>(data.GetMapping()),
1592 data.GetSize());
1593 if (document.HasParseError() || !document.IsObject()) {
1594 return;
1595 }
1596 auto root = document.GetObj();
1597 auto method = root.FindMember("method");
1598 if (method->value != "Skia.setResourceCacheMaxBytes") {
1599 return;
1600 }
1601 auto args = root.FindMember("args");
1602 if (args == root.MemberEnd() || !args->value.IsInt()) {
1603 return;
1604 }
1605
1606 task_runners_.GetRasterTaskRunner()->PostTask(
1607 [rasterizer = rasterizer_->GetWeakPtr(), max_bytes = args->value.GetInt(),
1608 response = message->response()] {
1609 if (rasterizer) {
1610 rasterizer->SetResourceCacheMaxBytes(static_cast<size_t>(max_bytes),
1611 true);
1612 }
1613 if (response) {
1614 // The framework side expects this to be valid json encoded as a list.
1615 // Return `[true]` to signal success.
1616 std::vector<uint8_t> data = {'[', 't', 'r', 'u', 'e', ']'};
1617 response->Complete(
1618 std::make_unique<fml::DataMapping>(std::move(data)));
1619 }
1620 });
1621}
1622
1623// |Engine::Delegate|
1624void Shell::OnPreEngineRestart() {
1625 FML_DCHECK(is_set_up_);
1627
1630 task_runners_.GetPlatformTaskRunner(),
1631 [view = platform_view_->GetWeakPtr(), &latch]() {
1632 if (view) {
1633 view->OnPreEngineRestart();
1634 }
1635 latch.Signal();
1636 });
1637 // This is blocking as any embedded platform views has to be flushed before
1638 // we re-run the Dart code.
1639 latch.Wait();
1640}
1641
1642// |Engine::Delegate|
1643void Shell::OnRootIsolateCreated() {
1644 if (is_added_to_service_protocol_) {
1645 return;
1646 }
1647 auto description = GetServiceProtocolDescription();
1649 task_runners_.GetPlatformTaskRunner(),
1650 [self = weak_factory_.GetWeakPtr(),
1651 description = std::move(description)]() {
1652 if (self) {
1653 self->vm_->GetServiceProtocol()->AddHandler(self.get(), description);
1654 }
1655 });
1656 is_added_to_service_protocol_ = true;
1657}
1658
1659// |Engine::Delegate|
1660void Shell::UpdateIsolateDescription(const std::string isolate_name,
1661 int64_t isolate_port) {
1662 Handler::Description description(isolate_port, isolate_name);
1663 vm_->GetServiceProtocol()->SetHandlerDescription(this, description);
1664}
1665
1666void Shell::SetNeedsReportTimings(bool value) {
1667 needs_report_timings_ = value;
1668}
1669
1670// |Engine::Delegate|
1671std::unique_ptr<std::vector<std::string>> Shell::ComputePlatformResolvedLocale(
1672 const std::vector<std::string>& supported_locale_data) {
1673 return platform_view_->ComputePlatformResolvedLocales(supported_locale_data);
1674}
1675
1676void Shell::LoadDartDeferredLibrary(
1677 intptr_t loading_unit_id,
1678 std::unique_ptr<const fml::Mapping> snapshot_data,
1679 std::unique_ptr<const fml::Mapping> snapshot_instructions) {
1681 [engine = engine_->GetWeakPtr(), loading_unit_id,
1682 data = std::move(snapshot_data),
1683 instructions = std::move(snapshot_instructions)]() mutable {
1684 if (engine) {
1685 engine->LoadDartDeferredLibrary(loading_unit_id, std::move(data),
1686 std::move(instructions));
1687 }
1688 }));
1689}
1690
1691void Shell::LoadDartDeferredLibraryError(intptr_t loading_unit_id,
1692 const std::string error_message,
1693 bool transient) {
1695 task_runners_.GetUITaskRunner(),
1696 [engine = weak_engine_, loading_unit_id, error_message, transient] {
1697 if (engine) {
1698 engine->LoadDartDeferredLibraryError(loading_unit_id, error_message,
1699 transient);
1700 }
1701 });
1702}
1703
1704void Shell::UpdateAssetResolverByType(
1705 std::unique_ptr<AssetResolver> updated_asset_resolver,
1708 task_runners_.GetUITaskRunner(),
1710 [engine = weak_engine_, type,
1711 asset_resolver = std::move(updated_asset_resolver)]() mutable {
1712 if (engine) {
1713 engine->GetAssetManager()->UpdateResolverByType(
1714 std::move(asset_resolver), type);
1715 }
1716 }));
1717}
1718
1719// |Engine::Delegate|
1720void Shell::RequestDartDeferredLibrary(intptr_t loading_unit_id) {
1721 task_runners_.GetPlatformTaskRunner()->PostTask(
1722 [view = platform_view_->GetWeakPtr(), loading_unit_id] {
1723 if (view) {
1724 view->RequestDartDeferredLibrary(loading_unit_id);
1725 }
1726 });
1727}
1728
1729// |Engine::Delegate|
1730double Shell::GetScaledFontSize(double unscaled_font_size,
1731 int configuration_id) const {
1732 return platform_view_->GetScaledFontSize(unscaled_font_size,
1733 configuration_id);
1734}
1735
1736void Shell::RequestViewFocusChange(const ViewFocusChangeRequest& request) {
1737 FML_DCHECK(is_set_up_);
1738
1740 task_runners_.GetPlatformTaskRunner(),
1741 [view = platform_view_->GetWeakPtr(), request] {
1742 if (view) {
1743 view->RequestViewFocusChange(request);
1744 }
1745 });
1746}
1747
1748void Shell::ReportTimings() {
1749 FML_DCHECK(is_set_up_);
1751
1752 auto timings = std::move(unreported_timings_);
1753 unreported_timings_ = {};
1754 task_runners_.GetUITaskRunner()->PostTask([timings, engine = weak_engine_] {
1755 if (engine) {
1756 engine->ReportTimings(timings);
1757 }
1758 });
1759}
1760
1761size_t Shell::UnreportedFramesCount() const {
1762 // Check that this is running on the raster thread to avoid race conditions.
1764 FML_DCHECK(unreported_timings_.size() % (FrameTiming::kStatisticsCount) == 0);
1765 return unreported_timings_.size() / (FrameTiming::kStatisticsCount);
1766}
1767
1768void Shell::OnFrameRasterized(const FrameTiming& timing) {
1769 FML_DCHECK(is_set_up_);
1771
1772 // The C++ callback defined in settings.h and set by Flutter runner. This is
1773 // independent of the timings report to the Dart side.
1774 if (settings_.frame_rasterized_callback) {
1775 settings_.frame_rasterized_callback(timing);
1776 }
1777
1778 if (!needs_report_timings_) {
1779 return;
1780 }
1781
1782 size_t old_count = unreported_timings_.size();
1783 (void)old_count;
1784 for (auto phase : FrameTiming::kPhases) {
1785 unreported_timings_.push_back(
1786 timing.Get(phase).ToEpochDelta().ToMicroseconds());
1787 }
1788 unreported_timings_.push_back(timing.GetLayerCacheCount());
1789 unreported_timings_.push_back(timing.GetLayerCacheBytes());
1790 unreported_timings_.push_back(timing.GetPictureCacheCount());
1791 unreported_timings_.push_back(timing.GetPictureCacheBytes());
1792 unreported_timings_.push_back(timing.GetFrameNumber());
1793 FML_DCHECK(unreported_timings_.size() ==
1794 old_count + FrameTiming::kStatisticsCount);
1795
1796 // In tests using iPhone 6S with profile mode, sending a batch of 1 frame or a
1797 // batch of 100 frames have roughly the same cost of less than 0.1ms. Sending
1798 // a batch of 500 frames costs about 0.2ms. The 1 second threshold usually
1799 // kicks in before we reaching the following 100 frames threshold. The 100
1800 // threshold here is mainly for unit tests (so we don't have to write a
1801 // 1-second unit test), and make sure that our vector won't grow too big with
1802 // future 120fps, 240fps, or 1000fps displays.
1803 //
1804 // In the profile/debug mode, the timings are used by development tools which
1805 // require a latency of no more than 100ms. Hence we lower that 1-second
1806 // threshold to 100ms because performance overhead isn't that critical in
1807 // those cases.
1808 if (!first_frame_rasterized_ || UnreportedFramesCount() >= 100) {
1809 first_frame_rasterized_ = true;
1810 ReportTimings();
1811 } else if (!frame_timings_report_scheduled_) {
1812#if FLUTTER_RELEASE
1813 constexpr int kBatchTimeInMilliseconds = 1000;
1814#else
1815 constexpr int kBatchTimeInMilliseconds = 100;
1816#endif
1817
1818 // Also make sure that frame times get reported with a max latency of 1
1819 // second. Otherwise, the timings of last few frames of an animation may
1820 // never be reported until the next animation starts.
1821 frame_timings_report_scheduled_ = true;
1822 task_runners_.GetRasterTaskRunner()->PostDelayedTask(
1823 [self = weak_factory_gpu_->GetWeakPtr()]() {
1824 if (!self) {
1825 return;
1826 }
1827 self->frame_timings_report_scheduled_ = false;
1828 if (self->UnreportedFramesCount() > 0) {
1829 self->ReportTimings();
1830 }
1831 },
1832 fml::TimeDelta::FromMilliseconds(kBatchTimeInMilliseconds));
1833 }
1834}
1835
1836fml::Milliseconds Shell::GetFrameBudget() {
1837 if (cached_display_refresh_rate_.has_value()) {
1838 return cached_display_refresh_rate_.value();
1839 }
1840 double display_refresh_rate = display_manager_->GetMainDisplayRefreshRate();
1841 if (display_refresh_rate > 0) {
1842 cached_display_refresh_rate_ =
1843 fml::RefreshRateToFrameBudget(display_refresh_rate);
1844 } else {
1845 cached_display_refresh_rate_ = fml::kDefaultFrameBudget;
1846 }
1847 return cached_display_refresh_rate_.value_or(fml::kDefaultFrameBudget);
1848}
1849
1850fml::TimePoint Shell::GetLatestFrameTargetTime() const {
1851 std::scoped_lock time_recorder_lock(time_recorder_mutex_);
1852 FML_CHECK(latest_frame_target_time_.has_value())
1853 << "GetLatestFrameTargetTime called before OnAnimatorBeginFrame";
1854 // Covered by FML_CHECK().
1855 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
1856 return latest_frame_target_time_.value();
1857}
1858
1859// |Rasterizer::Delegate|
1860bool Shell::ShouldDiscardLayerTree(int64_t view_id,
1861 const flutter::LayerTree& tree) {
1862 std::scoped_lock<std::mutex> lock(resize_mutex_);
1863 auto expected_frame_constraints = ExpectedFrameConstraints(view_id);
1864 return !expected_frame_constraints.IsSatisfiedBy(
1865 Size(tree.frame_size().width, tree.frame_size().height));
1866}
1867
1868// |ServiceProtocol::Handler|
1869fml::RefPtr<fml::TaskRunner> Shell::GetServiceProtocolHandlerTaskRunner(
1870 std::string_view method) const {
1871 FML_DCHECK(is_set_up_);
1872 auto found = service_protocol_handlers_.find(method);
1873 if (found != service_protocol_handlers_.end()) {
1874 return found->second.first;
1875 }
1876 return task_runners_.GetUITaskRunner();
1877}
1878
1879// |ServiceProtocol::Handler|
1880bool Shell::HandleServiceProtocolMessage(
1881 std::string_view method, // one if the extension names specified above.
1882 const ServiceProtocolMap& params,
1883 rapidjson::Document* response) {
1884 auto found = service_protocol_handlers_.find(method);
1885 if (found != service_protocol_handlers_.end()) {
1886 return found->second.second(params, response);
1887 }
1888 return false;
1889}
1890
1891// |ServiceProtocol::Handler|
1892ServiceProtocol::Handler::Description Shell::GetServiceProtocolDescription()
1893 const {
1895
1896 if (!weak_engine_) {
1898 }
1899
1900 return {
1901 weak_engine_->GetUIIsolateMainPort(),
1902 weak_engine_->GetUIIsolateName(),
1903 };
1904}
1905
1906static void ServiceProtocolParameterError(rapidjson::Document* response,
1907 std::string error_details) {
1908 auto& allocator = response->GetAllocator();
1909 response->SetObject();
1910 const int64_t kInvalidParams = -32602;
1911 response->AddMember("code", kInvalidParams, allocator);
1912 response->AddMember("message", "Invalid params", allocator);
1913 {
1914 rapidjson::Value details(rapidjson::kObjectType);
1915 details.AddMember("details", std::move(error_details), allocator);
1916 response->AddMember("data", details, allocator);
1917 }
1918}
1919
1920static void ServiceProtocolFailureError(rapidjson::Document* response,
1921 std::string message) {
1922 auto& allocator = response->GetAllocator();
1923 response->SetObject();
1924 const int64_t kJsonServerError = -32000;
1925 response->AddMember("code", kJsonServerError, allocator);
1926 response->AddMember("message", std::move(message), allocator);
1927}
1928
1929// Service protocol handler
1930bool Shell::OnServiceProtocolScreenshot(
1932 rapidjson::Document* response) {
1934 auto screenshot = rasterizer_->ScreenshotLastLayerTree(
1936 if (screenshot.data) {
1937 response->SetObject();
1938 auto& allocator = response->GetAllocator();
1939 response->AddMember("type", "Screenshot", allocator);
1940 rapidjson::Value image;
1941 image.SetString(static_cast<const char*>(screenshot.data->data()),
1942 screenshot.data->size(), allocator);
1943 response->AddMember("screenshot", image, allocator);
1944 return true;
1945 }
1946 ServiceProtocolFailureError(response, "Could not capture image screenshot.");
1947 return false;
1948}
1949
1950// Service protocol handler
1951bool Shell::OnServiceProtocolScreenshotSKP(
1953 rapidjson::Document* response) {
1955 if (settings_.enable_impeller) {
1957 response, "Cannot capture SKP screenshot with Impeller enabled.");
1958 return false;
1959 }
1960 auto screenshot = rasterizer_->ScreenshotLastLayerTree(
1962 if (screenshot.data) {
1963 response->SetObject();
1964 auto& allocator = response->GetAllocator();
1965 response->AddMember("type", "ScreenshotSkp", allocator);
1966 rapidjson::Value skp;
1967 skp.SetString(static_cast<const char*>(screenshot.data->data()),
1968 screenshot.data->size(), allocator);
1969 response->AddMember("skp", skp, allocator);
1970 return true;
1971 }
1972 ServiceProtocolFailureError(response, "Could not capture SKP screenshot.");
1973 return false;
1974}
1975
1976// Service protocol handler
1977bool Shell::OnServiceProtocolRunInView(
1979 rapidjson::Document* response) {
1981
1982 if (params.count("mainScript") == 0) {
1984 "'mainScript' parameter is missing.");
1985 return false;
1986 }
1987
1988 if (params.count("assetDirectory") == 0) {
1990 "'assetDirectory' parameter is missing.");
1991 return false;
1992 }
1993
1994 std::string main_script_path =
1995 fml::paths::FromURI(params.at("mainScript").data());
1996 std::string asset_directory_path =
1997 fml::paths::FromURI(params.at("assetDirectory").data());
1998
1999 auto main_script_file_mapping =
2000 std::make_unique<fml::FileMapping>(fml::OpenFile(
2001 main_script_path.c_str(), false, fml::FilePermission::kRead));
2002
2003 auto isolate_configuration = IsolateConfiguration::CreateForKernel(
2004 std::move(main_script_file_mapping));
2005
2006 RunConfiguration configuration(std::move(isolate_configuration));
2007
2008 configuration.SetEntrypointAndLibrary(engine_->GetLastEntrypoint(),
2009 engine_->GetLastEntrypointLibrary());
2010 configuration.SetEntrypointArgs(engine_->GetLastEntrypointArgs());
2011
2012 configuration.SetEngineId(engine_->GetLastEngineId());
2013
2014 configuration.AddAssetResolver(std::make_unique<DirectoryAssetBundle>(
2015 fml::OpenDirectory(asset_directory_path.c_str(), false,
2017 false));
2018
2019 // Preserve any original asset resolvers to avoid syncing unchanged assets
2020 // over the DevFS connection.
2021 auto old_asset_manager = engine_->GetAssetManager();
2022 if (old_asset_manager != nullptr) {
2023 for (auto& old_resolver : old_asset_manager->TakeResolvers()) {
2024 if (old_resolver->IsValidAfterAssetManagerChange()) {
2025 configuration.AddAssetResolver(std::move(old_resolver));
2026 }
2027 }
2028 }
2029
2030 auto& allocator = response->GetAllocator();
2031 response->SetObject();
2032 if (engine_->Restart(std::move(configuration))) {
2033 response->AddMember("type", "Success", allocator);
2034 auto new_description = GetServiceProtocolDescription();
2035 rapidjson::Value view(rapidjson::kObjectType);
2036 new_description.Write(this, view, allocator);
2037 response->AddMember("view", view, allocator);
2038 return true;
2039 } else {
2040 FML_DLOG(ERROR) << "Could not run configuration in engine.";
2042 "Could not run configuration in engine.");
2043 return false;
2044 }
2045
2046 FML_DCHECK(false);
2047 return false;
2048}
2049
2050// Service protocol handler
2051bool Shell::OnServiceProtocolFlushUIThreadTasks(
2053 rapidjson::Document* response) {
2055 // This API should not be invoked by production code.
2056 // It can potentially starve the service isolate if the main isolate pauses
2057 // at a breakpoint or is in an infinite loop.
2058 //
2059 // It should be invoked from the VM Service and blocks it until UI thread
2060 // tasks are processed.
2061 response->SetObject();
2062 response->AddMember("type", "Success", response->GetAllocator());
2063 return true;
2064}
2065
2066bool Shell::OnServiceProtocolGetDisplayRefreshRate(
2068 rapidjson::Document* response) {
2070 response->SetObject();
2071 response->AddMember("type", "DisplayRefreshRate", response->GetAllocator());
2072 response->AddMember("fps", display_manager_->GetMainDisplayRefreshRate(),
2073 response->GetAllocator());
2074 return true;
2075}
2076
2078 return display_manager_->GetMainDisplayRefreshRate();
2079}
2080
2082 int32_t priority) {
2084 FML_DCHECK(is_set_up_);
2085
2087 task_runners_.GetUITaskRunner(),
2088 [engine = engine_->GetWeakPtr(), factory = std::move(factory),
2089 priority]() {
2090 if (engine) {
2091 engine->GetImageGeneratorRegistry()->AddFactory(factory, priority);
2092 }
2093 });
2094}
2095
2096bool Shell::OnServiceProtocolGetSkSLs(
2098 rapidjson::Document* response) {
2100 response->SetObject();
2101 response->AddMember("type", "GetSkSLs", response->GetAllocator());
2102
2103 rapidjson::Value shaders_json(rapidjson::kObjectType);
2104#if !SLIMPELLER
2105 PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess();
2106 std::vector<PersistentCache::SkSLCache> sksls = persistent_cache->LoadSkSLs();
2107 for (const auto& sksl : sksls) {
2108 size_t b64_size = Base64::EncodedSize(sksl.value->size());
2109 sk_sp<SkData> b64_data = SkData::MakeUninitialized(b64_size + 1);
2110 char* b64_char = static_cast<char*>(b64_data->writable_data());
2111 Base64::Encode(sksl.value->data(), sksl.value->size(), b64_char);
2112 b64_char[b64_size] = 0; // make it null terminated for printing
2113 rapidjson::Value shader_value(b64_char, response->GetAllocator());
2114 std::string_view key_view(reinterpret_cast<const char*>(sksl.key->data()),
2115 sksl.key->size());
2116 auto encode_result = fml::Base32Encode(key_view);
2117 if (!encode_result.first) {
2118 continue;
2119 }
2120 rapidjson::Value shader_key(encode_result.second, response->GetAllocator());
2121 shaders_json.AddMember(shader_key, shader_value, response->GetAllocator());
2122 }
2123#endif // !SLIMPELLER
2124 response->AddMember("SkSLs", shaders_json, response->GetAllocator());
2125 return true;
2126}
2127
2128bool Shell::OnServiceProtocolEstimateRasterCacheMemory(
2130 rapidjson::Document* response) {
2132
2133 uint64_t layer_cache_byte_size = 0u;
2134 uint64_t picture_cache_byte_size = 0u;
2135
2136#if !SLIMPELLER
2137 const auto& raster_cache = rasterizer_->compositor_context()->raster_cache();
2138 layer_cache_byte_size = raster_cache.EstimateLayerCacheByteSize();
2139 picture_cache_byte_size = raster_cache.EstimatePictureCacheByteSize();
2140#endif // !SLIMPELLER
2141
2142 response->SetObject();
2143 response->AddMember("type", "EstimateRasterCacheMemory",
2144 response->GetAllocator());
2145 response->AddMember<uint64_t>("layerBytes", layer_cache_byte_size,
2146 response->GetAllocator());
2147 response->AddMember<uint64_t>("pictureBytes", picture_cache_byte_size,
2148 response->GetAllocator());
2149 return true;
2150}
2151
2152// Service protocol handler
2153bool Shell::OnServiceProtocolSetAssetBundlePath(
2155 rapidjson::Document* response) {
2157
2158 if (params.count("assetDirectory") == 0) {
2160 "'assetDirectory' parameter is missing.");
2161 return false;
2162 }
2163
2164 auto& allocator = response->GetAllocator();
2165 response->SetObject();
2166
2167 auto asset_manager = std::make_shared<AssetManager>();
2168
2169 if (!asset_manager->PushFront(std::make_unique<DirectoryAssetBundle>(
2170 fml::OpenDirectory(params.at("assetDirectory").data(), false,
2172 false))) {
2173 // The new asset directory path was invalid.
2174 FML_DLOG(ERROR) << "Could not update asset directory.";
2175 ServiceProtocolFailureError(response, "Could not update asset directory.");
2176 return false;
2177 }
2178
2179 // Preserve any original asset resolvers to avoid syncing unchanged assets
2180 // over the DevFS connection.
2181 auto old_asset_manager = engine_->GetAssetManager();
2182 if (old_asset_manager != nullptr) {
2183 for (auto& old_resolver : old_asset_manager->TakeResolvers()) {
2184 if (old_resolver->IsValidAfterAssetManagerChange()) {
2185 asset_manager->PushBack(std::move(old_resolver));
2186 }
2187 }
2188 }
2189
2190 if (engine_->UpdateAssetManager(asset_manager)) {
2191 response->AddMember("type", "Success", allocator);
2192 auto new_description = GetServiceProtocolDescription();
2193 rapidjson::Value view(rapidjson::kObjectType);
2194 new_description.Write(this, view, allocator);
2195 response->AddMember("view", view, allocator);
2196 return true;
2197 } else {
2198 FML_DLOG(ERROR) << "Could not update asset directory.";
2199 ServiceProtocolFailureError(response, "Could not update asset directory.");
2200 return false;
2201 }
2202
2203 FML_DCHECK(false);
2204 return false;
2205}
2206
2207bool Shell::OnServiceProtocolGetPipelineUsage(
2209 rapidjson::Document* response) {
2211
2212 response->SetObject();
2213
2214 auto context = io_manager_->GetImpellerContext();
2215
2216 if (!context) {
2217 FML_DLOG(ERROR) << "Pipeline usage profiling only available in Impeller";
2219 response, "Pipeline usage profiling only available in Impeller");
2220 return false;
2221 }
2222
2223 auto use_counts = context->GetPipelineLibrary()->GetPipelineUseCounts();
2224
2225 rapidjson::Value pipelines_json(rapidjson::kObjectType);
2226
2227 for (const auto& pipelineCount : use_counts) {
2228 std::string_view pipeline_name = pipelineCount.first.GetLabel();
2229 rapidjson::Value pipeline_key(pipeline_name.data(), pipeline_name.length(),
2230 response->GetAllocator());
2231
2232 pipelines_json.AddMember(pipeline_key, pipelineCount.second,
2233 response->GetAllocator());
2234 }
2235
2236 response->AddMember("Usages", pipelines_json, response->GetAllocator());
2237 return true;
2238}
2239
2240void Shell::SendFontChangeNotification() {
2241 // After system fonts are reloaded, we send a system channel message
2242 // to notify flutter framework.
2243 rapidjson::Document document;
2244 document.SetObject();
2245 auto& allocator = document.GetAllocator();
2246 rapidjson::Value message_value;
2247 message_value.SetString(kFontChange, allocator);
2248 document.AddMember(kTypeKey, message_value, allocator);
2249
2250 rapidjson::StringBuffer buffer;
2251 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
2252 document.Accept(writer);
2253 std::string message = buffer.GetString();
2254 std::unique_ptr<PlatformMessage> fontsChangeMessage =
2255 std::make_unique<flutter::PlatformMessage>(
2257 fml::MallocMapping::Copy(message.c_str(), message.length()), nullptr);
2258 OnPlatformViewDispatchPlatformMessage(std::move(fontsChangeMessage));
2259}
2260
2261bool Shell::OnServiceProtocolReloadAssetFonts(
2263 rapidjson::Document* response) {
2265 if (!engine_) {
2266 return false;
2267 }
2268 engine_->GetFontCollection().RegisterFonts(engine_->GetAssetManager());
2269 engine_->GetFontCollection().GetFontCollection()->ClearFontFamilyCache();
2270 SendFontChangeNotification();
2271
2272 auto& allocator = response->GetAllocator();
2273 response->SetObject();
2274 response->AddMember("type", "Success", allocator);
2275
2276 return true;
2277}
2278
2279void Shell::OnPlatformViewAddView(int64_t view_id,
2280 const ViewportMetrics& viewport_metrics,
2281 AddViewCallback callback) {
2282 TRACE_EVENT0("flutter", "Shell::AddView");
2283 FML_DCHECK(is_set_up_);
2286 << "Unexpected request to add the implicit view #"
2287 << kFlutterImplicitViewId << ". This view should never be added.";
2288
2289 task_runners_.GetUITaskRunner()->RunNowOrPostTask(
2290 task_runners_.GetUITaskRunner(), [engine = engine_->GetWeakPtr(), //
2291 viewport_metrics, //
2292 view_id, //
2293 callback = std::move(callback) //
2294 ] {
2295 if (engine) {
2296 engine->AddView(view_id, viewport_metrics, callback);
2297 }
2298 });
2299}
2300
2301void Shell::OnPlatformViewRemoveView(int64_t view_id,
2302 RemoveViewCallback callback) {
2303 TRACE_EVENT0("flutter", "Shell::RemoveView");
2304 FML_DCHECK(is_set_up_);
2307 << "Unexpected request to remove the implicit view #"
2308 << kFlutterImplicitViewId << ". This view should never be removed.";
2309 {
2310 std::scoped_lock<std::mutex> lock(resize_mutex_);
2311 expected_frame_constraints_.erase(view_id);
2312 }
2313 task_runners_.GetUITaskRunner()->RunNowOrPostTask(
2314 task_runners_.GetUITaskRunner(),
2315 [&task_runners = task_runners_, //
2316 engine = engine_->GetWeakPtr(), //
2317 rasterizer = rasterizer_->GetWeakPtr(), //
2318 view_id, //
2319 callback = std::move(callback) //
2320 ]() mutable {
2321 bool removed = false;
2322 if (engine) {
2323 removed = engine->RemoveView(view_id);
2324 }
2325 task_runners.GetRasterTaskRunner()->PostTask(
2326 [rasterizer, view_id, callback = std::move(callback), removed]() {
2327 if (rasterizer) {
2328 rasterizer->CollectView(view_id);
2329 }
2330 // Only call the callback after it is known for certain that the
2331 // raster thread will not try to use resources associated with
2332 // the view.
2333 callback(removed);
2334 });
2335 });
2336}
2337
2338void Shell::OnPlatformViewSendViewFocusEvent(const ViewFocusEvent& event) {
2339 TRACE_EVENT0("flutter", "Shell:: OnPlatformViewSendViewFocusEvent");
2340 FML_DCHECK(is_set_up_);
2342
2344 task_runners_.GetUITaskRunner(),
2345 [engine = engine_->GetWeakPtr(), event = event] {
2346 if (engine) {
2347 engine->SendViewFocusEvent(event);
2348 }
2349 });
2350}
2351
2352Rasterizer::Screenshot Shell::Screenshot(
2353 Rasterizer::ScreenshotType screenshot_type,
2354 bool base64_encode) {
2355 if (settings_.enable_impeller) {
2356 switch (screenshot_type) {
2358 FML_LOG(ERROR)
2359 << "Impeller backend cannot produce ScreenshotType::SkiaPicture.";
2360 return {};
2364 break;
2365 }
2366 }
2367 TRACE_EVENT0("flutter", "Shell::Screenshot");
2369 Rasterizer::Screenshot screenshot;
2371 task_runners_.GetRasterTaskRunner(), [&latch, //
2372 rasterizer = GetRasterizer(), //
2373 &screenshot, //
2374 screenshot_type, //
2375 base64_encode //
2376 ]() {
2377 if (rasterizer) {
2378 screenshot = rasterizer->ScreenshotLastLayerTree(screenshot_type,
2379 base64_encode);
2380 }
2381 latch.Signal();
2382 });
2383 latch.Wait();
2384 return screenshot;
2385}
2386
2388 FML_DCHECK(is_set_up_);
2389 if (task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread() ||
2390 task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread()) {
2392 "WaitForFirstFrame called from thread that can't wait "
2393 "because it is responsible for generating the frame.");
2394 }
2395
2396 // Check for overflow.
2397 auto now = std::chrono::steady_clock::now();
2398 auto max_duration = std::chrono::steady_clock::time_point::max() - now;
2399 auto desired_duration = std::chrono::milliseconds(timeout.ToMilliseconds());
2400 auto duration =
2401 now + (desired_duration > max_duration ? max_duration : desired_duration);
2402
2403 std::unique_lock<std::mutex> lock(waiting_for_first_frame_mutex_);
2404 bool success = waiting_for_first_frame_condition_.wait_until(
2405 lock, duration, [&waiting_for_first_frame = waiting_for_first_frame_] {
2406 return !waiting_for_first_frame.load();
2407 });
2408 if (success) {
2409 return fml::Status();
2410 } else {
2412 }
2413}
2414
2416 FML_DCHECK(is_set_up_);
2418
2419 if (!engine_) {
2420 return false;
2422 engine_->SetupDefaultFontManager();
2423 engine_->GetFontCollection().GetFontCollection()->ClearFontFamilyCache();
2424 // After system fonts are reloaded, we send a system channel message
2425 // to notify flutter framework.
2426 SendFontChangeNotification();
2427 return true;
2428}
2429
2430std::shared_ptr<const fml::SyncSwitch> Shell::GetIsGpuDisabledSyncSwitch()
2431 const {
2432 return is_gpu_disabled_sync_switch_;
2433}
2434
2435void Shell::SetGpuAvailability(GpuAvailability availability) {
2437 switch (availability) {
2439 is_gpu_disabled_sync_switch_->SetSwitch(false);
2440 return;
2444 task_runners_.GetIOTaskRunner(),
2445 [io_manager = io_manager_.get(), &latch]() {
2446 io_manager->GetSkiaUnrefQueue()->Drain();
2447 latch.Signal();
2448 });
2449 latch.Wait();
2450 }
2451 // FALLTHROUGH
2453 is_gpu_disabled_sync_switch_->SetSwitch(true);
2454 return;
2455 default:
2456 FML_DCHECK(false);
2457 }
2458}
2459
2460void Shell::OnDisplayUpdates(std::vector<std::unique_ptr<Display>> displays) {
2461 FML_DCHECK(is_set_up_);
2463
2464 std::vector<DisplayData> display_data;
2465 display_data.reserve(displays.size());
2466 for (const auto& display : displays) {
2467 display_data.push_back(display->GetDisplayData());
2468 }
2470 [engine = engine_->GetWeakPtr(),
2471 display_data = std::move(display_data)]() {
2472 if (engine) {
2473 engine->SetDisplays(display_data);
2474 }
2475 });
2477 display_manager_->HandleDisplayUpdates(std::move(displays));
2478}
2479
2480fml::TimePoint Shell::GetCurrentTimePoint() {
2481 return fml::TimePoint::Now();
2482}
2483
2484const std::shared_ptr<PlatformMessageHandler>&
2486 return platform_message_handler_;
2487}
2489const std::weak_ptr<VsyncWaiter> Shell::GetVsyncWaiter() const {
2490 if (!engine_) {
2491 return {};
2492 }
2493 return engine_->GetVsyncWaiter();
2494}
2495
2496const std::shared_ptr<fml::ConcurrentTaskRunner>
2498 FML_DCHECK(vm_);
2499 if (!vm_) {
2500 return nullptr;
2501 }
2502 return vm_->GetConcurrentWorkerTaskRunner();
2503}
2504
2505BoxConstraints Shell::ExpectedFrameConstraints(int64_t view_id) {
2506 auto found = expected_frame_constraints_.find(view_id);
2507
2508 if (found == expected_frame_constraints_.end()) {
2509 return {};
2510 }
2511
2512 return found->second;
2513}
2514
2515} // namespace flutter
std::unique_ptr< flutter::PlatformViewIOS > platform_view
AssetResolverType
Identifies the type of AssetResolver an instance is.
static fml::RefPtr< const DartSnapshot > VMSnapshotFromSettings(const Settings &settings)
From the fields present in the given settings object, infer the core snapshot.
static fml::RefPtr< const DartSnapshot > IsolateSnapshotFromSettings(const Settings &settings)
From the fields present in the given settings object, infer the isolate snapshot.
Describes a running instance of the Dart VM. There may only be one running instance of the Dart VM in...
Definition dart_vm.h:61
std::shared_ptr< const DartVMData > GetVMData() const
The VM and isolate snapshots used by this running Dart VM instance.
Definition dart_vm.cc:524
std::shared_ptr< fml::ConcurrentTaskRunner > GetConcurrentWorkerTaskRunner() const
The task runner whose tasks may be executed concurrently on a pool of worker threads....
Definition dart_vm.cc:541
std::shared_ptr< ServiceProtocol > GetServiceProtocol() const
The service protocol instance associated with this running Dart VM instance. This object manages nati...
Definition dart_vm.cc:532
static DartVMRef Create(const Settings &settings, fml::RefPtr< const DartSnapshot > vm_snapshot=nullptr, fml::RefPtr< const DartSnapshot > isolate_snapshot=nullptr)
While the engine operates entirely on the UI task runner, it needs the capabilities of the other comp...
Definition engine.h:136
RunStatus
Indicates the result of the call to Engine::Run.
Definition engine.h:74
static constexpr int kStatisticsCount
Definition settings.h:41
static std::unique_ptr< IsolateConfiguration > CreateForKernel(std::unique_ptr< const fml::Mapping > kernel)
Creates a JIT isolate configuration using the specified snapshot. This is a convenience method for th...
const DlISize & frame_size() const
Definition layer_tree.h:54
void RemoveWorkerTaskRunner(const fml::RefPtr< fml::TaskRunner > &task_runner)
static PersistentCache * GetCacheForProcess()
static void SetCacheSkSL(bool value)
void SetIsDumpingSkp(bool value)
void AddWorkerTaskRunner(const fml::RefPtr< fml::TaskRunner > &task_runner)
ScreenshotType
The type of the screenshot to obtain of the previously rendered layer tree.
Definition rasterizer.h:348
std::map< std::string_view, std::string_view > ServiceProtocolMap
static const std::string_view kGetPipelineUsageExtensionName
static const std::string_view kSetAssetBundlePathExtensionName
static const std::string_view kReloadAssetFonts
static const std::string_view kScreenshotSkpExtensionName
static const std::string_view kScreenshotExtensionName
static const std::string_view kGetDisplayRefreshRateExtensionName
static const std::string_view kRunInViewExtensionName
static const std::string_view kEstimateRasterCacheMemoryExtensionName
static const std::string_view kGetSkSLsExtensionName
static const std::string_view kFlushUIThreadTasksExtensionName
DartVM * GetDartVM()
Get a pointer to the Dart VM used by this running shell instance.
Definition shell.cc:960
std::function< std::unique_ptr< Engine >(Engine::Delegate &delegate, const PointerDataDispatcherMaker &dispatcher_maker, DartVM &vm, fml::RefPtr< const DartSnapshot > isolate_snapshot, TaskRunners task_runners, const PlatformData &platform_data, Settings settings, std::unique_ptr< Animator > animator, fml::WeakPtr< IOManager > io_manager, fml::RefPtr< SkiaUnrefQueue > unref_queue, fml::TaskRunnerAffineWeakPtr< SnapshotDelegate > snapshot_delegate, const std::shared_ptr< fml::SyncSwitch > &gpu_disabled_switch, const std::shared_future< impeller::RuntimeStageBackend > &runtime_stage_backend)> EngineCreateCallback
Definition shell.h:137
std::optional< DartErrorCode > GetUIIsolateLastError() const
Used by embedders to get the last error from the Dart UI Isolate, if one exists.
Definition shell.cc:807
static std::unique_ptr< Shell > Create(const PlatformData &platform_data, const TaskRunners &task_runners, Settings settings, const CreateCallback< PlatformView > &on_create_platform_view, const CreateCallback< Rasterizer > &on_create_rasterizer, bool is_gpu_disabled=false)
Creates a shell instance using the provided settings. The callbacks to create the various shell subco...
Definition shell.cc:223
void FlushMicrotaskQueue() const
Used by embedders to flush the microtask queue. Required when running with merged platform and UI thr...
Definition shell.cc:763
fml::TaskRunnerAffineWeakPtr< Engine > GetEngine()
Engines may only be accessed on the UI thread. This method is deprecated, and implementers should ins...
Definition shell.cc:941
bool EngineHasLivePorts() const
Used by embedders to check if the Engine is running and has any live ports remaining....
Definition shell.cc:827
~Shell()
Destroys the shell. This is a synchronous operation and synchronous barrier blocks are introduced on ...
Definition shell.cc:606
Rasterizer::Screenshot Screenshot(Rasterizer::ScreenshotType type, bool base64_encode)
Captures a screenshot and optionally Base64 encodes the data of the last layer tree rendered by the r...
Definition shell.cc:2343
static std::pair< DartVMRef, fml::RefPtr< const DartSnapshot > > InferVmInitDataFromSettings(Settings &settings)
Definition shell.cc:207
fml::WeakPtr< ShellIOManager > GetIOManager()
The IO Manager may only be accessed on the IO task runner.
Definition shell.cc:951
fml::TaskRunnerAffineWeakPtr< Rasterizer > GetRasterizer() const
Rasterizers may only be accessed on the raster task runner.
Definition shell.cc:936
void RunEngine(RunConfiguration run_configuration)
Starts an isolate for the given RunConfiguration.
Definition shell.cc:769
std::unique_ptr< Shell > Spawn(RunConfiguration run_configuration, const std::string &initial_route, const CreateCallback< PlatformView > &on_create_platform_view, const CreateCallback< Rasterizer > &on_create_rasterizer) const
Creates one Shell from another Shell where the created Shell takes the opportunity to share any inter...
Definition shell.cc:687
const std::weak_ptr< VsyncWaiter > GetVsyncWaiter() const
Definition shell.cc:2480
const std::shared_ptr< PlatformMessageHandler > & GetPlatformMessageHandler() const override
Returns the delegate object that handles PlatformMessage's from Flutter to the host platform (and its...
Definition shell.cc:2476
const std::shared_ptr< fml::ConcurrentTaskRunner > GetConcurrentWorkerTaskRunner() const
Definition shell.cc:2488
void NotifyLowMemoryWarning() const
Used by embedders to notify that there is a low memory warning. The shell will attempt to purge cache...
Definition shell.cc:741
bool EngineHasPendingMicrotasks() const
Used by embedders to check if the Engine is running and has any microtasks that have been queued but ...
Definition shell.cc:838
const Settings & GetSettings() const override
Definition shell.cc:923
fml::Status WaitForFirstFrame(fml::TimeDelta timeout)
Pauses the calling thread until the first frame is presented.
Definition shell.cc:2378
void OnDisplayUpdates(std::vector< std::unique_ptr< Display > > displays)
Notifies the display manager of the updates.
Definition shell.cc:2451
const TaskRunners & GetTaskRunners() const override
If callers wish to interact directly with any shell subcomponents, they must (on the platform thread)...
Definition shell.cc:927
std::shared_ptr< const fml::SyncSwitch > GetIsGpuDisabledSyncSwitch() const override
Accessor for the disable GPU SyncSwitch.
Definition shell.cc:2421
std::shared_ptr< fml::BasicTaskRunner > GetShutdownSafeIOTaskRunner()
The IO thread can be used for background tasks, including tasks that perform graphics operations usin...
Definition shell.cc:956
void SetGpuAvailability(GpuAvailability availability)
Marks the GPU as available or unavailable.
Definition shell.cc:2426
void RegisterImageDecoder(ImageGeneratorFactory factory, int32_t priority)
Install a new factory that can match against and decode image data.
Definition shell.cc:2072
const fml::RefPtr< fml::RasterThreadMerger > GetParentRasterThreadMerger() const override
Getting the raster thread merger from parent shell, it can be a null RefPtr when it's a root Shell or...
Definition shell.cc:931
std::function< std::unique_ptr< T >(Shell &)> CreateCallback
Definition shell.h:121
bool IsSetup() const
Used by embedders to check if all shell subcomponents are initialized. It is the embedder's responsib...
Definition shell.cc:849
double GetMainDisplayRefreshRate()
Queries the DisplayManager for the main display refresh rate.
Definition shell.cc:2068
bool ReloadSystemFonts()
Used by embedders to reload the system fonts in FontCollection. It also clears the cached font famili...
Definition shell.cc:2406
fml::WeakPtr< PlatformView > GetPlatformView()
Platform views may only be accessed on the platform task runner.
Definition shell.cc:946
fml::RefPtr< fml::TaskRunner > GetRasterTaskRunner() const
fml::RefPtr< fml::TaskRunner > GetUITaskRunner() const
fml::RefPtr< fml::TaskRunner > GetIOTaskRunner() const
fml::RefPtr< fml::TaskRunner > GetPlatformTaskRunner() const
A Mapping like NonOwnedMapping, but uses Free as its release proc.
Definition mapping.h:144
static MallocMapping Copy(const T *begin, const T *end)
Definition mapping.h:162
static MessageLoopTaskQueues * GetInstance()
static void RunNowOrPostTask(const fml::RefPtr< fml::TaskRunner > &runner, const fml::closure &task)
static void RunNowAndFlushMessages(const fml::RefPtr< fml::TaskRunner > &runner, const fml::closure &task)
virtual void PostTask(const fml::closure &task) override
virtual bool RunsTasksOnCurrentThread()
virtual TaskQueueId GetTaskQueueId()
virtual void PostDelayedTask(const fml::closure &task, fml::TimeDelta delay)
constexpr int64_t ToMilliseconds() const
Definition time_delta.h:63
static constexpr TimeDelta FromMilliseconds(int64_t millis)
Definition time_delta.h:46
static TimePoint Now()
Definition time_point.cc:49
int32_t value
const EmbeddedViewParams * params
FlutterVulkanImage * image
Settings settings_
TaskRunners task_runners_
fml::WeakPtr< IOManager > io_manager_
FlutterEngine engine
Definition main.cc:84
FlView * view
const char * message
if(engine==nullptr)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
G_BEGIN_DECLS FlutterViewId view_id
FlutterDesktopBinaryReply callback
#define FML_DLOG(severity)
Definition logging.h:121
#define FML_LOG(severity)
Definition logging.h:101
#define FML_CHECK(condition)
Definition logging.h:104
#define FML_DCHECK(condition)
Definition logging.h:122
std::shared_ptr< ImpellerAllocator > allocator
FlTexture * texture
@ CompilationError
The Dart error code for a compilation error.
@ ApiError
The Dart error code for an API error.
@ NoError
No error has occurred.
@ UnknownError
The Dart error code for an unknown error.
constexpr int64_t kFlutterImplicitViewId
Definition constants.h:35
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
static void ServiceProtocolFailureError(rapidjson::Document *response, std::string message)
Definition shell.cc:1911
std::function< std::shared_ptr< ImageGenerator >(sk_sp< SkData > buffer)> ImageGeneratorFactory
ImageGeneratorFactory is the top level primitive for specifying an image decoder in Flutter....
std::unordered_map< int32_t, CustomAccessibilityAction > CustomAccessibilityActionUpdates
void InitSkiaEventTracer(bool enabled, const std::optional< std::vector< std::string > > &allowlist)
std::function< std::unique_ptr< PointerDataDispatcher >(PointerDataDispatcher::Delegate &)> PointerDataDispatcherMaker
Signature for constructing PointerDataDispatcher.
DEF_SWITCHES_START aot vmservice shared library name
Definition switch_defs.h:27
constexpr char kFontChange[]
Definition shell.cc:56
static void ServiceProtocolParameterError(rapidjson::Document *response, std::string error_details)
Definition shell.cc:1897
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switch_defs.h:36
constexpr char kTypeKey[]
Definition shell.cc:55
constexpr char kSystemChannel[]
Definition shell.cc:54
constexpr char kSkiaChannel[]
Definition shell.cc:53
GpuAvailability
Values for |Shell::SetGpuAvailability|.
Definition shell.h:64
@ kAvailable
Indicates that GPU operations should be permitted.
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set profile Make the profiler discard new samples once the profiler sample buffer is full When this flag is not the profiler sample buffer is used as a ring buffer
Definition switch_defs.h:98
void InitializeICU(const std::string &icu_data_path)
Definition icu_util.cc:102
void InitializeICUFromMapping(std::unique_ptr< Mapping > mapping)
Definition icu_util.cc:113
std::string FromURI(const std::string &uri)
void TraceSetAllowlist(const std::vector< std::string > &allowlist)
size_t TraceNonce()
std::chrono::duration< double, std::milli > Milliseconds
Definition time_delta.h:18
void SetLogSettings(const LogSettings &settings)
constexpr LogSeverity kLogError
Definition log_level.h:15
fml::UniqueFD OpenDirectory(const char *path, bool create_if_necessary, FilePermission permission)
Definition file_posix.cc:97
internal::CopyableLambda< T > MakeCopyable(T lambda)
std::pair< bool, std::string > Base32Encode(std::string_view input)
Definition base32.cc:15
constexpr Milliseconds kDefaultFrameBudget
Definition time_delta.h:21
constexpr LogSeverity kLogInfo
Definition log_level.h:13
std::function< void()> closure
Definition closure.h:14
fml::UniqueFD OpenFile(const char *path, bool create_if_necessary, FilePermission permission)
This can open a directory on POSIX, but not on Windows.
Definition file_posix.cc:66
Milliseconds RefreshRateToFrameBudget(T refresh_rate)
Definition time_delta.h:24
TSize< Scalar > Size
Definition size.h:159
Definition ref_ptr.h:261
@ kApiErrorType
Definition dart_error.h:70
@ kCompilationErrorType
Definition dart_error.h:71
@ kUnknownErrorType
Definition dart_error.h:69
@ kNoError
Definition dart_error.h:68
void SetLogHandler(std::function< void(const char *)> handler)
Definition log.cc:46
std::vector< FlutterEngineDisplay > * displays
std::shared_ptr< ContextGLES > context
std::shared_ptr< PipelineGLES > pipeline
impeller::ShaderType type
static size_t Encode(const void *src, size_t length, void *dst)
Definition base64.cc:118
static size_t EncodedSize(size_t srcDataLength)
Definition base64.h:33
bool prefetched_default_font_manager
Definition settings.h:218
bool icu_initialization_required
Definition settings.h:329
MergedPlatformUIThread merged_platform_ui_thread
Definition settings.h:382
bool skia_deterministic_rendering_on_cpu
Definition settings.h:321
bool purge_persistent_cache
Definition settings.h:158
std::vector< std::string > trace_allowlist
Definition settings.h:150
MappingCallback icu_mapper
Definition settings.h:331
bool dump_skp_on_shader_compilation
Definition settings.h:156
std::optional< std::vector< std::string > > trace_skia_allowlist
Definition settings.h:151
std::string icu_data_path
Definition settings.h:330
FrameRasterizedCallback frame_rasterized_callback
Definition settings.h:340
size_t resource_cache_max_bytes_threshold
Definition settings.h:358
LogSeverity min_log_level
Represents the 2 code paths available when calling |SyncSwitchExecute|.
Definition sync_switch.h:35
Handlers & SetIfFalse(const std::function< void()> &handler)
Sets the handler that will be executed if the |SyncSwitch| is false.
Type height
Definition size.h:29
Type width
Definition size.h:28
int64_t texture_id
#define TRACE_FLOW_BEGIN(category, name, id)
#define TRACE_EVENT0(category_group, name)
#define TRACE_EVENT_ASYNC_END0(category_group, name, id)
#define TRACE_EVENT0_WITH_FLOW_IDS(category_group, name, flow_id_count, flow_ids)
#define TRACE_EVENT_ASYNC_BEGIN0(category_group, name, id)