Commit d81f26f4 authored by Sergey Ulanov's avatar Sergey Ulanov Committed by Commit Bot

Reland: [Fuchsia] Use sys::OutgoingDirectory in //base/fuchsia.

Now base::fuchsia::ServiceDirectory is a wrapper around
OutgoingDirectory. Most code outside of //base/fuchsia still uses
base::fuchsia::ServiceDirectory and should continue function the same
way as it did before.

Bug: 920920
Change-Id: I915454b8fb7929b66bd0cc5ae4372d2e6499ed8a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1721558
Commit-Queue: Sergey Ulanov <sergeyu@chromium.org>
Reviewed-by: default avatarWez <wez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#686288}
parent d46d3686
...@@ -1522,6 +1522,8 @@ jumbo_component("base") { ...@@ -1522,6 +1522,8 @@ jumbo_component("base") {
"files/file_posix.cc", "files/file_posix.cc",
"files/file_util_posix.cc", "files/file_util_posix.cc",
"files/memory_mapped_file_posix.cc", "files/memory_mapped_file_posix.cc",
"fuchsia/default_context.cc",
"fuchsia/default_context.h",
"fuchsia/default_job.cc", "fuchsia/default_job.cc",
"fuchsia/default_job.h", "fuchsia/default_job.h",
"fuchsia/file_utils.cc", "fuchsia/file_utils.cc",
...@@ -1530,6 +1532,8 @@ jumbo_component("base") { ...@@ -1530,6 +1532,8 @@ jumbo_component("base") {
"fuchsia/filtered_service_directory.h", "fuchsia/filtered_service_directory.h",
"fuchsia/fuchsia_logging.cc", "fuchsia/fuchsia_logging.cc",
"fuchsia/fuchsia_logging.h", "fuchsia/fuchsia_logging.h",
"fuchsia/scoped_service_binding.cc",
"fuchsia/scoped_service_binding.h",
"fuchsia/service_directory.cc", "fuchsia/service_directory.cc",
"fuchsia/service_directory.h", "fuchsia/service_directory.h",
"fuchsia/service_directory_client.cc", "fuchsia/service_directory_client.cc",
...@@ -1592,6 +1596,7 @@ jumbo_component("base") { ...@@ -1592,6 +1596,7 @@ jumbo_component("base") {
"//third_party/fuchsia-sdk/sdk:fdio", "//third_party/fuchsia-sdk/sdk:fdio",
"//third_party/fuchsia-sdk/sdk:fidl_cpp", "//third_party/fuchsia-sdk/sdk:fidl_cpp",
"//third_party/fuchsia-sdk/sdk:io", "//third_party/fuchsia-sdk/sdk:io",
"//third_party/fuchsia-sdk/sdk:sys_cpp",
"//third_party/fuchsia-sdk/sdk:zx", "//third_party/fuchsia-sdk/sdk:zx",
] ]
...@@ -1600,9 +1605,9 @@ jumbo_component("base") { ...@@ -1600,9 +1605,9 @@ jumbo_component("base") {
"//third_party/fuchsia-sdk/sdk:async_loop_cpp", "//third_party/fuchsia-sdk/sdk:async_loop_cpp",
"//third_party/fuchsia-sdk/sdk:deprecatedtimezone", "//third_party/fuchsia-sdk/sdk:deprecatedtimezone",
"//third_party/fuchsia-sdk/sdk:fidl", "//third_party/fuchsia-sdk/sdk:fidl",
"//third_party/fuchsia-sdk/sdk:svc",
"//third_party/fuchsia-sdk/sdk:sys", "//third_party/fuchsia-sdk/sdk:sys",
"//third_party/fuchsia-sdk/sdk:syslog", "//third_party/fuchsia-sdk/sdk:syslog",
"//third_party/fuchsia-sdk/sdk:vfs_cpp",
] ]
} }
...@@ -3024,7 +3029,6 @@ test("base_unittests") { ...@@ -3024,7 +3029,6 @@ test("base_unittests") {
"fuchsia/scoped_service_binding_unittest.cc", "fuchsia/scoped_service_binding_unittest.cc",
"fuchsia/service_directory_test_base.cc", "fuchsia/service_directory_test_base.cc",
"fuchsia/service_directory_test_base.h", "fuchsia/service_directory_test_base.h",
"fuchsia/service_directory_unittest.cc",
"fuchsia/service_provider_impl_unittest.cc", "fuchsia/service_provider_impl_unittest.cc",
"message_loop/message_loop_io_posix_unittest.cc", "message_loop/message_loop_io_posix_unittest.cc",
"posix/file_descriptor_shuffle_unittest.cc", "posix/file_descriptor_shuffle_unittest.cc",
...@@ -3042,6 +3046,7 @@ test("base_unittests") { ...@@ -3042,6 +3046,7 @@ test("base_unittests") {
"//third_party/fuchsia-sdk/sdk:fdio", "//third_party/fuchsia-sdk/sdk:fdio",
"//third_party/fuchsia-sdk/sdk:logger", "//third_party/fuchsia-sdk/sdk:logger",
"//third_party/fuchsia-sdk/sdk:sys", "//third_party/fuchsia-sdk/sdk:sys",
"//third_party/fuchsia-sdk/sdk:sys_cpp",
] ]
} }
......
// 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/default_context.h"
#include <lib/sys/cpp/component_context.h>
#include "base/fuchsia/file_utils.h"
#include "base/logging.h"
#include "base/no_destructor.h"
namespace base {
namespace fuchsia {
sys::ComponentContext* ComponentContextForCurrentProcess() {
static base::NoDestructor<std::unique_ptr<sys::ComponentContext>> value(
std::make_unique<sys::ComponentContext>(
sys::ServiceDirectory::CreateFromNamespace()));
return value.get()->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_DEFAULT_CONTEXT_H_
#define BASE_FUCHSIA_DEFAULT_CONTEXT_H_
#include <memory>
#include "base/base_export.h"
namespace sys {
class ComponentContext;
} // namespace sys
namespace base {
namespace fuchsia {
// Returns default sys::ComponentContext for the current process.
BASE_EXPORT sys::ComponentContext* ComponentContextForCurrentProcess();
} // namespace fuchsia
} // namespace base
#endif // BASE_FUCHSIA_DEFAULT_CONTEXT_H_
\ No newline at end of file
...@@ -4,51 +4,42 @@ ...@@ -4,51 +4,42 @@
#include "base/fuchsia/filtered_service_directory.h" #include "base/fuchsia/filtered_service_directory.h"
#include <lib/fdio/directory.h> #include <lib/async/default.h>
#include <utility> #include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/fuchsia/fuchsia_logging.h" #include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/service_directory_client.h"
namespace base { namespace base {
namespace fuchsia { namespace fuchsia {
FilteredServiceDirectory::FilteredServiceDirectory( FilteredServiceDirectory::FilteredServiceDirectory(
const ServiceDirectoryClient* directory) sys::ServiceDirectory* directory)
: directory_(directory) { : directory_(std::move(directory)) {
outgoing_directory_ = std::make_unique<ServiceDirectory>( outgoing_directory_.Serve(
outgoing_directory_client_.NewRequest()); outgoing_directory_client_.NewRequest().TakeChannel());
} }
FilteredServiceDirectory::~FilteredServiceDirectory() { FilteredServiceDirectory::~FilteredServiceDirectory() {}
outgoing_directory_->RemoveAllServices();
}
void FilteredServiceDirectory::AddService(const char* service_name) { void FilteredServiceDirectory::AddService(const char* service_name) {
outgoing_directory_->AddServiceUnsafe( outgoing_directory_.AddPublicService(
service_name, std::make_unique<vfs::Service>(
base::BindRepeating(&FilteredServiceDirectory::HandleRequest, [this, service_name](zx::channel channel,
base::Unretained(this), service_name)); async_dispatcher_t* dispatcher) {
DCHECK_EQ(dispatcher, async_get_default_dispatcher());
directory_->Connect(service_name, std::move(channel));
}),
service_name);
} }
fidl::InterfaceHandle<::fuchsia::io::Directory> void FilteredServiceDirectory::ConnectClient(
FilteredServiceDirectory::ConnectClient() { fidl::InterfaceRequest<::fuchsia::io::Directory> dir_request) {
fidl::InterfaceHandle<::fuchsia::io::Directory> client; // sys::OutgoingDirectory puts public services under ./svc . Connect to that
// ServiceDirectory puts public services under ./svc . Connect to that
// directory and return client handle for the connection, // directory and return client handle for the connection,
zx_status_t status = outgoing_directory_.GetOrCreateDirectory("svc")->Serve(
fdio_service_connect_at(outgoing_directory_client_.channel().get(), "svc", ::fuchsia::io::OPEN_RIGHT_READABLE | ::fuchsia::io::OPEN_RIGHT_WRITABLE,
client.NewRequest().TakeChannel().release()); dir_request.TakeChannel());
ZX_CHECK(status == ZX_OK, status) << "fdio_service_connect_at()";
return client;
}
void FilteredServiceDirectory::HandleRequest(const char* service_name,
zx::channel channel) {
directory_->ConnectToServiceUnsafe(service_name, std::move(channel));
} }
} // namespace fuchsia } // namespace fuchsia
......
...@@ -5,41 +5,39 @@ ...@@ -5,41 +5,39 @@
#ifndef BASE_FUCHSIA_FILTERED_SERVICE_DIRECTORY_H_ #ifndef BASE_FUCHSIA_FILTERED_SERVICE_DIRECTORY_H_
#define BASE_FUCHSIA_FILTERED_SERVICE_DIRECTORY_H_ #define BASE_FUCHSIA_FILTERED_SERVICE_DIRECTORY_H_
#include "base/fuchsia/service_directory.h"
#include <fuchsia/io/cpp/fidl.h> #include <fuchsia/io/cpp/fidl.h>
#include <lib/fidl/cpp/interface_handle.h> #include <lib/fidl/cpp/interface_handle.h>
#include <lib/sys/cpp/outgoing_directory.h>
#include <lib/sys/cpp/service_directory.h>
#include <lib/zx/channel.h> #include <lib/zx/channel.h>
#include <memory> #include <memory>
#include "base/base_export.h"
#include "base/macros.h" #include "base/macros.h"
namespace base { namespace base {
namespace fuchsia { namespace fuchsia {
class ServiceDirectoryClient;
// ServiceDirectory that uses the supplied ServiceDirectoryClient to satisfy // ServiceDirectory that uses the supplied ServiceDirectoryClient to satisfy
// requests for only a restricted set of services. // requests for only a restricted set of services.
class BASE_EXPORT FilteredServiceDirectory { class BASE_EXPORT FilteredServiceDirectory {
public: public:
// Creates proxy that proxies requests to the specified service |directory|, // Creates a directory that proxies requests to the specified service
// which must outlive the proxy. // |directory|.
explicit FilteredServiceDirectory(const ServiceDirectoryClient* directory); explicit FilteredServiceDirectory(sys::ServiceDirectory* directory);
~FilteredServiceDirectory(); ~FilteredServiceDirectory();
// Adds the specified service to the list of whitelisted services. // Adds the specified service to the list of whitelisted services.
void AddService(const char* service_name); void AddService(const char* service_name);
// Returns a client channel connected to the directory. The returned channel // Connects a directory client. The directory can be passed to a sandboxed
// can be passed to a sandboxed process to be used for /svc namespace. // process to be used for /svc namespace.
fidl::InterfaceHandle<::fuchsia::io::Directory> ConnectClient(); void ConnectClient(
fidl::InterfaceRequest<::fuchsia::io::Directory> dir_request);
private: private:
void HandleRequest(const char* service_name, zx::channel channel); const sys::ServiceDirectory* const directory_;
sys::OutgoingDirectory outgoing_directory_;
const ServiceDirectoryClient* const directory_;
std::unique_ptr<ServiceDirectory> outgoing_directory_;
// Client side of the channel used by |outgoing_directory_|. // Client side of the channel used by |outgoing_directory_|.
fidl::InterfaceHandle<::fuchsia::io::Directory> outgoing_directory_client_; fidl::InterfaceHandle<::fuchsia::io::Directory> outgoing_directory_client_;
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#include <utility> #include <utility>
#include "base/fuchsia/service_directory_client.h"
#include "base/fuchsia/service_directory_test_base.h" #include "base/fuchsia/service_directory_test_base.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -17,21 +16,23 @@ class FilteredServiceDirectoryTest : public ServiceDirectoryTestBase { ...@@ -17,21 +16,23 @@ class FilteredServiceDirectoryTest : public ServiceDirectoryTestBase {
public: public:
FilteredServiceDirectoryTest() { FilteredServiceDirectoryTest() {
filtered_service_directory_ = std::make_unique<FilteredServiceDirectory>( filtered_service_directory_ = std::make_unique<FilteredServiceDirectory>(
public_service_directory_client_.get()); public_service_directory_.get());
filtered_client_ = std::make_unique<ServiceDirectoryClient>( fidl::InterfaceHandle<::fuchsia::io::Directory> directory;
filtered_service_directory_->ConnectClient()); filtered_service_directory_->ConnectClient(directory.NewRequest());
filtered_client_ =
std::make_unique<sys::ServiceDirectory>(std::move(directory));
} }
protected: protected:
std::unique_ptr<FilteredServiceDirectory> filtered_service_directory_; std::unique_ptr<FilteredServiceDirectory> filtered_service_directory_;
std::unique_ptr<ServiceDirectoryClient> filtered_client_; std::unique_ptr<sys::ServiceDirectory> filtered_client_;
}; };
// Verify that we can connect to a whitelisted service. // Verify that we can connect to a whitelisted service.
TEST_F(FilteredServiceDirectoryTest, Connect) { TEST_F(FilteredServiceDirectoryTest, Connect) {
filtered_service_directory_->AddService(testfidl::TestInterface::Name_); filtered_service_directory_->AddService(testfidl::TestInterface::Name_);
auto stub = filtered_client_->ConnectToService<testfidl::TestInterface>(); auto stub = filtered_client_->Connect<testfidl::TestInterface>();
VerifyTestInterface(&stub, ZX_OK); VerifyTestInterface(&stub, ZX_OK);
} }
...@@ -39,15 +40,15 @@ TEST_F(FilteredServiceDirectoryTest, Connect) { ...@@ -39,15 +40,15 @@ TEST_F(FilteredServiceDirectoryTest, Connect) {
TEST_F(FilteredServiceDirectoryTest, ConnectMultiple) { TEST_F(FilteredServiceDirectoryTest, ConnectMultiple) {
filtered_service_directory_->AddService(testfidl::TestInterface::Name_); filtered_service_directory_->AddService(testfidl::TestInterface::Name_);
auto stub1 = filtered_client_->ConnectToService<testfidl::TestInterface>(); auto stub1 = filtered_client_->Connect<testfidl::TestInterface>();
auto stub2 = filtered_client_->ConnectToService<testfidl::TestInterface>(); auto stub2 = filtered_client_->Connect<testfidl::TestInterface>();
VerifyTestInterface(&stub1, ZX_OK); VerifyTestInterface(&stub1, ZX_OK);
VerifyTestInterface(&stub2, ZX_OK); VerifyTestInterface(&stub2, ZX_OK);
} }
// Verify that non-whitelisted services are blocked. // Verify that non-whitelisted services are blocked.
TEST_F(FilteredServiceDirectoryTest, ServiceBlocked) { TEST_F(FilteredServiceDirectoryTest, ServiceBlocked) {
auto stub = filtered_client_->ConnectToService<testfidl::TestInterface>(); auto stub = filtered_client_->Connect<testfidl::TestInterface>();
VerifyTestInterface(&stub, ZX_ERR_PEER_CLOSED); VerifyTestInterface(&stub, ZX_ERR_PEER_CLOSED);
} }
...@@ -58,7 +59,7 @@ TEST_F(FilteredServiceDirectoryTest, NoService) { ...@@ -58,7 +59,7 @@ TEST_F(FilteredServiceDirectoryTest, NoService) {
service_binding_.reset(); service_binding_.reset();
auto stub = filtered_client_->ConnectToService<testfidl::TestInterface>(); auto stub = filtered_client_->Connect<testfidl::TestInterface>();
VerifyTestInterface(&stub, ZX_ERR_PEER_CLOSED); VerifyTestInterface(&stub, ZX_ERR_PEER_CLOSED);
} }
...@@ -68,9 +69,9 @@ TEST_F(FilteredServiceDirectoryTest, NoServiceDir) { ...@@ -68,9 +69,9 @@ TEST_F(FilteredServiceDirectoryTest, NoServiceDir) {
filtered_service_directory_->AddService(testfidl::TestInterface::Name_); filtered_service_directory_->AddService(testfidl::TestInterface::Name_);
service_binding_.reset(); service_binding_.reset();
service_directory_.reset(); outgoing_directory_.reset();
auto stub = filtered_client_->ConnectToService<testfidl::TestInterface>(); auto stub = filtered_client_->Connect<testfidl::TestInterface>();
VerifyTestInterface(&stub, ZX_ERR_PEER_CLOSED); VerifyTestInterface(&stub, ZX_ERR_PEER_CLOSED);
} }
......
// 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/scoped_service_binding.h"
#include <lib/sys/cpp/outgoing_directory.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/vfs/cpp/service.h>
namespace base {
namespace fuchsia {
namespace internal {
ScopedServiceBindingBase::ScopedServiceBindingBase(
sys::OutgoingDirectory* outgoing_directory)
: ScopedServiceBindingBase(
outgoing_directory->GetOrCreateDirectory("svc")) {}
ScopedServiceBindingBase::ScopedServiceBindingBase(vfs::PseudoDir* pseudo_dir)
: pseudo_dir_(pseudo_dir) {}
ScopedServiceBindingBase::~ScopedServiceBindingBase() = default;
void ScopedServiceBindingBase::RegisterService(const char* service_name,
Connector connector) {
pseudo_dir_->AddEntry(service_name,
std::make_unique<vfs::Service>(std::move(connector)));
}
void ScopedServiceBindingBase::UnregisterService(const char* service_name) {
pseudo_dir_->RemoveEntry(service_name);
}
} // namespace internal
} // namespace fuchsia
} // namespace base
...@@ -5,25 +5,74 @@ ...@@ -5,25 +5,74 @@
#ifndef BASE_FUCHSIA_SCOPED_SERVICE_BINDING_H_ #ifndef BASE_FUCHSIA_SCOPED_SERVICE_BINDING_H_
#define BASE_FUCHSIA_SCOPED_SERVICE_BINDING_H_ #define BASE_FUCHSIA_SCOPED_SERVICE_BINDING_H_
#include <lib/fidl/cpp/binding.h>
#include <lib/fidl/cpp/binding_set.h> #include <lib/fidl/cpp/binding_set.h>
#include "base/bind.h" #include "base/base_export.h"
#include "base/callback.h"
#include "base/fuchsia/service_directory.h" #include "base/fuchsia/service_directory.h"
namespace sys {
class OutgoingDirectory;
} // namespace sys
namespace vfs {
class PseudoDir;
} // namespace vfs
namespace base { namespace base {
namespace fuchsia { namespace fuchsia {
namespace internal {
class BASE_EXPORT ScopedServiceBindingBase {
public:
explicit ScopedServiceBindingBase(sys::OutgoingDirectory* outgoing_directory);
explicit ScopedServiceBindingBase(vfs::PseudoDir* pseudo_dir);
~ScopedServiceBindingBase();
protected:
// Same type as vfs::Service::Connector, so the value can be passed directly
// to vfs::Service.
using Connector =
fit::function<void(zx::channel channel, async_dispatcher_t* dispatcher)>;
void RegisterService(const char* service_name, Connector connector);
void UnregisterService(const char* service_name);
private:
vfs::PseudoDir* const pseudo_dir_ = nullptr;
};
} // namespace internal
template <typename Interface> template <typename Interface>
class ScopedServiceBinding { class ScopedServiceBinding : public internal::ScopedServiceBindingBase {
public: public:
// |service_directory| and |impl| must outlive the binding. // Published a public service in the specified |outgoing_directory|.
ScopedServiceBinding(ServiceDirectory* service_directory, Interface* impl) // |outgoing_directory| and |impl| must outlive the binding.
: directory_(service_directory), impl_(impl) { ScopedServiceBinding(sys::OutgoingDirectory* outgoing_directory,
directory_->AddService( Interface* impl)
BindRepeating(&ScopedServiceBinding::BindClient, Unretained(this))); : ScopedServiceBindingBase(outgoing_directory), impl_(impl) {
RegisterService(Interface::Name_,
fit::bind_member(this, &ScopedServiceBinding::BindClient));
}
// Publishes a service in the specified |pseudo_dir|. |pseudo_dir| and |impl|
// must outlive the binding.
ScopedServiceBinding(vfs::PseudoDir* pseudo_dir, Interface* impl)
: ScopedServiceBindingBase(pseudo_dir), impl_(impl) {
RegisterService(Interface::Name_,
fit::bind_member(this, &ScopedServiceBinding::BindClient));
} }
~ScopedServiceBinding() { directory_->RemoveService(Interface::Name_); } // TODO(crbug.com/974072): Remove this constructor once all code has been
// migrated from base::fuchsia::ServiceDirectory to sys::OutgoingDirectory.
ScopedServiceBinding(ServiceDirectory* service_directory, Interface* impl)
: ScopedServiceBinding(service_directory->outgoing_directory(), impl) {}
~ScopedServiceBinding() { UnregisterService(Interface::Name_); }
void SetOnLastClientCallback(base::OnceClosure on_last_client_callback) { void SetOnLastClientCallback(base::OnceClosure on_last_client_callback) {
on_last_client_callback_ = std::move(on_last_client_callback); on_last_client_callback_ = std::move(on_last_client_callback);
...@@ -34,8 +83,10 @@ class ScopedServiceBinding { ...@@ -34,8 +83,10 @@ class ScopedServiceBinding {
bool has_clients() const { return bindings_.size() != 0; } bool has_clients() const { return bindings_.size() != 0; }
private: private:
void BindClient(fidl::InterfaceRequest<Interface> request) { void BindClient(zx::channel channel, async_dispatcher_t* dispatcher) {
bindings_.AddBinding(impl_, std::move(request)); bindings_.AddBinding(impl_,
fidl::InterfaceRequest<Interface>(std::move(channel)),
dispatcher);
} }
void OnBindingSetEmpty() { void OnBindingSetEmpty() {
...@@ -43,7 +94,8 @@ class ScopedServiceBinding { ...@@ -43,7 +94,8 @@ class ScopedServiceBinding {
std::move(on_last_client_callback_).Run(); std::move(on_last_client_callback_).Run();
} }
ServiceDirectory* const directory_; sys::OutgoingDirectory* const directory_ = nullptr;
vfs::PseudoDir* const pseudo_dir_ = nullptr;
Interface* const impl_; Interface* const impl_;
fidl::BindingSet<Interface> bindings_; fidl::BindingSet<Interface> bindings_;
base::OnceClosure on_last_client_callback_; base::OnceClosure on_last_client_callback_;
...@@ -58,19 +110,27 @@ enum class ScopedServiceBindingPolicy { kPreferNew, kPreferExisting }; ...@@ -58,19 +110,27 @@ enum class ScopedServiceBindingPolicy { kPreferNew, kPreferExisting };
template <typename Interface, template <typename Interface,
ScopedServiceBindingPolicy Policy = ScopedServiceBindingPolicy Policy =
ScopedServiceBindingPolicy::kPreferNew> ScopedServiceBindingPolicy::kPreferNew>
class ScopedSingleClientServiceBinding { class ScopedSingleClientServiceBinding
: public internal::ScopedServiceBindingBase {
public: public:
// |service_directory| and |impl| must outlive the binding. // |outgoing_directory| and |impl| must outlive the binding.
ScopedSingleClientServiceBinding(ServiceDirectory* service_directory, ScopedSingleClientServiceBinding(sys::OutgoingDirectory* outgoing_directory,
Interface* impl) Interface* impl)
: directory_(service_directory), binding_(impl) { : ScopedServiceBindingBase(outgoing_directory), binding_(impl) {
directory_->AddService(BindRepeating( RegisterService(
&ScopedSingleClientServiceBinding::BindClient, Unretained(this))); Interface::Name_,
fit::bind_member(this, &ScopedSingleClientServiceBinding::BindClient));
} }
~ScopedSingleClientServiceBinding() { // TODO(crbug.com/974072): Remove this constructor once all code has been
directory_->RemoveService(Interface::Name_); // migrated from base::fuchsia::ServiceDirectory to sys::OutgoingDirectory.
} ScopedSingleClientServiceBinding(ServiceDirectory* service_directory,
Interface* impl)
: ScopedSingleClientServiceBinding(
service_directory->outgoing_directory(),
impl) {}
~ScopedSingleClientServiceBinding() { UnregisterService(Interface::Name_); }
typename Interface::EventSender_& events() { return binding_.events(); } typename Interface::EventSender_& events() { return binding_.events(); }
...@@ -83,11 +143,13 @@ class ScopedSingleClientServiceBinding { ...@@ -83,11 +143,13 @@ class ScopedSingleClientServiceBinding {
bool has_clients() const { return binding_.is_bound(); } bool has_clients() const { return binding_.is_bound(); }
private: private:
void BindClient(fidl::InterfaceRequest<Interface> request) { void BindClient(zx::channel channel, async_dispatcher_t* dispatcher) {
if (Policy == ScopedServiceBindingPolicy::kPreferExisting && if (Policy == ScopedServiceBindingPolicy::kPreferExisting &&
binding_.is_bound()) binding_.is_bound()) {
return; return;
binding_.Bind(std::move(request)); }
binding_.Bind(fidl::InterfaceRequest<Interface>(std::move(channel)),
dispatcher);
} }
void OnBindingEmpty() { void OnBindingEmpty() {
...@@ -95,7 +157,6 @@ class ScopedSingleClientServiceBinding { ...@@ -95,7 +157,6 @@ class ScopedSingleClientServiceBinding {
std::move(on_last_client_callback_).Run(); std::move(on_last_client_callback_).Run();
} }
ServiceDirectory* const directory_;
fidl::Binding<Interface> binding_; fidl::Binding<Interface> binding_;
base::OnceClosure on_last_client_callback_; base::OnceClosure on_last_client_callback_;
......
...@@ -15,10 +15,8 @@ class ScopedServiceBindingTest : public ServiceDirectoryTestBase {}; ...@@ -15,10 +15,8 @@ class ScopedServiceBindingTest : public ServiceDirectoryTestBase {};
// Verifies that ScopedServiceBinding allows connection more than once. // Verifies that ScopedServiceBinding allows connection more than once.
TEST_F(ScopedServiceBindingTest, ConnectTwice) { TEST_F(ScopedServiceBindingTest, ConnectTwice) {
auto stub = public_service_directory_client_ auto stub = public_service_directory_->Connect<testfidl::TestInterface>();
->ConnectToService<testfidl::TestInterface>(); auto stub2 = public_service_directory_->Connect<testfidl::TestInterface>();
auto stub2 = public_service_directory_client_
->ConnectToService<testfidl::TestInterface>();
VerifyTestInterface(&stub, ZX_OK); VerifyTestInterface(&stub, ZX_OK);
VerifyTestInterface(&stub2, ZX_OK); VerifyTestInterface(&stub2, ZX_OK);
} }
...@@ -30,17 +28,17 @@ TEST_F(ScopedServiceBindingTest, SingleClientPreferNew) { ...@@ -30,17 +28,17 @@ TEST_F(ScopedServiceBindingTest, SingleClientPreferNew) {
service_binding_ = nullptr; service_binding_ = nullptr;
ScopedSingleClientServiceBinding<testfidl::TestInterface, ScopedSingleClientServiceBinding<testfidl::TestInterface,
ScopedServiceBindingPolicy::kPreferNew> ScopedServiceBindingPolicy::kPreferNew>
binding(service_directory_.get(), &test_service_); binding(outgoing_directory_.get(), &test_service_);
// Connect the first client, and verify that it is functional. // Connect the first client, and verify that it is functional.
auto existing_client = public_service_directory_client_ auto existing_client =
->ConnectToService<testfidl::TestInterface>(); public_service_directory_->Connect<testfidl::TestInterface>();
VerifyTestInterface(&existing_client, ZX_OK); VerifyTestInterface(&existing_client, ZX_OK);
// Connect the second client, so the existing one should be disconnected and // Connect the second client, so the existing one should be disconnected and
// the new should be functional. // the new should be functional.
auto new_client = public_service_directory_client_ auto new_client =
->ConnectToService<testfidl::TestInterface>(); public_service_directory_->Connect<testfidl::TestInterface>();
RunLoop().RunUntilIdle(); RunLoop().RunUntilIdle();
EXPECT_FALSE(existing_client); EXPECT_FALSE(existing_client);
VerifyTestInterface(&new_client, ZX_OK); VerifyTestInterface(&new_client, ZX_OK);
...@@ -53,17 +51,17 @@ TEST_F(ScopedServiceBindingTest, SingleClientPreferExisting) { ...@@ -53,17 +51,17 @@ TEST_F(ScopedServiceBindingTest, SingleClientPreferExisting) {
service_binding_ = nullptr; service_binding_ = nullptr;
ScopedSingleClientServiceBinding<testfidl::TestInterface, ScopedSingleClientServiceBinding<testfidl::TestInterface,
ScopedServiceBindingPolicy::kPreferExisting> ScopedServiceBindingPolicy::kPreferExisting>
binding(service_directory_.get(), &test_service_); binding(outgoing_directory_.get(), &test_service_);
// Connect the first client, and verify that it is functional. // Connect the first client, and verify that it is functional.
auto existing_client = public_service_directory_client_ auto existing_client =
->ConnectToService<testfidl::TestInterface>(); public_service_directory_->Connect<testfidl::TestInterface>();
VerifyTestInterface(&existing_client, ZX_OK); VerifyTestInterface(&existing_client, ZX_OK);
// Connect the second client, then verify that the it gets closed and the // Connect the second client, then verify that the it gets closed and the
// existing one remains functional. // existing one remains functional.
auto new_client = public_service_directory_client_ auto new_client =
->ConnectToService<testfidl::TestInterface>(); public_service_directory_->Connect<testfidl::TestInterface>();
RunLoop().RunUntilIdle(); RunLoop().RunUntilIdle();
EXPECT_FALSE(new_client); EXPECT_FALSE(new_client);
VerifyTestInterface(&existing_client, ZX_OK); VerifyTestInterface(&existing_client, ZX_OK);
...@@ -74,21 +72,39 @@ TEST_F(ScopedServiceBindingTest, SingleClientDefaultIsPreferNew) { ...@@ -74,21 +72,39 @@ TEST_F(ScopedServiceBindingTest, SingleClientDefaultIsPreferNew) {
// Teardown the default multi-client binding and create a prefer-new one. // Teardown the default multi-client binding and create a prefer-new one.
service_binding_ = nullptr; service_binding_ = nullptr;
ScopedSingleClientServiceBinding<testfidl::TestInterface> binding( ScopedSingleClientServiceBinding<testfidl::TestInterface> binding(
service_directory_.get(), &test_service_); outgoing_directory_.get(), &test_service_);
// Connect the first client, and verify that it is functional. // Connect the first client, and verify that it is functional.
auto existing_client = public_service_directory_client_ auto existing_client =
->ConnectToService<testfidl::TestInterface>(); public_service_directory_->Connect<testfidl::TestInterface>();
VerifyTestInterface(&existing_client, ZX_OK); VerifyTestInterface(&existing_client, ZX_OK);
// Connect the second client, so the existing one should be disconnected and // Connect the second client, so the existing one should be disconnected and
// the new should be functional. // the new should be functional.
auto new_client = public_service_directory_client_ auto new_client =
->ConnectToService<testfidl::TestInterface>(); public_service_directory_->Connect<testfidl::TestInterface>();
RunLoop().RunUntilIdle(); RunLoop().RunUntilIdle();
EXPECT_FALSE(existing_client); EXPECT_FALSE(existing_client);
VerifyTestInterface(&new_client, ZX_OK); VerifyTestInterface(&new_client, ZX_OK);
} }
// Verify that we can publish a debug service.
TEST_F(ScopedServiceBindingTest, ConnectDebugService) {
// Remove the public service binding.
service_binding_.reset();
// Publish the test service to the "debug" directory.
ScopedServiceBinding<testfidl::TestInterface> debug_service_binding(
outgoing_directory_->debug_dir(), &test_service_);
auto debug_stub =
debug_service_directory_->Connect<testfidl::TestInterface>();
VerifyTestInterface(&debug_stub, ZX_OK);
auto release_stub =
public_service_directory_->Connect<testfidl::TestInterface>();
VerifyTestInterface(&release_stub, ZX_ERR_PEER_CLOSED);
}
} // namespace fuchsia } // namespace fuchsia
} // namespace base } // namespace base
...@@ -4,11 +4,10 @@ ...@@ -4,11 +4,10 @@
#include "base/fuchsia/service_directory.h" #include "base/fuchsia/service_directory.h"
#include <lib/async/default.h> #include <lib/sys/cpp/component_context.h>
#include <lib/svc/dir.h> #include <lib/sys/cpp/outgoing_directory.h>
#include <zircon/process.h>
#include <zircon/processargs.h>
#include "base/fuchsia/default_context.h"
#include "base/fuchsia/fuchsia_logging.h" #include "base/fuchsia/fuchsia_logging.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop_current.h" #include "base/message_loop/message_loop_current.h"
...@@ -17,133 +16,43 @@ ...@@ -17,133 +16,43 @@
namespace base { namespace base {
namespace fuchsia { namespace fuchsia {
namespace {
std::unique_ptr<ServiceDirectory> CreateDefaultServiceDirectory() {
sys::OutgoingDirectory* outgoing =
ComponentContextForCurrentProcess()->outgoing().get();
outgoing->ServeFromStartupInfo();
return std::make_unique<ServiceDirectory>(outgoing);
}
} // namespace
ServiceDirectory::ServiceDirectory( ServiceDirectory::ServiceDirectory(
fidl::InterfaceRequest<::fuchsia::io::Directory> request) { fidl::InterfaceRequest<::fuchsia::io::Directory> request) {
Initialize(std::move(request)); Initialize(std::move(request));
} }
ServiceDirectory::ServiceDirectory() = default; ServiceDirectory::ServiceDirectory(sys::OutgoingDirectory* directory)
: directory_(directory) {}
ServiceDirectory::~ServiceDirectory() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(services_.empty());
// Only the root ServiceDirectory "owns" svc_dir_. ServiceDirectory::ServiceDirectory() = default;
if (!sub_directory_) { ServiceDirectory::~ServiceDirectory() = default;
zx_status_t status = svc_dir_destroy(svc_dir_);
ZX_DCHECK(status == ZX_OK, status);
}
}
// static // static
ServiceDirectory* ServiceDirectory::GetDefault() { ServiceDirectory* ServiceDirectory::GetDefault() {
static NoDestructor<ServiceDirectory> directory( static NoDestructor<std::unique_ptr<ServiceDirectory>> directory(
fidl::InterfaceRequest<::fuchsia::io::Directory>( CreateDefaultServiceDirectory());
zx::channel(zx_take_startup_handle(PA_DIRECTORY_REQUEST)))); return directory.get()->get();
return directory.get();
} }
void ServiceDirectory::Initialize( void ServiceDirectory::Initialize(
fidl::InterfaceRequest<::fuchsia::io::Directory> request) { fidl::InterfaceRequest<::fuchsia::io::Directory> request) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(!owned_directory_);
DCHECK(!svc_dir_); owned_directory_ = std::make_unique<sys::OutgoingDirectory>();
directory_ = owned_directory_.get();
zx_status_t status = directory_->GetOrCreateDirectory("svc")->Serve(
svc_dir_create(async_get_default_dispatcher(), ::fuchsia::io::OPEN_RIGHT_READABLE | ::fuchsia::io::OPEN_RIGHT_WRITABLE,
request.TakeChannel().release(), &svc_dir_); request.TakeChannel());
ZX_CHECK(status == ZX_OK, status);
debug_ = WrapUnique(new ServiceDirectory(svc_dir_, "debug"));
}
void ServiceDirectory::AddServiceUnsafe(
StringPiece name,
RepeatingCallback<void(zx::channel)> connect_callback) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(svc_dir_);
DCHECK(services_.find(name) == services_.end());
std::string name_str = name.as_string();
services_[name_str] = connect_callback;
if (sub_directory_) {
zx_status_t status =
svc_dir_add_service(svc_dir_, sub_directory_, name_str.c_str(), this,
&ServiceDirectory::HandleConnectRequest);
ZX_DCHECK(status == ZX_OK, status);
} else {
// Publish to "svc".
zx_status_t status =
svc_dir_add_service(svc_dir_, "svc", name_str.c_str(), this,
&ServiceDirectory::HandleConnectRequest);
ZX_DCHECK(status == ZX_OK, status);
// Publish to "public" for compatibility.
status = svc_dir_add_service(svc_dir_, "public", name_str.c_str(), this,
&ServiceDirectory::HandleConnectRequest);
ZX_DCHECK(status == ZX_OK, status);
// Publish to the legacy "flat" namespace, which is required by some
// clients.
status = svc_dir_add_service(svc_dir_, nullptr, name_str.c_str(), this,
&ServiceDirectory::HandleConnectRequest);
ZX_DCHECK(status == ZX_OK, status);
}
}
void ServiceDirectory::RemoveService(StringPiece name) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(svc_dir_);
std::string name_str = name.as_string();
auto it = services_.find(name_str);
DCHECK(it != services_.end());
services_.erase(it);
if (sub_directory_) {
zx_status_t status =
svc_dir_remove_service(svc_dir_, sub_directory_, name_str.c_str());
ZX_DCHECK(status == ZX_OK, status);
} else {
// Unregister from "svc", "public", and flat namespace.
zx_status_t status =
svc_dir_remove_service(svc_dir_, "svc", name_str.c_str());
ZX_DCHECK(status == ZX_OK, status);
status = svc_dir_remove_service(svc_dir_, "public", name_str.c_str());
ZX_DCHECK(status == ZX_OK, status);
status = svc_dir_remove_service(svc_dir_, nullptr, name_str.c_str());
ZX_DCHECK(status == ZX_OK, status);
}
}
void ServiceDirectory::RemoveAllServices() {
while (!services_.empty()) {
RemoveService(services_.begin()->first);
}
}
// static
void ServiceDirectory::HandleConnectRequest(void* context,
const char* service_name,
zx_handle_t service_request) {
auto* directory = reinterpret_cast<ServiceDirectory*>(context);
DCHECK_CALLED_ON_VALID_THREAD(directory->thread_checker_);
auto it = directory->services_.find(service_name);
// HandleConnectRequest() is expected to be called only for registered
// services.
DCHECK(it != directory->services_.end());
it->second.Run(zx::channel(service_request));
}
ServiceDirectory::ServiceDirectory(svc_dir_t* svc_dir, const char* name) {
DCHECK(svc_dir);
svc_dir_ = svc_dir;
sub_directory_ = name;
} }
} // namespace fuchsia } // namespace fuchsia
......
...@@ -17,9 +17,10 @@ ...@@ -17,9 +17,10 @@
#include "base/containers/flat_map.h" #include "base/containers/flat_map.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/threading/thread_checker.h"
typedef struct svc_dir svc_dir_t; namespace sys {
class OutgoingDirectory;
} // namespace sys
namespace base { namespace base {
namespace fuchsia { namespace fuchsia {
...@@ -34,14 +35,19 @@ namespace fuchsia { ...@@ -34,14 +35,19 @@ namespace fuchsia {
// Debug services are published to a "debug" sub-directory only accessible by // Debug services are published to a "debug" sub-directory only accessible by
// other services via the Hub. // other services via the Hub.
// //
// Not thread-safe. All methods must be called on the thread that created the // TODO(crbug.com/974072): Currently this class is just a wrapper around
// object. // sys::OutgoingDirectory. Migrate all code to use sys::OutgoingDirectory and
// remove this class.
class BASE_EXPORT ServiceDirectory { class BASE_EXPORT ServiceDirectory {
public: public:
// Responds to service requests over the supplied |request| channel. // Responds to service requests over the supplied |request| channel.
explicit ServiceDirectory( explicit ServiceDirectory(
fidl::InterfaceRequest<::fuchsia::io::Directory> request); fidl::InterfaceRequest<::fuchsia::io::Directory> request);
// Wraps a sys::OutgoingDirectory. The |directory| must outlive
// the ServiceDirectory object.
explicit ServiceDirectory(sys::OutgoingDirectory* directory);
// Creates an uninitialized ServiceDirectory instance. Initialize must be // Creates an uninitialized ServiceDirectory instance. Initialize must be
// called on the instance before any services can be registered. Unless you // called on the instance before any services can be registered. Unless you
// need separate construction & initialization for a ServiceDirectory member, // need separate construction & initialization for a ServiceDirectory member,
...@@ -58,51 +64,11 @@ class BASE_EXPORT ServiceDirectory { ...@@ -58,51 +64,11 @@ class BASE_EXPORT ServiceDirectory {
// supplied |directory_request| channel. // supplied |directory_request| channel.
void Initialize(fidl::InterfaceRequest<::fuchsia::io::Directory> request); void Initialize(fidl::InterfaceRequest<::fuchsia::io::Directory> request);
template <typename Interface> sys::OutgoingDirectory* outgoing_directory() { return directory_; }
void AddService(RepeatingCallback<void(fidl::InterfaceRequest<Interface>)>
connect_callback) {
AddServiceUnsafe(
Interface::Name_,
BindRepeating(
[](decltype(connect_callback) callback, zx::channel request) {
callback.Run(
fidl::InterfaceRequest<Interface>(std::move(request)));
},
connect_callback));
}
void RemoveService(StringPiece name);
void RemoveAllServices();
// Returns the debug ServiceDirectory.
ServiceDirectory* debug() const { return debug_.get(); }
// Passes requests for |name| through to a generic |connect_callback|.
// This is used only when proxying requests for interfaces not known at
// compile-time. Use the type-safe APIs above whenever possible.
void AddServiceUnsafe(StringPiece name,
RepeatingCallback<void(zx::channel)> connect_callback);
private: private:
// Sub-directory constructor. std::unique_ptr<sys::OutgoingDirectory> owned_directory_;
ServiceDirectory(svc_dir_t* svc_dir, const char* name); sys::OutgoingDirectory* directory_;
// Called by |svc_dir_| to handle service requests.
static void HandleConnectRequest(void* context,
const char* service_name,
zx_handle_t service_request);
THREAD_CHECKER(thread_checker_);
// Owned by the root directory.
svc_dir_t* svc_dir_ = nullptr;
flat_map<std::string, RepeatingCallback<void(zx::channel)>> services_;
// The debug sub-directory. Empty if this is a sub-directory.
std::unique_ptr<ServiceDirectory> debug_;
// If mon-null, this directory represents a sub-directory of the root
// ServiceDirectory.
const char* sub_directory_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ServiceDirectory); DISALLOW_COPY_AND_ASSIGN(ServiceDirectory);
}; };
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <utility> #include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/test/test_timeouts.h" #include "base/test/test_timeouts.h"
namespace base { namespace base {
...@@ -17,48 +18,37 @@ ServiceDirectoryTestBase::ServiceDirectoryTestBase() ...@@ -17,48 +18,37 @@ ServiceDirectoryTestBase::ServiceDirectoryTestBase()
: run_timeout_(TestTimeouts::action_timeout(), BindRepeating([]() { : run_timeout_(TestTimeouts::action_timeout(), BindRepeating([]() {
ADD_FAILURE() << "Run() timed out."; ADD_FAILURE() << "Run() timed out.";
})) { })) {
// TODO(https://crbug.com/920920): Remove the ServiceDirectory's implicit
// "public" sub-directory and update this setup logic.
// Mount service dir and publish the service. // Mount service dir and publish the service.
outgoing_directory_ = std::make_unique<sys::OutgoingDirectory>();
fidl::InterfaceHandle<::fuchsia::io::Directory> directory; fidl::InterfaceHandle<::fuchsia::io::Directory> directory;
service_directory_ = zx_status_t status =
std::make_unique<ServiceDirectory>(directory.NewRequest()); outgoing_directory_->Serve(directory.NewRequest().TakeChannel());
ZX_CHECK(status == ZX_OK, status);
service_binding_ = service_binding_ =
std::make_unique<ScopedServiceBinding<testfidl::TestInterface>>( std::make_unique<ScopedServiceBinding<testfidl::TestInterface>>(
service_directory_.get(), &test_service_); outgoing_directory_.get(), &test_service_);
// Create the ServiceDirectoryClient, connected to the "svc" sub-directory. // Create the sys::ServiceDirectory, connected to the "svc" sub-directory.
fidl::InterfaceHandle<::fuchsia::io::Directory> svc_directory; fidl::InterfaceHandle<::fuchsia::io::Directory> svc_directory;
CHECK_EQ(fdio_service_connect_at( CHECK_EQ(fdio_service_connect_at(
directory.channel().get(), "/svc/.", directory.channel().get(), "svc",
svc_directory.NewRequest().TakeChannel().release()), svc_directory.NewRequest().TakeChannel().release()),
ZX_OK); ZX_OK);
public_service_directory_client_ = public_service_directory_ =
std::make_unique<ServiceDirectoryClient>(std::move(svc_directory)); std::make_unique<sys::ServiceDirectory>(std::move(svc_directory));
// Create the ServiceDirectoryClient, connected to the "debug" sub-directory. // Create the sys::ServiceDirectory, connected to the "debug" sub-directory.
fidl::InterfaceHandle<::fuchsia::io::Directory> debug_directory; fidl::InterfaceHandle<::fuchsia::io::Directory> debug_directory;
CHECK_EQ(fdio_service_connect_at( CHECK_EQ(fdio_service_connect_at(
directory.channel().get(), "/debug/.", directory.channel().get(), "debug",
debug_directory.NewRequest().TakeChannel().release()), debug_directory.NewRequest().TakeChannel().release()),
ZX_OK); ZX_OK);
debug_service_directory_client_ = debug_service_directory_ =
std::make_unique<ServiceDirectoryClient>(std::move(debug_directory)); std::make_unique<sys::ServiceDirectory>(std::move(debug_directory));
// Create the ServiceDirectoryClient, connected to the "public" sub-directory
// (same contents as "svc", provided for compatibility).
fidl::InterfaceHandle<::fuchsia::io::Directory> public_directory;
CHECK_EQ(fdio_service_connect_at(
directory.channel().get(), "/public/.",
public_directory.NewRequest().TakeChannel().release()),
ZX_OK);
legacy_public_service_directory_client_ =
std::make_unique<ServiceDirectoryClient>(std::move(public_directory));
// Create a ServiceDirectoryClient for the "private" part of the directory. // Create a sys::ServiceDirectory for the "private" part of the directory.
root_service_directory_client_ = root_service_directory_ =
std::make_unique<ServiceDirectoryClient>(std::move(directory)); std::make_unique<sys::ServiceDirectory>(std::move(directory));
} }
ServiceDirectoryTestBase::~ServiceDirectoryTestBase() = default; ServiceDirectoryTestBase::~ServiceDirectoryTestBase() = default;
......
...@@ -5,11 +5,12 @@ ...@@ -5,11 +5,12 @@
#ifndef BASE_FUCHSIA_SERVICE_DIRECTORY_TEST_BASE_H_ #ifndef BASE_FUCHSIA_SERVICE_DIRECTORY_TEST_BASE_H_
#define BASE_FUCHSIA_SERVICE_DIRECTORY_TEST_BASE_H_ #define BASE_FUCHSIA_SERVICE_DIRECTORY_TEST_BASE_H_
#include <lib/sys/cpp/outgoing_directory.h>
#include <lib/sys/cpp/service_directory.h>
#include <zircon/types.h> #include <zircon/types.h>
#include <memory> #include <memory>
#include "base/fuchsia/scoped_service_binding.h" #include "base/fuchsia/scoped_service_binding.h"
#include "base/fuchsia/service_directory_client.h"
#include "base/fuchsia/test_interface_impl.h" #include "base/fuchsia/test_interface_impl.h"
#include "base/fuchsia/testfidl/cpp/fidl.h" #include "base/fuchsia/testfidl/cpp/fidl.h"
#include "base/run_loop.h" #include "base/run_loop.h"
...@@ -34,16 +35,14 @@ class ServiceDirectoryTestBase : public testing::Test { ...@@ -34,16 +35,14 @@ class ServiceDirectoryTestBase : public testing::Test {
base::test::ScopedTaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY, base::test::ScopedTaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY,
base::test::ScopedTaskEnvironment::MainThreadType::IO}; base::test::ScopedTaskEnvironment::MainThreadType::IO};
std::unique_ptr<ServiceDirectory> service_directory_; std::unique_ptr<sys::OutgoingDirectory> outgoing_directory_;
TestInterfaceImpl test_service_; TestInterfaceImpl test_service_;
std::unique_ptr<ScopedServiceBinding<testfidl::TestInterface>> std::unique_ptr<ScopedServiceBinding<testfidl::TestInterface>>
service_binding_; service_binding_;
std::unique_ptr<ServiceDirectoryClient> public_service_directory_client_; std::unique_ptr<sys::ServiceDirectory> public_service_directory_;
std::unique_ptr<ServiceDirectoryClient> debug_service_directory_client_; std::unique_ptr<sys::ServiceDirectory> debug_service_directory_;
std::unique_ptr<ServiceDirectoryClient> std::unique_ptr<sys::ServiceDirectory> root_service_directory_;
legacy_public_service_directory_client_;
std::unique_ptr<ServiceDirectoryClient> root_service_directory_client_;
DISALLOW_COPY_AND_ASSIGN(ServiceDirectoryTestBase); DISALLOW_COPY_AND_ASSIGN(ServiceDirectoryTestBase);
}; };
......
// Copyright 2018 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/service_directory.h"
#include <utility>
#include "base/fuchsia/service_directory_test_base.h"
#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
namespace fuchsia {
class ServiceDirectoryTest : public ServiceDirectoryTestBase {};
// Verifies that ServiceDirectoryClient can consume a public service in
// ServiceDirectory and that connection is disconnected when the client stub is
// destroyed.
TEST_F(ServiceDirectoryTest, ConnectDisconnect) {
auto stub = public_service_directory_client_
->ConnectToService<testfidl::TestInterface>();
VerifyTestInterface(&stub, ZX_OK);
RunLoop run_loop;
service_binding_->SetOnLastClientCallback(run_loop.QuitClosure());
stub.Unbind();
run_loop.Run();
}
// Verify that we can connect to a service through both "public" and "svc".
TEST_F(ServiceDirectoryTest, ConnectNewAndLegacyServices) {
auto stub = public_service_directory_client_
->ConnectToService<testfidl::TestInterface>();
auto stub2 = legacy_public_service_directory_client_
->ConnectToService<testfidl::TestInterface>();
VerifyTestInterface(&stub, ZX_OK);
VerifyTestInterface(&stub2, ZX_OK);
}
// Verify that we can connect to the same service more than once.
TEST_F(ServiceDirectoryTest, ConnectMulti) {
auto stub = public_service_directory_client_
->ConnectToService<testfidl::TestInterface>();
auto stub2 = public_service_directory_client_
->ConnectToService<testfidl::TestInterface>();
VerifyTestInterface(&stub, ZX_OK);
VerifyTestInterface(&stub2, ZX_OK);
}
// Verify that services are also exported to the legacy flat service namespace.
TEST_F(ServiceDirectoryTest, ConnectLegacy) {
auto stub = root_service_directory_client_
->ConnectToService<testfidl::TestInterface>();
VerifyTestInterface(&stub, ZX_OK);
}
// Verify that ServiceDirectoryClient can handle the case when the service
// directory connection is disconnected.
TEST_F(ServiceDirectoryTest, DirectoryGone) {
service_binding_.reset();
service_directory_.reset();
fidl::InterfacePtr<testfidl::TestInterface> stub;
zx_status_t status =
public_service_directory_client_->ConnectToService(stub.NewRequest());
EXPECT_EQ(status, ZX_ERR_PEER_CLOSED);
VerifyTestInterface(&stub, ZX_ERR_PEER_CLOSED);
}
// Verify that the case when the service doesn't exist is handled properly.
TEST_F(ServiceDirectoryTest, NoService) {
service_binding_.reset();
auto stub = public_service_directory_client_
->ConnectToService<testfidl::TestInterface>();
VerifyTestInterface(&stub, ZX_ERR_PEER_CLOSED);
}
// Verify that we can connect to a debug service.
TEST_F(ServiceDirectoryTest, ConnectDebugService) {
// Remove the public service binding.
service_binding_.reset();
// Publish the test service to the "debug" directory.
ScopedServiceBinding<testfidl::TestInterface> debug_service_binding(
service_directory_->debug(), &test_service_);
auto debug_stub = debug_service_directory_client_
->ConnectToService<testfidl::TestInterface>();
VerifyTestInterface(&debug_stub, ZX_OK);
auto release_stub = public_service_directory_client_
->ConnectToService<testfidl::TestInterface>();
VerifyTestInterface(&release_stub, ZX_ERR_PEER_CLOSED);
}
} // namespace fuchsia
} // namespace base
...@@ -4,11 +4,23 @@ ...@@ -4,11 +4,23 @@
#include "base/fuchsia/service_provider_impl.h" #include "base/fuchsia/service_provider_impl.h"
#include <lib/sys/cpp/outgoing_directory.h>
#include <utility> #include <utility>
namespace base { namespace base {
namespace fuchsia { namespace fuchsia {
// static
std::unique_ptr<ServiceProviderImpl>
ServiceProviderImpl::CreateForOutgoingDirectory(
sys::OutgoingDirectory* outgoing_directory) {
fidl::InterfaceHandle<::fuchsia::io::Directory> service_directory;
outgoing_directory->GetOrCreateDirectory("svc")->Serve(
::fuchsia::io::OPEN_RIGHT_READABLE | ::fuchsia::io::OPEN_RIGHT_WRITABLE,
service_directory.NewRequest().TakeChannel());
return std::make_unique<ServiceProviderImpl>(std::move(service_directory));
}
ServiceProviderImpl::ServiceProviderImpl( ServiceProviderImpl::ServiceProviderImpl(
fidl::InterfaceHandle<::fuchsia::io::Directory> service_directory) fidl::InterfaceHandle<::fuchsia::io::Directory> service_directory)
: directory_(std::move(service_directory)) {} : directory_(std::move(service_directory)) {}
......
...@@ -17,6 +17,10 @@ ...@@ -17,6 +17,10 @@
#include "base/fuchsia/service_directory_client.h" #include "base/fuchsia/service_directory_client.h"
#include "base/macros.h" #include "base/macros.h"
namespace sys {
class OutgoingDirectory;
} // namespace sys
namespace base { namespace base {
namespace fuchsia { namespace fuchsia {
...@@ -25,6 +29,11 @@ namespace fuchsia { ...@@ -25,6 +29,11 @@ namespace fuchsia {
// TODO(https://crbug.com/920920): Remove this when ServiceProvider is gone. // TODO(https://crbug.com/920920): Remove this when ServiceProvider is gone.
class BASE_EXPORT ServiceProviderImpl : public ::fuchsia::sys::ServiceProvider { class BASE_EXPORT ServiceProviderImpl : public ::fuchsia::sys::ServiceProvider {
public: public:
// Constructor that creates ServiceProvider for public services in the
// specified OutgoingDirectory.
static std::unique_ptr<ServiceProviderImpl> CreateForOutgoingDirectory(
sys::OutgoingDirectory* outgoing_directory);
explicit ServiceProviderImpl( explicit ServiceProviderImpl(
fidl::InterfaceHandle<::fuchsia::io::Directory> service_directory); fidl::InterfaceHandle<::fuchsia::io::Directory> service_directory);
~ServiceProviderImpl() override; ~ServiceProviderImpl() override;
......
...@@ -4,12 +4,12 @@ ...@@ -4,12 +4,12 @@
#include "base/fuchsia/service_provider_impl.h" #include "base/fuchsia/service_provider_impl.h"
#include <lib/sys/cpp/outgoing_directory.h>
#include <lib/zx/channel.h> #include <lib/zx/channel.h>
#include <utility> #include <utility>
#include "base/fuchsia/scoped_service_binding.h" #include "base/fuchsia/scoped_service_binding.h"
#include "base/fuchsia/service_directory.h"
#include "base/fuchsia/test_interface_impl.h" #include "base/fuchsia/test_interface_impl.h"
#include "base/fuchsia/testfidl/cpp/fidl.h" #include "base/fuchsia/testfidl/cpp/fidl.h"
#include "base/run_loop.h" #include "base/run_loop.h"
...@@ -21,7 +21,12 @@ namespace fuchsia { ...@@ -21,7 +21,12 @@ namespace fuchsia {
class ServiceProviderImplTest : public testing::Test { class ServiceProviderImplTest : public testing::Test {
public: public:
ServiceProviderImplTest() = default; ServiceProviderImplTest() {
provider_impl_ =
ServiceProviderImpl::CreateForOutgoingDirectory(&service_directory_);
provider_impl_->AddBinding(provider_client_.NewRequest());
}
~ServiceProviderImplTest() override = default; ~ServiceProviderImplTest() override = default;
void VerifyTestInterface(fidl::InterfacePtr<testfidl::TestInterface>* stub, void VerifyTestInterface(fidl::InterfacePtr<testfidl::TestInterface>* stub,
...@@ -55,26 +60,24 @@ class ServiceProviderImplTest : public testing::Test { ...@@ -55,26 +60,24 @@ class ServiceProviderImplTest : public testing::Test {
base::test::ScopedTaskEnvironment::MainThreadType::IO}; base::test::ScopedTaskEnvironment::MainThreadType::IO};
TestInterfaceImpl test_service_; TestInterfaceImpl test_service_;
sys::OutgoingDirectory service_directory_;
std::unique_ptr<ServiceProviderImpl> provider_impl_;
::fuchsia::sys::ServiceProviderPtr provider_client_;
DISALLOW_COPY_AND_ASSIGN(ServiceProviderImplTest); DISALLOW_COPY_AND_ASSIGN(ServiceProviderImplTest);
}; };
// Verifies that we can connect to the service service more than once. // Verifies that we can connect to the service more than once.
TEST_F(ServiceProviderImplTest, ConnectMulti) { TEST_F(ServiceProviderImplTest, ConnectMulti) {
fidl::InterfaceHandle<::fuchsia::io::Directory> directory_channel;
ServiceDirectory service_directory(directory_channel.NewRequest());
ServiceProviderImpl provider_impl(std::move(directory_channel));
ScopedServiceBinding<testfidl::TestInterface> service_binding( ScopedServiceBinding<testfidl::TestInterface> service_binding(
&service_directory, &test_service_); &service_directory_, &test_service_);
::fuchsia::sys::ServiceProviderPtr provider_client;
provider_impl.AddBinding(provider_client.NewRequest());
testfidl::TestInterfacePtr stub; testfidl::TestInterfacePtr stub;
provider_client->ConnectToService(testfidl::TestInterface::Name_, provider_client_->ConnectToService(testfidl::TestInterface::Name_,
stub.NewRequest().TakeChannel()); stub.NewRequest().TakeChannel());
testfidl::TestInterfacePtr stub2; testfidl::TestInterfacePtr stub2;
provider_client->ConnectToService(testfidl::TestInterface::Name_, provider_client_->ConnectToService(testfidl::TestInterface::Name_,
stub2.NewRequest().TakeChannel()); stub2.NewRequest().TakeChannel());
VerifyTestInterface(&stub, ZX_OK); VerifyTestInterface(&stub, ZX_OK);
...@@ -83,15 +86,8 @@ TEST_F(ServiceProviderImplTest, ConnectMulti) { ...@@ -83,15 +86,8 @@ TEST_F(ServiceProviderImplTest, ConnectMulti) {
// Verify that the case when the service doesn't exist is handled properly. // Verify that the case when the service doesn't exist is handled properly.
TEST_F(ServiceProviderImplTest, NoService) { TEST_F(ServiceProviderImplTest, NoService) {
fidl::InterfaceHandle<::fuchsia::io::Directory> directory_channel;
ServiceDirectory service_directory(directory_channel.NewRequest());
ServiceProviderImpl provider_impl(std::move(directory_channel));
::fuchsia::sys::ServiceProviderPtr provider_client;
provider_impl.AddBinding(provider_client.NewRequest());
testfidl::TestInterfacePtr stub; testfidl::TestInterfacePtr stub;
provider_client->ConnectToService(testfidl::TestInterface::Name_, provider_client_->ConnectToService(testfidl::TestInterface::Name_,
stub.NewRequest().TakeChannel()); stub.NewRequest().TakeChannel());
VerifyTestInterface(&stub, ZX_ERR_PEER_CLOSED); VerifyTestInterface(&stub, ZX_ERR_PEER_CLOSED);
......
...@@ -5,91 +5,106 @@ ...@@ -5,91 +5,106 @@
#include "base/fuchsia/startup_context.h" #include "base/fuchsia/startup_context.h"
#include <fuchsia/io/cpp/fidl.h> #include <fuchsia/io/cpp/fidl.h>
#include <lib/sys/cpp/outgoing_directory.h>
#include <lib/sys/cpp/service_directory.h>
#include "base/fuchsia/file_utils.h" #include "base/fuchsia/file_utils.h"
namespace base { namespace base {
namespace fuchsia { namespace fuchsia {
StartupContext::StartupContext(::fuchsia::sys::StartupInfo startup_info) StartupContext::StartupContext(::fuchsia::sys::StartupInfo startup_info) {
: startup_info_(std::move(startup_info)) { std::unique_ptr<sys::ServiceDirectory> incoming_services;
// Component manager generates |flat_namespace|, so things are horribly broken // Component manager generates |flat_namespace|, so things are horribly broken
// if |flat_namespace| is malformed. // if |flat_namespace| is malformed.
CHECK_EQ(startup_info_.flat_namespace.directories.size(), CHECK_EQ(startup_info.flat_namespace.directories.size(),
startup_info_.flat_namespace.paths.size()); startup_info.flat_namespace.paths.size());
// Find the /svc directory and wrap it into a ServiceDirectoryClient. // Find the /svc directory and wrap it into a sys::ServiceDirectory.
for (size_t i = 0; i < startup_info_.flat_namespace.paths.size(); ++i) { for (size_t i = 0; i < startup_info.flat_namespace.paths.size(); ++i) {
if (startup_info_.flat_namespace.paths[i] == kServiceDirectoryPath) { if (startup_info.flat_namespace.paths[i] == kServiceDirectoryPath) {
incoming_services_ = std::make_unique<ServiceDirectoryClient>( incoming_services = std::make_unique<sys::ServiceDirectory>(
fidl::InterfaceHandle<::fuchsia::io::Directory>( std::move(startup_info.flat_namespace.directories[i]));
std::move(startup_info_.flat_namespace.directories[i])));
break; break;
} }
} }
// TODO(https://crbug.com/933834): Remove these workarounds when we migrate to // TODO(https://crbug.com/933834): Remove these workarounds when we migrate to
// the new component manager. // the new component manager.
if (!incoming_services_ && startup_info_.launch_info.flat_namespace) { if (!incoming_services && startup_info.launch_info.flat_namespace) {
LOG(WARNING) << "Falling back to LaunchInfo namespace"; LOG(WARNING) << "Falling back to LaunchInfo namespace";
for (size_t i = 0; for (size_t i = 0;
i < startup_info_.launch_info.flat_namespace->paths.size(); ++i) { i < startup_info.launch_info.flat_namespace->paths.size(); ++i) {
if (startup_info_.launch_info.flat_namespace->paths[i] == if (startup_info.launch_info.flat_namespace->paths[i] ==
kServiceDirectoryPath) { kServiceDirectoryPath) {
incoming_services_ = std::make_unique<ServiceDirectoryClient>( incoming_services = std::make_unique<sys::ServiceDirectory>(
fidl::InterfaceHandle<::fuchsia::io::Directory>(std::move( std::move(startup_info.launch_info.flat_namespace->directories[i]));
startup_info_.launch_info.flat_namespace->directories[i])));
break; break;
} }
} }
} }
if (!incoming_services_ && startup_info_.launch_info.additional_services) {
if (!incoming_services && startup_info.launch_info.additional_services) {
LOG(WARNING) << "Falling back to additional ServiceList services"; LOG(WARNING) << "Falling back to additional ServiceList services";
// Construct a ServiceDirectory and publish the additional services into it. // Construct a OutgoingDirectory and publish the additional services into
fidl::InterfaceHandle<::fuchsia::io::Directory> incoming_directory; // it.
additional_services_.Bind( additional_services_.Bind(
std::move(startup_info_.launch_info.additional_services->provider)); std::move(startup_info.launch_info.additional_services->provider));
additional_services_directory_ = additional_services_directory_ = std::make_unique<sys::OutgoingDirectory>();
std::make_unique<ServiceDirectory>(incoming_directory.NewRequest()); for (auto& name : startup_info.launch_info.additional_services->names) {
for (auto& name : startup_info_.launch_info.additional_services->names) { additional_services_directory_->AddPublicService(
additional_services_directory_->AddServiceUnsafe( std::make_unique<vfs::Service>([this, name](
name, base::BindRepeating( zx::channel channel,
&::fuchsia::sys::ServiceProvider::ConnectToService, async_dispatcher_t* dispatcher) {
base::Unretained(additional_services_.get()), name)); additional_services_->ConnectToService(name, std::move(channel));
}),
name);
} }
// Publish those services to the caller as |incoming_services_|. // Publish those services to the caller as |incoming_services|.
incoming_services_ = std::make_unique<ServiceDirectoryClient>( fidl::InterfaceHandle<::fuchsia::io::Directory> incoming_directory;
fidl::InterfaceHandle<::fuchsia::io::Directory>( additional_services_directory_->GetOrCreateDirectory("svc")->Serve(
std::move(incoming_directory))); ::fuchsia::io::OPEN_RIGHT_READABLE | ::fuchsia::io::OPEN_RIGHT_WRITABLE,
incoming_directory.NewRequest().TakeChannel());
incoming_services =
std::make_unique<sys::ServiceDirectory>(std::move(incoming_directory));
} }
if (!incoming_services_) { if (!incoming_services) {
LOG(WARNING) << "Component started without a service directory"; LOG(WARNING) << "Component started without a service directory";
// Create a dummy ServiceDirectoryClient with a channel that's not // Create a dummy ServiceDirectoryClient with a channel that's not
// connected on the other end. // connected on the other end.
fidl::InterfaceHandle<::fuchsia::io::Directory> dummy_directory; fidl::InterfaceHandle<::fuchsia::io::Directory> dummy_directory;
ignore_result(dummy_directory.NewRequest()); ignore_result(dummy_directory.NewRequest());
incoming_services_ = incoming_services =
std::make_unique<ServiceDirectoryClient>(std::move(dummy_directory)); std::make_unique<sys::ServiceDirectory>(std::move(dummy_directory));
} }
component_context_ =
std::make_unique<sys::ComponentContext>(std::move(incoming_services));
outgoing_directory_request_ =
std::move(startup_info.launch_info.directory_request);
service_directory_ =
std::make_unique<ServiceDirectory>(component_context_->outgoing().get());
service_directory_client_ = std::make_unique<ServiceDirectoryClient>(
component_context_->svc()->CloneChannel());
} }
StartupContext::~StartupContext() { StartupContext::~StartupContext() = default;
// |additional_services_directory_| needs to be empty for clean teardown.
if (additional_services_directory_) void StartupContext::ServeOutgoingDirectory() {
additional_services_directory_->RemoveAllServices(); DCHECK(outgoing_directory_request_);
component_context_->outgoing()->Serve(std::move(outgoing_directory_request_));
} }
ServiceDirectory* StartupContext::public_services() { ServiceDirectory* StartupContext::public_services() {
if (!public_services_ && startup_info_.launch_info.directory_request) { if (outgoing_directory_request_)
public_services_ = std::make_unique<ServiceDirectory>( ServeOutgoingDirectory();
fidl::InterfaceRequest<::fuchsia::io::Directory>( return service_directory_.get();
std::move(startup_info_.launch_info.directory_request)));
}
return public_services_.get();
} }
} // namespace fuchsia } // namespace fuchsia
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define BASE_FUCHSIA_STARTUP_CONTEXT_H_ #define BASE_FUCHSIA_STARTUP_CONTEXT_H_
#include <fuchsia/sys/cpp/fidl.h> #include <fuchsia/sys/cpp/fidl.h>
#include <lib/sys/cpp/component_context.h>
#include <memory> #include <memory>
#include "base/base_export.h" #include "base/base_export.h"
...@@ -26,28 +27,42 @@ class BASE_EXPORT StartupContext { ...@@ -26,28 +27,42 @@ class BASE_EXPORT StartupContext {
explicit StartupContext(::fuchsia::sys::StartupInfo startup_info); explicit StartupContext(::fuchsia::sys::StartupInfo startup_info);
virtual ~StartupContext(); virtual ~StartupContext();
// Returns the namespace of services published for use by the component. // Returns the ComponentContext for the current component.
const ServiceDirectoryClient* incoming_services() const { sys::ComponentContext* component_context() const {
DCHECK(incoming_services_); return component_context_.get();
return incoming_services_.get();
} }
// Returns the outgoing directory into which this component binds services. // Starts serving outgoing directory in the |component_context()|. Can be
// Note that all services should be bound immediately after the first call to // called at most once. All outgoing services should be published in
// this API, before returning control to the message loop, at which point we // |component_context()->outgoing()| before calling this function.
// will start processing service connection requests. void ServeOutgoingDirectory();
ServiceDirectory* public_services();
private: // TODO(crbug.com/974072): ServiceDirectory and ServiceDirectoryClient are
::fuchsia::sys::StartupInfo startup_info_; // deprecated. Remove incoming_services() and public_services() once all
// clients have been migrated to sys::OutgoingDirectory and
// sys::ServiceDirectory.
ServiceDirectoryClient* incoming_services() const {
return service_directory_client_.get();
}
std::unique_ptr<ServiceDirectoryClient> incoming_services_; // Legacy ServiceDirectory instance. Also calls |ServeOutgoingDirectory()| if
std::unique_ptr<ServiceDirectory> public_services_; // it hasn't been called yet, which means outgoing services should be bound
// immediately after the first call to this API.
ServiceDirectory* public_services();
private:
// TODO(https://crbug.com/933834): Remove these when we migrate to the new // TODO(https://crbug.com/933834): Remove these when we migrate to the new
// component manager APIs. // component manager APIs.
::fuchsia::sys::ServiceProviderPtr additional_services_; ::fuchsia::sys::ServiceProviderPtr additional_services_;
std::unique_ptr<ServiceDirectory> additional_services_directory_; std::unique_ptr<sys::OutgoingDirectory> additional_services_directory_;
std::unique_ptr<sys::ComponentContext> component_context_;
// Used to store outgoing directory until ServeOutgoingDirectory() is called.
zx::channel outgoing_directory_request_;
std::unique_ptr<ServiceDirectory> service_directory_;
std::unique_ptr<ServiceDirectoryClient> service_directory_client_;
DISALLOW_COPY_AND_ASSIGN(StartupContext); DISALLOW_COPY_AND_ASSIGN(StartupContext);
}; };
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "fuchsia/engine/context_provider_main.h" #include "fuchsia/engine/context_provider_main.h"
#include <lib/sys/cpp/outgoing_directory.h>
#include "base/fuchsia/scoped_service_binding.h" #include "base/fuchsia/scoped_service_binding.h"
#include "base/fuchsia/service_directory.h" #include "base/fuchsia/service_directory.h"
#include "base/logging.h" #include "base/logging.h"
...@@ -23,7 +25,7 @@ int ContextProviderMain() { ...@@ -23,7 +25,7 @@ int ContextProviderMain() {
directory, &context_provider); directory, &context_provider);
base::fuchsia::ScopedServiceBinding<fuchsia::web::Debug> debug_binding( base::fuchsia::ScopedServiceBinding<fuchsia::web::Debug> debug_binding(
directory->debug(), &context_provider); directory->outgoing_directory()->debug_dir(), &context_provider);
base::RunLoop run_loop; base::RunLoop run_loop;
cr_fuchsia::LifecycleImpl lifecycle(directory, run_loop.QuitClosure()); cr_fuchsia::LifecycleImpl lifecycle(directory, run_loop.QuitClosure());
......
...@@ -163,6 +163,7 @@ test("cast_runner_integration_tests") { ...@@ -163,6 +163,7 @@ test("cast_runner_integration_tests") {
"//fuchsia/base:test_support", "//fuchsia/base:test_support",
"//net:test_support", "//net:test_support",
"//testing/gtest", "//testing/gtest",
"//third_party/fuchsia-sdk/sdk:modular",
] ]
package_deps = [ [ package_deps = [ [
"//fuchsia/engine:web_engine", "//fuchsia/engine:web_engine",
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <fuchsia/modular/cpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/fidl/cpp/binding.h> #include <lib/fidl/cpp/binding.h>
#include <lib/zx/channel.h> #include <lib/zx/channel.h>
...@@ -208,6 +210,20 @@ class CastRunnerIntegrationTest : public testing::Test { ...@@ -208,6 +210,20 @@ class CastRunnerIntegrationTest : public testing::Test {
fuchsia::sys::StartupInfo startup_info; fuchsia::sys::StartupInfo startup_info;
startup_info.launch_info.url = component_url.as_string(); startup_info.launch_info.url = component_url.as_string();
fidl::InterfaceHandle<fuchsia::io::Directory> outgoing_directory;
startup_info.launch_info.directory_request =
outgoing_directory.NewRequest().TakeChannel();
fidl::InterfaceHandle<::fuchsia::io::Directory> svc_directory;
CHECK_EQ(fdio_service_connect_at(
outgoing_directory.channel().get(), "svc",
svc_directory.NewRequest().TakeChannel().release()),
ZX_OK);
component_services_client_ =
std::make_unique<base::fuchsia::ServiceDirectoryClient>(
std::move(svc_directory));
// Place the ServiceDirectory in the |flat_namespace|. // Place the ServiceDirectory in the |flat_namespace|.
startup_info.flat_namespace.paths.emplace_back( startup_info.flat_namespace.paths.emplace_back(
base::fuchsia::kServiceDirectoryPath); base::fuchsia::kServiceDirectoryPath);
...@@ -259,6 +275,8 @@ class CastRunnerIntegrationTest : public testing::Test { ...@@ -259,6 +275,8 @@ class CastRunnerIntegrationTest : public testing::Test {
// Incoming service directory, ComponentContext and per-component state. // Incoming service directory, ComponentContext and per-component state.
std::unique_ptr<base::fuchsia::ServiceDirectory> component_services_; std::unique_ptr<base::fuchsia::ServiceDirectory> component_services_;
std::unique_ptr<cr_fuchsia::FakeComponentContext> component_context_; std::unique_ptr<cr_fuchsia::FakeComponentContext> component_context_;
std::unique_ptr<base::fuchsia::ServiceDirectoryClient>
component_services_client_;
FakeComponentState* component_state_ = nullptr; FakeComponentState* component_state_ = nullptr;
// ServiceDirectory into which the CastRunner will publish itself. // ServiceDirectory into which the CastRunner will publish itself.
...@@ -455,4 +473,33 @@ TEST_F(CastRunnerIntegrationTest, ApplicationControllerNotSupported) { ...@@ -455,4 +473,33 @@ TEST_F(CastRunnerIntegrationTest, ApplicationControllerNotSupported) {
ASSERT_TRUE(component_state_); ASSERT_TRUE(component_state_);
EXPECT_FALSE(component_state_->controller_receiver()->controller()); EXPECT_FALSE(component_state_->controller_receiver()->controller());
} }
// Verify that we can connect to the Lifecycle interface and terminate the
// component. Service connection is sent immediately after the component start
// request, so this test also verifies that the component doesn't start handling
// incoming service requests before the service has been published.
TEST_F(CastRunnerIntegrationTest, Lifecycle) {
const char kCastChannelAppId[] = "00000001";
const char kCastChannelAppPath[] = "/defaultresponse";
provide_controller_receiver_ = false;
app_config_manager_.AddAppMapping(kCastChannelAppId,
test_server_.GetURL(kCastChannelAppPath));
fuchsia::sys::ComponentControllerPtr component_controller =
StartCastComponent(base::StringPrintf("cast:%s", kCastChannelAppId));
fuchsia::modular::LifecyclePtr lifecycle;
component_services_client_->ConnectToService(lifecycle.NewRequest());
lifecycle->Terminate();
base::RunLoop run_loop;
component_controller.set_error_handler([&run_loop](zx_status_t status) {
EXPECT_EQ(status, ZX_ERR_PEER_CLOSED);
run_loop.Quit();
});
run_loop.Run();
}
} // namespace castrunner } // namespace castrunner
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
#include <fuchsia/netstack/cpp/fidl.h> #include <fuchsia/netstack/cpp/fidl.h>
#include <fuchsia/sysmem/cpp/fidl.h> #include <fuchsia/sysmem/cpp/fidl.h>
#include <fuchsia/ui/scenic/cpp/fidl.h> #include <fuchsia/ui/scenic/cpp/fidl.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/sys/cpp/service_directory.h>
#include <memory> #include <memory>
#include <utility> #include <utility>
...@@ -23,8 +26,8 @@ ...@@ -23,8 +26,8 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/containers/span.h" #include "base/containers/span.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/fuchsia/default_context.h"
#include "base/fuchsia/filtered_service_directory.h" #include "base/fuchsia/filtered_service_directory.h"
#include "base/fuchsia/service_directory_client.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/process/launch.h" #include "base/process/launch.h"
#include "base/process/process.h" #include "base/process/process.h"
...@@ -149,7 +152,7 @@ void SandboxPolicyFuchsia::Initialize(service_manager::SandboxType type) { ...@@ -149,7 +152,7 @@ void SandboxPolicyFuchsia::Initialize(service_manager::SandboxType type) {
service_directory_task_runner_ = base::ThreadTaskRunnerHandle::Get(); service_directory_task_runner_ = base::ThreadTaskRunnerHandle::Get();
service_directory_ = service_directory_ =
std::make_unique<base::fuchsia::FilteredServiceDirectory>( std::make_unique<base::fuchsia::FilteredServiceDirectory>(
base::fuchsia::ServiceDirectoryClient::ForCurrentProcess()); base::fuchsia::ComponentContextForCurrentProcess()->svc().get());
for (const char* service_name : kDefaultServices) { for (const char* service_name : kDefaultServices) {
service_directory_->AddService(service_name); service_directory_->AddService(service_name);
} }
...@@ -158,7 +161,7 @@ void SandboxPolicyFuchsia::Initialize(service_manager::SandboxType type) { ...@@ -158,7 +161,7 @@ void SandboxPolicyFuchsia::Initialize(service_manager::SandboxType type) {
} }
// Bind the service directory and store the client channel for // Bind the service directory and store the client channel for
// UpdateLaunchOptionsForSandbox()'s use. // UpdateLaunchOptionsForSandbox()'s use.
service_directory_client_ = service_directory_->ConnectClient(); service_directory_->ConnectClient(service_directory_client_.NewRequest());
CHECK(service_directory_client_); CHECK(service_directory_client_);
} }
} }
......
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