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

[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: I3e37aa91d89aa6cf0a650754e12222036c23bddd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1659603
Auto-Submit: Sergey Ulanov <sergeyu@chromium.org>
Commit-Queue: Sergey Ulanov <sergeyu@chromium.org>
Reviewed-by: default avatarWez <wez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#680194}
parent 72943981
...@@ -1497,6 +1497,8 @@ jumbo_component("base") { ...@@ -1497,6 +1497,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",
...@@ -1567,6 +1569,7 @@ jumbo_component("base") { ...@@ -1567,6 +1569,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",
] ]
...@@ -1575,9 +1578,9 @@ jumbo_component("base") { ...@@ -1575,9 +1578,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",
] ]
} }
...@@ -2984,7 +2987,6 @@ test("base_unittests") { ...@@ -2984,7 +2987,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",
......
// 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 {
// Returns default sys::ComponentContext for the current process.
sys::ComponentContext* ComponentContextForCurrentProcess() {
static base::NoDestructor<std::unique_ptr<sys::ComponentContext>> value(
sys::ComponentContext::Create());
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);
} }
......
...@@ -6,8 +6,10 @@ ...@@ -6,8 +6,10 @@
#define BASE_FUCHSIA_SCOPED_SERVICE_BINDING_H_ #define BASE_FUCHSIA_SCOPED_SERVICE_BINDING_H_
#include <lib/fidl/cpp/binding_set.h> #include <lib/fidl/cpp/binding_set.h>
#include <lib/sys/cpp/outgoing_directory.h>
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h"
#include "base/fuchsia/service_directory.h" #include "base/fuchsia/service_directory.h"
namespace base { namespace base {
...@@ -16,14 +18,41 @@ namespace fuchsia { ...@@ -16,14 +18,41 @@ namespace fuchsia {
template <typename Interface> template <typename Interface>
class ScopedServiceBinding { class ScopedServiceBinding {
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))); : directory_(outgoing_directory), impl_(impl) {
directory_->AddPublicService<Interface>(
[this](fidl::InterfaceRequest<Interface> request) {
BindClient(std::move(request));
});
}
// Publishes a service in the specified |pseudo_dir|. |pseudo_dir| and |impl|
// must outlive the binding.
ScopedServiceBinding(vfs::PseudoDir* pseudo_dir, Interface* impl)
: pseudo_dir_(pseudo_dir), impl_(impl) {
pseudo_dir_->AddEntry(
Interface::Name_,
std::make_unique<vfs::Service>(fidl::InterfaceRequestHandler<Interface>(
[this](fidl::InterfaceRequest<Interface> request) {
BindClient(std::move(request));
})));
} }
~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() {
if (directory_) {
directory_->RemovePublicService<Interface>();
} else {
pseudo_dir_->RemoveEntry(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);
...@@ -43,7 +72,8 @@ class ScopedServiceBinding { ...@@ -43,7 +72,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_;
...@@ -60,16 +90,26 @@ template <typename Interface, ...@@ -60,16 +90,26 @@ template <typename Interface,
ScopedServiceBindingPolicy::kPreferNew> ScopedServiceBindingPolicy::kPreferNew>
class ScopedSingleClientServiceBinding { class ScopedSingleClientServiceBinding {
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) { : directory_(std::move(outgoing_directory)), binding_(impl) {
directory_->AddService(BindRepeating( directory_->AddPublicService<Interface>(
&ScopedSingleClientServiceBinding::BindClient, Unretained(this))); [this](fidl::InterfaceRequest<Interface> request) {
BindClient(std::move(request));
});
} }
// TODO(crbug.com/974072): Remove this constructor once all code has been
// migrated from base::fuchsia::ServiceDirectory to sys::OutgoingDirectory.
ScopedSingleClientServiceBinding(ServiceDirectory* service_directory,
Interface* impl)
: ScopedSingleClientServiceBinding(
service_directory->outgoing_directory(),
impl) {}
~ScopedSingleClientServiceBinding() { ~ScopedSingleClientServiceBinding() {
directory_->RemoveService(Interface::Name_); directory_->RemovePublicService<Interface>();
} }
typename Interface::EventSender_& events() { return binding_.events(); } typename Interface::EventSender_& events() { return binding_.events(); }
...@@ -85,8 +125,9 @@ class ScopedSingleClientServiceBinding { ...@@ -85,8 +125,9 @@ class ScopedSingleClientServiceBinding {
private: private:
void BindClient(fidl::InterfaceRequest<Interface> request) { void BindClient(fidl::InterfaceRequest<Interface> request) {
if (Policy == ScopedServiceBindingPolicy::kPreferExisting && if (Policy == ScopedServiceBindingPolicy::kPreferExisting &&
binding_.is_bound()) binding_.is_bound()) {
return; return;
}
binding_.Bind(std::move(request)); binding_.Bind(std::move(request));
} }
...@@ -95,7 +136,7 @@ class ScopedSingleClientServiceBinding { ...@@ -95,7 +136,7 @@ class ScopedSingleClientServiceBinding {
std::move(on_last_client_callback_).Run(); std::move(on_last_client_callback_).Run();
} }
ServiceDirectory* const directory_; sys::OutgoingDirectory* 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"
...@@ -22,128 +21,27 @@ ServiceDirectory::ServiceDirectory( ...@@ -22,128 +21,27 @@ ServiceDirectory::ServiceDirectory(
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<ServiceDirectory> directory(
fidl::InterfaceRequest<::fuchsia::io::Directory>( ComponentContextForCurrentProcess()->outgoing().get());
zx::channel(zx_take_startup_handle(PA_DIRECTORY_REQUEST))));
return directory.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/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
...@@ -32,16 +33,14 @@ class ServiceDirectoryTestBase : public testing::Test { ...@@ -32,16 +33,14 @@ class ServiceDirectoryTestBase : public testing::Test {
MessageLoopForIO message_loop_; MessageLoopForIO message_loop_;
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,11 +4,11 @@ ...@@ -4,11 +4,11 @@
#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/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
...@@ -20,7 +20,12 @@ namespace fuchsia { ...@@ -20,7 +20,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,
...@@ -52,27 +57,25 @@ class ServiceProviderImplTest : public testing::Test { ...@@ -52,27 +57,25 @@ class ServiceProviderImplTest : public testing::Test {
MessageLoopForIO message_loop_; MessageLoopForIO message_loop_;
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);
VerifyTestInterface(&stub2, ZX_OK); VerifyTestInterface(&stub2, ZX_OK);
...@@ -80,16 +83,9 @@ TEST_F(ServiceProviderImplTest, ConnectMulti) { ...@@ -80,16 +83,9 @@ 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,92 +5,95 @@ ...@@ -5,92 +5,95 @@
#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));
} }
}
StartupContext::~StartupContext() { component_context_ = std::make_unique<sys::ComponentContext>(
// |additional_services_directory_| needs to be empty for clean teardown. std::move(incoming_services),
if (additional_services_directory_) std::move(startup_info.launch_info.directory_request));
additional_services_directory_->RemoveAllServices();
}
ServiceDirectory* StartupContext::public_services() { service_directory_ =
if (!public_services_ && startup_info_.launch_info.directory_request) { std::make_unique<ServiceDirectory>(component_context_->outgoing().get());
public_services_ = std::make_unique<ServiceDirectory>( service_directory_client_ = std::make_unique<ServiceDirectoryClient>(
fidl::InterfaceRequest<::fuchsia::io::Directory>( component_context_->svc()->CloneChannel());
std::move(startup_info_.launch_info.directory_request)));
}
return public_services_.get();
} }
StartupContext::~StartupContext() = default;
} // namespace fuchsia } // namespace fuchsia
} // namespace base } // namespace base
...@@ -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,32 @@ class BASE_EXPORT StartupContext { ...@@ -26,28 +27,32 @@ 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. Note that all
const ServiceDirectoryClient* incoming_services() const { // outgoing services should be bound immediately after the first call to this
DCHECK(incoming_services_); // API, before returning control to the message loop, at which point we will
return incoming_services_.get(); // start processing service connection requests.
sys::ComponentContext* component_context() const {
return component_context_.get();
} }
// Returns the outgoing directory into which this component binds services. // TODO(crbug.com/974072): These are legacy ServiceDirectory and
// Note that all services should be bound immediately after the first call to // ServiceDirectoryClient. Remove once all clients have been migrated to
// this API, before returning control to the message loop, at which point we // sys::OutgoingDirectory and sys::ServiceDirectory.
// will start processing service connection requests. ServiceDirectoryClient* incoming_services() const {
ServiceDirectory* public_services(); return service_directory_client_.get();
}
ServiceDirectory* public_services() { return service_directory_.get(); }
private: private:
::fuchsia::sys::StartupInfo startup_info_;
std::unique_ptr<ServiceDirectoryClient> incoming_services_;
std::unique_ptr<ServiceDirectory> public_services_;
// 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_;
std::unique_ptr<ServiceDirectory> service_directory_;
std::unique_ptr<ServiceDirectoryClient> service_directory_client_;
DISALLOW_COPY_AND_ASSIGN(StartupContext); DISALLOW_COPY_AND_ASSIGN(StartupContext);
}; };
......
...@@ -23,7 +23,7 @@ int ContextProviderMain() { ...@@ -23,7 +23,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());
......
...@@ -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"
...@@ -144,7 +147,7 @@ void SandboxPolicyFuchsia::Initialize(service_manager::SandboxType type) { ...@@ -144,7 +147,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);
} }
...@@ -153,7 +156,7 @@ void SandboxPolicyFuchsia::Initialize(service_manager::SandboxType type) { ...@@ -153,7 +156,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