void Engine::Initialize()

in shell/platform/fuchsia/flutter/engine.cc [118:670]


void Engine::Initialize(
    bool use_flatland,
    scenic::ViewRefPair view_ref_pair,
    std::shared_ptr<sys::ServiceDirectory> svc,
    std::shared_ptr<sys::ServiceDirectory> runner_services,
    flutter::Settings settings,
    UniqueFDIONS fdio_ns,
    fidl::InterfaceRequest<fuchsia::io::Directory> directory_request,
    FlutterRunnerProductConfiguration product_config,
    const std::vector<std::string>& dart_entrypoint_args,
    bool for_v1_component) {
  // Flatland uses |view_creation_token_| for linking. Gfx uses |view_token_|.
  FML_CHECK((use_flatland && view_creation_token_.value.is_valid()) ||
            (!use_flatland && view_token_.value.is_valid()));

  // Get the task runners from the managed threads. The current thread will be
  // used as the "platform" thread.
  fml::RefPtr<fml::TaskRunner> platform_task_runner =
      fml::MessageLoop::GetCurrent().GetTaskRunner();

  const flutter::TaskRunners task_runners(
      thread_label_,                                // Dart thread labels
      platform_task_runner,                         // platform
      thread_host_.raster_thread->GetTaskRunner(),  // raster
      thread_host_.ui_thread->GetTaskRunner(),      // ui
      thread_host_.io_thread->GetTaskRunner()       // io
  );

  // Connect to Scenic.
  auto scenic = runner_services->Connect<fuchsia::ui::scenic::Scenic>();
  fuchsia::ui::scenic::SessionEndpoints gfx_protocols;
  fuchsia::ui::scenic::SessionHandle session;
  gfx_protocols.set_session(session.NewRequest());
  fuchsia::ui::scenic::SessionListenerHandle session_listener;
  auto session_listener_request = session_listener.NewRequest();
  gfx_protocols.set_session_listener(session_listener.Bind());
  fuchsia::ui::views::FocuserHandle focuser;
  fuchsia::ui::views::ViewRefFocusedHandle view_ref_focused;
  fuchsia::ui::pointer::TouchSourceHandle touch_source;
  fuchsia::ui::pointer::MouseSourceHandle mouse_source;

  fuchsia::ui::composition::ViewBoundProtocols flatland_view_protocols;
  if (use_flatland) {
    flatland_view_protocols.set_view_focuser(focuser.NewRequest());
    flatland_view_protocols.set_view_ref_focused(view_ref_focused.NewRequest());
    flatland_view_protocols.set_touch_source(touch_source.NewRequest());
    flatland_view_protocols.set_mouse_source(mouse_source.NewRequest());
  } else {
    gfx_protocols.set_view_focuser(focuser.NewRequest());
    gfx_protocols.set_view_ref_focused(view_ref_focused.NewRequest());
    // TODO(fxbug.dev/85125): Enable TouchSource for GFX.
    // gfx_protocols.set_touch_source(touch_source.NewRequest());
  }
  scenic->CreateSessionT(std::move(gfx_protocols), [] {});

  // Connect to Flatland.
  fuchsia::ui::composition::FlatlandHandle flatland;
  zx_status_t flatland_status =
      runner_services->Connect<fuchsia::ui::composition::Flatland>(
          flatland.NewRequest());
  if (flatland_status != ZX_OK && use_flatland) {
    FML_LOG(WARNING) << "fuchsia::ui::composition::Flatland connection failed: "
                     << zx_status_get_string(flatland_status);
  }

  // Connect to SemanticsManager service.
  fuchsia::accessibility::semantics::SemanticsManagerHandle semantics_manager;
  zx_status_t semantics_status =
      runner_services
          ->Connect<fuchsia::accessibility::semantics::SemanticsManager>(
              semantics_manager.NewRequest());
  if (semantics_status != ZX_OK) {
    FML_LOG(WARNING)
        << "fuchsia::accessibility::semantics::SemanticsManager connection "
           "failed: "
        << zx_status_get_string(semantics_status);
  }

  // Connect to ImeService service.
  fuchsia::ui::input::ImeServiceHandle ime_service;
  zx_status_t ime_status =
      runner_services->Connect<fuchsia::ui::input::ImeService>(
          ime_service.NewRequest());
  if (ime_status != ZX_OK) {
    FML_LOG(WARNING) << "fuchsia::ui::input::ImeService connection failed: "
                     << zx_status_get_string(ime_status);
  }

  // Connect to Keyboard service.
  fuchsia::ui::input3::KeyboardHandle keyboard;
  zx_status_t keyboard_status =
      runner_services->Connect<fuchsia::ui::input3::Keyboard>(
          keyboard.NewRequest());
  FML_DCHECK(keyboard_status == ZX_OK)
      << "fuchsia::ui::input3::Keyboard connection failed: "
      << zx_status_get_string(keyboard_status);

  // Make clones of the `ViewRef` before sending it to various places.
  fuchsia::ui::views::ViewRef platform_view_ref;
  view_ref_pair.view_ref.Clone(&platform_view_ref);
  fuchsia::ui::views::ViewRef accessibility_view_ref;
  view_ref_pair.view_ref.Clone(&accessibility_view_ref);
  fuchsia::ui::views::ViewRef isolate_view_ref;
  view_ref_pair.view_ref.Clone(&isolate_view_ref);

  // Session is terminated on the raster thread, but we must terminate ourselves
  // on the platform thread.
  //
  // This handles the fidl error callback when the Session connection is
  // broken. The SessionListener interface also has an OnError method, which is
  // invoked on the platform thread (in PlatformView).
  fml::closure session_error_callback = [task_runner = platform_task_runner,
                                         weak = weak_factory_.GetWeakPtr()]() {
    task_runner->PostTask([weak]() {
      if (weak) {
        FML_LOG(ERROR) << "Terminating from session_error_callback";
        weak->Terminate();
      }
    });
  };

  // Set up the session connection and other Scenic helpers on the raster
  // thread. We also need to wait for the external view embedder to be set up
  // before creating the shell.
  fuchsia::ui::composition::ParentViewportWatcherPtr parent_viewport_watcher;
  fml::AutoResetWaitableEvent view_embedder_latch;
  auto session_inspect_node =
      dart_utils::RootInspectNode::CreateRootChild("vsync_stats");
  task_runners.GetRasterTaskRunner()->PostTask(fml::MakeCopyable(
      [this, &view_embedder_latch,
       session_inspect_node = std::move(session_inspect_node),
       session = std::move(session), flatland = std::move(flatland),
       session_error_callback = std::move(session_error_callback), use_flatland,
       view_token = std::move(view_token_),
       view_creation_token = std::move(view_creation_token_),
       flatland_view_protocols = std::move(flatland_view_protocols),
       request = parent_viewport_watcher.NewRequest(),
       view_ref_pair = std::move(view_ref_pair),
       max_frames_in_flight = product_config.get_max_frames_in_flight(),
       vsync_offset = product_config.get_vsync_offset(),
       software_rendering = product_config.software_rendering()]() mutable {
        if (use_flatland) {
          if (software_rendering) {
            surface_producer_ = std::make_shared<SoftwareSurfaceProducer>(
                /*scenic_session=*/nullptr);
          } else {
            surface_producer_ = std::make_shared<VulkanSurfaceProducer>(
                /*scenic_session=*/nullptr);
          }

          flatland_connection_ = std::make_shared<FlatlandConnection>(
              thread_label_, std::move(flatland),
              std::move(session_error_callback), [](auto) {},
              max_frames_in_flight, vsync_offset);

          fuchsia::ui::views::ViewIdentityOnCreation view_identity = {
              .view_ref = std::move(view_ref_pair.view_ref),
              .view_ref_control = std::move(view_ref_pair.control_ref)};
          flatland_view_embedder_ =
              std::make_shared<FlatlandExternalViewEmbedder>(
                  std::move(view_creation_token), std::move(view_identity),
                  std::move(flatland_view_protocols), std::move(request),
                  flatland_connection_, surface_producer_,
                  intercept_all_input_);
        } else {
          session_connection_ = std::make_shared<GfxSessionConnection>(
              thread_label_, std::move(session_inspect_node),
              std::move(session), std::move(session_error_callback),
              [](auto) {}, max_frames_in_flight, vsync_offset);

          if (software_rendering) {
            surface_producer_ = std::make_shared<SoftwareSurfaceProducer>(
                session_connection_->get());
          } else {
            surface_producer_ = std::make_shared<VulkanSurfaceProducer>(
                session_connection_->get());
          }

          external_view_embedder_ = std::make_shared<GfxExternalViewEmbedder>(
              thread_label_, std::move(view_token), std::move(view_ref_pair),
              session_connection_, surface_producer_, intercept_all_input_);
        }
        view_embedder_latch.Signal();
      }));
  view_embedder_latch.Wait();

  AccessibilityBridge::SetSemanticsEnabledCallback
      set_semantics_enabled_callback = [this](bool enabled) {
        auto platform_view = shell_->GetPlatformView();

        if (platform_view) {
          platform_view->SetSemanticsEnabled(enabled);
        }
      };

  AccessibilityBridge::DispatchSemanticsActionCallback
      dispatch_semantics_action_callback =
          [this](int32_t node_id, flutter::SemanticsAction action) {
            auto platform_view = shell_->GetPlatformView();

            if (platform_view) {
              platform_view->DispatchSemanticsAction(node_id, action, {});
            }
          };

  const std::string accessibility_inspect_name =
      std::to_string(GetKoid(accessibility_view_ref));
  accessibility_bridge_ = std::make_unique<AccessibilityBridge>(
      std::move(set_semantics_enabled_callback),
      std::move(dispatch_semantics_action_callback),
      std::move(semantics_manager), std::move(accessibility_view_ref),
      dart_utils::RootInspectNode::CreateRootChild(
          std::move(accessibility_inspect_name)));

  OnEnableWireframe on_enable_wireframe_callback = std::bind(
      &Engine::DebugWireframeSettingsChanged, this, std::placeholders::_1);

  OnCreateGfxView on_create_gfx_view_callback =
      std::bind(&Engine::CreateGfxView, this, std::placeholders::_1,
                std::placeholders::_2, std::placeholders::_3,
                std::placeholders::_4, std::placeholders::_5);

  OnCreateFlatlandView on_create_flatland_view_callback =
      std::bind(&Engine::CreateFlatlandView, this, std::placeholders::_1,
                std::placeholders::_2, std::placeholders::_3,
                std::placeholders::_4, std::placeholders::_5);

  OnUpdateView on_update_view_callback = std::bind(
      &Engine::UpdateView, this, std::placeholders::_1, std::placeholders::_2,
      std::placeholders::_3, std::placeholders::_4, use_flatland);

  OnDestroyGfxView on_destroy_gfx_view_callback =
      std::bind(&Engine::DestroyGfxView, this, std::placeholders::_1,
                std::placeholders::_2);

  OnDestroyFlatlandView on_destroy_flatland_view_callback =
      std::bind(&Engine::DestroyFlatlandView, this, std::placeholders::_1,
                std::placeholders::_2);

  OnCreateSurface on_create_surface_callback =
      std::bind(&Engine::CreateSurface, this);

  // SessionListener has a OnScenicError method; invoke this callback on the
  // platform thread when that happens. The Session itself should also be
  // disconnected when this happens, and it will also attempt to terminate.
  fit::closure on_session_listener_error_callback =
      [task_runner = platform_task_runner,
       weak = weak_factory_.GetWeakPtr()]() {
        task_runner->PostTask([weak]() {
          if (weak) {
            FML_LOG(ERROR) << "Terminating from "
                              "on_session_listener_error_callback";
            weak->Terminate();
          }
        });
      };

  // Launch the engine in the appropriate configuration.
  // Note: this initializes the Asset Manager on the global PersistantCache
  // so it must be called before WarmupSkps() is called below.
  auto run_configuration = flutter::RunConfiguration::InferFromSettings(
      settings, task_runners.GetIOTaskRunner());
  run_configuration.SetEntrypointArgs(std::move(dart_entrypoint_args));

  OnSemanticsNodeUpdate on_semantics_node_update_callback =
      [this](flutter::SemanticsNodeUpdates updates, float pixel_ratio) {
        accessibility_bridge_->AddSemanticsNodeUpdate(updates, pixel_ratio);
      };

  OnRequestAnnounce on_request_announce_callback =
      [this](const std::string& message) {
        accessibility_bridge_->RequestAnnounce(message);
      };

  // Setup the callback that will instantiate the platform view.
  flutter::Shell::CreateCallback<flutter::PlatformView>
      on_create_platform_view = fml::MakeCopyable(
          [this, use_flatland, view_ref = std::move(platform_view_ref),
           session_listener_request = std::move(session_listener_request),
           parent_viewport_watcher = std::move(parent_viewport_watcher),
           ime_service = std::move(ime_service), keyboard = std::move(keyboard),
           focuser = std::move(focuser),
           view_ref_focused = std::move(view_ref_focused),
           touch_source = std::move(touch_source),
           mouse_source = std::move(mouse_source),
           on_session_listener_error_callback =
               std::move(on_session_listener_error_callback),
           on_enable_wireframe_callback =
               std::move(on_enable_wireframe_callback),
           on_create_gfx_view_callback = std::move(on_create_gfx_view_callback),
           on_create_flatland_view_callback =
               std::move(on_create_flatland_view_callback),
           on_update_view_callback = std::move(on_update_view_callback),
           on_destroy_gfx_view_callback =
               std::move(on_destroy_gfx_view_callback),
           on_destroy_flatland_view_callback =
               std::move(on_destroy_flatland_view_callback),
           on_create_surface_callback = std::move(on_create_surface_callback),
           on_semantics_node_update_callback =
               std::move(on_semantics_node_update_callback),
           on_request_announce_callback =
               std::move(on_request_announce_callback),
           external_view_embedder = GetExternalViewEmbedder(),
           await_vsync_callback =
               [this, use_flatland](FireCallbackCallback cb) {
                 if (use_flatland) {
                   flatland_connection_->AwaitVsync(cb);
                 } else {
                   session_connection_->AwaitVsync(cb);
                 }
               },
           await_vsync_for_secondary_callback_callback =
               [this, use_flatland](FireCallbackCallback cb) {
                 if (use_flatland) {
                   flatland_connection_->AwaitVsyncForSecondaryCallback(cb);
                 } else {
                   session_connection_->AwaitVsyncForSecondaryCallback(cb);
                 }
               },
           product_config](flutter::Shell& shell) mutable {
            OnShaderWarmup on_shader_warmup = nullptr;
            if (product_config.enable_shader_warmup()) {
              FML_DCHECK(surface_producer_);
              if (product_config.enable_shader_warmup_dart_hooks()) {
                on_shader_warmup =
                    [this, &shell](
                        const std::vector<std::string>& skp_names,
                        std::function<void(uint32_t)> completion_callback,
                        uint64_t width, uint64_t height) {
                      WarmupSkps(
                          shell.GetDartVM()
                              ->GetConcurrentMessageLoop()
                              ->GetTaskRunner()
                              .get(),
                          shell.GetTaskRunners().GetRasterTaskRunner().get(),
                          surface_producer_, SkISize::Make(width, height),
                          flutter::PersistentCache::GetCacheForProcess()
                              ->asset_manager(),
                          skp_names, completion_callback);
                    };
              } else {
                WarmupSkps(shell.GetDartVM()
                               ->GetConcurrentMessageLoop()
                               ->GetTaskRunner()
                               .get(),
                           shell.GetTaskRunners().GetRasterTaskRunner().get(),
                           surface_producer_, SkISize::Make(1024, 600),
                           flutter::PersistentCache::GetCacheForProcess()
                               ->asset_manager(),
                           std::nullopt, std::nullopt);
              }
            }

            std::unique_ptr<flutter::PlatformView> platform_view;
            if (use_flatland) {
              platform_view =
                  std::make_unique<flutter_runner::FlatlandPlatformView>(
                      shell, shell.GetTaskRunners(), std::move(view_ref),
                      std::move(external_view_embedder), std::move(ime_service),
                      std::move(keyboard), std::move(touch_source),
                      std::move(mouse_source), std::move(focuser),
                      std::move(view_ref_focused),
                      std::move(parent_viewport_watcher),
                      std::move(on_enable_wireframe_callback),
                      std::move(on_create_flatland_view_callback),
                      std::move(on_update_view_callback),
                      std::move(on_destroy_flatland_view_callback),
                      std::move(on_create_surface_callback),
                      std::move(on_semantics_node_update_callback),
                      std::move(on_request_announce_callback),
                      std::move(on_shader_warmup),
                      std::move(await_vsync_callback),
                      std::move(await_vsync_for_secondary_callback_callback));
            } else {
              platform_view = std::make_unique<flutter_runner::GfxPlatformView>(
                  shell, shell.GetTaskRunners(), std::move(view_ref),
                  std::move(external_view_embedder), std::move(ime_service),
                  std::move(keyboard), std::move(touch_source),
                  std::move(mouse_source), std::move(focuser),
                  std::move(view_ref_focused),
                  std::move(session_listener_request),
                  std::move(on_session_listener_error_callback),
                  std::move(on_enable_wireframe_callback),
                  std::move(on_create_gfx_view_callback),
                  std::move(on_update_view_callback),
                  std::move(on_destroy_gfx_view_callback),
                  std::move(on_create_surface_callback),
                  std::move(on_semantics_node_update_callback),
                  std::move(on_request_announce_callback),
                  std::move(on_shader_warmup), std::move(await_vsync_callback),
                  std::move(await_vsync_for_secondary_callback_callback));
            }
            return platform_view;
          });

  // Setup the callback that will instantiate the rasterizer.
  flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
      [](flutter::Shell& shell) {
        return std::make_unique<flutter::Rasterizer>(shell);
      };

  settings.root_isolate_create_callback =
      std::bind(&Engine::OnMainIsolateStart, this);
  settings.root_isolate_shutdown_callback =
      std::bind([weak = weak_factory_.GetWeakPtr(),
                 runner = task_runners.GetPlatformTaskRunner()]() {
        runner->PostTask([weak = std::move(weak)] {
          if (weak) {
            weak->OnMainIsolateShutdown();
          }
        });
      });

  // Connect and set up the system font provider.
  fuchsia::fonts::ProviderSyncPtr sync_font_provider;
  runner_services->Connect(sync_font_provider.NewRequest());
  settings.font_initialization_data =
      sync_font_provider.Unbind().TakeChannel().release();

  {
    TRACE_EVENT0("flutter", "CreateShell");
    shell_ = flutter::Shell::Create(
        flutter::PlatformData(),             // default window data
        std::move(task_runners),             // host task runners
        std::move(settings),                 // shell launch settings
        std::move(on_create_platform_view),  // platform view create callback
        std::move(on_create_rasterizer)      // rasterizer create callback
    );
  }

  if (!shell_) {
    FML_LOG(ERROR) << "Could not launch the shell.";
    return;
  }

  // Shell has been created. Before we run the engine, set up the isolate
  // configurator.
  {
    fuchsia::sys::EnvironmentPtr environment;
    if (for_v1_component) {
      svc->Connect(environment.NewRequest());
    }

    isolate_configurator_ = std::make_unique<IsolateConfigurator>(
        std::move(fdio_ns),
        // v2 components do not use fuchsia.sys.Environment.
        for_v1_component ? std::move(environment) : nullptr,
        directory_request.TakeChannel(), std::move(isolate_view_ref.reference));
  }

  //  This platform does not get a separate surface platform view creation
  //  notification. Fire one eagerly.
  shell_->GetPlatformView()->NotifyCreated();

  // Connect to the memory pressure provider.  If the connection fails, the
  // initialization of the engine will simply proceed, printing a warning
  // message.  The engine will be fully functional, except that the Flutter
  // shell will not be notified when memory is low.
  {
    memory_pressure_provider_.set_error_handler([](zx_status_t status) {
      FML_LOG(WARNING)
          << "Failed to connect to " << fuchsia::memorypressure::Provider::Name_
          << ": " << zx_status_get_string(status)
          << " This is not a fatal error, but the heap will not be "
          << " compacted when memory is low.";
    });

    // Note that we're using the runner's services, not the component's.
    // The Flutter Shell should be notified when memory is low regardless of
    // whether the component has direct access to the
    // fuchsia.memorypressure.Provider service.
    ZX_ASSERT(runner_services->Connect(
                  memory_pressure_provider_.NewRequest()) == ZX_OK);

    FML_VLOG(-1) << "Registering memorypressure watcher";

    // Register for changes, which will make the request for the initial
    // memory level.
    memory_pressure_provider_->RegisterWatcher(
        memory_pressure_watcher_binding_.NewBinding());
  }

  // Connect to the intl property provider.  If the connection fails, the
  // initialization of the engine will simply proceed, printing a warning
  // message.  The engine will be fully functional, except that the user's
  // locale preferences would not be communicated to flutter engine.
  {
    intl_property_provider_.set_error_handler([](zx_status_t status) {
      FML_LOG(WARNING) << "Failed to connect to "
                       << fuchsia::intl::PropertyProvider::Name_ << ": "
                       << zx_status_get_string(status)
                       << " This is not a fatal error, but the user locale "
                       << " preferences will not be forwarded to flutter apps";
    });

    // Note that we're using the runner's services, not the component's.
    // Flutter locales should be updated regardless of whether the component has
    // direct access to the fuchsia.intl.PropertyProvider service.
    ZX_ASSERT(runner_services->Connect(intl_property_provider_.NewRequest()) ==
              ZX_OK);

    auto get_profile_callback = [weak = weak_factory_.GetWeakPtr()](
                                    const fuchsia::intl::Profile& profile) {
      if (!weak) {
        return;
      }
      if (!profile.has_locales()) {
        FML_LOG(WARNING) << "Got intl Profile without locales";
      }
      auto message = MakeLocalizationPlatformMessage(profile);
      FML_VLOG(-1) << "Sending LocalizationPlatformMessage";
      weak->shell_->GetPlatformView()->DispatchPlatformMessage(
          std::move(message));
    };

    FML_VLOG(-1) << "Requesting intl Profile";

    // Make the initial request
    intl_property_provider_->GetProfile(get_profile_callback);

    // And register for changes
    intl_property_provider_.events().OnChange = [this, runner_services,
                                                 get_profile_callback]() {
      FML_VLOG(-1) << fuchsia::intl::PropertyProvider::Name_ << ": OnChange";
      runner_services->Connect(intl_property_provider_.NewRequest());
      intl_property_provider_->GetProfile(get_profile_callback);
    };
  }

  auto on_run_failure = [weak = weak_factory_.GetWeakPtr()]() {
    // The engine could have been killed by the caller right after the
    // constructor was called but before it could run on the UI thread.
    if (weak) {
      FML_LOG(ERROR) << "Terminating from on_run_failure";
      weak->Terminate();
    }
  };

  shell_->GetTaskRunners().GetUITaskRunner()->PostTask(
      fml::MakeCopyable([engine = shell_->GetEngine(),                      //
                         run_configuration = std::move(run_configuration),  //
                         on_run_failure                                     //
  ]() mutable {
        if (!engine) {
          return;
        }

        if (engine->Run(std::move(run_configuration)) ==
            flutter::Engine::RunStatus::Failure) {
          on_run_failure();
        }
      }));
}