Commit e15433f3 authored by Wez's avatar Wez Committed by Commit Bot

[fuchsia] Simplify implementation of the CastRunner.

The implementation of the fuchsia.sys.Runner for Cast apps is refactored
to be easier to maintain, in the following ways:

1. Instead of deriving from WebContentRunner and overriding certain
   behaviours, the CastRunner now instantiates WebContentRunner instances
   internally, to use to manage CastComponents.

2. CastRunner now implements fuchsia.sys.Runner itself, and manages the
   PendingCastComponents, prior to creating & handing off CastComponents
   to be managed by the WebContentRunner(s).

3. The CreateContextParams for the main and isolated contexts are
   constructed using a common base, rather than copying & filtering the
   main context parameters, to create parameters for isolated contexts.

Bug: 1071544
Change-Id: Ic66ca0a9805e9b00d213c62845e5101ff9dea76e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2153055
Commit-Queue: Wez <wez@chromium.org>
Reviewed-by: default avatarDavid Dorwin <ddorwin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#761177}
parent 07596fa6
......@@ -46,10 +46,13 @@ bool CastComponent::Params::AreComplete() const {
return true;
}
CastComponent::CastComponent(CastRunner* runner, CastComponent::Params params)
CastComponent::CastComponent(WebContentRunner* runner,
CastComponent::Params params,
bool is_headless)
: WebComponent(runner,
std::move(params.startup_context),
std::move(params.controller_request)),
is_headless_(is_headless),
agent_manager_(std::move(params.agent_manager)),
application_config_(std::move(params.application_config)),
url_rewrite_rules_provider_(std::move(params.url_rewrite_rules_provider)),
......@@ -64,6 +67,10 @@ CastComponent::CastComponent(CastRunner* runner, CastComponent::Params params)
CastComponent::~CastComponent() = default;
void CastComponent::SetOnDestroyedCallback(base::OnceClosure on_destroyed) {
on_destroyed_ = std::move(on_destroyed);
}
void CastComponent::StartComponent() {
if (application_config_.has_enable_remote_debugging() &&
application_config_.enable_remote_debugging()) {
......@@ -116,14 +123,12 @@ void CastComponent::StartComponent() {
}
}
CastRunner* CastComponent::runner() const {
return static_cast<CastRunner*>(WebComponent::runner());
}
void CastComponent::DestroyComponent(int termination_exit_code,
fuchsia::sys::TerminationReason reason) {
DCHECK(!constructor_active_);
std::move(on_destroyed_).Run();
WebComponent::DestroyComponent(termination_exit_code, reason);
}
......@@ -147,7 +152,7 @@ void CastComponent::CreateView(
zx::eventpair view_token,
fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> incoming_services,
fidl::InterfaceHandle<fuchsia::sys::ServiceProvider> outgoing_services) {
if (runner()->is_headless()) {
if (is_headless_) {
// For headless CastComponents, |view_token| does not actually connect to a
// Scenic View. It is merely used as a conduit for propagating termination
// signals.
......@@ -167,7 +172,7 @@ void CastComponent::CreateView(
void CastComponent::OnZxHandleSignalled(zx_handle_t handle,
zx_signals_t signals) {
DCHECK_EQ(signals, ZX_SOCKET_PEER_CLOSED);
DCHECK(runner()->is_headless());
DCHECK(is_headless_);
frame()->DisableHeadlessRendering();
}
......@@ -23,8 +23,6 @@ namespace cr_fuchsia {
class AgentManager;
}
class CastRunner;
FORWARD_DECLARE_TEST(HeadlessCastRunnerIntegrationTest, Headless);
// A specialization of WebComponent which adds Cast-specific services.
......@@ -62,11 +60,15 @@ class CastComponent : public WebComponent,
base::Optional<uint64_t> media_session_id;
};
CastComponent(CastRunner* runner, Params params);
CastComponent(WebContentRunner* runner, Params params, bool is_headless);
~CastComponent() final;
void SetOnDestroyedCallback(base::OnceClosure on_destroyed);
// WebComponent overrides.
void StartComponent() final;
void DestroyComponent(int termination_exit_code,
fuchsia::sys::TerminationReason reason) final;
const chromium::cast::ApplicationConfig& application_config() {
return application_config_;
......@@ -74,16 +76,10 @@ class CastComponent : public WebComponent,
cr_fuchsia::AgentManager* agent_manager() { return agent_manager_.get(); }
CastRunner* runner() const;
private:
void OnRewriteRulesReceived(
std::vector<fuchsia::web::UrlRequestRewriteRule> url_rewrite_rules);
// WebComponent overrides.
void DestroyComponent(int termination_exit_code,
fuchsia::sys::TerminationReason reason) final;
// fuchsia::web::NavigationEventListener implementation.
// Triggers the injection of API channels into the page content.
void OnNavigationStateChanged(
......@@ -101,6 +97,9 @@ class CastComponent : public WebComponent,
// Called when the headless "view" token is disconnected.
void OnZxHandleSignalled(zx_handle_t handle, zx_signals_t signals) final;
const bool is_headless_;
base::OnceClosure on_destroyed_;
std::unique_ptr<cr_fuchsia::AgentManager> agent_manager_;
chromium::cast::ApplicationConfig application_config_;
chromium::cast::UrlRequestRewriteRulesProviderPtr url_rewrite_rules_provider_;
......
......@@ -6,6 +6,7 @@
#include <fuchsia/sys/cpp/fidl.h>
#include <fuchsia/web/cpp/fidl.h>
#include <lib/fit/function.h>
#include <memory>
#include <string>
#include <utility>
......@@ -16,6 +17,8 @@
#include "base/fuchsia/fuchsia_logging.h"
#include "base/logging.h"
#include "fuchsia/base/agent_manager.h"
#include "fuchsia/runners/cast/pending_cast_component.h"
#include "fuchsia/runners/common/web_content_runner.h"
#include "url/gurl.h"
namespace {
......@@ -48,37 +51,6 @@ static constexpr const char* kServices[] = {
// * fuchsia.legacymetrics.MetricsRecorder
};
// Creates a CreateContextParams object which can be used as a basis
// for starting isolated Runners.
fuchsia::web::CreateContextParams BuildCreateContextParamsForIsolatedRunners(
const fuchsia::web::CreateContextParams& create_context_params) {
fuchsia::web::CreateContextParams output;
// Isolated contexts are only allowed a limited set of features.
// Only pass those features from |create_context_params|.
static constexpr fuchsia::web::ContextFeatureFlags kAllowedFeatures =
fuchsia::web::ContextFeatureFlags::AUDIO |
fuchsia::web::ContextFeatureFlags::LEGACYMETRICS |
fuchsia::web::ContextFeatureFlags::HEADLESS |
fuchsia::web::ContextFeatureFlags::VULKAN |
fuchsia::web::ContextFeatureFlags::HARDWARE_VIDEO_DECODER |
fuchsia::web::ContextFeatureFlags::HARDWARE_VIDEO_DECODER_ONLY;
DCHECK(create_context_params.has_features());
output.set_features(create_context_params.features() & kAllowedFeatures);
if (create_context_params.has_user_agent_product()) {
output.set_user_agent_product(create_context_params.user_agent_product());
}
if (create_context_params.has_user_agent_version()) {
output.set_user_agent_version(create_context_params.user_agent_version());
}
if (create_context_params.has_remote_debugging_port()) {
output.set_remote_debugging_port(
create_context_params.remote_debugging_port());
}
return output;
}
bool IsPermissionGrantedInAppConfig(
const chromium::cast::ApplicationConfig& application_config,
fuchsia::web::PermissionType permission_type) {
......@@ -93,14 +65,35 @@ bool IsPermissionGrantedInAppConfig(
} // namespace
CastRunner::CastRunner(
WebContentRunner::GetContextParamsCallback get_context_params_callback,
bool is_headless)
: WebContentRunner(base::BindRepeating(&CastRunner::GetMainContextParams,
base::Unretained(this))),
get_context_params_callback_(std::move(get_context_params_callback)),
is_headless_(is_headless),
service_directory_(CreateServiceDirectory()) {}
CastRunner::CastRunner(bool is_headless)
: is_headless_(is_headless),
main_services_(std::make_unique<base::fuchsia::FilteredServiceDirectory>(
base::fuchsia::ComponentContextForCurrentProcess()->svc().get())),
main_context_(std::make_unique<WebContentRunner>(
base::BindRepeating(&CastRunner::GetMainContextParams,
base::Unretained(this)))),
isolated_services_(
std::make_unique<base::fuchsia::FilteredServiceDirectory>(
base::fuchsia::ComponentContextForCurrentProcess()
->svc()
.get())) {
// Specify the services to connect via the Runner process' service directory.
for (const char* name : kServices) {
main_services_->AddService(name);
isolated_services_->AddService(name);
}
// Add handlers to main context's service directory for redirected services.
main_services_->outgoing_directory()->AddPublicService<fuchsia::media::Audio>(
fit::bind_member(this, &CastRunner::OnAudioServiceRequest));
main_services_->outgoing_directory()
->AddPublicService<fuchsia::legacymetrics::MetricsRecorder>(
fit::bind_member(this, &CastRunner::OnMetricsRecorderServiceRequest));
// Isolated contexts can use the normal Audio service, and don't record
// metrics.
isolated_services_->AddService(fuchsia::media::Audio::Name_);
}
CastRunner::~CastRunner() = default;
......@@ -128,65 +121,54 @@ void CastRunner::StartComponent(
std::move(controller_request), cast_url.GetContent()));
}
void CastRunner::DestroyComponent(WebComponent* component) {
WebContentRunner::DestroyComponent(component);
if (component == audio_capturer_component_)
audio_capturer_component_ = nullptr;
if (on_component_destroyed_callback_) {
// |this| may be deleted and should not be used after this line.
std::move(on_component_destroyed_callback_).Run(this);
}
void CastRunner::SetOnMainContextLostCallbackForTest(
base::OnceClosure on_context_lost) {
main_context_->SetOnContextLostCallbackForTest(std::move(on_context_lost));
}
std::unique_ptr<base::fuchsia::FilteredServiceDirectory>
CastRunner::CreateServiceDirectory() {
auto service_directory =
std::make_unique<base::fuchsia::FilteredServiceDirectory>(
base::fuchsia::ComponentContextForCurrentProcess()->svc().get());
for (auto* name : kServices) {
service_directory->AddService(name);
void CastRunner::LaunchPendingComponent(PendingCastComponent* pending_component,
CastComponent::Params params) {
WebContentRunner* component_owner = main_context_.get();
const bool is_isolated =
params.application_config
.has_content_directories_for_isolated_application();
if (is_isolated) {
// Create an isolated context which will own the CastComponent.
auto context =
std::make_unique<WebContentRunner>(GetIsolatedContextParams(std::move(
*params.application_config
.mutable_content_directories_for_isolated_application())));
context->SetOnEmptyCallback(base::BindOnce(
&CastRunner::OnIsolatedContextEmpty, base::Unretained(this),
base::Unretained(context.get())));
component_owner = context.get();
isolated_contexts_.insert(std::move(context));
}
// Handle fuchsia.media.Audio requests so we can redirect to the agent if
// necessary.
service_directory->outgoing_directory()->AddPublicService(
std::make_unique<vfs::Service>([this](zx::channel channel,
async_dispatcher_t* dispatcher) {
this->ConnectAudioProtocol(
fidl::InterfaceRequest<fuchsia::media::Audio>(std::move(channel)));
}),
fuchsia::media::Audio::Name_);
// Proxy fuchsia.legacymetrics.MetricsRecorder connection requests to the
// Agent.
service_directory->outgoing_directory()->AddPublicService(
std::make_unique<vfs::Service>(
[this](zx::channel channel, async_dispatcher_t*) {
this->ConnectMetricsRecorderProtocol(
fidl::InterfaceRequest<fuchsia::legacymetrics::MetricsRecorder>(
std::move(channel)));
}),
fuchsia::legacymetrics::MetricsRecorder::Name_);
return service_directory;
}
// Launch the URL specified in the component |params|.
GURL app_url = GURL(params.application_config.web_url());
auto cast_component = std::make_unique<CastComponent>(
component_owner, std::move(params), is_headless_);
cast_component->SetOnDestroyedCallback(
base::BindOnce(&CastRunner::OnComponentDestroyed, base::Unretained(this),
base::Unretained(cast_component.get())));
cast_component->StartComponent();
cast_component->LoadUrl(std::move(app_url),
std::vector<fuchsia::net::http::Header>());
void CastRunner::LaunchPendingComponent(PendingCastComponent* pending_component,
CastComponent::Params params) {
// The runner which will host the newly created CastComponent.
CastRunner* component_owner = this;
if (params.application_config
.has_content_directories_for_isolated_application()) {
// Create an isolated CastRunner instance which will own the
// CastComponent.
component_owner = CreateChildRunnerForIsolatedComponent(&params);
if (!is_isolated) {
// If this component has the microphone permission then use it to route
// Audio service requests through.
if (IsPermissionGrantedInAppConfig(
cast_component->application_config(),
fuchsia::web::PermissionType::MICROPHONE)) {
audio_capturer_component_ = cast_component.get();
}
}
component_owner->CreateAndRegisterCastComponent(std::move(params));
// Register the new component and clean up the |pending_component|.
component_owner->RegisterComponent(std::move(cast_component));
pending_components_.erase(pending_component);
}
......@@ -196,61 +178,72 @@ void CastRunner::CancelPendingComponent(
DCHECK_EQ(count, 1u);
}
void CastRunner::CreateAndRegisterCastComponent(
CastComponent::Params component_params) {
GURL app_url = GURL(component_params.application_config.web_url());
auto cast_component =
std::make_unique<CastComponent>(this, std::move(component_params));
cast_component->StartComponent();
cast_component->LoadUrl(std::move(app_url),
std::vector<fuchsia::net::http::Header>());
void CastRunner::OnComponentDestroyed(CastComponent* component) {
if (component == audio_capturer_component_)
audio_capturer_component_ = nullptr;
}
if (IsPermissionGrantedInAppConfig(
cast_component->application_config(),
fuchsia::web::PermissionType::MICROPHONE)) {
audio_capturer_component_ = cast_component.get();
fuchsia::web::CreateContextParams CastRunner::GetCommonContextParams() {
fuchsia::web::CreateContextParams params;
params.set_features(fuchsia::web::ContextFeatureFlags::AUDIO |
fuchsia::web::ContextFeatureFlags::WIDEVINE_CDM);
if (is_headless_) {
LOG(WARNING) << "Running in headless mode.";
*params.mutable_features() |= fuchsia::web::ContextFeatureFlags::HEADLESS;
} else {
*params.mutable_features() |=
fuchsia::web::ContextFeatureFlags::HARDWARE_VIDEO_DECODER |
fuchsia::web::ContextFeatureFlags::HARDWARE_VIDEO_DECODER_ONLY;
if (!disable_vulkan_for_test_)
*params.mutable_features() |= fuchsia::web::ContextFeatureFlags::VULKAN;
}
RegisterComponent(std::move(cast_component));
const char kCastPlayreadyKeySystem[] = "com.chromecast.playready";
params.set_playready_key_system(kCastPlayreadyKeySystem);
// TODO(b/141956135): Use CrKey version provided by the Agent.
params.set_user_agent_product("CrKey");
params.set_user_agent_version("1.43.000000");
params.set_remote_debugging_port(CastRunner::kRemoteDebuggingPort);
return params;
}
CastRunner* CastRunner::CreateChildRunnerForIsolatedComponent(
CastComponent::Params* component_params) {
// Construct the CreateContextParams in order to create a new Context. Some
// common parameters must be inherited from default params returned from
// |get_context_params_callback_|.
fuchsia::web::CreateContextParams isolated_context_params =
BuildCreateContextParamsForIsolatedRunners(
get_context_params_callback_.Run());
isolated_context_params.set_content_directories(
std::move(*component_params->application_config
.mutable_content_directories_for_isolated_application()));
auto create_context_params_callback = base::BindRepeating(
[](fuchsia::web::CreateContextParams isolated_context_params) {
return isolated_context_params;
},
base::Passed(std::move(isolated_context_params)));
auto cast_runner = std::make_unique<CastRunner>(
std::move(create_context_params_callback), is_headless());
cast_runner->on_component_destroyed_callback_ = base::BindOnce(
&CastRunner::OnIsolatedRunnerEmpty, base::Unretained(this));
CastRunner* cast_runner_ptr = cast_runner.get();
isolated_runners_.insert(std::move(cast_runner));
return cast_runner_ptr;
fuchsia::web::CreateContextParams CastRunner::GetMainContextParams() {
fuchsia::web::CreateContextParams params = GetCommonContextParams();
*params.mutable_features() |=
fuchsia::web::ContextFeatureFlags::NETWORK |
fuchsia::web::ContextFeatureFlags::LEGACYMETRICS;
main_services_->ConnectClient(
params.mutable_service_directory()->NewRequest());
// TODO(crbug.com/1023514): Remove this switch when it is no longer
// necessary.
params.set_unsafely_treat_insecure_origins_as_secure(
{"allow-running-insecure-content"});
return params;
}
void CastRunner::OnIsolatedRunnerEmpty(CastRunner* runner) {
auto runner_iterator = isolated_runners_.find(runner);
DCHECK(runner_iterator != isolated_runners_.end());
fuchsia::web::CreateContextParams CastRunner::GetIsolatedContextParams(
std::vector<fuchsia::web::ContentDirectoryProvider> content_directories) {
fuchsia::web::CreateContextParams params = GetCommonContextParams();
params.set_content_directories(std::move(content_directories));
isolated_services_->ConnectClient(
params.mutable_service_directory()->NewRequest());
return params;
}
isolated_runners_.erase(runner_iterator);
void CastRunner::OnIsolatedContextEmpty(WebContentRunner* context) {
auto it = isolated_contexts_.find(context);
DCHECK(it != isolated_contexts_.end());
isolated_contexts_.erase(it);
}
void CastRunner::ConnectAudioProtocol(
void CastRunner::OnAudioServiceRequest(
fidl::InterfaceRequest<fuchsia::media::Audio> request) {
// If we have a component that allows AudioCapturer access then redirect the
// fuchsia.media.Audio requests to the corresponding agent.
......@@ -261,28 +254,19 @@ void CastRunner::ConnectAudioProtocol(
return;
}
// Otherwise use the default fuchsia.media.Audio implementation.
// Otherwise use the Runner's fuchsia.media.Audio service.
base::fuchsia::ComponentContextForCurrentProcess()->svc()->Connect(
std::move(request));
}
void CastRunner::ConnectMetricsRecorderProtocol(
void CastRunner::OnMetricsRecorderServiceRequest(
fidl::InterfaceRequest<fuchsia::legacymetrics::MetricsRecorder> request) {
// TODO(https://crbug.com/1065707): Remove this hack once Runners are using
// Component Framework v2.
CastComponent* component =
reinterpret_cast<CastComponent*>(GetAnyComponent());
reinterpret_cast<CastComponent*>(main_context_->GetAnyComponent());
DCHECK(component);
component->agent_manager()->ConnectToAgentService(
component->application_config().agent_url(), std::move(request));
}
fuchsia::web::CreateContextParams CastRunner::GetMainContextParams() {
fuchsia::web::CreateContextParams create_context_params =
get_context_params_callback_.Run();
// Override with the custom service directory.
service_directory_->ConnectClient(
create_context_params.mutable_service_directory()->NewRequest());
return create_context_params;
}
......@@ -5,6 +5,7 @@
#ifndef FUCHSIA_RUNNERS_CAST_CAST_RUNNER_H_
#define FUCHSIA_RUNNERS_CAST_CAST_RUNNER_H_
#include <chromium/cast/cpp/fidl.h>
#include <fuchsia/legacymetrics/cpp/fidl.h>
#include <fuchsia/sys/cpp/fidl.h>
#include <fuchsia/web/cpp/fidl.h>
......@@ -13,14 +14,12 @@
#include <vector>
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/fuchsia/startup_context.h"
#include "base/macros.h"
#include "fuchsia/fidl/chromium/cast/cpp/fidl.h"
#include "fuchsia/runners/cast/cast_component.h"
#include "fuchsia/runners/cast/pending_cast_component.h"
#include "fuchsia/runners/common/web_content_runner.h"
namespace base {
namespace fuchsia {
......@@ -28,76 +27,80 @@ class FilteredServiceDirectory;
} // namespace fuchsia
} // namespace base
class WebContentRunner;
// sys::Runner which instantiates Cast activities specified via cast/casts URIs.
class CastRunner : public WebContentRunner,
class CastRunner : public fuchsia::sys::Runner,
public PendingCastComponent::Delegate {
public:
using OnDestructionCallback = base::OnceCallback<void(CastRunner*)>;
static constexpr uint16_t kRemoteDebuggingPort = 9222;
// Creates a Runner for Cast components.
// |get_context_params_callback|: Returns the context parameters to use.
// |is_headless|: True if |get_context_params_callback| sets the HEADLESS
// feature flag.
CastRunner(GetContextParamsCallback get_context_params_callback,
bool is_headless);
// Creates the Runner for Cast components.
// |is_headless|: True if this instance should create Contexts with the
// HEADLESS feature set.
explicit CastRunner(bool is_headless);
~CastRunner() final;
CastRunner(const CastRunner&) = delete;
CastRunner& operator=(const CastRunner&) = delete;
// WebContentRunner implementation.
void DestroyComponent(WebComponent* component) final;
// fuchsia::sys::Runner implementation.
void StartComponent(fuchsia::sys::Package package,
fuchsia::sys::StartupInfo startup_info,
fidl::InterfaceRequest<fuchsia::sys::ComponentController>
controller_request) final;
// Returns true if this Runner is configured not to use Scenic.
bool is_headless() const { return is_headless_; }
void SetOnMainContextLostCallbackForTest(base::OnceClosure on_context_lost);
private:
// Creates and returns the service directory that is passed to the main web
// context.
std::unique_ptr<base::fuchsia::FilteredServiceDirectory>
CreateServiceDirectory();
// 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) final;
void CancelPendingComponent(PendingCastComponent* pending_component) final;
// Creates a component in this Runner, using the supplied |params|.
void CreateAndRegisterCastComponent(CastComponent::Params component_params);
// Handles component destruction.
void OnComponentDestroyed(CastComponent* component);
// Called when the isolated component in |runner| is ready to be destroyed.
void OnIsolatedRunnerEmpty(CastRunner* runner);
// Handlers used to provide parameters for main & isolated Contexts.
fuchsia::web::CreateContextParams GetCommonContextParams();
fuchsia::web::CreateContextParams GetMainContextParams();
fuchsia::web::CreateContextParams GetIsolatedContextParams(
std::vector<fuchsia::web::ContentDirectoryProvider> content_directories);
// Creates a CastRunner configured to serve data from content directories in
// |params|.
CastRunner* CreateChildRunnerForIsolatedComponent(
// |component_params|.
WebContentRunner* CreateIsolatedContextForParams(
CastComponent::Params* component_params);
// Handler for fuchsia.media.Audio requests in |service_directory_|.
void ConnectAudioProtocol(
fidl::InterfaceRequest<fuchsia::media::Audio> request);
// Called when an isolated component terminates, to allow the Context hosting
// it to be torn down.
void OnIsolatedContextEmpty(WebContentRunner* context);
// Handler for fuchsia.legacymetrics.MetricsRecorder requests in
// |service_directory_|.
void ConnectMetricsRecorderProtocol(
// Connection handlers for redirected services.
void OnAudioServiceRequest(
fidl::InterfaceRequest<fuchsia::media::Audio> request);
void OnMetricsRecorderServiceRequest(
fidl::InterfaceRequest<fuchsia::legacymetrics::MetricsRecorder> request);
// Returns the parameters with which the main context should be created.
fuchsia::web::CreateContextParams GetMainContextParams();
const WebContentRunner::GetContextParamsCallback get_context_params_callback_;
// True if this Runner uses Context(s) with the HEADLESS feature set.
const bool is_headless_;
// 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<base::fuchsia::FilteredServiceDirectory> main_services_;
const std::unique_ptr<WebContentRunner> main_context_;
// Holds fuchsia.web.Contexts used to host isolated components.
const std::unique_ptr<base::fuchsia::FilteredServiceDirectory>
isolated_services_;
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().
......@@ -105,21 +108,11 @@ class CastRunner : public WebContentRunner,
base::UniquePtrComparator>
pending_components_;
// Invoked upon destruction of "isolated" runners, used to signal termination
// to parents.
OnDestructionCallback on_component_destroyed_callback_;
// Manages isolated CastRunners owned by |this| instance.
base::flat_set<std::unique_ptr<CastRunner>, base::UniquePtrComparator>
isolated_runners_;
// ServiceDirectory passed to the main Context, to allow Audio capturer
// service requests to be routed to the relevant Agent.
const std::unique_ptr<base::fuchsia::FilteredServiceDirectory>
service_directory_;
// Last component that was created with permission to access MICROPHONE.
CastComponent* audio_capturer_component_ = nullptr;
// True if Contexts should be created without VULKAN set.
bool disable_vulkan_for_test_ = false;
};
#endif // FUCHSIA_RUNNERS_CAST_CAST_RUNNER_H_
......@@ -225,32 +225,10 @@ class CastRunnerIntegrationTest : public testing::Test {
EnsureFuchsiaDirSchemeInitialized();
// Create the CastRunner, published into |outgoing_directory_|.
fuchsia::web::ContextFeatureFlags feature_flags =
fuchsia::web::ContextFeatureFlags::NETWORK |
fuchsia::web::ContextFeatureFlags::LEGACYMETRICS;
if (enable_headless) {
feature_flags |= fuchsia::web::ContextFeatureFlags::HEADLESS;
}
if (enable_vulkan) {
feature_flags |= fuchsia::web::ContextFeatureFlags::VULKAN;
}
WebContentRunner::GetContextParamsCallback get_context_params =
base::BindLambdaForTesting([feature_flags]() {
fuchsia::web::CreateContextParams create_context_params;
create_context_params.set_features(feature_flags);
create_context_params.set_service_directory(
base::fuchsia::OpenDirectory(
base::FilePath(base::fuchsia::kServiceDirectoryPath)));
CHECK(create_context_params.service_directory());
create_context_params.set_remote_debugging_port(
CastRunner::kRemoteDebuggingPort);
return create_context_params;
});
cast_runner_ = std::make_unique<CastRunner>(std::move(get_context_params),
enable_headless);
cast_runner_->PublishRunnerService(&outgoing_directory_);
cast_runner_ = std::make_unique<CastRunner>(enable_headless);
if (!enable_vulkan)
cast_runner_->set_disable_vulkan_for_test();
cast_runner_binding_.emplace(&outgoing_directory_, cast_runner_.get());
StartAndPublishWebEngine();
......@@ -500,6 +478,8 @@ class CastRunnerIntegrationTest : public testing::Test {
sys::OutgoingDirectory outgoing_directory_;
std::unique_ptr<CastRunner> cast_runner_;
base::Optional<base::fuchsia::ScopedServiceBinding<fuchsia::sys::Runner>>
cast_runner_binding_;
fuchsia::sys::RunnerPtr cast_runner_ptr_;
base::TestComponentContextForProcess test_component_context_{
base::TestComponentContextForProcess::InitialState::kCloneAll};
......@@ -535,7 +515,8 @@ TEST_F(CastRunnerIntegrationTest, CanRecreateContext) {
// Setup a loop to wait for Context destruction after WebEngine is killed
// below.
base::RunLoop context_lost_loop;
cast_runner_->SetOnContextLostCallback(context_lost_loop.QuitClosure());
cast_runner_->SetOnMainContextLostCallbackForTest(
context_lost_loop.QuitClosure());
web_engine_controller_->Kill();
......
......@@ -6,18 +6,15 @@
#include "base/command_line.h"
#include "base/fuchsia/default_context.h"
#include "base/fuchsia/file_utils.h"
#include "base/fuchsia/scoped_service_binding.h"
#include "base/message_loop/message_pump_type.h"
#include "base/no_destructor.h"
#include "base/optional.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_executor.h"
#include "base/values.h"
#include "build/buildflag.h"
#include "fuchsia/base/config_reader.h"
#include "fuchsia/base/fuchsia_dir_scheme.h"
#include "fuchsia/base/init_logging.h"
#include "fuchsia/runners/buildflags.h"
#include "fuchsia/runners/cast/cast_runner.h"
namespace {
......@@ -34,43 +31,6 @@ bool IsHeadless() {
return false;
}
fuchsia::web::CreateContextParams CreateMainContextParams() {
fuchsia::web::ContextFeatureFlags features =
fuchsia::web::ContextFeatureFlags::NETWORK |
fuchsia::web::ContextFeatureFlags::AUDIO |
fuchsia::web::ContextFeatureFlags::WIDEVINE_CDM |
fuchsia::web::ContextFeatureFlags::LEGACYMETRICS;
if (IsHeadless()) {
LOG(WARNING) << "Running in headless mode.";
features |= fuchsia::web::ContextFeatureFlags::HEADLESS;
} else {
features |= fuchsia::web::ContextFeatureFlags::VULKAN |
fuchsia::web::ContextFeatureFlags::HARDWARE_VIDEO_DECODER |
fuchsia::web::ContextFeatureFlags::HARDWARE_VIDEO_DECODER_ONLY;
}
fuchsia::web::CreateContextParams create_context_params;
create_context_params.set_features(features);
const char kCastPlayreadyKeySystem[] = "com.chromecast.playready";
create_context_params.set_playready_key_system(kCastPlayreadyKeySystem);
// TODO(b/141956135): Use CrKey version provided by the Agent.
create_context_params.set_user_agent_product("CrKey");
create_context_params.set_user_agent_version("1.43.000000");
create_context_params.set_remote_debugging_port(
CastRunner::kRemoteDebuggingPort);
// TODO(crbug.com/1023514): Remove this switch when it is no longer
// necessary.
create_context_params.set_unsafely_treat_insecure_origins_as_secure(
{"allow-running-insecure-content"});
return create_context_params;
}
} // namespace
int main(int argc, char** argv) {
......@@ -84,12 +44,10 @@ int main(int argc, char** argv) {
cr_fuchsia::RegisterFuchsiaDirScheme();
WebContentRunner::GetContextParamsCallback get_context_params_callback =
base::BindRepeating(&CreateMainContextParams);
CastRunner runner(std::move(get_context_params_callback), IsHeadless());
runner.PublishRunnerService(
base::fuchsia::ComponentContextForCurrentProcess()->outgoing().get());
CastRunner runner(IsHeadless());
base::fuchsia::ScopedServiceBinding<fuchsia::sys::Runner> binding(
base::fuchsia::ComponentContextForCurrentProcess()->outgoing().get(),
&runner);
base::fuchsia::ComponentContextForCurrentProcess()
->outgoing()
......
......@@ -65,8 +65,7 @@ void WebComponent::StartComponent() {
// Create the underlying Frame and get its NavigationController.
fuchsia::web::CreateFrameParams create_params;
create_params.set_enable_remote_debugging(enable_remote_debugging_);
runner_->GetContext()->CreateFrameWithParams(std::move(create_params),
frame_.NewRequest());
frame_ = runner_->CreateFrame(std::move(create_params));
// If the Frame unexpectedly disconnect us then tear-down this Component.
frame_.set_error_handler([this](zx_status_t status) {
......
......@@ -41,26 +41,32 @@ WebContentRunner::WebContentRunner(
GetContextParamsCallback get_context_params_callback)
: get_context_params_callback_(std::move(get_context_params_callback)) {}
WebContentRunner::~WebContentRunner() = default;
void WebContentRunner::PublishRunnerService(
sys::OutgoingDirectory* outgoing_directory) {
service_binding_.emplace(outgoing_directory, this);
WebContentRunner::WebContentRunner(
fuchsia::web::CreateContextParams context_params)
: context_(CreateWebContext(std::move(context_params))) {
context_.set_error_handler([](zx_status_t status) {
ZX_LOG(ERROR, status) << "Connection to one-shot Context lost.";
});
}
fuchsia::web::Context* WebContentRunner::GetContext() {
WebContentRunner::~WebContentRunner() = default;
fuchsia::web::FramePtr WebContentRunner::CreateFrame(
fuchsia::web::CreateFrameParams params) {
if (!context_) {
DCHECK(get_context_params_callback_);
context_ = CreateWebContext(get_context_params_callback_.Run());
context_.set_error_handler([this](zx_status_t status) {
// If the browser instance died, then exit everything and do not attempt
// to recover. appmgr will relaunch the runner when it is needed again.
ZX_LOG(ERROR, status) << "Connection to Context lost.";
if (on_context_lost_callback_) {
std::move(on_context_lost_callback_).Run();
}
});
}
return context_.get();
fuchsia::web::FramePtr frame;
context_->CreateFrameWithParams(std::move(params), frame.NewRequest());
return frame;
}
void WebContentRunner::StartComponent(
......@@ -95,6 +101,8 @@ WebComponent* WebContentRunner::GetAnyComponent() {
void WebContentRunner::DestroyComponent(WebComponent* component) {
components_.erase(components_.find(component));
if (components_.empty() && on_empty_callback_)
std::move(on_empty_callback_).Run();
}
void WebContentRunner::RegisterComponent(
......@@ -102,6 +110,11 @@ void WebContentRunner::RegisterComponent(
components_.insert(std::move(component));
}
void WebContentRunner::SetOnContextLostCallback(base::OnceClosure callback) {
void WebContentRunner::SetOnEmptyCallback(base::OnceClosure on_empty) {
on_empty_callback_ = std::move(on_empty);
}
void WebContentRunner::SetOnContextLostCallbackForTest(
base::OnceClosure callback) {
on_context_lost_callback_ = std::move(callback);
}
......@@ -13,7 +13,6 @@
#include "base/callback.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/fuchsia/scoped_service_binding.h"
#include "base/macros.h"
#include "base/optional.h"
......@@ -25,24 +24,26 @@ class WebContentRunner : public fuchsia::sys::Runner {
using GetContextParamsCallback =
base::RepeatingCallback<fuchsia::web::CreateContextParams()>;
// Creates a Runner for web-based components, and publishes it to the
// specified OutgoingDirectory.
// Creates a Runner which will (re-)create the Context, if not already
// running, when StartComponent() is called,
// |get_context_params_callback|: Returns parameters for the Runner's
// web.Context.
// fuchsia.web.Context.
explicit WebContentRunner(
GetContextParamsCallback get_context_params_callback);
~WebContentRunner() override;
// Creates a Runner using a Context configured with |context_params|.
// The Runner becomes non-functional if the Context terminates.
explicit WebContentRunner(fuchsia::web::CreateContextParams context_params);
// Publishes the fuchsia.sys.Runner service to |outgoing_directory|.
void PublishRunnerService(sys::OutgoingDirectory* outgoing_directory);
~WebContentRunner() override;
// Gets a pointer to this runner's Context, creating one if needed.
fuchsia::web::Context* GetContext();
// Creates a Frame in this Runner's Context. If no Context exists then
// |get_context_params_callback_| will be used to create one, if set.
fuchsia::web::FramePtr CreateFrame(fuchsia::web::CreateFrameParams params);
// Used by WebComponent instances to signal that the ComponentController
// channel was dropped, and therefore the component should be destroyed.
virtual void DestroyComponent(WebComponent* component);
void DestroyComponent(WebComponent* component);
// fuchsia::sys::Runner implementation.
void StartComponent(fuchsia::sys::Package package,
......@@ -53,10 +54,14 @@ class WebContentRunner : public fuchsia::sys::Runner {
// Registers a WebComponent, or specialization, with this Runner.
void RegisterComponent(std::unique_ptr<WebComponent> component);
// Sets a callback that's called when the context is lost.
void SetOnContextLostCallback(base::OnceClosure callback);
// Sets a callback to invoke when |components_| next becomes empty.
void SetOnEmptyCallback(base::OnceClosure on_empty);
// Sets a callback that's called when |context_| disconnects.
void SetOnContextLostCallbackForTest(base::OnceClosure on_context_lost);
protected:
// TODO(https://crbug.com/1065707): Remove this once capability routing for
// the fuchsia.legacymetrics.Provider service is properly set up.
// Returns a pointer to any currently running component, or nullptr if no
// components are currently running.
WebComponent* GetAnyComponent();
......@@ -72,10 +77,7 @@ class WebContentRunner : public fuchsia::sys::Runner {
std::set<std::unique_ptr<WebComponent>, base::UniquePtrComparator>
components_;
// Publishes this Runner into the service directory specified at construction.
// This is not set for child runner instances.
base::Optional<base::fuchsia::ScopedServiceBinding<fuchsia::sys::Runner>>
service_binding_;
base::OnceClosure on_empty_callback_;
base::OnceClosure on_context_lost_callback_;
......
......@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/fuchsia/default_context.h"
#include "base/fuchsia/file_utils.h"
#include "base/fuchsia/scoped_service_binding.h"
#include "base/message_loop/message_pump_type.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_executor.h"
......@@ -58,8 +59,9 @@ int main(int argc, char** argv) {
base::BindRepeating(&GetContextParams);
WebContentRunner runner(std::move(get_context_params_callback));
runner.PublishRunnerService(
base::fuchsia::ComponentContextForCurrentProcess()->outgoing().get());
base::fuchsia::ScopedServiceBinding<fuchsia::sys::Runner> binding(
base::fuchsia::ComponentContextForCurrentProcess()->outgoing().get(),
&runner);
base::fuchsia::ComponentContextForCurrentProcess()
->outgoing()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment