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