chromium/fuchsia_web/runners/cast/cast_runner.h

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FUCHSIA_WEB_RUNNERS_CAST_CAST_RUNNER_H_
#define FUCHSIA_WEB_RUNNERS_CAST_CAST_RUNNER_H_

#include <chromium/cast/cpp/fidl.h>
#include <fuchsia/component/runner/cpp/fidl.h>
#include <fuchsia/web/cpp/fidl.h>

#include <memory>
#include <optional>
#include <set>
#include <vector>

#include "base/containers/flat_set.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/fuchsia/startup_context.h"
#include "base/functional/callback.h"
#include "fuchsia_web/runners/cast/cast_component.h"
#include "fuchsia_web/runners/cast/pending_cast_component.h"
#include "fuchsia_web/runners/common/web_content_runner.h"

class WebInstanceHost;

// ComponentRunner that runs Cast activities specified via cast/casts URIs.
class CastRunner final : public fuchsia::component::runner::ComponentRunner,
                         public chromium::cast::DataReset,
                         public PendingCastComponent::Delegate {
 public:
  struct Options {
    // Set to true to run components without generating output via Scenic.
    bool headless = false;

    // Set to true to run components without without web optimizations (e.g.
    // JavaScript Just-In-Time compilation) or features (e.g. WebAssembly) that
    // require dynamic code generation.
    bool disable_codegen = false;
  };

  static constexpr uint16_t kRemoteDebuggingPort = 9222;

  // Creates the Runner for Cast components.
  // `web_instance_host` is used to create a "main" instance to host Cast apps
  // and serve `FrameHost` instances, and isolated containers for apps that
  // need them.
  CastRunner(WebInstanceHost& web_instance_host, Options options);
  ~CastRunner() override;

  CastRunner(const CastRunner&) = delete;
  CastRunner& operator=(const CastRunner&) = delete;

  // fuchsia::component::runner::ComponentRunner implementation.
  void Start(
      fuchsia::component::runner::ComponentStartInfo start_info,
      fidl::InterfaceRequest<fuchsia::component::runner::ComponentController>
          controller) override;

  // chromium::cast::DataReset implementation.
  void DeletePersistentData(DeletePersistentDataCallback callback) override;

  // Returns a connection request handler for the fuchsia.web.FrameHost
  // protocol exposed by the main web_instance.
  fidl::InterfaceRequestHandler<fuchsia::web::FrameHost>
  GetFrameHostRequestHandler();

  // Disables use of the VULKAN feature when creating Contexts. Must be set
  // before calling StartComponent().
  void set_disable_vulkan_for_test() { disable_vulkan_for_test_ = true; }

 private:
  // PendingCastComponent::Delegate implementation.
  void LaunchPendingComponent(PendingCastComponent* pending_component,
                              CastComponent::Params params) override;
  void CancelPendingComponent(PendingCastComponent* pending_component) override;

  // Handlers used to provide parameters for main & isolated Contexts.
  WebContentRunner::WebInstanceConfig GetCommonWebInstanceConfig();
  WebContentRunner::WebInstanceConfig GetMainWebInstanceConfig();
  WebContentRunner::WebInstanceConfig
  GetIsolatedWebInstanceConfigWithFuchsiaDirs(
      std::vector<fuchsia::web::ContentDirectoryProvider> content_directories);
  // TODO(crbug.com/40131115): Remove this once the CastStreamingReceiver
  // Component has been implemented.
  WebContentRunner::WebInstanceConfig
  GetIsolatedWebInstanceConfigForCastStreaming();

  // Returns CreateContextParams for |app_config|. Returns nullopt if there is
  // no need to create an isolated context.
  std::optional<WebContentRunner::WebInstanceConfig>
  GetWebInstanceConfigForAppConfig(
      chromium::cast::ApplicationConfig* app_config);

  // Launches an isolated Context with the given `config` and returns the newly
  // created WebContentRunner.
  WebContentRunner* CreateIsolatedRunner(
      WebContentRunner::WebInstanceConfig config);

  // Called when an isolated component terminates, to allow the Context hosting
  // it to be torn down.
  void OnIsolatedContextEmpty(WebContentRunner* context);

  // Internal implementation of StartComponent(), called after validating the
  // component URL and ensuring that CORS-exempt headers have been fetched.
  void StartComponentInternal(
      const GURL& url,
      std::unique_ptr<base::StartupContext> startup_context,
      fidl::InterfaceRequest<fuchsia::component::runner::ComponentController>
          controller_request);

  // Moves all data persisted by the main Context to a staging directory,
  // which will be deleted the next time the Runner starts up, and configures
  // the Runner to reject new component-launch requests until it is shutdown.
  // Returns false if tha data directory cannot be cleaned-up.
  bool DeletePersistentDataInternal();

  // TODO(crbug.com/40755074): Used to detect when the persisted cache directory
  // was erased. The sentinel file is created at the top-level of the cache
  // directory, so cannot be deleted by the Context, only by the cache being
  // erased.
  void CreatePersistedCacheSentinel();
  bool WasPersistedCacheErased();

  // Passed to WebContentRunners to use to create web_instance Components.
  const raw_ref<WebInstanceHost> web_instance_host_;

  // True if this Runner uses Context(s) with the HEADLESS feature set.
  const bool is_headless_;

  // True if this Runner should create web Contexts with dynamic code generation
  // disabled.
  const bool disable_codegen_;

  // Holds the main fuchsia.web.Context used to host CastComponents.
  // Note that although |main_context_| is actually a WebContentRunner, that is
  // only being used to maintain the Context for the hosted components.
  const std::unique_ptr<WebContentRunner> main_context_;

  // Holds `fuchsia.web.Context`s used to host isolated components.
  base::flat_set<std::unique_ptr<WebContentRunner>, base::UniquePtrComparator>
      isolated_contexts_;

  // Temporarily holds a PendingCastComponent instance, responsible for fetching
  // the parameters required to launch the component, for each call to
  // StartComponent().
  base::flat_set<std::unique_ptr<PendingCastComponent>,
                 base::UniquePtrComparator>
      pending_components_;

  // Used to fetch & cache the list of CORS exempt HTTP headers to configure
  // each web.Context with.
  std::optional<std::vector<std::vector<uint8_t>>> cors_exempt_headers_;
  chromium::cast::CorsExemptHeaderProviderPtr cors_exempt_headers_provider_;
  std::vector<base::OnceClosure> on_have_cors_exempt_headers_;

  // True if Contexts should be created without VULKAN set.
  bool disable_vulkan_for_test_ = false;

  // True if cast runner entered data reset mode. Prevents new components
  // in the main context from being launched. This is set to true once data
  // reset starts and does not switch back to false upon completion.
  bool data_reset_in_progress_ = false;

  // True if the cache sentinel file should exist.
  // TODO(crbug.com/40755074): Remove once an explicit cache flush signal
  // exists.
  bool was_cache_sentinel_created_ = false;
};

#endif  // FUCHSIA_WEB_RUNNERS_CAST_CAST_RUNNER_H_