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