Flutter Engine
The Flutter Engine
engine.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "engine.h"
6
7#include <fuchsia/accessibility/semantics/cpp/fidl.h>
8#include <fuchsia/media/cpp/fidl.h>
9#include <lib/async/cpp/task.h>
10#include <lib/zx/eventpair.h>
11#include <lib/zx/thread.h>
12#include <zircon/rights.h>
13#include <zircon/status.h>
14#include <zircon/types.h>
15#include <memory>
16
17#include "flutter/common/graphics/persistent_cache.h"
18#include "flutter/common/task_runners.h"
19#include "flutter/fml/make_copyable.h"
20#include "flutter/fml/message_loop.h"
21#include "flutter/fml/synchronization/waitable_event.h"
22#include "flutter/fml/task_runner.h"
23#include "flutter/runtime/dart_vm_lifecycle.h"
24#include "flutter/shell/common/rasterizer.h"
25#include "flutter/shell/common/run_configuration.h"
26#include "flutter/shell/common/serialization_callbacks.h"
27#include "flutter/shell/common/thread_host.h"
32
33#include "../runtime/dart/utils/files.h"
34#include "../runtime/dart/utils/root_inspect_node.h"
35#include "focus_delegate.h"
36#include "fuchsia_intl.h"
37#include "platform_view.h"
39#include "surface.h"
40#include "vsync_waiter.h"
42
43namespace flutter_runner {
44namespace {
45
46zx_koid_t GetKoid(const fuchsia::ui::views::ViewRef& view_ref) {
47 zx_handle_t handle = view_ref.reference.get();
48 zx_info_handle_basic_t info;
49 zx_status_t status = zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info,
50 sizeof(info), nullptr, nullptr);
51 return status == ZX_OK ? info.koid : ZX_KOID_INVALID;
52}
53
54std::unique_ptr<flutter::PlatformMessage> MakeLocalizationPlatformMessage(
55 const fuchsia::intl::Profile& intl_profile) {
56 return std::make_unique<flutter::PlatformMessage>(
57 "flutter/localization", MakeLocalizationPlatformMessageData(intl_profile),
58 nullptr);
59}
60
61//
62// Fuchsia scheduler role naming scheme employed here:
63//
64// Roles based on thread function:
65// <prefix>.type.{platform,ui,raster,io,profiler}
66//
67// Roles based on fml::Thread::ThreadPriority:
68// <prefix>.thread.{background,display,raster,normal}
69//
70
71void SetThreadRole(
72 const fuchsia::media::ProfileProviderSyncPtr& profile_provider,
73 const std::string& role) {
74 ZX_ASSERT(profile_provider);
75
76 zx::thread dup;
77 const zx_status_t dup_status =
78 zx::thread::self()->duplicate(ZX_RIGHT_SAME_RIGHTS, &dup);
79 if (dup_status != ZX_OK) {
80 FML_LOG(WARNING)
81 << "Failed to duplicate thread handle when setting thread config: "
82 << zx_status_get_string(dup_status)
83 << ". Thread will run at default priority.";
84 return;
85 }
86
87 int64_t unused_period;
88 int64_t unused_capacity;
89 const zx_status_t status = profile_provider->RegisterHandlerWithCapacity(
90 std::move(dup), role, 0, 0.f, &unused_period, &unused_capacity);
91 if (status != ZX_OK) {
92 FML_LOG(WARNING) << "Failed to set thread role to \"" << role
93 << "\": " << zx_status_get_string(status)
94 << ". Thread will run at default priority.";
95 return;
96 }
97}
98
99void SetThreadConfig(
100 const std::string& name_prefix,
101 const fuchsia::media::ProfileProviderSyncPtr& profile_provider,
102 const fml::Thread::ThreadConfig& config) {
103 ZX_ASSERT(profile_provider);
104
106
107 // Derive the role name from the prefix and priority. See comment above about
108 // the role naming scheme.
109 std::string role;
110 switch (config.priority) {
112 role = name_prefix + ".thread.background";
113 break;
115 role = name_prefix + ".thread.display";
116 break;
118 role = name_prefix + ".thread.raster";
119 break;
121 role = name_prefix + ".thread.normal";
122 break;
123 default:
124 FML_LOG(WARNING) << "Unknown thread priority "
125 << static_cast<int>(config.priority)
126 << ". Thread will run at default priority.";
127 return;
128 }
129 ZX_ASSERT(!role.empty());
130
131 SetThreadRole(profile_provider, role);
132}
133
134} // namespace
135
137 const std::string& name_prefix,
138 const std::shared_ptr<sys::ServiceDirectory>& services) {
140 fml::Thread::ThreadConfig(name_prefix + ".platform"));
141
142 // Default the config setter to setup the thread name only.
144
145 // Override the config setter if the media profile provider is available.
146 if (services) {
147 // Connect to the media profile provider to assign thread priorities using
148 // Fuchsia's scheduler role API. Failure to connect will print a warning and
149 // proceed with engine initialization, leaving threads created by the engine
150 // at default priority.
151 //
152 // The use of std::shared_ptr here is to work around the unfortunate
153 // requirement for flutter::ThreadConfigSetter (i.e. std::function<>) that
154 // the target callable be copy-constructible. This awkwardly conflicts with
155 // fuchsia::media::ProfileProviderSyncPtr being move-only. std::shared_ptr
156 // provides copyable object that references the move-only SyncPtr.
157 std::shared_ptr<fuchsia::media::ProfileProviderSyncPtr>
158 media_profile_provider =
159 std::make_shared<fuchsia::media::ProfileProviderSyncPtr>();
160
161 const zx_status_t connect_status =
162 services->Connect(media_profile_provider->NewRequest());
163 if (connect_status != ZX_OK) {
164 FML_LOG(WARNING)
165 << "Failed to connect to " << fuchsia::media::ProfileProvider::Name_
166 << ": " << zx_status_get_string(connect_status)
167 << " This is not a fatal error, but threads created by the engine "
168 "will run at default priority, regardless of the requested "
169 "priority.";
170 } else {
171 // Set the role for (this) platform thread. See comment above about the
172 // role naming scheme.
173 SetThreadRole(*media_profile_provider, name_prefix + ".type.platform");
174
175 // This lambda must be copyable or the assignment fails to compile,
176 // necessitating the use of std::shared_ptr for the profile provider.
177 config_setter = [name_prefix, media_profile_provider](
178 const fml::Thread::ThreadConfig& config) {
179 SetThreadConfig(name_prefix, *media_profile_provider, config);
180 };
181 }
182 }
183
184 flutter::ThreadHost::ThreadHostConfig thread_host_config{config_setter};
185
186 thread_host_config.SetRasterConfig(
190 thread_host_config.SetUIConfig(
192 flutter::ThreadHost::Type::kUi, name_prefix),
194 thread_host_config.SetIOConfig(
196 flutter::ThreadHost::Type::kIo, name_prefix),
198
199 return flutter::ThreadHost(thread_host_config);
200}
201
203 std::string thread_label,
204 std::shared_ptr<sys::ServiceDirectory> svc,
205 std::shared_ptr<sys::ServiceDirectory> runner_services,
207 fuchsia::ui::views::ViewCreationToken view_creation_token,
208 std::pair<fuchsia::ui::views::ViewRefControl,
209 fuchsia::ui::views::ViewRef> view_ref_pair,
210 UniqueFDIONS fdio_ns,
211 fidl::InterfaceRequest<fuchsia::io::Directory> directory_request,
213 const std::vector<std::string>& dart_entrypoint_args)
214 : delegate_(delegate),
215 thread_label_(std::move(thread_label)),
216 thread_host_(CreateThreadHost(thread_label_, runner_services)),
217 view_creation_token_(std::move(view_creation_token)),
218 memory_pressure_watcher_binding_(this),
219 latest_memory_pressure_level_(fuchsia::memorypressure::Level::NORMAL),
220 intercept_all_input_(product_config.get_intercept_all_input()),
221 weak_factory_(this) {
222 Initialize(std::move(view_ref_pair), std::move(svc),
223 std::move(runner_services), std::move(settings),
224 std::move(fdio_ns), std::move(directory_request),
225 std::move(product_config), dart_entrypoint_args);
226}
227
228void Engine::Initialize(
229 std::pair<fuchsia::ui::views::ViewRefControl, fuchsia::ui::views::ViewRef>
230 view_ref_pair,
231 std::shared_ptr<sys::ServiceDirectory> svc,
232 std::shared_ptr<sys::ServiceDirectory> runner_services,
234 UniqueFDIONS fdio_ns,
235 fidl::InterfaceRequest<fuchsia::io::Directory> directory_request,
237 const std::vector<std::string>& dart_entrypoint_args) {
238 // Flatland uses |view_creation_token_| for linking.
239 FML_CHECK(view_creation_token_.value.is_valid());
240
241 // Get the task runners from the managed threads. The current thread will be
242 // used as the "platform" thread.
243 fml::RefPtr<fml::TaskRunner> platform_task_runner =
245
246 const flutter::TaskRunners task_runners(
247 thread_label_, // Dart thread labels
248 platform_task_runner, // platform
249 thread_host_.raster_thread->GetTaskRunner(), // raster
250 thread_host_.ui_thread->GetTaskRunner(), // ui
251 thread_host_.io_thread->GetTaskRunner() // io
252 );
253
254 fuchsia::ui::views::FocuserHandle focuser;
255 fuchsia::ui::views::ViewRefFocusedHandle view_ref_focused;
256 fuchsia::ui::pointer::TouchSourceHandle touch_source;
257 fuchsia::ui::pointer::MouseSourceHandle mouse_source;
258
259 fuchsia::ui::composition::ViewBoundProtocols view_protocols;
260 view_protocols.set_view_focuser(focuser.NewRequest());
261 view_protocols.set_view_ref_focused(view_ref_focused.NewRequest());
262 view_protocols.set_touch_source(touch_source.NewRequest());
263 view_protocols.set_mouse_source(mouse_source.NewRequest());
264
265 // Connect to Flatland.
266 fuchsia::ui::composition::FlatlandHandle flatland;
267 zx_status_t flatland_status =
268 runner_services->Connect<fuchsia::ui::composition::Flatland>(
269 flatland.NewRequest());
270 if (flatland_status != ZX_OK) {
271 FML_LOG(WARNING) << "fuchsia::ui::composition::Flatland connection failed: "
272 << zx_status_get_string(flatland_status);
273 }
274
275 // Connect to SemanticsManager service.
276 fuchsia::accessibility::semantics::SemanticsManagerHandle semantics_manager;
277 zx_status_t semantics_status =
278 runner_services
279 ->Connect<fuchsia::accessibility::semantics::SemanticsManager>(
280 semantics_manager.NewRequest());
281 if (semantics_status != ZX_OK) {
282 FML_LOG(WARNING)
283 << "fuchsia::accessibility::semantics::SemanticsManager connection "
284 "failed: "
285 << zx_status_get_string(semantics_status);
286 }
287
288 // Connect to ImeService service.
289 fuchsia::ui::input::ImeServiceHandle ime_service;
290 zx_status_t ime_status =
291 runner_services->Connect<fuchsia::ui::input::ImeService>(
292 ime_service.NewRequest());
293 if (ime_status != ZX_OK) {
294 FML_LOG(WARNING) << "fuchsia::ui::input::ImeService connection failed: "
295 << zx_status_get_string(ime_status);
296 }
297
298 // Connect to Keyboard service.
299 fuchsia::ui::input3::KeyboardHandle keyboard;
300 zx_status_t keyboard_status =
301 runner_services->Connect<fuchsia::ui::input3::Keyboard>(
302 keyboard.NewRequest());
303 FML_DCHECK(keyboard_status == ZX_OK)
304 << "fuchsia::ui::input3::Keyboard connection failed: "
305 << zx_status_get_string(keyboard_status);
306
307 // Connect to Pointerinjector service.
308 fuchsia::ui::pointerinjector::RegistryHandle pointerinjector_registry;
309 zx_status_t pointerinjector_registry_status =
310 runner_services->Connect<fuchsia::ui::pointerinjector::Registry>(
311 pointerinjector_registry.NewRequest());
312 if (pointerinjector_registry_status != ZX_OK) {
313 FML_LOG(WARNING)
314 << "fuchsia::ui::pointerinjector::Registry connection failed: "
315 << zx_status_get_string(pointerinjector_registry_status);
316 }
317
318 // Make clones of the `ViewRef` before sending it to various places.
319 fuchsia::ui::views::ViewRef platform_view_ref;
320 view_ref_pair.second.Clone(&platform_view_ref);
321 fuchsia::ui::views::ViewRef accessibility_view_ref;
322 view_ref_pair.second.Clone(&accessibility_view_ref);
323 fuchsia::ui::views::ViewRef isolate_view_ref;
324 view_ref_pair.second.Clone(&isolate_view_ref);
325
326 // Session is terminated on the raster thread, but we must terminate ourselves
327 // on the platform thread.
328 //
329 // This handles the fidl error callback when the Session connection is
330 // broken. The SessionListener interface also has an OnError method, which is
331 // invoked on the platform thread (in PlatformView).
332 fml::closure session_error_callback = [task_runner = platform_task_runner,
333 weak = weak_factory_.GetWeakPtr()]() {
334 task_runner->PostTask([weak]() {
335 if (weak) {
336 FML_LOG(ERROR) << "Terminating from session_error_callback";
337 weak->Terminate();
338 }
339 });
340 };
341
342 // Set up the session connection and other Scenic helpers on the raster
343 // thread. We also need to wait for the external view embedder to be set up
344 // before creating the shell.
345 fuchsia::ui::composition::ParentViewportWatcherPtr parent_viewport_watcher;
346 fml::AutoResetWaitableEvent view_embedder_latch;
347 auto session_inspect_node =
349 task_runners.GetRasterTaskRunner()->PostTask(fml::MakeCopyable(
350 [this, &view_embedder_latch,
351 session_inspect_node = std::move(session_inspect_node),
352 flatland = std::move(flatland),
353 session_error_callback = std::move(session_error_callback),
354 view_creation_token = std::move(view_creation_token_),
355 view_protocols = std::move(view_protocols),
356 request = parent_viewport_watcher.NewRequest(),
357 view_ref_pair = std::move(view_ref_pair),
358 software_rendering = product_config.software_rendering()]() mutable {
359 if (software_rendering) {
360 surface_producer_ = std::make_shared<SoftwareSurfaceProducer>();
361 } else {
362 surface_producer_ = std::make_shared<VulkanSurfaceProducer>();
363 }
364
365 flatland_connection_ = std::make_shared<FlatlandConnection>(
366 thread_label_, std::move(flatland),
367 std::move(session_error_callback), [](auto) {});
368
369 fuchsia::ui::views::ViewIdentityOnCreation view_identity = {
370 .view_ref = std::move(view_ref_pair.second),
371 .view_ref_control = std::move(view_ref_pair.first)};
372 view_embedder_ = std::make_shared<ExternalViewEmbedder>(
373 std::move(view_creation_token), std::move(view_identity),
374 std::move(view_protocols), std::move(request), flatland_connection_,
375 surface_producer_, intercept_all_input_);
376
377 view_embedder_latch.Signal();
378 }));
379 view_embedder_latch.Wait();
380
382 set_semantics_enabled_callback = [this](bool enabled) {
383 auto platform_view = shell_->GetPlatformView();
384
385 if (platform_view) {
386 platform_view->SetSemanticsEnabled(enabled);
387 }
388 };
389
391 dispatch_semantics_action_callback =
392 [this](int32_t node_id, flutter::SemanticsAction action) {
393 auto platform_view = shell_->GetPlatformView();
394
395 if (platform_view) {
396 platform_view->DispatchSemanticsAction(node_id, action, {});
397 }
398 };
399
400 const std::string accessibility_inspect_name =
401 std::to_string(GetKoid(accessibility_view_ref));
402 accessibility_bridge_ = std::make_unique<AccessibilityBridge>(
403 std::move(set_semantics_enabled_callback),
404 std::move(dispatch_semantics_action_callback),
405 std::move(semantics_manager), std::move(accessibility_view_ref),
407 std::move(accessibility_inspect_name)));
408
409 OnEnableWireframeCallback on_enable_wireframe_callback = std::bind(
410 &Engine::DebugWireframeSettingsChanged, this, std::placeholders::_1);
411
412 OnCreateViewCallback on_create_view_callback = std::bind(
413 &Engine::CreateView, this, std::placeholders::_1, std::placeholders::_2,
414 std::placeholders::_3, std::placeholders::_4, std::placeholders::_5);
415
416 OnUpdateViewCallback on_update_view_callback = std::bind(
417 &Engine::UpdateView, this, std::placeholders::_1, std::placeholders::_2,
418 std::placeholders::_3, std::placeholders::_4);
419
420 OnDestroyViewCallback on_destroy_view_callback = std::bind(
421 &Engine::DestroyView, this, std::placeholders::_1, std::placeholders::_2);
422
423 OnCreateSurfaceCallback on_create_surface_callback =
424 std::bind(&Engine::CreateSurface, this);
425
426 // SessionListener has a OnScenicError method; invoke this callback on the
427 // platform thread when that happens. The Session itself should also be
428 // disconnected when this happens, and it will also attempt to terminate.
429 fit::closure on_session_listener_error_callback =
430 [task_runner = platform_task_runner,
431 weak = weak_factory_.GetWeakPtr()]() {
432 task_runner->PostTask([weak]() {
433 if (weak) {
434 FML_LOG(ERROR) << "Terminating from "
435 "on_session_listener_error_callback";
436 weak->Terminate();
437 }
438 });
439 };
440
441 // Launch the engine in the appropriate configuration.
442 // Note: this initializes the Asset Manager on the global PersistantCache
443 // so it must be called before WarmupSkps() is called below.
444 auto run_configuration = flutter::RunConfiguration::InferFromSettings(
445 settings, task_runners.GetIOTaskRunner());
446 run_configuration.SetEntrypointArgs(std::move(dart_entrypoint_args));
447
448 OnSemanticsNodeUpdateCallback on_semantics_node_update_callback =
449 [this](flutter::SemanticsNodeUpdates updates, float pixel_ratio) {
450 accessibility_bridge_->AddSemanticsNodeUpdate(updates, pixel_ratio);
451 };
452
453 OnRequestAnnounceCallback on_request_announce_callback =
454 [this](const std::string& message) {
455 accessibility_bridge_->RequestAnnounce(message);
456 };
457
458 // Setup the callback that will instantiate the platform view.
460 on_create_platform_view = fml::MakeCopyable(
461 [this, view_ref = std::move(platform_view_ref),
462 parent_viewport_watcher = std::move(parent_viewport_watcher),
463 ime_service = std::move(ime_service), keyboard = std::move(keyboard),
464 focuser = std::move(focuser),
465 view_ref_focused = std::move(view_ref_focused),
466 touch_source = std::move(touch_source),
467 mouse_source = std::move(mouse_source),
468 pointerinjector_registry = std::move(pointerinjector_registry),
469 on_session_listener_error_callback =
470 std::move(on_session_listener_error_callback),
471 on_enable_wireframe_callback =
472 std::move(on_enable_wireframe_callback),
473 on_create_view_callback = std::move(on_create_view_callback),
474 on_update_view_callback = std::move(on_update_view_callback),
475 on_destroy_view_callback = std::move(on_destroy_view_callback),
476 on_create_surface_callback = std::move(on_create_surface_callback),
477 on_semantics_node_update_callback =
478 std::move(on_semantics_node_update_callback),
479 on_request_announce_callback =
480 std::move(on_request_announce_callback),
481 external_view_embedder = GetExternalViewEmbedder(),
482 await_vsync_callback =
483 [this](FireCallbackCallback cb) {
484 flatland_connection_->AwaitVsync(cb);
485 },
486 await_vsync_for_secondary_callback_callback =
487 [this](FireCallbackCallback cb) {
488 flatland_connection_->AwaitVsyncForSecondaryCallback(cb);
489 },
490 product_config, svc](flutter::Shell& shell) mutable {
491 OnShaderWarmupCallback on_shader_warmup_callback = nullptr;
492 if (product_config.enable_shader_warmup()) {
493 FML_DCHECK(surface_producer_);
494 if (product_config.enable_shader_warmup_dart_hooks()) {
495 on_shader_warmup_callback =
496 [this, &shell](
497 const std::vector<std::string>& skp_names,
498 std::function<void(uint32_t)> completion_callback,
499 uint64_t width, uint64_t height) {
500 WarmupSkps(
501 shell.GetDartVM()
502 ->GetConcurrentMessageLoop()
503 ->GetTaskRunner()
504 .get(),
505 shell.GetTaskRunners().GetRasterTaskRunner().get(),
506 surface_producer_, SkISize::Make(width, height),
508 ->asset_manager(),
509 skp_names, completion_callback);
510 };
511 } else {
512 WarmupSkps(shell.GetDartVM()
513 ->GetConcurrentMessageLoop()
514 ->GetTaskRunner()
515 .get(),
516 shell.GetTaskRunners().GetRasterTaskRunner().get(),
517 surface_producer_, SkISize::Make(1024, 600),
519 ->asset_manager(),
520 std::nullopt, std::nullopt);
521 }
522 }
523
524 return std::make_unique<flutter_runner::PlatformView>(
525 shell, shell.GetTaskRunners(), std::move(view_ref),
526 std::move(external_view_embedder), std::move(ime_service),
527 std::move(keyboard), std::move(touch_source),
528 std::move(mouse_source), std::move(focuser),
529 std::move(view_ref_focused), std::move(parent_viewport_watcher),
530 std::move(pointerinjector_registry),
531 std::move(on_enable_wireframe_callback),
532 std::move(on_create_view_callback),
533 std::move(on_update_view_callback),
534 std::move(on_destroy_view_callback),
535 std::move(on_create_surface_callback),
536 std::move(on_semantics_node_update_callback),
537 std::move(on_request_announce_callback),
538 std::move(on_shader_warmup_callback),
539 std::move(await_vsync_callback),
540 std::move(await_vsync_for_secondary_callback_callback),
541 std::move(svc));
542 });
543
544 // Setup the callback that will instantiate the rasterizer.
546 [](flutter::Shell& shell) {
547 return std::make_unique<flutter::Rasterizer>(shell);
548 };
549
550 settings.root_isolate_create_callback =
551 std::bind(&Engine::OnMainIsolateStart, this);
552 settings.root_isolate_shutdown_callback =
553 std::bind([weak = weak_factory_.GetWeakPtr(),
554 runner = task_runners.GetPlatformTaskRunner()]() {
555 runner->PostTask([weak = std::move(weak)] {
556 if (weak) {
557 weak->OnMainIsolateShutdown();
558 }
559 });
560 });
561
562 // Connect and set up the system font provider.
563 fuchsia::fonts::ProviderSyncPtr sync_font_provider;
564 runner_services->Connect(sync_font_provider.NewRequest());
565 settings.font_initialization_data =
566 sync_font_provider.Unbind().TakeChannel().release();
567
568 {
569 TRACE_EVENT0("flutter", "CreateShell");
570 shell_ = flutter::Shell::Create(
571 flutter::PlatformData(), // default window data
572 std::move(task_runners), // host task runners
573 std::move(settings), // shell launch settings
574 std::move(on_create_platform_view), // platform view create callback
575 std::move(on_create_rasterizer) // rasterizer create callback
576 );
577 }
578
579 if (!shell_) {
580 FML_LOG(ERROR) << "Could not launch the shell.";
581 return;
582 }
583
584 // Shell has been created. Before we run the engine, set up the isolate
585 // configurator.
586 isolate_configurator_ = std::make_unique<IsolateConfigurator>(
587 std::move(fdio_ns), directory_request.TakeChannel(),
588 std::move(isolate_view_ref.reference));
589
590 // This platform does not get a separate surface platform view creation
591 // notification. Fire one eagerly.
592 shell_->GetPlatformView()->NotifyCreated();
593
594 // Connect to the memory pressure provider. If the connection fails, the
595 // initialization of the engine will simply proceed, printing a warning
596 // message. The engine will be fully functional, except that the Flutter
597 // shell will not be notified when memory is low.
598 {
599 memory_pressure_provider_.set_error_handler([](zx_status_t status) {
600 FML_LOG(WARNING)
601 << "Failed to connect to " << fuchsia::memorypressure::Provider::Name_
602 << ": " << zx_status_get_string(status)
603 << " This is not a fatal error, but the heap will not be "
604 << " compacted when memory is low.";
605 });
606
607 // Note that we're using the runner's services, not the component's.
608 // The Flutter Shell should be notified when memory is low regardless of
609 // whether the component has direct access to the
610 // fuchsia.memorypressure.Provider service.
611 ZX_ASSERT(runner_services->Connect(
612 memory_pressure_provider_.NewRequest()) == ZX_OK);
613
614 FML_VLOG(1) << "Registering memorypressure watcher";
615
616 // Register for changes, which will make the request for the initial
617 // memory level.
618 memory_pressure_provider_->RegisterWatcher(
619 memory_pressure_watcher_binding_.NewBinding());
620 }
621
622 // Connect to the intl property provider. If the connection fails, the
623 // initialization of the engine will simply proceed, printing a warning
624 // message. The engine will be fully functional, except that the user's
625 // locale preferences would not be communicated to flutter engine.
626 {
627 intl_property_provider_.set_error_handler([](zx_status_t status) {
628 FML_LOG(WARNING) << "Failed to connect to "
629 << fuchsia::intl::PropertyProvider::Name_ << ": "
630 << zx_status_get_string(status)
631 << " This is not a fatal error, but the user locale "
632 << " preferences will not be forwarded to flutter apps";
633 });
634
635 // Note that we're using the runner's services, not the component's.
636 // Flutter locales should be updated regardless of whether the component has
637 // direct access to the fuchsia.intl.PropertyProvider service.
638 ZX_ASSERT(runner_services->Connect(intl_property_provider_.NewRequest()) ==
639 ZX_OK);
640
641 auto get_profile_callback = [weak = weak_factory_.GetWeakPtr()](
642 const fuchsia::intl::Profile& profile) {
643 if (!weak) {
644 return;
645 }
646 if (!profile.has_locales()) {
647 FML_LOG(WARNING) << "Got intl Profile without locales";
648 }
649 auto message = MakeLocalizationPlatformMessage(profile);
650 FML_VLOG(1) << "Sending LocalizationPlatformMessage";
651 weak->shell_->GetPlatformView()->DispatchPlatformMessage(
652 std::move(message));
653 };
654
655 FML_VLOG(1) << "Requesting intl Profile";
656
657 // Make the initial request
658 intl_property_provider_->GetProfile(get_profile_callback);
659
660 // And register for changes
661 intl_property_provider_.events().OnChange = [this, runner_services,
662 get_profile_callback]() {
663 FML_VLOG(1) << fuchsia::intl::PropertyProvider::Name_ << ": OnChange";
664 runner_services->Connect(intl_property_provider_.NewRequest());
665 intl_property_provider_->GetProfile(get_profile_callback);
666 };
667 }
668
669 auto on_run_failure = [weak = weak_factory_.GetWeakPtr()]() {
670 // The engine could have been killed by the caller right after the
671 // constructor was called but before it could run on the UI thread.
672 if (weak) {
673 FML_LOG(ERROR) << "Terminating from on_run_failure";
674 weak->Terminate();
675 }
676 };
677
678 shell_->GetTaskRunners().GetUITaskRunner()->PostTask(
679 fml::MakeCopyable([engine = shell_->GetEngine(), //
680 run_configuration = std::move(run_configuration), //
681 on_run_failure //
682 ]() mutable {
683 if (!engine) {
684 return;
685 }
686
687 if (engine->Run(std::move(run_configuration)) ==
689 on_run_failure();
690 }
691 }));
692}
693
694Engine::~Engine() {
695 shell_.reset();
696
697 // Destroy rendering objects on the raster thread.
698 fml::AutoResetWaitableEvent view_embedder_latch;
699 thread_host_.raster_thread->GetTaskRunner()->PostTask(
700 fml::MakeCopyable([this, &view_embedder_latch]() mutable {
701 view_embedder_.reset();
702 flatland_connection_.reset();
703 surface_producer_.reset();
704 view_embedder_latch.Signal();
705 }));
706 view_embedder_latch.Wait();
707}
708
709std::optional<uint32_t> Engine::GetEngineReturnCode() const {
710 if (!shell_) {
711 return std::nullopt;
712 }
713 std::optional<uint32_t> code;
716 shell_->GetTaskRunners().GetUITaskRunner(),
717 [&latch, &code, engine = shell_->GetEngine()]() {
718 if (engine) {
719 code = engine->GetUIIsolateReturnCode();
720 }
721 latch.Signal();
722 });
723 latch.Wait();
724 return code;
725}
726
727void Engine::OnMainIsolateStart() {
728 if (!isolate_configurator_ ||
729 !isolate_configurator_->ConfigureCurrentIsolate()) {
730 FML_LOG(ERROR) << "Could not configure some native embedder bindings for a "
731 "new root isolate.";
732 }
733}
734
735void Engine::OnMainIsolateShutdown() {
736 Terminate();
737}
738
739void Engine::Terminate() {
740 delegate_.OnEngineTerminate(this);
741 // Warning. Do not do anything after this point as the delegate may have
742 // collected this object.
743}
744
745void Engine::DebugWireframeSettingsChanged(bool enabled) {
746 FML_CHECK(shell_);
747
748 shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask([]() {
749 // TODO(fxbug.dev/116000): Investigate if we can add flatland wireframe code
750 // for debugging.
751 });
752}
753
754void Engine::CreateView(int64_t view_id,
755 ViewCallback on_view_created,
756 ViewCreatedCallback on_view_bound,
757 bool hit_testable,
758 bool focusable) {
759 FML_CHECK(shell_);
760 shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
761 [this, view_id, hit_testable, focusable,
762 on_view_created = std::move(on_view_created),
763 on_view_bound = std::move(on_view_bound)]() {
764 FML_CHECK(view_embedder_);
765 view_embedder_->CreateView(view_id, std::move(on_view_created),
766 std::move(on_view_bound));
767 view_embedder_->SetViewProperties(view_id, SkRect::MakeEmpty(),
768 hit_testable, focusable);
769 });
770}
771
772void Engine::UpdateView(int64_t view_id,
773 SkRect occlusion_hint,
774 bool hit_testable,
775 bool focusable) {
776 FML_CHECK(shell_);
777 shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
778 [this, view_id, occlusion_hint, hit_testable, focusable]() {
779 FML_CHECK(view_embedder_);
780 view_embedder_->SetViewProperties(view_id, occlusion_hint, hit_testable,
781 focusable);
782 });
783}
784
785void Engine::DestroyView(int64_t view_id, ViewIdCallback on_view_unbound) {
786 FML_CHECK(shell_);
787
788 shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
789 [this, view_id, on_view_unbound = std::move(on_view_unbound)]() {
790 FML_CHECK(view_embedder_);
791 view_embedder_->DestroyView(view_id, std::move(on_view_unbound));
792 });
793}
794
795std::unique_ptr<flutter::Surface> Engine::CreateSurface() {
796 return std::make_unique<Surface>(thread_label_, GetExternalViewEmbedder(),
797 surface_producer_->gr_context());
798}
799
800std::shared_ptr<flutter::ExternalViewEmbedder>
801Engine::GetExternalViewEmbedder() {
802 FML_CHECK(view_embedder_);
803 return view_embedder_;
804}
805
806#if !defined(DART_PRODUCT)
807void Engine::WriteProfileToTrace() const {
808 Dart_Port main_port = shell_->GetEngine()->GetUIIsolateMainPort();
809 char* error = NULL;
810 bool success = Dart_WriteProfileToTimeline(main_port, &error);
811 if (!success) {
812 FML_LOG(ERROR) << "Failed to write Dart profile to trace: " << error;
813 free(error);
814 }
815}
816#endif // !defined(DART_PRODUCT)
817
818void Engine::WarmupSkps(
819 fml::BasicTaskRunner* concurrent_task_runner,
820 fml::BasicTaskRunner* raster_task_runner,
821 std::shared_ptr<SurfaceProducer> surface_producer,
823 std::shared_ptr<flutter::AssetManager> asset_manager,
824 std::optional<const std::vector<std::string>> skp_names,
825 std::optional<std::function<void(uint32_t)>> maybe_completion_callback,
826 bool synchronous) {
827 // Wrap the optional validity checks up in a lambda to simplify the various
828 // callsites below
829 auto completion_callback = [maybe_completion_callback](uint32_t skp_count) {
830 if (maybe_completion_callback.has_value() &&
831 maybe_completion_callback.value()) {
832 maybe_completion_callback.value()(skp_count);
833 }
834 };
835
836 // We use this bizzare raw pointer to a smart pointer thing here because we
837 // want to keep the surface alive until all gpu work is done and the
838 // callbacks skia takes for this are function pointers so we are unable to
839 // use a lambda that captures the smart pointer. We need two levels of
840 // indirection because it needs to be the same across all invocations of the
841 // raster task lambda from a single invocation of WarmupSkps, but be
842 // different across different invocations of WarmupSkps (so we cant
843 // statically initialialize it in the lambda itself). Basically the result
844 // of a mashup of wierd call dynamics, multithreading, and lifecycle
845 // management with C style Skia callbacks.
846 std::unique_ptr<SurfaceProducerSurface>* skp_warmup_surface =
847 new std::unique_ptr<SurfaceProducerSurface>(nullptr);
848
849 // tell concurrent task runner to deserialize all skps available from
850 // the asset manager
851 concurrent_task_runner->PostTask([raster_task_runner, size,
852 skp_warmup_surface, surface_producer,
853 asset_manager, skp_names,
854 completion_callback, synchronous]() {
855 TRACE_DURATION("flutter", "DeserializeSkps");
856 std::vector<std::unique_ptr<fml::Mapping>> skp_mappings;
857 if (skp_names) {
858 for (auto& skp_name : skp_names.value()) {
859 auto skp_mapping = asset_manager->GetAsMapping(skp_name);
860 if (skp_mapping) {
861 skp_mappings.push_back(std::move(skp_mapping));
862 } else {
863 FML_LOG(ERROR) << "Failed to get mapping for " << skp_name;
864 }
865 }
866 } else {
867 skp_mappings = asset_manager->GetAsMappings(".*\\.skp$", "shaders");
868 }
869
870 if (skp_mappings.empty()) {
871 FML_LOG(WARNING)
872 << "Engine::WarmupSkps got zero SKP mappings, returning early";
873 completion_callback(0);
874 return;
875 }
876
877 size_t total_size = 0;
878 for (auto& mapping : skp_mappings) {
879 total_size += mapping->GetSize();
880 }
881
882 FML_LOG(INFO) << "Shader warmup got " << skp_mappings.size()
883 << " skp's with a total size of " << total_size << " bytes";
884
885 std::vector<sk_sp<SkPicture>> pictures;
886 unsigned int i = 0;
887 for (auto& mapping : skp_mappings) {
888 std::unique_ptr<SkMemoryStream> stream =
889 SkMemoryStream::MakeDirect(mapping->GetMapping(), mapping->GetSize());
890 SkDeserialProcs procs = {0};
894 SkPicture::MakeFromStream(stream.get(), &procs);
895 if (!picture) {
896 FML_LOG(ERROR) << "Failed to deserialize picture " << i;
897 continue;
898 }
899
900 // Tell raster task runner to warmup have the compositor
901 // context warm up the newly deserialized picture
902 raster_task_runner->PostTask([picture, skp_warmup_surface, size,
903 surface_producer, completion_callback, i,
904 count = skp_mappings.size(), synchronous] {
905 TRACE_DURATION("flutter", "WarmupSkp");
906 if (*skp_warmup_surface == nullptr) {
907 skp_warmup_surface->reset(
908 surface_producer->ProduceOffscreenSurface(size).release());
909
910 if (*skp_warmup_surface == nullptr) {
911 FML_LOG(ERROR) << "Failed to create offscreen warmup surface";
912 // Tell client that zero shaders were warmed up because warmup
913 // failed.
914 completion_callback(0);
915 return;
916 }
917 }
918
919 // Do the actual warmup
920 (*skp_warmup_surface)
921 ->GetSkiaSurface()
922 ->getCanvas()
923 ->drawPicture(picture);
924
925 if (i == count - 1) {
926 // We call this here instead of inside fFinishedProc below because
927 // we want to unblock the dart animation code as soon as the
928 // raster thread is free to enque work, rather than waiting for
929 // the GPU work itself to finish.
930 completion_callback(count);
931 }
932
933 if (surface_producer->gr_context()) {
934 if (i < count - 1) {
935 // For all but the last skp we fire and forget
936 surface_producer->gr_context()->flushAndSubmit();
937 } else {
938 // For the last skp we provide a callback that frees the warmup
939 // surface and calls the completion callback
940 struct GrFlushInfo flush_info;
941 flush_info.fFinishedContext = skp_warmup_surface;
942 flush_info.fFinishedProc = [](void* skp_warmup_surface) {
943 delete static_cast<std::unique_ptr<SurfaceProducerSurface>*>(
944 skp_warmup_surface);
945 };
946
947 surface_producer->gr_context()->flush(flush_info);
948 surface_producer->gr_context()->submit(
949 synchronous ? GrSyncCpu::kYes : GrSyncCpu::kNo);
950 }
951 } else {
952 if (i == count - 1) {
953 delete skp_warmup_surface;
954 }
955 }
956 });
957 i++;
958 }
959 });
960}
961
962void Engine::OnLevelChanged(
963 fuchsia::memorypressure::Level level,
964 fuchsia::memorypressure::Watcher::OnLevelChangedCallback callback) {
965 // The callback must be invoked immediately to acknowledge the message.
966 // This is the "Throttle push using acknowledgements" pattern:
967 // https://fuchsia.dev/fuchsia-src/concepts/api/fidl#throttle_push_using_acknowledgements
968 callback();
969
970 FML_LOG(WARNING) << "memorypressure watcher: OnLevelChanged from "
971 << static_cast<int>(latest_memory_pressure_level_) << " to "
972 << static_cast<int>(level);
973
974 if (latest_memory_pressure_level_ == fuchsia::memorypressure::Level::NORMAL &&
975 (level == fuchsia::memorypressure::Level::WARNING ||
976 level == fuchsia::memorypressure::Level::CRITICAL)) {
977 FML_LOG(WARNING)
978 << "memorypressure watcher: notifying Flutter that memory is low";
979 shell_->NotifyLowMemoryWarning();
980 }
981 latest_memory_pressure_level_ = level;
982}
983
984} // namespace flutter_runner
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
std::unique_ptr< flutter::PlatformViewIOS > platform_view
int count
Definition: FontMgrTest.cpp:50
static size_t total_size(SkSBlockAllocator< N > &pool)
static std::unique_ptr< SkMemoryStream > MakeDirect(const void *data, size_t length)
Definition: SkStream.cpp:310
static sk_sp< SkPicture > MakeFromStream(SkStream *stream, const SkDeserialProcs *procs=nullptr)
Definition: SkPicture.cpp:147
static inspect::Node CreateRootChild(const std::string &name)
static std::shared_ptr< AssetManager > asset_manager()
static PersistentCache * GetCacheForProcess()
static RunConfiguration InferFromSettings(const Settings &settings, const fml::RefPtr< fml::TaskRunner > &io_worker=nullptr, IsolateLaunchType launch_type=IsolateLaunchType::kNewGroup)
Attempts to infer a run configuration from the settings object. This tries to create a run configurat...
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
std::function< std::unique_ptr< T >(Shell &)> CreateCallback
Definition: shell.h:120
std::function< void(bool)> SetSemanticsEnabledCallback
std::function< void(int32_t, flutter::SemanticsAction)> DispatchSemanticsActionCallback
static flutter::ThreadHost CreateThreadHost(const std::string &name_prefix, const std::shared_ptr< sys::ServiceDirectory > &runner_services=nullptr)
Definition: engine.cc:136
Engine(Delegate &delegate, std::string thread_label, std::shared_ptr< sys::ServiceDirectory > svc, std::shared_ptr< sys::ServiceDirectory > runner_services, flutter::Settings settings, fuchsia::ui::views::ViewCreationToken view_creation_token, std::pair< fuchsia::ui::views::ViewRefControl, fuchsia::ui::views::ViewRef > view_ref_pair, UniqueFDIONS fdio_ns, fidl::InterfaceRequest< fuchsia::io::Directory > directory_request, FlutterRunnerProductConfiguration product_config, const std::vector< std::string > &dart_entrypoint_args)
Definition: engine.cc:202
An interface over the ability to schedule tasks on a TaskRunner.
Definition: task_runner.h:20
virtual void PostTask(const fml::closure &task)=0
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
Definition: message_loop.cc:56
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
Definition: message_loop.cc:19
static void RunNowOrPostTask(const fml::RefPtr< fml::TaskRunner > &runner, const fml::closure &task)
Definition: task_runner.cc:55
@ kNormal
Default priority level.
@ kRaster
Suitable for thread which raster data.
@ kBackground
Suitable for threads that shouldn't disrupt high priority work.
@ kDisplay
Suitable for threads which generate data for the display.
static void SetCurrentThreadName(const ThreadConfig &config)
Definition: thread.cc:135
DART_EXPORT bool Dart_WriteProfileToTimeline(Dart_Port main_port, char **error)
int64_t Dart_Port
Definition: dart_api.h:1525
@ kRaster
Suitable for thread which raster data.
Definition: embedder.h:266
ThreadHost thread_host_
MockDelegate delegate_
FlutterEngine engine
Definition: main.cc:68
if(end==-1)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
const uint8_t uint32_t uint32_t GError ** error
#define FML_VLOG(verbose_level)
Definition: logging.h:98
#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
Win32Message message
sk_sp< const SkPicture > picture
Definition: SkRecords.h:299
std::function< void(const std::vector< std::string > &, std::function< void(uint32_t)>, uint64_t, uint64_t)> OnShaderWarmupCallback
Definition: platform_view.h:61
fit::function< void(int64_t, ViewCallback, ViewCreatedCallback, bool, bool)> OnCreateViewCallback
Definition: platform_view.h:51
fit::function< void(int64_t, ViewIdCallback)> OnDestroyViewCallback
Definition: platform_view.h:52
std::function< void(fml::TimePoint, fml::TimePoint)> FireCallbackCallback
Definition: vsync_waiter.h:20
fit::function< void(int64_t, SkRect, bool, bool)> OnUpdateViewCallback
Definition: platform_view.h:44
fit::function< std::unique_ptr< flutter::Surface >()> OnCreateSurfaceCallback
Definition: platform_view.h:46
std::function< void()> ViewCallback
fit::function< void(flutter::SemanticsNodeUpdates, float)> OnSemanticsNodeUpdateCallback
Definition: platform_view.h:48
std::function< void(fuchsia::ui::composition::ContentId)> ViewIdCallback
fml::MallocMapping MakeLocalizationPlatformMessageData(const Profile &intl_profile)
Definition: fuchsia_intl.cc:29
fit::function< void(std::string)> OnRequestAnnounceCallback
Definition: platform_view.h:49
std::function< void(fuchsia::ui::composition::ContentId, fuchsia::ui::composition::ChildViewWatcherHandle child_view_watcher)> ViewCreatedCallback
fit::function< void(bool)> OnEnableWireframeCallback
Definition: platform_view.h:42
sk_sp< SkImage > DeserializeImageWithoutData(const void *data, size_t length, void *ctx)
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
sk_sp< SkTypeface > DeserializeTypefaceWithoutData(const void *data, size_t length, void *ctx)
fml::Thread::ThreadConfigSetter ThreadConfigSetter
Definition: thread_host.h:18
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
internal::CopyableLambda< T > MakeCopyable(T lambda)
Definition: make_copyable.h:57
std::function< void()> closure
Definition: closure.h:14
vk::UniqueSurfaceKHR CreateSurface(const ContextVK &context)
Definition: ref_ptr.h:256
static SkString to_string(int n)
Definition: nanobench.cpp:119
int32_t height
int32_t width
GrGpuFinishedContext fFinishedContext
Definition: GrTypes.h:220
SkDeserialTypefaceProc fTypefaceProc
SkDeserialImageProc fImageProc
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595
static std::string MakeThreadName(Type type, const std::string &prefix)
Use the prefix and thread type to generator a thread name.
Definition: thread_host.cc:15
void SetRasterConfig(const ThreadConfig &)
Specified the IO Thread Config, meanwhile set the mask.
Definition: thread_host.cc:48
The collection of all the threads used by the engine.
Definition: thread_host.h:21
std::unique_ptr< fml::Thread > io_thread
Definition: thread_host.h:86
std::unique_ptr< fml::Thread > raster_thread
Definition: thread_host.h:85
std::unique_ptr< fml::Thread > ui_thread
Definition: thread_host.h:84
The ThreadConfig is the thread info include thread name, thread priority.
Definition: thread.h:35
ThreadPriority priority
Definition: thread.h:45
#define ERROR(message)
Definition: elf_loader.cc:260
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131