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