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/ui/scenic/cpp/fidl.h>
9 #include <lib/async/cpp/task.h>
10 #include <zircon/status.h>
11 #include <zircon/types.h>
12 #include <memory>
13 
14 #include "flutter/common/graphics/persistent_cache.h"
15 #include "flutter/common/task_runners.h"
16 #include "flutter/fml/make_copyable.h"
17 #include "flutter/fml/message_loop.h"
18 #include "flutter/fml/synchronization/waitable_event.h"
19 #include "flutter/fml/task_runner.h"
20 #include "flutter/runtime/dart_vm_lifecycle.h"
21 #include "flutter/shell/common/rasterizer.h"
22 #include "flutter/shell/common/run_configuration.h"
23 #include "flutter/shell/common/serialization_callbacks.h"
24 #include "third_party/skia/include/core/SkPicture.h"
25 #include "third_party/skia/include/core/SkSerialProcs.h"
26 #include "third_party/skia/include/ports/SkFontMgr_fuchsia.h"
27 
28 #include "../runtime/dart/utils/files.h"
29 #include "../runtime/dart/utils/root_inspect_node.h"
30 #include "flatland_platform_view.h"
31 #include "focus_delegate.h"
32 #include "fuchsia_intl.h"
33 #include "gfx_platform_view.h"
34 #include "surface.h"
35 #include "vsync_waiter.h"
36 
37 namespace flutter_runner {
38 namespace {
39 
40 zx_koid_t GetKoid(const fuchsia::ui::views::ViewRef& view_ref) {
41  zx_handle_t handle = view_ref.reference.get();
42  zx_info_handle_basic_t info;
43  zx_status_t status = zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info,
44  sizeof(info), nullptr, nullptr);
45  return status == ZX_OK ? info.koid : ZX_KOID_INVALID;
46 }
47 
48 std::unique_ptr<flutter::PlatformMessage> MakeLocalizationPlatformMessage(
49  const fuchsia::intl::Profile& intl_profile) {
50  return std::make_unique<flutter::PlatformMessage>(
51  "flutter/localization", MakeLocalizationPlatformMessageData(intl_profile),
52  nullptr);
53 }
54 
55 } // namespace
56 
57 flutter::ThreadHost Engine::CreateThreadHost(const std::string& name_prefix) {
58  fml::Thread::SetCurrentThreadName(name_prefix + ".platform");
59  return flutter::ThreadHost(name_prefix, flutter::ThreadHost::Type::RASTER |
60  flutter::ThreadHost::Type::UI |
61  flutter::ThreadHost::Type::IO);
62 }
63 
65  std::string thread_label,
66  std::shared_ptr<sys::ServiceDirectory> svc,
67  std::shared_ptr<sys::ServiceDirectory> runner_services,
68  flutter::Settings settings,
69  fuchsia::ui::views::ViewToken view_token,
70  scenic::ViewRefPair view_ref_pair,
71  UniqueFDIONS fdio_ns,
72  fidl::InterfaceRequest<fuchsia::io::Directory> directory_request,
73  FlutterRunnerProductConfiguration product_config)
74  : delegate_(delegate),
75  thread_label_(std::move(thread_label)),
76  thread_host_(CreateThreadHost(thread_label_)),
77  view_token_(std::move(view_token)),
78  memory_pressure_watcher_binding_(this),
79  latest_memory_pressure_level_(fuchsia::memorypressure::Level::NORMAL),
80  intercept_all_input_(product_config.get_intercept_all_input()),
81  weak_factory_(this) {
82  Initialize(/*=use_flatland*/ false, std::move(view_ref_pair), std::move(svc),
83  std::move(runner_services), std::move(settings),
84  std::move(fdio_ns), std::move(directory_request),
85  std::move(product_config));
86 }
87 
89  std::string thread_label,
90  std::shared_ptr<sys::ServiceDirectory> svc,
91  std::shared_ptr<sys::ServiceDirectory> runner_services,
92  flutter::Settings settings,
93  fuchsia::ui::views::ViewCreationToken view_creation_token,
94  scenic::ViewRefPair view_ref_pair,
95  UniqueFDIONS fdio_ns,
96  fidl::InterfaceRequest<fuchsia::io::Directory> directory_request,
97  FlutterRunnerProductConfiguration product_config)
98  : delegate_(delegate),
99  thread_label_(std::move(thread_label)),
100  thread_host_(CreateThreadHost(thread_label_)),
101  view_creation_token_(std::move(view_creation_token)),
102  memory_pressure_watcher_binding_(this),
103  latest_memory_pressure_level_(fuchsia::memorypressure::Level::NORMAL),
104  intercept_all_input_(product_config.get_intercept_all_input()),
105  weak_factory_(this) {
106  Initialize(/*=use_flatland*/ true, std::move(view_ref_pair), std::move(svc),
107  std::move(runner_services), std::move(settings),
108  std::move(fdio_ns), std::move(directory_request),
109  std::move(product_config));
110 }
111 
112 void Engine::Initialize(
113  bool use_flatland,
114  scenic::ViewRefPair view_ref_pair,
115  std::shared_ptr<sys::ServiceDirectory> svc,
116  std::shared_ptr<sys::ServiceDirectory> runner_services,
117  flutter::Settings settings,
118  UniqueFDIONS fdio_ns,
119  fidl::InterfaceRequest<fuchsia::io::Directory> directory_request,
120  FlutterRunnerProductConfiguration product_config) {
121  // Flatland uses |view_creation_token_| for linking. Gfx uses |view_token_|.
122  FML_CHECK((use_flatland && view_creation_token_.value.is_valid()) ||
123  (!use_flatland && view_token_.value.is_valid()));
124 
125  // Get the task runners from the managed threads. The current thread will be
126  // used as the "platform" thread.
127  fml::RefPtr<fml::TaskRunner> platform_task_runner =
129 
130  const flutter::TaskRunners task_runners(
131  thread_label_, // Dart thread labels
132  platform_task_runner, // platform
133  thread_host_.raster_thread->GetTaskRunner(), // raster
134  thread_host_.ui_thread->GetTaskRunner(), // ui
135  thread_host_.io_thread->GetTaskRunner() // io
136  );
137 
138  // Connect to Scenic.
139  auto scenic = runner_services->Connect<fuchsia::ui::scenic::Scenic>();
140  fuchsia::ui::scenic::SessionEndpoints gfx_protocols;
141  fidl::InterfaceHandle<fuchsia::ui::scenic::Session> session;
142  gfx_protocols.set_session(session.NewRequest());
143  fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> session_listener;
144  auto session_listener_request = session_listener.NewRequest();
145  gfx_protocols.set_session_listener(session_listener.Bind());
146  fidl::InterfaceHandle<fuchsia::ui::views::Focuser> focuser;
147  fidl::InterfaceHandle<fuchsia::ui::views::ViewRefFocused> view_ref_focused;
148  fidl::InterfaceHandle<fuchsia::ui::pointer::TouchSource> touch_source;
149  fidl::InterfaceHandle<fuchsia::ui::pointer::MouseSource> mouse_source;
150 
151  fuchsia::ui::composition::ViewBoundProtocols flatland_view_protocols;
152  if (use_flatland) {
153  flatland_view_protocols.set_view_focuser(focuser.NewRequest());
154  flatland_view_protocols.set_view_ref_focused(view_ref_focused.NewRequest());
155  flatland_view_protocols.set_touch_source(touch_source.NewRequest());
156  flatland_view_protocols.set_mouse_source(mouse_source.NewRequest());
157  } else {
158  gfx_protocols.set_view_focuser(focuser.NewRequest());
159  gfx_protocols.set_view_ref_focused(view_ref_focused.NewRequest());
160  // TODO(fxbug.dev/85125): Enable TouchSource for GFX.
161  // gfx_protocols.set_touch_source(touch_source.NewRequest());
162  }
163  scenic->CreateSessionT(std::move(gfx_protocols), [] {});
164 
165  // Connect to Flatland.
166  fidl::InterfaceHandle<fuchsia::ui::composition::Flatland> flatland;
167  zx_status_t flatland_status =
168  runner_services->Connect<fuchsia::ui::composition::Flatland>(
169  flatland.NewRequest());
170  if (flatland_status != ZX_OK && use_flatland) {
171  FML_LOG(WARNING) << "fuchsia::ui::composition::Flatland connection failed: "
172  << zx_status_get_string(flatland_status);
173  }
174 
175  // Connect to SemanticsManager service.
176  fidl::InterfaceHandle<fuchsia::accessibility::semantics::SemanticsManager>
177  semantics_manager;
178  zx_status_t semantics_status =
179  runner_services
180  ->Connect<fuchsia::accessibility::semantics::SemanticsManager>(
181  semantics_manager.NewRequest());
182  if (semantics_status != ZX_OK) {
183  FML_LOG(WARNING)
184  << "fuchsia::accessibility::semantics::SemanticsManager connection "
185  "failed: "
186  << zx_status_get_string(semantics_status);
187  }
188 
189  // Connect to ImeService service.
190  fidl::InterfaceHandle<fuchsia::ui::input::ImeService> ime_service;
191  zx_status_t ime_status =
192  runner_services->Connect<fuchsia::ui::input::ImeService>(
193  ime_service.NewRequest());
194  if (ime_status != ZX_OK) {
195  FML_LOG(WARNING) << "fuchsia::ui::input::ImeService connection failed: "
196  << zx_status_get_string(ime_status);
197  }
198 
199  // Connect to Keyboard service.
200  fidl::InterfaceHandle<fuchsia::ui::input3::Keyboard> keyboard;
201  zx_status_t keyboard_status =
202  runner_services->Connect<fuchsia::ui::input3::Keyboard>(
203  keyboard.NewRequest());
204  FML_DCHECK(keyboard_status == ZX_OK)
205  << "fuchsia::ui::input3::Keyboard connection failed: "
206  << zx_status_get_string(keyboard_status);
207 
208  // Make clones of the `ViewRef` before sending it to various places.
209  fuchsia::ui::views::ViewRef platform_view_ref;
210  view_ref_pair.view_ref.Clone(&platform_view_ref);
211  fuchsia::ui::views::ViewRef accessibility_view_ref;
212  view_ref_pair.view_ref.Clone(&accessibility_view_ref);
213  fuchsia::ui::views::ViewRef isolate_view_ref;
214  view_ref_pair.view_ref.Clone(&isolate_view_ref);
215 
216  // Session is terminated on the raster thread, but we must terminate ourselves
217  // on the platform thread.
218  //
219  // This handles the fidl error callback when the Session connection is
220  // broken. The SessionListener interface also has an OnError method, which is
221  // invoked on the platform thread (in PlatformView).
222  fml::closure session_error_callback = [task_runner = platform_task_runner,
223  weak = weak_factory_.GetWeakPtr()]() {
224  task_runner->PostTask([weak]() {
225  if (weak) {
226  weak->Terminate();
227  }
228  });
229  };
230 
231  // Set up the session connection and other Scenic helpers on the raster
232  // thread. We also need to wait for the external view embedder to be set up
233  // before creating the shell.
234  fuchsia::ui::composition::ParentViewportWatcherPtr parent_viewport_watcher;
235  fml::AutoResetWaitableEvent view_embedder_latch;
236  auto session_inspect_node =
238  task_runners.GetRasterTaskRunner()->PostTask(fml::MakeCopyable(
239  [this, &view_embedder_latch,
240  session_inspect_node = std::move(session_inspect_node),
241  session = std::move(session), flatland = std::move(flatland),
242  session_error_callback = std::move(session_error_callback), use_flatland,
243  view_token = std::move(view_token_),
244  view_creation_token = std::move(view_creation_token_),
245  flatland_view_protocols = std::move(flatland_view_protocols),
246  request = parent_viewport_watcher.NewRequest(),
247  view_ref_pair = std::move(view_ref_pair),
248  max_frames_in_flight = product_config.get_max_frames_in_flight(),
249  vsync_offset = product_config.get_vsync_offset()]() mutable {
250  if (use_flatland) {
251  flatland_connection_ = std::make_shared<FlatlandConnection>(
252  thread_label_, std::move(flatland),
253  std::move(session_error_callback), [](auto) {},
254  max_frames_in_flight, vsync_offset);
255  surface_producer_.emplace(/*scenic_session=*/nullptr);
256  fuchsia::ui::views::ViewIdentityOnCreation view_identity = {
257  .view_ref = std::move(view_ref_pair.view_ref),
258  .view_ref_control = std::move(view_ref_pair.control_ref)};
259  flatland_view_embedder_ =
260  std::make_shared<FlatlandExternalViewEmbedder>(
261  thread_label_, std::move(view_creation_token),
262  std::move(view_identity), std::move(flatland_view_protocols),
263  std::move(request), *flatland_connection_.get(),
264  surface_producer_.value(), intercept_all_input_);
265  } else {
266  session_connection_ = std::make_shared<GfxSessionConnection>(
267  thread_label_, std::move(session_inspect_node),
268  std::move(session), std::move(session_error_callback),
269  [](auto) {}, max_frames_in_flight, vsync_offset);
270  surface_producer_.emplace(session_connection_->get());
271  external_view_embedder_ = std::make_shared<GfxExternalViewEmbedder>(
272  thread_label_, std::move(view_token), std::move(view_ref_pair),
273  *session_connection_.get(), surface_producer_.value(),
274  intercept_all_input_);
275  }
276  view_embedder_latch.Signal();
277  }));
278  view_embedder_latch.Wait();
279 
281  set_semantics_enabled_callback = [this](bool enabled) {
282  auto platform_view = shell_->GetPlatformView();
283 
284  if (platform_view) {
285  platform_view->SetSemanticsEnabled(enabled);
286  }
287  };
288 
290  dispatch_semantics_action_callback =
291  [this](int32_t node_id, flutter::SemanticsAction action) {
292  auto platform_view = shell_->GetPlatformView();
293 
294  if (platform_view) {
295  platform_view->DispatchSemanticsAction(node_id, action, {});
296  }
297  };
298 
299  const std::string accessibility_inspect_name =
300  std::to_string(GetKoid(accessibility_view_ref));
301  accessibility_bridge_ = std::make_unique<AccessibilityBridge>(
302  std::move(set_semantics_enabled_callback),
303  std::move(dispatch_semantics_action_callback),
304  std::move(semantics_manager), std::move(accessibility_view_ref),
306  std::move(accessibility_inspect_name)));
307 
308  OnEnableWireframe on_enable_wireframe_callback = std::bind(
309  &Engine::DebugWireframeSettingsChanged, this, std::placeholders::_1);
310 
311  OnCreateGfxView on_create_gfx_view_callback =
312  std::bind(&Engine::CreateGfxView, this, std::placeholders::_1,
313  std::placeholders::_2, std::placeholders::_3,
314  std::placeholders::_4, std::placeholders::_5);
315 
316  OnCreateFlatlandView on_create_flatland_view_callback =
317  std::bind(&Engine::CreateFlatlandView, this, std::placeholders::_1,
318  std::placeholders::_2, std::placeholders::_3,
319  std::placeholders::_4, std::placeholders::_5);
320 
321  OnUpdateView on_update_view_callback = std::bind(
322  &Engine::UpdateView, this, std::placeholders::_1, std::placeholders::_2,
323  std::placeholders::_3, std::placeholders::_4, use_flatland);
324 
325  OnDestroyGfxView on_destroy_gfx_view_callback =
326  std::bind(&Engine::DestroyGfxView, this, std::placeholders::_1,
327  std::placeholders::_2);
328 
329  OnDestroyFlatlandView on_destroy_flatland_view_callback =
330  std::bind(&Engine::DestroyFlatlandView, this, std::placeholders::_1,
331  std::placeholders::_2);
332 
333  OnCreateSurface on_create_surface_callback =
334  std::bind(&Engine::CreateSurface, this);
335 
336  // SessionListener has a OnScenicError method; invoke this callback on the
337  // platform thread when that happens. The Session itself should also be
338  // disconnected when this happens, and it will also attempt to terminate.
339  fit::closure on_session_listener_error_callback =
340  [task_runner = platform_task_runner,
341  weak = weak_factory_.GetWeakPtr()]() {
342  task_runner->PostTask([weak]() {
343  if (weak) {
344  weak->Terminate();
345  }
346  });
347  };
348 
349  // Launch the engine in the appropriate configuration.
350  // Note: this initializes the Asset Manager on the global PersistantCache
351  // so it must be called before WarmupSkps() is called below.
352  auto run_configuration = flutter::RunConfiguration::InferFromSettings(
353  settings, task_runners.GetIOTaskRunner());
354 
355  OnSemanticsNodeUpdate on_semantics_node_update_callback =
356  [this](flutter::SemanticsNodeUpdates updates, float pixel_ratio) {
357  accessibility_bridge_->AddSemanticsNodeUpdate(updates, pixel_ratio);
358  };
359 
360  OnRequestAnnounce on_request_announce_callback =
361  [this](const std::string& message) {
362  accessibility_bridge_->RequestAnnounce(message);
363  };
364 
365  // Setup the callback that will instantiate the platform view.
367  on_create_platform_view = fml::MakeCopyable(
368  [this, use_flatland, view_ref = std::move(platform_view_ref),
369  session_listener_request = std::move(session_listener_request),
370  parent_viewport_watcher = std::move(parent_viewport_watcher),
371  ime_service = std::move(ime_service), keyboard = std::move(keyboard),
372  focuser = std::move(focuser),
373  view_ref_focused = std::move(view_ref_focused),
374  touch_source = std::move(touch_source),
375  mouse_source = std::move(mouse_source),
376  on_session_listener_error_callback =
377  std::move(on_session_listener_error_callback),
378  on_enable_wireframe_callback =
379  std::move(on_enable_wireframe_callback),
380  on_create_gfx_view_callback = std::move(on_create_gfx_view_callback),
381  on_create_flatland_view_callback =
382  std::move(on_create_flatland_view_callback),
383  on_update_view_callback = std::move(on_update_view_callback),
384  on_destroy_gfx_view_callback =
385  std::move(on_destroy_gfx_view_callback),
386  on_destroy_flatland_view_callback =
387  std::move(on_destroy_flatland_view_callback),
388  on_create_surface_callback = std::move(on_create_surface_callback),
389  on_semantics_node_update_callback =
390  std::move(on_semantics_node_update_callback),
391  on_request_announce_callback =
392  std::move(on_request_announce_callback),
393  external_view_embedder = GetExternalViewEmbedder(),
394  await_vsync_callback =
395  [this, use_flatland](FireCallbackCallback cb) {
396  if (use_flatland) {
397  flatland_connection_->AwaitVsync(cb);
398  } else {
399  session_connection_->AwaitVsync(cb);
400  }
401  },
402  await_vsync_for_secondary_callback_callback =
403  [this, use_flatland](FireCallbackCallback cb) {
404  if (use_flatland) {
405  flatland_connection_->AwaitVsyncForSecondaryCallback(cb);
406  } else {
407  session_connection_->AwaitVsyncForSecondaryCallback(cb);
408  }
409  },
410  product_config](flutter::Shell& shell) mutable {
411  OnShaderWarmup on_shader_warmup = nullptr;
412  if (product_config.enable_shader_warmup()) {
413  FML_DCHECK(surface_producer_);
414  if (product_config.enable_shader_warmup_dart_hooks()) {
415  on_shader_warmup =
416  [this, &shell](
417  const std::vector<std::string>& skp_names,
418  std::function<void(uint32_t)> completion_callback,
419  uint64_t width, uint64_t height) {
420  WarmupSkps(
421  shell.GetDartVM()
422  ->GetConcurrentMessageLoop()
423  ->GetTaskRunner()
424  .get(),
425  shell.GetTaskRunners().GetRasterTaskRunner().get(),
426  surface_producer_.value(), width, height,
428  ->asset_manager(),
429  skp_names, completion_callback);
430  };
431  } else {
432  WarmupSkps(shell.GetDartVM()
433  ->GetConcurrentMessageLoop()
434  ->GetTaskRunner()
435  .get(),
436  shell.GetTaskRunners().GetRasterTaskRunner().get(),
437  surface_producer_.value(), 1024, 600,
439  ->asset_manager(),
440  std::nullopt, std::nullopt);
441  }
442  }
443 
444  std::unique_ptr<flutter::PlatformView> platform_view;
445  if (use_flatland) {
446  platform_view =
447  std::make_unique<flutter_runner::FlatlandPlatformView>(
448  shell, shell.GetTaskRunners(), std::move(view_ref),
449  std::move(external_view_embedder), std::move(ime_service),
450  std::move(keyboard), std::move(touch_source),
451  std::move(mouse_source), std::move(focuser),
452  std::move(view_ref_focused),
453  std::move(parent_viewport_watcher),
454  std::move(on_enable_wireframe_callback),
455  std::move(on_create_flatland_view_callback),
456  std::move(on_update_view_callback),
457  std::move(on_destroy_flatland_view_callback),
458  std::move(on_create_surface_callback),
459  std::move(on_semantics_node_update_callback),
460  std::move(on_request_announce_callback),
461  std::move(on_shader_warmup),
462  std::move(await_vsync_callback),
463  std::move(await_vsync_for_secondary_callback_callback));
464  } else {
465  platform_view = std::make_unique<flutter_runner::GfxPlatformView>(
466  shell, shell.GetTaskRunners(), std::move(view_ref),
467  std::move(external_view_embedder), std::move(ime_service),
468  std::move(keyboard), std::move(touch_source),
469  std::move(mouse_source), std::move(focuser),
470  std::move(view_ref_focused),
471  std::move(session_listener_request),
472  std::move(on_session_listener_error_callback),
473  std::move(on_enable_wireframe_callback),
474  std::move(on_create_gfx_view_callback),
475  std::move(on_update_view_callback),
476  std::move(on_destroy_gfx_view_callback),
477  std::move(on_create_surface_callback),
478  std::move(on_semantics_node_update_callback),
479  std::move(on_request_announce_callback),
480  std::move(on_shader_warmup), std::move(await_vsync_callback),
481  std::move(await_vsync_for_secondary_callback_callback));
482  }
483  return platform_view;
484  });
485 
486  // Setup the callback that will instantiate the rasterizer.
488  [](flutter::Shell& shell) {
489  return std::make_unique<flutter::Rasterizer>(shell);
490  };
491 
493  std::bind(&Engine::OnMainIsolateStart, this);
495  std::bind([weak = weak_factory_.GetWeakPtr(),
496  runner = task_runners.GetPlatformTaskRunner()]() {
497  runner->PostTask([weak = std::move(weak)] {
498  if (weak) {
499  weak->OnMainIsolateShutdown();
500  }
501  });
502  });
503 
504  // Connect and set up the system font provider.
505  fuchsia::fonts::ProviderSyncPtr sync_font_provider;
506  runner_services->Connect(sync_font_provider.NewRequest());
507  settings.font_initialization_data =
508  sync_font_provider.Unbind().TakeChannel().release();
509 
510  {
511  TRACE_EVENT0("flutter", "CreateShell");
512  shell_ = flutter::Shell::Create(
513  flutter::PlatformData(), // default window data
514  std::move(task_runners), // host task runners
515  std::move(settings), // shell launch settings
516  std::move(on_create_platform_view), // platform view create callback
517  std::move(on_create_rasterizer) // rasterizer create callback
518  );
519  }
520 
521  if (!shell_) {
522  FML_LOG(ERROR) << "Could not launch the shell.";
523  return;
524  }
525 
526  // Shell has been created. Before we run the engine, set up the isolate
527  // configurator.
528  {
529  fuchsia::sys::EnvironmentPtr environment;
530  svc->Connect(environment.NewRequest());
531 
532  isolate_configurator_ = std::make_unique<IsolateConfigurator>(
533  std::move(fdio_ns), //
534  std::move(environment), //
535  directory_request.TakeChannel(), //
536  std::move(isolate_view_ref.reference) //
537  );
538  }
539 
540  // This platform does not get a separate surface platform view creation
541  // notification. Fire one eagerly.
542  shell_->GetPlatformView()->NotifyCreated();
543 
544  // Connect to the memory pressure provider. If the connection fails, the
545  // initialization of the engine will simply proceed, printing a warning
546  // message. The engine will be fully functional, except that the Flutter
547  // shell will not be notified when memory is low.
548  {
549  memory_pressure_provider_.set_error_handler([](zx_status_t status) {
550  FML_LOG(WARNING)
551  << "Failed to connect to " << fuchsia::memorypressure::Provider::Name_
552  << ": " << zx_status_get_string(status)
553  << " This is not a fatal error, but the heap will not be "
554  << " compacted when memory is low.";
555  });
556 
557  // Note that we're using the runner's services, not the component's.
558  // The Flutter Shell should be notified when memory is low regardless of
559  // whether the component has direct access to the
560  // fuchsia.memorypressure.Provider service.
561  ZX_ASSERT(runner_services->Connect(
562  memory_pressure_provider_.NewRequest()) == ZX_OK);
563 
564  FML_VLOG(-1) << "Registering memorypressure watcher";
565 
566  // Register for changes, which will make the request for the initial
567  // memory level.
568  memory_pressure_provider_->RegisterWatcher(
569  memory_pressure_watcher_binding_.NewBinding());
570  }
571 
572  // Connect to the intl property provider. If the connection fails, the
573  // initialization of the engine will simply proceed, printing a warning
574  // message. The engine will be fully functional, except that the user's
575  // locale preferences would not be communicated to flutter engine.
576  {
577  intl_property_provider_.set_error_handler([](zx_status_t status) {
578  FML_LOG(WARNING) << "Failed to connect to "
579  << fuchsia::intl::PropertyProvider::Name_ << ": "
580  << zx_status_get_string(status)
581  << " This is not a fatal error, but the user locale "
582  << " preferences will not be forwarded to flutter apps";
583  });
584 
585  // Note that we're using the runner's services, not the component's.
586  // Flutter locales should be updated regardless of whether the component has
587  // direct access to the fuchsia.intl.PropertyProvider service.
588  ZX_ASSERT(runner_services->Connect(intl_property_provider_.NewRequest()) ==
589  ZX_OK);
590 
591  auto get_profile_callback = [weak = weak_factory_.GetWeakPtr()](
592  const fuchsia::intl::Profile& profile) {
593  if (!weak) {
594  return;
595  }
596  if (!profile.has_locales()) {
597  FML_LOG(WARNING) << "Got intl Profile without locales";
598  }
599  auto message = MakeLocalizationPlatformMessage(profile);
600  FML_VLOG(-1) << "Sending LocalizationPlatformMessage";
601  weak->shell_->GetPlatformView()->DispatchPlatformMessage(
602  std::move(message));
603  };
604 
605  FML_VLOG(-1) << "Requesting intl Profile";
606 
607  // Make the initial request
608  intl_property_provider_->GetProfile(get_profile_callback);
609 
610  // And register for changes
611  intl_property_provider_.events().OnChange = [this, runner_services,
612  get_profile_callback]() {
613  FML_VLOG(-1) << fuchsia::intl::PropertyProvider::Name_ << ": OnChange";
614  runner_services->Connect(intl_property_provider_.NewRequest());
615  intl_property_provider_->GetProfile(get_profile_callback);
616  };
617  }
618 
619  auto on_run_failure = [weak = weak_factory_.GetWeakPtr()]() {
620  // The engine could have been killed by the caller right after the
621  // constructor was called but before it could run on the UI thread.
622  if (weak) {
623  weak->Terminate();
624  }
625  };
626 
627  shell_->GetTaskRunners().GetUITaskRunner()->PostTask(
628  fml::MakeCopyable([engine = shell_->GetEngine(), //
629  run_configuration = std::move(run_configuration), //
630  on_run_failure //
631  ]() mutable {
632  if (!engine) {
633  return;
634  }
635 
636  if (engine->Run(std::move(run_configuration)) ==
638  on_run_failure();
639  }
640  }));
641 }
642 
644  shell_.reset();
645 
646  // Destroy rendering objects on the raster thread.
647  fml::AutoResetWaitableEvent view_embedder_latch;
648  thread_host_.raster_thread->GetTaskRunner()->PostTask(
649  fml::MakeCopyable([this, &view_embedder_latch]() mutable {
650  flatland_view_embedder_.reset();
651  external_view_embedder_.reset();
652  surface_producer_.reset();
653  flatland_connection_.reset();
654  session_connection_.reset();
655 
656  view_embedder_latch.Signal();
657  }));
658  view_embedder_latch.Wait();
659 }
660 
661 std::optional<uint32_t> Engine::GetEngineReturnCode() const {
662  if (!shell_) {
663  return std::nullopt;
664  }
665  std::optional<uint32_t> code;
668  shell_->GetTaskRunners().GetUITaskRunner(),
669  [&latch, &code, engine = shell_->GetEngine()]() {
670  if (engine) {
671  code = engine->GetUIIsolateReturnCode();
672  }
673  latch.Signal();
674  });
675  latch.Wait();
676  return code;
677 }
678 
679 void Engine::OnMainIsolateStart() {
680  if (!isolate_configurator_ ||
681  !isolate_configurator_->ConfigureCurrentIsolate()) {
682  FML_LOG(ERROR) << "Could not configure some native embedder bindings for a "
683  "new root isolate.";
684  }
685  FML_DLOG(INFO) << "Main isolate for engine '" << thread_label_
686  << "' was started.";
687 }
688 
689 void Engine::OnMainIsolateShutdown() {
690  FML_DLOG(INFO) << "Main isolate for engine '" << thread_label_
691  << "' shutting down.";
692  Terminate();
693 }
694 
695 void Engine::Terminate() {
696  delegate_.OnEngineTerminate(this);
697  // Warning. Do not do anything after this point as the delegate may have
698  // collected this object.
699 }
700 
701 void Engine::DebugWireframeSettingsChanged(bool enabled) {
702  FML_CHECK(shell_);
703 
704  // TODO(fxbug.dev/64201): Investigate if we can add flatland wireframe code
705  // for debugging.
706  shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask([this, enabled]() {
707  if (external_view_embedder_) {
708  external_view_embedder_->EnableWireframe(enabled);
709  }
710  });
711 }
712 
713 void Engine::CreateGfxView(int64_t view_id,
714  ViewCallback on_view_created,
715  GfxViewIdCallback on_view_bound,
716  bool hit_testable,
717  bool focusable) {
718  FML_CHECK(shell_);
719  shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
720  [this, view_id, hit_testable, focusable,
721  on_view_created = std::move(on_view_created),
722  on_view_bound = std::move(on_view_bound)]() {
723  FML_CHECK(external_view_embedder_);
724  external_view_embedder_->CreateView(view_id, std::move(on_view_created),
725  std::move(on_view_bound));
726  external_view_embedder_->SetViewProperties(view_id, SkRect::MakeEmpty(),
727  hit_testable, focusable);
728  });
729 }
730 
731 void Engine::CreateFlatlandView(int64_t view_id,
732  ViewCallback on_view_created,
733  FlatlandViewCreatedCallback on_view_bound,
734  bool hit_testable,
735  bool focusable) {
736  FML_CHECK(shell_);
737  shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
738  [this, view_id, hit_testable, focusable,
739  on_view_created = std::move(on_view_created),
740  on_view_bound = std::move(on_view_bound)]() {
741  FML_CHECK(flatland_view_embedder_);
742  flatland_view_embedder_->CreateView(view_id, std::move(on_view_created),
743  std::move(on_view_bound));
744  flatland_view_embedder_->SetViewProperties(view_id, SkRect::MakeEmpty(),
745  hit_testable, focusable);
746  });
747 }
748 
749 void Engine::UpdateView(int64_t view_id,
750  SkRect occlusion_hint,
751  bool hit_testable,
752  bool focusable,
753  bool use_flatland) {
754  FML_CHECK(shell_);
755  shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
756  [this, use_flatland, view_id, occlusion_hint, hit_testable, focusable]() {
757  if (use_flatland) {
758  FML_CHECK(flatland_view_embedder_);
759  flatland_view_embedder_->SetViewProperties(view_id, occlusion_hint,
760  hit_testable, focusable);
761  } else {
762  FML_CHECK(external_view_embedder_);
763  external_view_embedder_->SetViewProperties(view_id, occlusion_hint,
764  hit_testable, focusable);
765  }
766  });
767 }
768 
769 void Engine::DestroyGfxView(int64_t view_id,
770  GfxViewIdCallback on_view_unbound) {
771  FML_CHECK(shell_);
772 
773  // TODO(fxbug.dev/64201): Add flatland hookup. |view_id| may be interpreted
774  // based on use_flatland from the initializer.
775  shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
776  [this, view_id, on_view_unbound = std::move(on_view_unbound)]() {
777  FML_CHECK(external_view_embedder_);
778  external_view_embedder_->DestroyView(view_id,
779  std::move(on_view_unbound));
780  });
781 }
782 
783 void Engine::DestroyFlatlandView(int64_t view_id,
784  FlatlandViewIdCallback on_view_unbound) {
785  FML_CHECK(shell_);
786 
787  // TODO(fxbug.dev/64201): Add flatland hookup. |view_id| may be interpreted
788  // based on use_flatland from the initializer.
789  shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
790  [this, view_id, on_view_unbound = std::move(on_view_unbound)]() {
791  FML_CHECK(flatland_view_embedder_);
792  flatland_view_embedder_->DestroyView(view_id,
793  std::move(on_view_unbound));
794  });
795 }
796 
797 std::unique_ptr<flutter::Surface> Engine::CreateSurface() {
798  return std::make_unique<Surface>(thread_label_, GetExternalViewEmbedder(),
799  surface_producer_->gr_context());
800 }
801 
802 std::shared_ptr<flutter::ExternalViewEmbedder>
803 Engine::GetExternalViewEmbedder() {
804  FML_CHECK(external_view_embedder_ || flatland_view_embedder_);
805 
806  if (external_view_embedder_) {
807  return external_view_embedder_;
808  }
809  return flatland_view_embedder_;
810 }
811 
812 #if !defined(DART_PRODUCT)
814  Dart_Port main_port = shell_->GetEngine()->GetUIIsolateMainPort();
815  char* error = NULL;
816  bool success = Dart_WriteProfileToTimeline(main_port, &error);
817  if (!success) {
818  FML_LOG(ERROR) << "Failed to write Dart profile to trace: " << error;
819  free(error);
820  }
821 }
822 #endif // !defined(DART_PRODUCT)
823 
824 void Engine::WarmupSkps(
825  fml::BasicTaskRunner* concurrent_task_runner,
826  fml::BasicTaskRunner* raster_task_runner,
827  VulkanSurfaceProducer& surface_producer,
828  uint64_t width,
829  uint64_t height,
830  std::shared_ptr<flutter::AssetManager> asset_manager,
831  std::optional<const std::vector<std::string>> skp_names,
832  std::optional<std::function<void(uint32_t)>> completion_callback) {
833  SkISize size = SkISize::Make(width, height);
834 
835  // We use a raw pointer here because we want to keep this alive until all gpu
836  // work is done and the callbacks skia takes for this are function pointers
837  // so we are unable to use a lambda that captures the smart pointer.
838  SurfaceProducerSurface* skp_warmup_surface =
839  surface_producer.ProduceOffscreenSurface(size).release();
840  if (!skp_warmup_surface) {
841  FML_LOG(ERROR) << "Failed to create offscreen warmup surface";
842  // Tell client that zero shaders were warmed up because warmup failed.
843  if (completion_callback.has_value() && completion_callback.value()) {
844  completion_callback.value()(0);
845  }
846  return;
847  }
848 
849  // tell concurrent task runner to deserialize all skps available from
850  // the asset manager
851  concurrent_task_runner->PostTask([raster_task_runner, skp_warmup_surface,
852  &surface_producer, asset_manager, skp_names,
853  completion_callback]() {
854  TRACE_DURATION("flutter", "DeserializeSkps");
855  std::vector<std::unique_ptr<fml::Mapping>> skp_mappings;
856  if (skp_names) {
857  for (auto& skp_name : skp_names.value()) {
858  auto skp_mapping = asset_manager->GetAsMapping(skp_name);
859  if (skp_mapping) {
860  skp_mappings.push_back(std::move(skp_mapping));
861  } else {
862  FML_LOG(ERROR) << "Failed to get mapping for " << skp_name;
863  }
864  }
865  } else {
866  skp_mappings = asset_manager->GetAsMappings(".*\\.skp$", "shaders");
867  }
868 
869  size_t total_size = 0;
870  for (auto& mapping : skp_mappings) {
871  total_size += mapping->GetSize();
872  }
873 
874  FML_LOG(INFO) << "Shader warmup got " << skp_mappings.size()
875  << " skp's with a total size of " << total_size << " bytes";
876 
877  std::vector<sk_sp<SkPicture>> pictures;
878  unsigned int i = 0;
879  for (auto& mapping : skp_mappings) {
880  std::unique_ptr<SkMemoryStream> stream =
881  SkMemoryStream::MakeDirect(mapping->GetMapping(), mapping->GetSize());
882  SkDeserialProcs procs = {0};
883  procs.fImageProc = flutter::DeserializeImageWithoutData;
884  procs.fTypefaceProc = flutter::DeserializeTypefaceWithoutData;
885  sk_sp<SkPicture> picture =
886  SkPicture::MakeFromStream(stream.get(), &procs);
887  if (!picture) {
888  FML_LOG(ERROR) << "Failed to deserialize picture " << i;
889  continue;
890  }
891 
892  // Tell raster task runner to warmup have the compositor
893  // context warm up the newly deserialized picture
894  raster_task_runner->PostTask([skp_warmup_surface, picture,
895  &surface_producer, completion_callback, i,
896  count = skp_mappings.size()] {
897  TRACE_DURATION("flutter", "WarmupSkp");
898  skp_warmup_surface->GetSkiaSurface()->getCanvas()->drawPicture(picture);
899 
900  if (i < count - 1) {
901  // For all but the last skp we fire and forget
902  surface_producer.gr_context()->flushAndSubmit();
903  } else {
904  // For the last skp we provide a callback that frees the warmup
905  // surface and calls the completion callback
906  struct GrFlushInfo flush_info;
907  flush_info.fFinishedContext = skp_warmup_surface;
908  flush_info.fFinishedProc = [](void* skp_warmup_surface) {
909  delete static_cast<SurfaceProducerSurface*>(skp_warmup_surface);
910  };
911 
912  surface_producer.gr_context()->flush(flush_info);
913  surface_producer.gr_context()->submit();
914 
915  // We call this here instead of inside fFinishedProc above because
916  // we want to unblock the dart animation code as soon as the raster
917  // thread is free to enque work, rather than waiting for the GPU work
918  // itself to finish.
919  if (completion_callback.has_value() && completion_callback.value()) {
920  completion_callback.value()(count);
921  }
922  }
923  });
924  i++;
925  }
926  });
927 }
928 
929 void Engine::OnLevelChanged(
930  fuchsia::memorypressure::Level level,
931  fuchsia::memorypressure::Watcher::OnLevelChangedCallback callback) {
932  // The callback must be invoked immediately to acknowledge the message.
933  // This is the "Throttle push using acknowledgements" pattern:
934  // https://fuchsia.dev/fuchsia-src/concepts/api/fidl#throttle_push_using_acknowledgements
935  callback();
936 
937  FML_LOG(WARNING) << "memorypressure watcher: OnLevelChanged from "
938  << static_cast<int>(latest_memory_pressure_level_) << " to "
939  << static_cast<int>(level);
940 
941  if (latest_memory_pressure_level_ == fuchsia::memorypressure::Level::NORMAL &&
942  (level == fuchsia::memorypressure::Level::WARNING ||
943  level == fuchsia::memorypressure::Level::CRITICAL)) {
944  FML_LOG(WARNING)
945  << "memorypressure watcher: notifying Flutter that memory is low";
946  shell_->NotifyLowMemoryWarning();
947  }
948  latest_memory_pressure_level_ = level;
949 }
950 
951 } // namespace flutter_runner
std::function< void(const std::vector< std::string > &, std::function< void(uint32_t)>, uint64_t, uint64_t)> OnShaderWarmup
Definition: platform_view.h:52
std::unique_ptr< fml::Thread > ui_thread
Definition: thread_host.h:27
fit::function< void(std::string)> OnRequestAnnounce
Definition: platform_view.h:45
static flutter::ThreadHost CreateThreadHost(const std::string &name_prefix)
Definition: engine.cc:57
virtual void PostTask(const fml::closure &task)=0
std::function< std::unique_ptr< T >(Shell &)> CreateCallback
Definition: shell.h:114
const uint8_t uint32_t uint32_t GError ** error
fit::function< void(int64_t, GfxViewIdCallback)> OnDestroyGfxView
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:90
#define FML_DCHECK(condition)
Definition: logging.h:86
std::function< void(const DartIsolate &)> root_isolate_create_callback
Definition: settings.h:216
std::unique_ptr< flutter::PlatformViewIOS > platform_view
fit::function< std::unique_ptr< flutter::Surface >()> OnCreateSurface
Definition: platform_view.h:42
sk_sp< SkImage > DeserializeImageWithoutData(const void *data, size_t length, void *ctx)
static void RunNowOrPostTask(fml::RefPtr< fml::TaskRunner > runner, const fml::closure &task)
Definition: task_runner.cc:55
Definition: ref_ptr.h:252
Dart_NativeFunction function
Definition: fuchsia.cc:51
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
Definition: message_loop.cc:19
std::unordered_map< int32_t, SemanticsNode > SemanticsNodeUpdates
fml::MallocMapping MakeLocalizationPlatformMessageData(const Profile &intl_profile)
Definition: fuchsia_intl.cc:29
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
#define FML_LOG(severity)
Definition: logging.h:65
fit::function< void(int64_t, ViewCallback, FlatlandViewCreatedCallback, bool, bool)> OnCreateFlatlandView
std::function< void(fuchsia::ui::composition::ContentId, fuchsia::ui::composition::ChildViewWatcherPtr child_view_watcher)> FlatlandViewCreatedCallback
FlKeyEvent FlKeyResponderAsyncCallback callback
fit::function< void(int64_t, SkRect, bool, bool)> OnUpdateView
Definition: platform_view.h:41
sk_sp< SkTypeface > DeserializeTypefaceWithoutData(const void *data, size_t length, void *ctx)
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
Definition: message_loop.cc:56
fit::function< void(flutter::SemanticsNodeUpdates, float)> OnSemanticsNodeUpdate
Definition: platform_view.h:44
fit::function< void(int64_t, FlatlandViewIdCallback)> OnDestroyFlatlandView
std::function< void()> closure
Definition: closure.h:14
internal::CopyableLambda< T > MakeCopyable(T lambda)
Definition: make_copyable.h:57
static RunConfiguration InferFromSettings(const Settings &settings, fml::RefPtr< fml::TaskRunner > io_worker=nullptr)
Attempts to infer a run configuration from the settings object. This tries to create a run configurat...
fml::closure root_isolate_shutdown_callback
Definition: settings.h:222
std::function< void(fml::TimePoint, fml::TimePoint)> FireCallbackCallback
Definition: vsync_waiter.h:20
fit::function< void(int64_t, ViewCallback, GfxViewIdCallback, bool, bool)> OnCreateGfxView
SemanticsAction action
The collection of all the threads used by the engine.
Definition: thread_host.h:16
std::function< void(fuchsia::ui::composition::ContentId)> FlatlandViewIdCallback
int32_t width
std::function< void(bool)> SetSemanticsEnabledCallback
std::function< void()> ViewCallback
static std::unique_ptr< Shell > Create(const PlatformData &platform_data, 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:126
virtual void OnEngineTerminate(const Engine *holder)=0
virtual sk_sp< SkSurface > GetSkiaSurface() const =0
int32_t height
An interface over the ability to schedule tasks on a TaskRunner.
Definition: task_runner.h:20
static PersistentCache * GetCacheForProcess()
#define FML_CHECK(condition)
Definition: logging.h:68
std::unique_ptr< SurfaceProducerSurface > ProduceOffscreenSurface(const SkISize &size)
std::unique_ptr< fml::Thread > io_thread
Definition: thread_host.h:29
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::ViewToken view_token, scenic::ViewRefPair view_ref_pair, UniqueFDIONS fdio_ns, fidl::InterfaceRequest< fuchsia::io::Directory > directory_request, FlutterRunnerProductConfiguration product_config)
Definition: engine.cc:64
static void SetCurrentThreadName(const std::string &name)
Definition: thread.cc:70
#define FML_DLOG(severity)
Definition: logging.h:85
#define FML_VLOG(verbose_level)
Definition: logging.h:81
std::function< void(int32_t, flutter::SemanticsAction)> DispatchSemanticsActionCallback
fit::function< void(bool)> OnEnableWireframe
Definition: platform_view.h:39
uint32_t font_initialization_data
Definition: settings.h:195
std::unique_ptr< fml::Thread > raster_thread
Definition: thread_host.h:28
void WriteProfileToTrace() const
Definition: engine.cc:813
std::function< void(scenic::ResourceId)> GfxViewIdCallback
std::optional< uint32_t > GetEngineReturnCode() const
Definition: engine.cc:661
static inspect::Node CreateRootChild(const std::string &name)
static std::shared_ptr< AssetManager > asset_manager()