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