Commit 4798d085 authored by Wez's avatar Wez Committed by Commit Bot

[Fuchsia] Add helper for working with fuchsia.sys.StartupInfo.

StartupContext creates helper classes wrapping the incoming and outgoing
service directory handles, to simplify use of them by component
implementations.

WebRunner & CastRunner are updated to use the StartupInfo helper, and
the CastRunner test StartCastComponent helper is updated to place the
CastChannel service in the component's incoming service directory, for
now.

Bug: 920920
Test: Existing component tests (e.g. cast_runner_integration_tests)
Change-Id: I92e9f0f0aad26aecef0da036684bb66733a267ac
Reviewed-on: https://chromium-review.googlesource.com/c/1473820
Auto-Submit: Wez <wez@chromium.org>
Reviewed-by: default avatarKevin Marshall <kmarshall@chromium.org>
Commit-Queue: Wez <wez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#632744}
parent 3f335272
......@@ -1421,6 +1421,8 @@ jumbo_component("base") {
"fuchsia/service_directory_client.h",
"fuchsia/service_provider_impl.cc",
"fuchsia/service_provider_impl.h",
"fuchsia/startup_context.cc",
"fuchsia/startup_context.h",
"memory/platform_shared_memory_region_fuchsia.cc",
"memory/protected_memory_posix.cc",
"memory/shared_memory_fuchsia.cc",
......
......@@ -12,8 +12,10 @@
#include <lib/zx/channel.h>
#include <string>
#include "base/base_export.h"
#include "base/callback.h"
#include "base/fuchsia/service_directory_client.h"
#include "base/macros.h"
namespace base {
namespace fuchsia {
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/fuchsia/startup_context.h"
#include <fuchsia/io/cpp/fidl.h>
namespace base {
namespace fuchsia {
StartupContext::StartupContext(::fuchsia::sys::StartupInfo startup_info)
: startup_info_(std::move(startup_info)) {
// Component manager generates |flat_namespace|, so things are horribly broken
// if |flat_namespace| is malformed.
CHECK_EQ(startup_info_.flat_namespace.directories.size(),
startup_info_.flat_namespace.paths.size());
// Find the /svc directory and wrap it into a ServiceDirectoryClient.
for (size_t i = 0; i < startup_info_.flat_namespace.paths.size(); ++i) {
if (startup_info_.flat_namespace.paths[i] == "/svc") {
incoming_services_ = std::make_unique<ServiceDirectoryClient>(
fidl::InterfaceHandle<::fuchsia::io::Directory>(
std::move(startup_info_.flat_namespace.directories[i])));
break;
}
}
}
StartupContext::~StartupContext() = default;
base::fuchsia::ServiceDirectory* StartupContext::public_services() {
if (!public_services_ && startup_info_.launch_info.directory_request) {
public_services_ = std::make_unique<ServiceDirectory>(
fidl::InterfaceRequest<::fuchsia::io::Directory>(
std::move(startup_info_.launch_info.directory_request)));
}
return public_services_.get();
}
} // namespace fuchsia
} // namespace base
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_FUCHSIA_STARTUP_CONTEXT_H_
#define BASE_FUCHSIA_STARTUP_CONTEXT_H_
#include <fuchsia/sys/cpp/fidl.h>
#include <memory>
#include "base/base_export.h"
#include "base/fuchsia/service_directory.h"
#include "base/fuchsia/service_directory_client.h"
#include "base/macros.h"
namespace base {
namespace fuchsia {
// Helper for unpacking a fuchsia.sys.StartupInfo and creating convenience
// wrappers for the various fields (e.g. the incoming & outgoing service
// directories, resolve launch URL etc).
// Embedders may derived from StartupContext to e.g. add bound pointers to
// embedder-specific services, as required.
class BASE_EXPORT StartupContext {
public:
explicit StartupContext(::fuchsia::sys::StartupInfo startup_info);
virtual ~StartupContext();
// Returns the namespace of services published for use by the component.
const ServiceDirectoryClient* incoming_services() const {
return incoming_services_.get();
}
// Returns the "public" directory into which this component binds services.
// Note that all services should be bound immediately after the first call to
// this API, before returning control to the message loop, at which point we
// will start processing service connection requests.
ServiceDirectory* public_services();
private:
::fuchsia::sys::StartupInfo startup_info_;
std::unique_ptr<ServiceDirectoryClient> incoming_services_;
std::unique_ptr<ServiceDirectory> public_services_;
DISALLOW_COPY_AND_ASSIGN(StartupContext);
};
} // namespace fuchsia
} // namespace base
#endif // BASE_FUCHSIA_STARTUP_CONTEXT_H_
......@@ -20,31 +20,22 @@ constexpr int kBindingsFailureExitCode = 129;
CastComponent::CastComponent(
CastRunner* runner,
fuchsia::sys::StartupInfo startup_info,
std::unique_ptr<base::fuchsia::StartupContext> context,
fidl::InterfaceRequest<fuchsia::sys::ComponentController>
controller_request)
: WebComponent(runner,
std::move(startup_info),
std::move(controller_request)),
: WebComponent(runner, std::move(context), std::move(controller_request)),
navigation_observer_binding_(this) {
base::AutoReset<bool> constructor_active_reset(&constructor_active_, true);
if (!additional_services() || std::find(additional_service_names().begin(),
additional_service_names().end(),
chromium::cast::CastChannel::Name_) ==
additional_service_names().end()) {
LOG(ERROR) << "Component instantiated without required service: "
<< chromium::cast::CastChannel::Name_;
DestroyComponent(1, fuchsia::sys::TerminationReason::UNSUPPORTED);
return;
}
cast_channel_ = std::make_unique<CastChannelBindings>(
frame(), &connector_,
additional_services()->ConnectToService<chromium::cast::CastChannel>(),
startup_context()
->incoming_services()
->ConnectToService<chromium::cast::CastChannel>(),
base::BindOnce(&CastComponent::DestroyComponent, base::Unretained(this),
kBindingsFailureExitCode,
fuchsia::sys::TerminationReason::INTERNAL_ERROR));
frame()->SetNavigationEventObserver(
navigation_observer_binding_.NewBinding());
}
......
......@@ -21,7 +21,7 @@ class CastComponent : public WebComponent,
public chromium::web::NavigationEventObserver {
public:
CastComponent(CastRunner* runner,
fuchsia::sys::StartupInfo startup_info,
std::unique_ptr<base::fuchsia::StartupContext> startup_context,
fidl::InterfaceRequest<fuchsia::sys::ComponentController>
controller_request);
~CastComponent() override;
......
......@@ -48,16 +48,18 @@ void CastRunner::StartComponent(
const std::string cast_app_id(cast_url.GetContent());
app_config_manager_->GetConfig(
cast_app_id,
[this, startup_info = std::move(startup_info),
[this,
startup_context = std::make_unique<base::fuchsia::StartupContext>(
std::move(startup_info)),
controller_request = std::move(controller_request)](
chromium::cast::ApplicationConfigPtr app_config) mutable {
GetConfigCallback(std::move(startup_info),
GetConfigCallback(std::move(startup_context),
std::move(controller_request), std::move(app_config));
});
}
void CastRunner::GetConfigCallback(
fuchsia::sys::StartupInfo startup_info,
std::unique_ptr<base::fuchsia::StartupContext> startup_context,
fidl::InterfaceRequest<fuchsia::sys::ComponentController>
controller_request,
chromium::cast::ApplicationConfigPtr app_config) {
......@@ -66,6 +68,7 @@ void CastRunner::GetConfigCallback(
// For test purposes, we need to call RegisterComponent even if there is no
// URL to launch.
// TODO: Replace this hack, e.g. with an test-specific callback.
RegisterComponent(std::unique_ptr<WebComponent>(nullptr));
return;
}
......@@ -73,7 +76,7 @@ void CastRunner::GetConfigCallback(
// If a config was returned then use it to launch a component.
GURL cast_app_url(app_config->web_url);
auto component = std::make_unique<CastComponent>(
this, std::move(startup_info), std::move(controller_request));
this, std::move(startup_context), std::move(controller_request));
component->LoadUrl(std::move(cast_app_url));
RegisterComponent(std::move(component));
}
......@@ -6,6 +6,7 @@
#define FUCHSIA_RUNNERS_CAST_CAST_RUNNER_H_
#include "base/callback.h"
#include "base/fuchsia/startup_context.h"
#include "base/macros.h"
#include "fuchsia/fidl/chromium/cast/cpp/fidl.h"
#include "fuchsia/fidl/chromium/web/cpp/fidl.h"
......@@ -29,7 +30,7 @@ class CastRunner : public WebContentRunner {
private:
void GetConfigCallback(
fuchsia::sys::StartupInfo startup_info,
std::unique_ptr<base::fuchsia::StartupContext> startup_context,
fidl::InterfaceRequest<fuchsia::sys::ComponentController>
controller_request,
chromium::cast::ApplicationConfigPtr app_config);
......
......@@ -21,7 +21,6 @@ fidl::InterfaceHandle<fuchsia::io::Directory> StartCastComponent(
fidl::Binding<chromium::cast::CastChannel>* cast_channel_binding) {
// Construct, bind, and populate a ServiceDirectory for publishing
// the CastChannel service to the CastComponent.
auto service_list = std::make_unique<fuchsia::sys::ServiceList>();
fidl::InterfaceHandle<fuchsia::io::Directory> directory;
base::fuchsia::ServiceDirectory cast_channel_directory(
directory.NewRequest());
......@@ -35,21 +34,20 @@ fidl::InterfaceHandle<fuchsia::io::Directory> StartCastComponent(
},
base::Passed(service_connect_runloop.QuitClosure()),
base::Unretained(cast_channel_binding)));
service_list->names.push_back(chromium::cast::CastChannel::Name_);
service_list->host_directory = directory.TakeChannel();
// Configure the Runner, including a service directory channel to publish
// services to.
fuchsia::sys::StartupInfo startup_info;
startup_info.launch_info.url = cast_url.as_string();
startup_info.launch_info.additional_services = std::move(service_list);
fidl::InterfaceHandle<fuchsia::io::Directory> component_services;
startup_info.launch_info.directory_request =
component_services.NewRequest().TakeChannel();
// The FlatNamespace vectors must be non-null, but may be empty.
startup_info.flat_namespace.paths.resize(0);
startup_info.flat_namespace.directories.resize(0);
// Publish the ServiceDirectory into the FlatNamespace for CastChannel to be
// picked up from.
startup_info.flat_namespace.paths.emplace_back("/svc");
startup_info.flat_namespace.directories.emplace_back(directory.TakeChannel());
fuchsia::sys::Package package;
package.resolved_url = cast_url.as_string();
......
......@@ -37,23 +37,14 @@ void WebComponent::LoadUrl(const GURL& url) {
WebComponent::WebComponent(
WebContentRunner* runner,
fuchsia::sys::StartupInfo startup_info,
std::unique_ptr<base::fuchsia::StartupContext> context,
fidl::InterfaceRequest<fuchsia::sys::ComponentController>
controller_request)
: runner_(runner), controller_binding_(this) {
: runner_(runner),
startup_context_(std::move(context)),
controller_binding_(this) {
DCHECK(runner);
// Handle the incoming services directory for this component.
if (startup_info.launch_info.additional_services &&
startup_info.launch_info.additional_services->host_directory) {
additional_services_ =
std::make_unique<base::fuchsia::ServiceDirectoryClient>(
fidl::InterfaceHandle<fuchsia::io::Directory>(std::move(
startup_info.launch_info.additional_services->host_directory)));
additional_service_names_ =
std::move(startup_info.launch_info.additional_services->names);
}
// If the ComponentController request is valid then bind it, and configure it
// to destroy this component on error.
if (controller_request.is_valid()) {
......@@ -70,17 +61,12 @@ WebComponent::WebComponent(
// Create the underlying Frame and get its NavigationController.
runner_->context()->CreateFrame(frame_.NewRequest());
// Create a ServiceDirectory for this component, and publish a ViewProvider
// into it, for the caller to use to create a View for this component.
// Note that we must publish ViewProvider before returning control to the
// message-loop, to ensure that it is available before the ServiceDirectory
// starts processing requests.
service_directory_ = std::make_unique<base::fuchsia::ServiceDirectory>(
fidl::InterfaceRequest<fuchsia::io::Directory>(
std::move(startup_info.launch_info.directory_request)));
// Publish ViewProvider before returning control to the message-loop, to
// ensure that it is available before the ServiceDirectory starts processing
// requests.
view_provider_binding_ = std::make_unique<
base::fuchsia::ScopedServiceBinding<fuchsia::ui::app::ViewProvider>>(
service_directory_.get(), this);
startup_context()->public_services(), this);
}
void WebComponent::Kill() {
......
......@@ -17,6 +17,7 @@
#include "base/fuchsia/scoped_service_binding.h"
#include "base/fuchsia/service_directory.h"
#include "base/fuchsia/service_directory_client.h"
#include "base/fuchsia/startup_context.h"
#include "base/logging.h"
#include "fuchsia/fidl/chromium/web/cpp/fidl.h"
#include "url/gurl.h"
......@@ -32,12 +33,12 @@ class WebComponent : public fuchsia::sys::ComponentController,
public fuchsia::ui::app::ViewProvider {
public:
// Creates a WebComponent encapsulating a web.Frame. A ViewProvider service
// will be published to the service-directory specified in |startup_info|, and
// if |controller_request| is valid then it will be bound to this component,
// and the component configured to teardown if that channel closes.
// will be published to the service-directory specified by |startup_context|,
// and if |controller_request| is valid then it will be bound to this
// component, and the componentconfigured to teardown if that channel closes.
// |runner| must outlive this component.
WebComponent(WebContentRunner* runner,
fuchsia::sys::StartupInfo startup_info,
std::unique_ptr<base::fuchsia::StartupContext> startup_context,
fidl::InterfaceRequest<fuchsia::sys::ComponentController>
controller_request);
......@@ -65,23 +66,15 @@ class WebComponent : public fuchsia::sys::ComponentController,
virtual void DestroyComponent(int termination_exit_code,
fuchsia::sys::TerminationReason reason);
// Returns the directory of incoming services provided to the component, or
// nullptr if none was provided.
base::fuchsia::ServiceDirectoryClient* additional_services() const {
return additional_services_.get();
}
// Returns the names of services available in additional_services().
const std::vector<std::string>& additional_service_names() const {
return additional_service_names_;
}
base::fuchsia::ServiceDirectory* service_directory() const {
return service_directory_.get();
// Returns the component's startup context (e.g. incoming services, public
// service directory, etc).
base::fuchsia::StartupContext* startup_context() const {
return startup_context_.get();
}
private:
WebContentRunner* const runner_ = nullptr;
const std::unique_ptr<base::fuchsia::StartupContext> startup_context_;
chromium::web::FramePtr frame_;
......
......@@ -15,6 +15,7 @@
#include "base/fuchsia/scoped_service_binding.h"
#include "base/fuchsia/service_directory.h"
#include "base/fuchsia/service_directory_client.h"
#include "base/fuchsia/startup_context.h"
#include "base/logging.h"
#include "fuchsia/runners/common/web_component.h"
#include "url/gurl.h"
......@@ -74,7 +75,9 @@ void WebContentRunner::StartComponent(
}
std::unique_ptr<WebComponent> component = std::make_unique<WebComponent>(
this, std::move(startup_info), std::move(controller_request));
this,
std::make_unique<base::fuchsia::StartupContext>(std::move(startup_info)),
std::move(controller_request));
component->LoadUrl(url);
RegisterComponent(std::move(component));
}
......
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