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
1229// |PlatformView::Delegate|
1230void Shell::OnPlatformViewDispatchSemanticsAction(int64_t view_id,
1231 int32_t node_id,
1234 FML_DCHECK(is_set_up_);
1236
1238 task_runners_.GetUITaskRunner(),
1239 fml::MakeCopyable([engine = engine_->GetWeakPtr(), view_id, node_id,
1240 action, args = std::move(args)]() mutable {
1241 if (engine) {
1242 engine->DispatchSemanticsAction(view_id, node_id, action,
1243 std::move(args));
1244 }
1245 }));
1246}
1247
1248// |PlatformView::Delegate|
1249void Shell::OnPlatformViewSetSemanticsEnabled(bool enabled) {
1250 FML_DCHECK(is_set_up_);
1252
1254 task_runners_.GetUITaskRunner(),
1255 [engine = engine_->GetWeakPtr(), enabled] {
1256 if (engine) {
1257 engine->SetSemanticsEnabled(enabled);
1258 }
1259 });
1260}
1261
1262// |PlatformView::Delegate|
1263void Shell::OnPlatformViewSetAccessibilityFeatures(int32_t flags) {
1264 FML_DCHECK(is_set_up_);
1266
1268 task_runners_.GetUITaskRunner(), [engine = engine_->GetWeakPtr(), flags] {
1269 if (engine) {
1270 engine->SetAccessibilityFeatures(flags);
1271 }
1272 });
1273}
1274
1275// |PlatformView::Delegate|
1276void Shell::OnPlatformViewRegisterTexture(
1277 std::shared_ptr<flutter::Texture> texture) {
1278 FML_DCHECK(is_set_up_);
1280
1281 task_runners_.GetRasterTaskRunner()->PostTask(
1282 [rasterizer = rasterizer_->GetWeakPtr(), texture] {
1283 if (rasterizer) {
1284 if (auto registry = rasterizer->GetTextureRegistry()) {
1285 registry->RegisterTexture(texture);
1286 }
1287 }
1288 });
1289}
1290
1291// |PlatformView::Delegate|
1292void Shell::OnPlatformViewUnregisterTexture(int64_t texture_id) {
1293 FML_DCHECK(is_set_up_);
1295
1296 task_runners_.GetRasterTaskRunner()->PostTask(
1297 [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() {
1298 if (rasterizer) {
1299 if (auto registry = rasterizer->GetTextureRegistry()) {
1300 registry->UnregisterTexture(texture_id);
1301 }
1302 }
1303 });
1304}
1305
1306// |PlatformView::Delegate|
1307void Shell::OnPlatformViewMarkTextureFrameAvailable(int64_t texture_id) {
1308 FML_DCHECK(is_set_up_);
1310
1311 // Tell the rasterizer that one of its textures has a new frame available.
1312 task_runners_.GetRasterTaskRunner()->PostTask(
1313 [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() {
1314 if (!rasterizer) {
1315 return;
1316 }
1317 auto registry = rasterizer->GetTextureRegistry();
1318
1319 if (!registry) {
1320 return;
1321 }
1322
1323 auto texture = registry->GetTexture(texture_id);
1324
1325 if (!texture) {
1326 return;
1327 }
1328
1329 texture->MarkNewFrameAvailable();
1330 });
1331
1332 // Schedule a new frame without having to rebuild the layer tree.
1334 [engine = engine_->GetWeakPtr()]() {
1335 if (engine) {
1336 engine->ScheduleFrame(false);
1337 }
1338 });
1339}
1340
1341// |PlatformView::Delegate|
1342void Shell::OnPlatformViewSetNextFrameCallback(const fml::closure& closure) {
1343 FML_DCHECK(is_set_up_);
1345
1346 task_runners_.GetRasterTaskRunner()->PostTask(
1347 [rasterizer = rasterizer_->GetWeakPtr(), closure = closure]() {
1348 if (rasterizer) {
1349 rasterizer->SetNextFrameCallback(closure);
1350 }
1351 });
1352}
1353
1354// |PlatformView::Delegate|
1355const Settings& Shell::OnPlatformViewGetSettings() const {
1356 return settings_;
1357}
1358
1359// |Animator::Delegate|
1360void Shell::OnAnimatorBeginFrame(fml::TimePoint frame_target_time,
1361 uint64_t frame_number) {
1362 FML_DCHECK(is_set_up_);
1364
1365 // record the target time for use by rasterizer.
1366 {
1367 std::scoped_lock time_recorder_lock(time_recorder_mutex_);
1368 latest_frame_target_time_.emplace(frame_target_time);
1369 }
1370 if (engine_) {
1371 engine_->BeginFrame(frame_target_time, frame_number);
1372 }
1373}
1374
1375// |Animator::Delegate|
1376void Shell::OnAnimatorNotifyIdle(fml::TimeDelta deadline) {
1377 FML_DCHECK(is_set_up_);
1379
1380 if (engine_) {
1381 engine_->NotifyIdle(deadline);
1382 }
1383}
1384
1385void Shell::OnAnimatorUpdateLatestFrameTargetTime(
1386 fml::TimePoint frame_target_time) {
1387 FML_DCHECK(is_set_up_);
1388
1389 // record the target time for use by rasterizer.
1390 {
1391 std::scoped_lock time_recorder_lock(time_recorder_mutex_);
1392 if (!latest_frame_target_time_) {
1393 latest_frame_target_time_ = frame_target_time;
1394 } else if (latest_frame_target_time_ < frame_target_time) {
1395 latest_frame_target_time_ = frame_target_time;
1396 }
1397 }
1398}
1399
1400// |Animator::Delegate|
1401void Shell::OnAnimatorDraw(std::shared_ptr<FramePipeline> pipeline) {
1402 FML_DCHECK(is_set_up_);
1403
1405 [&waiting_for_first_frame = waiting_for_first_frame_,
1406 &waiting_for_first_frame_condition = waiting_for_first_frame_condition_,
1407 rasterizer = rasterizer_->GetWeakPtr(),
1408 weak_pipeline = std::weak_ptr<FramePipeline>(pipeline)]() mutable {
1409 if (rasterizer) {
1410 std::shared_ptr<FramePipeline> pipeline = weak_pipeline.lock();
1411 if (pipeline) {
1412 rasterizer->Draw(pipeline);
1413 }
1414
1415 if (waiting_for_first_frame.load()) {
1416 waiting_for_first_frame.store(false);
1417 waiting_for_first_frame_condition.notify_all();
1418 }
1419 }
1420 }));
1421}
1422
1423// |Animator::Delegate|
1424void Shell::OnAnimatorDrawLastLayerTrees(
1425 std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
1426 FML_DCHECK(is_set_up_);
1427
1428 auto task = fml::MakeCopyable(
1429 [rasterizer = rasterizer_->GetWeakPtr(),
1430 frame_timings_recorder = std::move(frame_timings_recorder)]() mutable {
1431 if (rasterizer) {
1432 rasterizer->DrawLastLayerTrees(std::move(frame_timings_recorder));
1433 }
1434 });
1435
1437}
1438
1439// |Engine::Delegate|
1440void Shell::OnEngineUpdateSemantics(int64_t view_id,
1441 SemanticsNodeUpdates update,
1443 FML_DCHECK(is_set_up_);
1445
1446 task_runners_.GetPlatformTaskRunner()->RunNowOrPostTask(
1447 task_runners_.GetPlatformTaskRunner(),
1448 [view = platform_view_->GetWeakPtr(), update = std::move(update),
1449 actions = std::move(actions), view_id = view_id] {
1450 if (view) {
1451 view->UpdateSemantics(view_id, update, actions);
1452 }
1453 });
1454}
1455
1456// |Engine::Delegate|
1457void Shell::OnEngineSetApplicationLocale(std::string locale) {
1458 FML_DCHECK(is_set_up_);
1460
1461 task_runners_.GetPlatformTaskRunner()->RunNowOrPostTask(
1462 task_runners_.GetPlatformTaskRunner(),
1463 [view = platform_view_->GetWeakPtr(), locale_holder = std::move(locale)] {
1464 if (view) {
1465 view->SetApplicationLocale(locale_holder);
1466 }
1467 });
1468}
1469
1470// |Engine::Delegate|
1471void Shell::OnEngineSetSemanticsTreeEnabled(bool enabled) {
1472 FML_DCHECK(is_set_up_);
1474
1475 task_runners_.GetPlatformTaskRunner()->RunNowOrPostTask(
1476 task_runners_.GetPlatformTaskRunner(),
1477 [view = platform_view_->GetWeakPtr(), enabled] {
1478 if (view) {
1479 view->SetSemanticsTreeEnabled(enabled);
1480 }
1481 });
1482}
1483
1484// |Engine::Delegate|
1485void Shell::OnEngineHandlePlatformMessage(
1486 std::unique_ptr<PlatformMessage> message) {
1487 FML_DCHECK(is_set_up_);
1489
1490 if (message->channel() == kSkiaChannel) {
1491 HandleEngineSkiaMessage(std::move(message));
1492 return;
1493 }
1494
1495 if (platform_message_handler_) {
1496 if (route_messages_through_platform_thread_ &&
1497 !platform_message_handler_
1498 ->DoesHandlePlatformMessageOnPlatformThread()) {
1499#if _WIN32
1500 // On Windows capturing a TaskRunner with a TaskRunner will cause an
1501 // uncaught exception in process shutdown because of the deletion order of
1502 // global variables. See also
1503 // https://github.com/flutter/flutter/issues/111575.
1504 // This won't be an issue until Windows supports background platform
1505 // channels (https://github.com/flutter/flutter/issues/93945). Then this
1506 // can potentially be addressed by capturing a weak_ptr to an object that
1507 // retains the ui TaskRunner, instead of the TaskRunner directly.
1508 FML_DCHECK(false);
1509#endif
1510 // We route messages through the platform thread temporarily when the
1511 // shell is being initialized to be backwards compatible with setting
1512 // message handlers in the same event as starting the isolate, but after
1513 // it is started.
1514 auto ui_task_runner = task_runners_.GetUITaskRunner();
1516 [weak_platform_message_handler =
1517 std::weak_ptr<PlatformMessageHandler>(platform_message_handler_),
1518 message = std::move(message), ui_task_runner]() mutable {
1519 ui_task_runner->PostTask(
1520 fml::MakeCopyable([weak_platform_message_handler,
1521 message = std::move(message)]() mutable {
1522 auto platform_message_handler =
1523 weak_platform_message_handler.lock();
1524 if (platform_message_handler) {
1525 platform_message_handler->HandlePlatformMessage(
1526 std::move(message));
1527 }
1528 }));
1529 }));
1530 } else {
1531 platform_message_handler_->HandlePlatformMessage(std::move(message));
1532 }
1533 } else {
1534 task_runners_.GetPlatformTaskRunner()->PostTask(
1535 fml::MakeCopyable([view = platform_view_->GetWeakPtr(),
1536 message = std::move(message)]() mutable {
1537 if (view) {
1538 view->HandlePlatformMessage(std::move(message));
1539 }
1540 }));
1541 }
1542}
1543
1544void Shell::OnEngineChannelUpdate(std::string name, bool listening) {
1545 FML_DCHECK(is_set_up_);
1546
1547 task_runners_.GetPlatformTaskRunner()->PostTask(
1548 [view = platform_view_->GetWeakPtr(), name = std::move(name), listening] {
1549 if (view) {
1550 view->SendChannelUpdate(name, listening);
1551 }
1552 });
1553}
1554
1555void Shell::HandleEngineSkiaMessage(std::unique_ptr<PlatformMessage> message) {
1556 const auto& data = message->data();
1557
1558 rapidjson::Document document;
1559 document.Parse(reinterpret_cast<const char*>(data.GetMapping()),
1560 data.GetSize());
1561 if (document.HasParseError() || !document.IsObject()) {
1562 return;
1563 }
1564 auto root = document.GetObject();
1565 auto method = root.FindMember("method");
1566 if (method->value != "Skia.setResourceCacheMaxBytes") {
1567 return;
1568 }
1569 auto args = root.FindMember("args");
1570 if (args == root.MemberEnd() || !args->value.IsInt()) {
1571 return;
1572 }
1573
1574 task_runners_.GetRasterTaskRunner()->PostTask(
1575 [rasterizer = rasterizer_->GetWeakPtr(), max_bytes = args->value.GetInt(),
1576 response = message->response()] {
1577 if (rasterizer) {
1578 rasterizer->SetResourceCacheMaxBytes(static_cast<size_t>(max_bytes),
1579 true);
1580 }
1581 if (response) {
1582 // The framework side expects this to be valid json encoded as a list.
1583 // Return `[true]` to signal success.
1584 std::vector<uint8_t> data = {'[', 't', 'r', 'u', 'e', ']'};
1585 response->Complete(
1586 std::make_unique<fml::DataMapping>(std::move(data)));
1587 }
1588 });
1589}
1590
1591// |Engine::Delegate|
1592void Shell::OnPreEngineRestart() {
1593 FML_DCHECK(is_set_up_);
1595
1598 task_runners_.GetPlatformTaskRunner(),
1599 [view = platform_view_->GetWeakPtr(), &latch]() {
1600 if (view) {
1601 view->OnPreEngineRestart();
1602 }
1603 latch.Signal();
1604 });
1605 // This is blocking as any embedded platform views has to be flushed before
1606 // we re-run the Dart code.
1607 latch.Wait();
1608}
1609
1610// |Engine::Delegate|
1611void Shell::OnRootIsolateCreated() {
1612 if (is_added_to_service_protocol_) {
1613 return;
1614 }
1615 auto description = GetServiceProtocolDescription();
1617 task_runners_.GetPlatformTaskRunner(),
1618 [self = weak_factory_.GetWeakPtr(),
1619 description = std::move(description)]() {
1620 if (self) {
1621 self->vm_->GetServiceProtocol()->AddHandler(self.get(), description);
1622 }
1623 });
1624 is_added_to_service_protocol_ = true;
1625}
1626
1627// |Engine::Delegate|
1628void Shell::UpdateIsolateDescription(const std::string isolate_name,
1629 int64_t isolate_port) {
1630 Handler::Description description(isolate_port, isolate_name);
1631 vm_->GetServiceProtocol()->SetHandlerDescription(this, description);
1632}
1633
1634void Shell::SetNeedsReportTimings(bool value) {
1635 needs_report_timings_ = value;
1636}
1637
1638// |Engine::Delegate|
1639std::unique_ptr<std::vector<std::string>> Shell::ComputePlatformResolvedLocale(
1640 const std::vector<std::string>& supported_locale_data) {
1641 return platform_view_->ComputePlatformResolvedLocales(supported_locale_data);
1642}
1643
1644void Shell::LoadDartDeferredLibrary(
1645 intptr_t loading_unit_id,
1646 std::unique_ptr<const fml::Mapping> snapshot_data,
1647 std::unique_ptr<const fml::Mapping> snapshot_instructions) {
1649 [engine = engine_->GetWeakPtr(), loading_unit_id,
1650 data = std::move(snapshot_data),
1651 instructions = std::move(snapshot_instructions)]() mutable {
1652 if (engine) {
1653 engine->LoadDartDeferredLibrary(loading_unit_id, std::move(data),
1654 std::move(instructions));
1655 }
1656 }));
1657}
1658
1659void Shell::LoadDartDeferredLibraryError(intptr_t loading_unit_id,
1660 const std::string error_message,
1661 bool transient) {
1663 task_runners_.GetUITaskRunner(),
1664 [engine = weak_engine_, loading_unit_id, error_message, transient] {
1665 if (engine) {
1666 engine->LoadDartDeferredLibraryError(loading_unit_id, error_message,
1667 transient);
1668 }
1669 });
1670}
1671
1672void Shell::UpdateAssetResolverByType(
1673 std::unique_ptr<AssetResolver> updated_asset_resolver,
1676 task_runners_.GetUITaskRunner(),
1678 [engine = weak_engine_, type,
1679 asset_resolver = std::move(updated_asset_resolver)]() mutable {
1680 if (engine) {
1681 engine->GetAssetManager()->UpdateResolverByType(
1682 std::move(asset_resolver), type);
1683 }
1684 }));
1685}
1686
1687// |Engine::Delegate|
1688void Shell::RequestDartDeferredLibrary(intptr_t loading_unit_id) {
1689 task_runners_.GetPlatformTaskRunner()->PostTask(
1690 [view = platform_view_->GetWeakPtr(), loading_unit_id] {
1691 if (view) {
1692 view->RequestDartDeferredLibrary(loading_unit_id);
1693 }
1694 });
1695}
1696
1697// |Engine::Delegate|
1698double Shell::GetScaledFontSize(double unscaled_font_size,
1699 int configuration_id) const {
1700 return platform_view_->GetScaledFontSize(unscaled_font_size,
1701 configuration_id);
1702}
1703
1704void Shell::RequestViewFocusChange(const ViewFocusChangeRequest& request) {
1705 FML_DCHECK(is_set_up_);
1706
1708 task_runners_.GetPlatformTaskRunner(),
1709 [view = platform_view_->GetWeakPtr(), request] {
1710 if (view) {
1711 view->RequestViewFocusChange(request);
1712 }
1713 });
1714}
1715
1716void Shell::ReportTimings() {
1717 FML_DCHECK(is_set_up_);
1719
1720 auto timings = std::move(unreported_timings_);
1721 unreported_timings_ = {};
1722 task_runners_.GetUITaskRunner()->PostTask([timings, engine = weak_engine_] {
1723 if (engine) {
1724 engine->ReportTimings(timings);
1725 }
1726 });
1727}
1728
1729size_t Shell::UnreportedFramesCount() const {
1730 // Check that this is running on the raster thread to avoid race conditions.
1732 FML_DCHECK(unreported_timings_.size() % (FrameTiming::kStatisticsCount) == 0);
1733 return unreported_timings_.size() / (FrameTiming::kStatisticsCount);
1734}
1735
1736void Shell::OnFrameRasterized(const FrameTiming& timing) {
1737 FML_DCHECK(is_set_up_);
1739
1740 // The C++ callback defined in settings.h and set by Flutter runner. This is
1741 // independent of the timings report to the Dart side.
1742 if (settings_.frame_rasterized_callback) {
1743 settings_.frame_rasterized_callback(timing);
1744 }
1745
1746 if (!needs_report_timings_) {
1747 return;
1748 }
1749
1750 size_t old_count = unreported_timings_.size();
1751 (void)old_count;
1752 for (auto phase : FrameTiming::kPhases) {
1753 unreported_timings_.push_back(
1754 timing.Get(phase).ToEpochDelta().ToMicroseconds());
1755 }
1756 unreported_timings_.push_back(timing.GetLayerCacheCount());
1757 unreported_timings_.push_back(timing.GetLayerCacheBytes());
1758 unreported_timings_.push_back(timing.GetPictureCacheCount());
1759 unreported_timings_.push_back(timing.GetPictureCacheBytes());
1760 unreported_timings_.push_back(timing.GetFrameNumber());
1761 FML_DCHECK(unreported_timings_.size() ==
1762 old_count + FrameTiming::kStatisticsCount);
1763
1764 // In tests using iPhone 6S with profile mode, sending a batch of 1 frame or a
1765 // batch of 100 frames have roughly the same cost of less than 0.1ms. Sending
1766 // a batch of 500 frames costs about 0.2ms. The 1 second threshold usually
1767 // kicks in before we reaching the following 100 frames threshold. The 100
1768 // threshold here is mainly for unit tests (so we don't have to write a
1769 // 1-second unit test), and make sure that our vector won't grow too big with
1770 // future 120fps, 240fps, or 1000fps displays.
1771 //
1772 // In the profile/debug mode, the timings are used by development tools which
1773 // require a latency of no more than 100ms. Hence we lower that 1-second
1774 // threshold to 100ms because performance overhead isn't that critical in
1775 // those cases.
1776 if (!first_frame_rasterized_ || UnreportedFramesCount() >= 100) {
1777 first_frame_rasterized_ = true;
1778 ReportTimings();
1779 } else if (!frame_timings_report_scheduled_) {
1780#if FLUTTER_RELEASE
1781 constexpr int kBatchTimeInMilliseconds = 1000;
1782#else
1783 constexpr int kBatchTimeInMilliseconds = 100;
1784#endif
1785
1786 // Also make sure that frame times get reported with a max latency of 1
1787 // second. Otherwise, the timings of last few frames of an animation may
1788 // never be reported until the next animation starts.
1789 frame_timings_report_scheduled_ = true;
1790 task_runners_.GetRasterTaskRunner()->PostDelayedTask(
1791 [self = weak_factory_gpu_->GetWeakPtr()]() {
1792 if (!self) {
1793 return;
1794 }
1795 self->frame_timings_report_scheduled_ = false;
1796 if (self->UnreportedFramesCount() > 0) {
1797 self->ReportTimings();
1798 }
1799 },
1800 fml::TimeDelta::FromMilliseconds(kBatchTimeInMilliseconds));
1801 }
1802}
1803
1804fml::Milliseconds Shell::GetFrameBudget() {
1805 if (cached_display_refresh_rate_.has_value()) {
1806 return cached_display_refresh_rate_.value();
1807 }
1808 double display_refresh_rate = display_manager_->GetMainDisplayRefreshRate();
1809 if (display_refresh_rate > 0) {
1810 cached_display_refresh_rate_ =
1811 fml::RefreshRateToFrameBudget(display_refresh_rate);
1812 } else {
1813 cached_display_refresh_rate_ = fml::kDefaultFrameBudget;
1814 }
1815 return cached_display_refresh_rate_.value_or(fml::kDefaultFrameBudget);
1816}
1817
1818fml::TimePoint Shell::GetLatestFrameTargetTime() const {
1819 std::scoped_lock time_recorder_lock(time_recorder_mutex_);
1820 FML_CHECK(latest_frame_target_time_.has_value())
1821 << "GetLatestFrameTargetTime called before OnAnimatorBeginFrame";
1822 // Covered by FML_CHECK().
1823 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
1824 return latest_frame_target_time_.value();
1825}
1826
1827// |Rasterizer::Delegate|
1828bool Shell::ShouldDiscardLayerTree(int64_t view_id,
1829 const flutter::LayerTree& tree) {
1830 std::scoped_lock<std::mutex> lock(resize_mutex_);
1831 auto expected_frame_constraints = ExpectedFrameConstraints(view_id);
1832 return !expected_frame_constraints.IsSatisfiedBy(
1833 Size(tree.frame_size().width, tree.frame_size().height));
1834}
1835
1836// |ServiceProtocol::Handler|
1837fml::RefPtr<fml::TaskRunner> Shell::GetServiceProtocolHandlerTaskRunner(
1838 std::string_view method) const {
1839 FML_DCHECK(is_set_up_);
1840 auto found = service_protocol_handlers_.find(method);
1841 if (found != service_protocol_handlers_.end()) {
1842 return found->second.first;
1843 }
1844 return task_runners_.GetUITaskRunner();
1845}
1846
1847// |ServiceProtocol::Handler|
1848bool Shell::HandleServiceProtocolMessage(
1849 std::string_view method, // one if the extension names specified above.
1850 const ServiceProtocolMap& params,
1851 rapidjson::Document* response) {
1852 auto found = service_protocol_handlers_.find(method);
1853 if (found != service_protocol_handlers_.end()) {
1854 return found->second.second(params, response);
1855 }
1856 return false;
1857}
1858
1859// |ServiceProtocol::Handler|
1860ServiceProtocol::Handler::Description Shell::GetServiceProtocolDescription()
1861 const {
1863
1864 if (!weak_engine_) {
1866 }
1867
1868 return {
1869 weak_engine_->GetUIIsolateMainPort(),
1870 weak_engine_->GetUIIsolateName(),
1871 };
1872}
1873
1874static void ServiceProtocolParameterError(rapidjson::Document* response,
1875 std::string error_details) {
1876 auto& allocator = response->GetAllocator();
1877 response->SetObject();
1878 const int64_t kInvalidParams = -32602;
1879 response->AddMember("code", kInvalidParams, allocator);
1880 response->AddMember("message", "Invalid params", allocator);
1881 {
1882 rapidjson::Value details(rapidjson::kObjectType);
1883 details.AddMember("details", std::move(error_details), allocator);
1884 response->AddMember("data", details, allocator);
1885 }
1886}
1887
1888static void ServiceProtocolFailureError(rapidjson::Document* response,
1889 std::string message) {
1890 auto& allocator = response->GetAllocator();
1891 response->SetObject();
1892 const int64_t kJsonServerError = -32000;
1893 response->AddMember("code", kJsonServerError, allocator);
1894 response->AddMember("message", std::move(message), allocator);
1895}
1896
1897// Service protocol handler
1898bool Shell::OnServiceProtocolScreenshot(
1900 rapidjson::Document* response) {
1902 auto screenshot = rasterizer_->ScreenshotLastLayerTree(
1904 if (screenshot.data) {
1905 response->SetObject();
1906 auto& allocator = response->GetAllocator();
1907 response->AddMember("type", "Screenshot", allocator);
1908 rapidjson::Value image;
1909 image.SetString(static_cast<const char*>(screenshot.data->data()),
1910 screenshot.data->size(), allocator);
1911 response->AddMember("screenshot", image, allocator);
1912 return true;
1913 }
1914 ServiceProtocolFailureError(response, "Could not capture image screenshot.");
1915 return false;
1916}
1917
1918// Service protocol handler
1919bool Shell::OnServiceProtocolScreenshotSKP(
1921 rapidjson::Document* response) {
1923 if (settings_.enable_impeller) {
1925 response, "Cannot capture SKP screenshot with Impeller enabled.");
1926 return false;
1927 }
1928 auto screenshot = rasterizer_->ScreenshotLastLayerTree(
1930 if (screenshot.data) {
1931 response->SetObject();
1932 auto& allocator = response->GetAllocator();
1933 response->AddMember("type", "ScreenshotSkp", allocator);
1934 rapidjson::Value skp;
1935 skp.SetString(static_cast<const char*>(screenshot.data->data()),
1936 screenshot.data->size(), allocator);
1937 response->AddMember("skp", skp, allocator);
1938 return true;
1939 }
1940 ServiceProtocolFailureError(response, "Could not capture SKP screenshot.");
1941 return false;
1942}
1943
1944// Service protocol handler
1945bool Shell::OnServiceProtocolRunInView(
1947 rapidjson::Document* response) {
1949
1950 if (params.count("mainScript") == 0) {
1952 "'mainScript' parameter is missing.");
1953 return false;
1954 }
1955
1956 if (params.count("assetDirectory") == 0) {
1958 "'assetDirectory' parameter is missing.");
1959 return false;
1960 }
1961
1962 std::string main_script_path =
1963 fml::paths::FromURI(params.at("mainScript").data());
1964 std::string asset_directory_path =
1965 fml::paths::FromURI(params.at("assetDirectory").data());
1966
1967 auto main_script_file_mapping =
1968 std::make_unique<fml::FileMapping>(fml::OpenFile(
1969 main_script_path.c_str(), false, fml::FilePermission::kRead));
1970
1971 auto isolate_configuration = IsolateConfiguration::CreateForKernel(
1972 std::move(main_script_file_mapping));
1973
1974 RunConfiguration configuration(std::move(isolate_configuration));
1975
1976 configuration.SetEntrypointAndLibrary(engine_->GetLastEntrypoint(),
1977 engine_->GetLastEntrypointLibrary());
1978 configuration.SetEntrypointArgs(engine_->GetLastEntrypointArgs());
1979
1980 configuration.SetEngineId(engine_->GetLastEngineId());
1981
1982 configuration.AddAssetResolver(std::make_unique<DirectoryAssetBundle>(
1983 fml::OpenDirectory(asset_directory_path.c_str(), false,
1985 false));
1986
1987 // Preserve any original asset resolvers to avoid syncing unchanged assets
1988 // over the DevFS connection.
1989 auto old_asset_manager = engine_->GetAssetManager();
1990 if (old_asset_manager != nullptr) {
1991 for (auto& old_resolver : old_asset_manager->TakeResolvers()) {
1992 if (old_resolver->IsValidAfterAssetManagerChange()) {
1993 configuration.AddAssetResolver(std::move(old_resolver));
1994 }
1995 }
1996 }
1997
1998 auto& allocator = response->GetAllocator();
1999 response->SetObject();
2000 if (engine_->Restart(std::move(configuration))) {
2001 response->AddMember("type", "Success", allocator);
2002 auto new_description = GetServiceProtocolDescription();
2003 rapidjson::Value view(rapidjson::kObjectType);
2004 new_description.Write(this, view, allocator);
2005 response->AddMember("view", view, allocator);
2006 return true;
2007 } else {
2008 FML_DLOG(ERROR) << "Could not run configuration in engine.";
2010 "Could not run configuration in engine.");
2011 return false;
2012 }
2013
2014 FML_DCHECK(false);
2015 return false;
2016}
2017
2018// Service protocol handler
2019bool Shell::OnServiceProtocolFlushUIThreadTasks(
2021 rapidjson::Document* response) {
2023 // This API should not be invoked by production code.
2024 // It can potentially starve the service isolate if the main isolate pauses
2025 // at a breakpoint or is in an infinite loop.
2026 //
2027 // It should be invoked from the VM Service and blocks it until UI thread
2028 // tasks are processed.
2029 response->SetObject();
2030 response->AddMember("type", "Success", response->GetAllocator());
2031 return true;
2032}
2033
2034bool Shell::OnServiceProtocolGetDisplayRefreshRate(
2036 rapidjson::Document* response) {
2038 response->SetObject();
2039 response->AddMember("type", "DisplayRefreshRate", response->GetAllocator());
2040 response->AddMember("fps", display_manager_->GetMainDisplayRefreshRate(),
2041 response->GetAllocator());
2042 return true;
2043}
2044
2046 return display_manager_->GetMainDisplayRefreshRate();
2047}
2048
2050 int32_t priority) {
2052 FML_DCHECK(is_set_up_);
2053
2055 task_runners_.GetUITaskRunner(),
2056 [engine = engine_->GetWeakPtr(), factory = std::move(factory),
2057 priority]() {
2058 if (engine) {
2059 engine->GetImageGeneratorRegistry()->AddFactory(factory, priority);
2060 }
2061 });
2062}
2063
2064bool Shell::OnServiceProtocolGetSkSLs(
2066 rapidjson::Document* response) {
2068 response->SetObject();
2069 response->AddMember("type", "GetSkSLs", response->GetAllocator());
2070
2071 rapidjson::Value shaders_json(rapidjson::kObjectType);
2072#if !SLIMPELLER
2073 PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess();
2074 std::vector<PersistentCache::SkSLCache> sksls = persistent_cache->LoadSkSLs();
2075 for (const auto& sksl : sksls) {
2076 size_t b64_size = Base64::EncodedSize(sksl.value->size());
2077 sk_sp<SkData> b64_data = SkData::MakeUninitialized(b64_size + 1);
2078 char* b64_char = static_cast<char*>(b64_data->writable_data());
2079 Base64::Encode(sksl.value->data(), sksl.value->size(), b64_char);
2080 b64_char[b64_size] = 0; // make it null terminated for printing
2081 rapidjson::Value shader_value(b64_char, response->GetAllocator());
2082 std::string_view key_view(reinterpret_cast<const char*>(sksl.key->data()),
2083 sksl.key->size());
2084 auto encode_result = fml::Base32Encode(key_view);
2085 if (!encode_result.first) {
2086 continue;
2087 }
2088 rapidjson::Value shader_key(encode_result.second, response->GetAllocator());
2089 shaders_json.AddMember(shader_key, shader_value, response->GetAllocator());
2090 }
2091#endif // !SLIMPELLER
2092 response->AddMember("SkSLs", shaders_json, response->GetAllocator());
2093 return true;
2094}
2095
2096bool Shell::OnServiceProtocolEstimateRasterCacheMemory(
2098 rapidjson::Document* response) {
2100
2101 uint64_t layer_cache_byte_size = 0u;
2102 uint64_t picture_cache_byte_size = 0u;
2103
2104#if !SLIMPELLER
2105 const auto& raster_cache = rasterizer_->compositor_context()->raster_cache();
2106 layer_cache_byte_size = raster_cache.EstimateLayerCacheByteSize();
2107 picture_cache_byte_size = raster_cache.EstimatePictureCacheByteSize();
2108#endif // !SLIMPELLER
2109
2110 response->SetObject();
2111 response->AddMember("type", "EstimateRasterCacheMemory",
2112 response->GetAllocator());
2113 response->AddMember<uint64_t>("layerBytes", layer_cache_byte_size,
2114 response->GetAllocator());
2115 response->AddMember<uint64_t>("pictureBytes", picture_cache_byte_size,
2116 response->GetAllocator());
2117 return true;
2118}
2119
2120// Service protocol handler
2121bool Shell::OnServiceProtocolSetAssetBundlePath(
2123 rapidjson::Document* response) {
2125
2126 if (params.count("assetDirectory") == 0) {
2128 "'assetDirectory' parameter is missing.");
2129 return false;
2130 }
2131
2132 auto& allocator = response->GetAllocator();
2133 response->SetObject();
2134
2135 auto asset_manager = std::make_shared<AssetManager>();
2136
2137 if (!asset_manager->PushFront(std::make_unique<DirectoryAssetBundle>(
2138 fml::OpenDirectory(params.at("assetDirectory").data(), false,
2140 false))) {
2141 // The new asset directory path was invalid.
2142 FML_DLOG(ERROR) << "Could not update asset directory.";
2143 ServiceProtocolFailureError(response, "Could not update asset directory.");
2144 return false;
2145 }
2146
2147 // Preserve any original asset resolvers to avoid syncing unchanged assets
2148 // over the DevFS connection.
2149 auto old_asset_manager = engine_->GetAssetManager();
2150 if (old_asset_manager != nullptr) {
2151 for (auto& old_resolver : old_asset_manager->TakeResolvers()) {
2152 if (old_resolver->IsValidAfterAssetManagerChange()) {
2153 asset_manager->PushBack(std::move(old_resolver));
2154 }
2155 }
2156 }
2157
2158 if (engine_->UpdateAssetManager(asset_manager)) {
2159 response->AddMember("type", "Success", allocator);
2160 auto new_description = GetServiceProtocolDescription();
2161 rapidjson::Value view(rapidjson::kObjectType);
2162 new_description.Write(this, view, allocator);
2163 response->AddMember("view", view, allocator);
2164 return true;
2165 } else {
2166 FML_DLOG(ERROR) << "Could not update asset directory.";
2167 ServiceProtocolFailureError(response, "Could not update asset directory.");
2168 return false;
2169 }
2170
2171 FML_DCHECK(false);
2172 return false;
2173}
2174
2175bool Shell::OnServiceProtocolGetPipelineUsage(
2177 rapidjson::Document* response) {
2179
2180 response->SetObject();
2181
2182 auto context = io_manager_->GetImpellerContext();
2183
2184 if (!context) {
2185 FML_DLOG(ERROR) << "Pipeline usage profiling only available in Impeller";
2187 response, "Pipeline usage profiling only available in Impeller");
2188 return false;
2189 }
2190
2191 auto use_counts = context->GetPipelineLibrary()->GetPipelineUseCounts();
2192
2193 rapidjson::Value pipelines_json(rapidjson::kObjectType);
2194
2195 for (const auto& pipelineCount : use_counts) {
2196 std::string_view pipeline_name = pipelineCount.first.GetLabel();
2197 rapidjson::Value pipeline_key(pipeline_name.data(), pipeline_name.length(),
2198 response->GetAllocator());
2199
2200 pipelines_json.AddMember(pipeline_key, pipelineCount.second,
2201 response->GetAllocator());
2202 }
2203
2204 response->AddMember("Usages", pipelines_json, response->GetAllocator());
2205 return true;
2206}
2207
2208void Shell::SendFontChangeNotification() {
2209 // After system fonts are reloaded, we send a system channel message
2210 // to notify flutter framework.
2211 rapidjson::Document document;
2212 document.SetObject();
2213 auto& allocator = document.GetAllocator();
2214 rapidjson::Value message_value;
2215 message_value.SetString(kFontChange, allocator);
2216 document.AddMember(kTypeKey, message_value, allocator);
2217
2218 rapidjson::StringBuffer buffer;
2219 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
2220 document.Accept(writer);
2221 std::string message = buffer.GetString();
2222 std::unique_ptr<PlatformMessage> fontsChangeMessage =
2223 std::make_unique<flutter::PlatformMessage>(
2225 fml::MallocMapping::Copy(message.c_str(), message.length()), nullptr);
2226 OnPlatformViewDispatchPlatformMessage(std::move(fontsChangeMessage));
2227}
2228
2229bool Shell::OnServiceProtocolReloadAssetFonts(
2231 rapidjson::Document* response) {
2233 if (!engine_) {
2234 return false;
2235 }
2236 engine_->GetFontCollection().RegisterFonts(engine_->GetAssetManager());
2237 engine_->GetFontCollection().GetFontCollection()->ClearFontFamilyCache();
2238 SendFontChangeNotification();
2239
2240 auto& allocator = response->GetAllocator();
2241 response->SetObject();
2242 response->AddMember("type", "Success", allocator);
2243
2244 return true;
2245}
2246
2247void Shell::OnPlatformViewAddView(int64_t view_id,
2248 const ViewportMetrics& viewport_metrics,
2249 AddViewCallback callback) {
2250 TRACE_EVENT0("flutter", "Shell::AddView");
2251 FML_DCHECK(is_set_up_);
2254 << "Unexpected request to add the implicit view #"
2255 << kFlutterImplicitViewId << ". This view should never be added.";
2256
2257 task_runners_.GetUITaskRunner()->RunNowOrPostTask(
2258 task_runners_.GetUITaskRunner(), [engine = engine_->GetWeakPtr(), //
2259 viewport_metrics, //
2260 view_id, //
2261 callback = std::move(callback) //
2262 ] {
2263 if (engine) {
2264 engine->AddView(view_id, viewport_metrics, callback);
2265 }
2266 });
2267}
2268
2269void Shell::OnPlatformViewRemoveView(int64_t view_id,
2270 RemoveViewCallback callback) {
2271 TRACE_EVENT0("flutter", "Shell::RemoveView");
2272 FML_DCHECK(is_set_up_);
2275 << "Unexpected request to remove the implicit view #"
2276 << kFlutterImplicitViewId << ". This view should never be removed.";
2277 {
2278 std::scoped_lock<std::mutex> lock(resize_mutex_);
2279 expected_frame_constraints_.erase(view_id);
2280 }
2281 task_runners_.GetUITaskRunner()->RunNowOrPostTask(
2282 task_runners_.GetUITaskRunner(),
2283 [&task_runners = task_runners_, //
2284 engine = engine_->GetWeakPtr(), //
2285 rasterizer = rasterizer_->GetWeakPtr(), //
2286 view_id, //
2287 callback = std::move(callback) //
2288 ]() mutable {
2289 bool removed = false;
2290 if (engine) {
2291 removed = engine->RemoveView(view_id);
2292 }
2293 task_runners.GetRasterTaskRunner()->PostTask(
2294 [rasterizer, view_id, callback = std::move(callback), removed]() {
2295 if (rasterizer) {
2296 rasterizer->CollectView(view_id);
2297 }
2298 // Only call the callback after it is known for certain that the
2299 // raster thread will not try to use resources associated with
2300 // the view.
2301 callback(removed);
2302 });
2303 });
2304}
2305
2306void Shell::OnPlatformViewSendViewFocusEvent(const ViewFocusEvent& event) {
2307 TRACE_EVENT0("flutter", "Shell:: OnPlatformViewSendViewFocusEvent");
2308 FML_DCHECK(is_set_up_);
2310
2312 task_runners_.GetUITaskRunner(),
2313 [engine = engine_->GetWeakPtr(), event = event] {
2314 if (engine) {
2315 engine->SendViewFocusEvent(event);
2316 }
2317 });
2318}
2319
2320Rasterizer::Screenshot Shell::Screenshot(
2321 Rasterizer::ScreenshotType screenshot_type,
2322 bool base64_encode) {
2323 if (settings_.enable_impeller) {
2324 switch (screenshot_type) {
2326 FML_LOG(ERROR)
2327 << "Impeller backend cannot produce ScreenshotType::SkiaPicture.";
2328 return {};
2332 break;
2333 }
2334 }
2335 TRACE_EVENT0("flutter", "Shell::Screenshot");
2337 Rasterizer::Screenshot screenshot;
2339 task_runners_.GetRasterTaskRunner(), [&latch, //
2340 rasterizer = GetRasterizer(), //
2341 &screenshot, //
2342 screenshot_type, //
2343 base64_encode //
2344 ]() {
2345 if (rasterizer) {
2346 screenshot = rasterizer->ScreenshotLastLayerTree(screenshot_type,
2347 base64_encode);
2348 }
2349 latch.Signal();
2350 });
2351 latch.Wait();
2352 return screenshot;
2353}
2354
2356 FML_DCHECK(is_set_up_);
2357 if (task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread() ||
2358 task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread()) {
2360 "WaitForFirstFrame called from thread that can't wait "
2361 "because it is responsible for generating the frame.");
2362 }
2363
2364 // Check for overflow.
2365 auto now = std::chrono::steady_clock::now();
2366 auto max_duration = std::chrono::steady_clock::time_point::max() - now;
2367 auto desired_duration = std::chrono::milliseconds(timeout.ToMilliseconds());
2368 auto duration =
2369 now + (desired_duration > max_duration ? max_duration : desired_duration);
2370
2371 std::unique_lock<std::mutex> lock(waiting_for_first_frame_mutex_);
2372 bool success = waiting_for_first_frame_condition_.wait_until(
2373 lock, duration, [&waiting_for_first_frame = waiting_for_first_frame_] {
2374 return !waiting_for_first_frame.load();
2375 });
2376 if (success) {
2377 return fml::Status();
2378 } else {
2380 }
2381}
2382
2384 FML_DCHECK(is_set_up_);
2386
2387 if (!engine_) {
2388 return false;
2390 engine_->SetupDefaultFontManager();
2391 engine_->GetFontCollection().GetFontCollection()->ClearFontFamilyCache();
2392 // After system fonts are reloaded, we send a system channel message
2393 // to notify flutter framework.
2394 SendFontChangeNotification();
2395 return true;
2396}
2397
2398std::shared_ptr<const fml::SyncSwitch> Shell::GetIsGpuDisabledSyncSwitch()
2399 const {
2400 return is_gpu_disabled_sync_switch_;
2401}
2402
2403void Shell::SetGpuAvailability(GpuAvailability availability) {
2405 switch (availability) {
2407 is_gpu_disabled_sync_switch_->SetSwitch(false);
2408 return;
2412 task_runners_.GetIOTaskRunner(),
2413 [io_manager = io_manager_.get(), &latch]() {
2414 io_manager->GetSkiaUnrefQueue()->Drain();
2415 latch.Signal();
2416 });
2417 latch.Wait();
2418 }
2419 // FALLTHROUGH
2421 is_gpu_disabled_sync_switch_->SetSwitch(true);
2422 return;
2423 default:
2424 FML_DCHECK(false);
2425 }
2426}
2427
2428void Shell::OnDisplayUpdates(std::vector<std::unique_ptr<Display>> displays) {
2429 FML_DCHECK(is_set_up_);
2431
2432 std::vector<DisplayData> display_data;
2433 display_data.reserve(displays.size());
2434 for (const auto& display : displays) {
2435 display_data.push_back(display->GetDisplayData());
2436 }
2438 [engine = engine_->GetWeakPtr(),
2439 display_data = std::move(display_data)]() {
2440 if (engine) {
2441 engine->SetDisplays(display_data);
2442 }
2443 });
2445 display_manager_->HandleDisplayUpdates(std::move(displays));
2446}
2447
2448fml::TimePoint Shell::GetCurrentTimePoint() {
2449 return fml::TimePoint::Now();
2450}
2451
2452const std::shared_ptr<PlatformMessageHandler>&
2454 return platform_message_handler_;
2455}
2457const std::weak_ptr<VsyncWaiter> Shell::GetVsyncWaiter() const {
2458 if (!engine_) {
2459 return {};
2460 }
2461 return engine_->GetVsyncWaiter();
2462}
2463
2464const std::shared_ptr<fml::ConcurrentTaskRunner>
2466 FML_DCHECK(vm_);
2467 if (!vm_) {
2468 return nullptr;
2469 }
2470 return vm_->GetConcurrentWorkerTaskRunner();
2471}
2472
2473BoxConstraints Shell::ExpectedFrameConstraints(int64_t view_id) {
2474 auto found = expected_frame_constraints_.find(view_id);
2475
2476 if (found == expected_frame_constraints_.end()) {
2477 return {};
2478 }
2479
2480 return found->second;
2481}
2482
2483} // namespace flutter
std::unique_ptr< flutter::PlatformViewIOS > platform_view
GLenum type
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:522
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:539
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:530
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:2311
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:2448
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:2444
const std::shared_ptr< fml::ConcurrentTaskRunner > GetConcurrentWorkerTaskRunner() const
Definition shell.cc:2456
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:2346
void OnDisplayUpdates(std::vector< std::unique_ptr< Display > > displays)
Notifies the display manager of the updates.
Definition shell.cc:2419
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:2389
void SetGpuAvailability(GpuAvailability availability)
Marks the GPU as available or unavailable.
Definition shell.cc:2394
void RegisterImageDecoder(ImageGeneratorFactory factory, int32_t priority)
Install a new factory that can match against and decode image data.
Definition shell.cc:2040
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:2036
bool ReloadSystemFonts()
Used by embedders to reload the system fonts in FontCollection. It also clears the cached font famili...
Definition shell.cc:2374
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:1879
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:1865
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
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:326
MergedPlatformUIThread merged_platform_ui_thread
Definition settings.h:379
bool skia_deterministic_rendering_on_cpu
Definition settings.h:318
bool purge_persistent_cache
Definition settings.h:158
std::vector< std::string > trace_allowlist
Definition settings.h:150
MappingCallback icu_mapper
Definition settings.h:328
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:327
FrameRasterizedCallback frame_rasterized_callback
Definition settings.h:337
size_t resource_cache_max_bytes_threshold
Definition settings.h:355
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)