1*6777b538SAndroid Build Coastguard Worker // Copyright 2018 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_FUCHSIA_SCOPED_SERVICE_BINDING_H_ 6*6777b538SAndroid Build Coastguard Worker #define BASE_FUCHSIA_SCOPED_SERVICE_BINDING_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1427626): Remove this include once the explicit 9*6777b538SAndroid Build Coastguard Worker // async_get_default_dispatcher() is no longer needed. 10*6777b538SAndroid Build Coastguard Worker #include <lib/async/default.h> 11*6777b538SAndroid Build Coastguard Worker #include <lib/fidl/cpp/binding.h> 12*6777b538SAndroid Build Coastguard Worker #include <lib/fidl/cpp/binding_set.h> 13*6777b538SAndroid Build Coastguard Worker #include <lib/fidl/cpp/interface_request.h> 14*6777b538SAndroid Build Coastguard Worker #include <lib/fidl/cpp/wire/connect_service.h> 15*6777b538SAndroid Build Coastguard Worker #include <lib/zx/channel.h> 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Worker #include <optional> 18*6777b538SAndroid Build Coastguard Worker #include <string_view> 19*6777b538SAndroid Build Coastguard Worker #include <utility> 20*6777b538SAndroid Build Coastguard Worker 21*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h" 22*6777b538SAndroid Build Coastguard Worker #include "base/fuchsia/scoped_service_publisher.h" 23*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h" 24*6777b538SAndroid Build Coastguard Worker 25*6777b538SAndroid Build Coastguard Worker namespace sys { 26*6777b538SAndroid Build Coastguard Worker class OutgoingDirectory; 27*6777b538SAndroid Build Coastguard Worker } // namespace sys 28*6777b538SAndroid Build Coastguard Worker 29*6777b538SAndroid Build Coastguard Worker namespace vfs { 30*6777b538SAndroid Build Coastguard Worker class PseudoDir; 31*6777b538SAndroid Build Coastguard Worker } // namespace vfs 32*6777b538SAndroid Build Coastguard Worker 33*6777b538SAndroid Build Coastguard Worker namespace base { 34*6777b538SAndroid Build Coastguard Worker 35*6777b538SAndroid Build Coastguard Worker template <typename Interface> 36*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT ScopedServiceBinding { 37*6777b538SAndroid Build Coastguard Worker public: 38*6777b538SAndroid Build Coastguard Worker // Publishes a public service in the specified |outgoing_directory|. 39*6777b538SAndroid Build Coastguard Worker // |outgoing_directory| and |impl| must outlive the binding. The service is 40*6777b538SAndroid Build Coastguard Worker // unpublished on destruction. 41*6777b538SAndroid Build Coastguard Worker ScopedServiceBinding(sys::OutgoingDirectory* outgoing_directory, 42*6777b538SAndroid Build Coastguard Worker Interface* impl, 43*6777b538SAndroid Build Coastguard Worker std::string_view name = Interface::Name_) 44*6777b538SAndroid Build Coastguard Worker : publisher_(outgoing_directory, bindings_.GetHandler(impl), name) {} 45*6777b538SAndroid Build Coastguard Worker 46*6777b538SAndroid Build Coastguard Worker // Publishes a service in the specified |pseudo_dir|. |pseudo_dir| and |impl| 47*6777b538SAndroid Build Coastguard Worker // must outlive the binding. The service is unpublished on destruction. 48*6777b538SAndroid Build Coastguard Worker ScopedServiceBinding(vfs::PseudoDir* pseudo_dir, 49*6777b538SAndroid Build Coastguard Worker Interface* impl, 50*6777b538SAndroid Build Coastguard Worker std::string_view name = Interface::Name_) 51*6777b538SAndroid Build Coastguard Worker : publisher_(pseudo_dir, bindings_.GetHandler(impl), name) {} 52*6777b538SAndroid Build Coastguard Worker 53*6777b538SAndroid Build Coastguard Worker ScopedServiceBinding(const ScopedServiceBinding&) = delete; 54*6777b538SAndroid Build Coastguard Worker ScopedServiceBinding& operator=(const ScopedServiceBinding&) = delete; 55*6777b538SAndroid Build Coastguard Worker 56*6777b538SAndroid Build Coastguard Worker ~ScopedServiceBinding() = default; 57*6777b538SAndroid Build Coastguard Worker 58*6777b538SAndroid Build Coastguard Worker // |on_last_client_callback| will be called every time the number of connected 59*6777b538SAndroid Build Coastguard Worker // clients drops to 0. SetOnLastClientCallback(base::RepeatingClosure on_last_client_callback)60*6777b538SAndroid Build Coastguard Worker void SetOnLastClientCallback(base::RepeatingClosure on_last_client_callback) { 61*6777b538SAndroid Build Coastguard Worker bindings_.set_empty_set_handler( 62*6777b538SAndroid Build Coastguard Worker [callback = std::move(on_last_client_callback)] { callback.Run(); }); 63*6777b538SAndroid Build Coastguard Worker } 64*6777b538SAndroid Build Coastguard Worker has_clients()65*6777b538SAndroid Build Coastguard Worker bool has_clients() const { return bindings_.size() != 0; } 66*6777b538SAndroid Build Coastguard Worker 67*6777b538SAndroid Build Coastguard Worker private: 68*6777b538SAndroid Build Coastguard Worker fidl::BindingSet<Interface> bindings_; 69*6777b538SAndroid Build Coastguard Worker ScopedServicePublisher<Interface> publisher_; 70*6777b538SAndroid Build Coastguard Worker }; 71*6777b538SAndroid Build Coastguard Worker 72*6777b538SAndroid Build Coastguard Worker template <typename Protocol> 73*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT ScopedNaturalServiceBinding { 74*6777b538SAndroid Build Coastguard Worker public: 75*6777b538SAndroid Build Coastguard Worker // Publishes a public service in the specified |outgoing_directory|. 76*6777b538SAndroid Build Coastguard Worker // |outgoing_directory| and |impl| must outlive the binding. The service is 77*6777b538SAndroid Build Coastguard Worker // unpublished on destruction. 78*6777b538SAndroid Build Coastguard Worker ScopedNaturalServiceBinding( 79*6777b538SAndroid Build Coastguard Worker sys::OutgoingDirectory* outgoing_directory, 80*6777b538SAndroid Build Coastguard Worker fidl::Server<Protocol>* impl, 81*6777b538SAndroid Build Coastguard Worker std::string_view name = fidl::DiscoverableProtocolName<Protocol>) 82*6777b538SAndroid Build Coastguard Worker : publisher_( 83*6777b538SAndroid Build Coastguard Worker outgoing_directory, 84*6777b538SAndroid Build Coastguard Worker bindings_.CreateHandler( 85*6777b538SAndroid Build Coastguard Worker impl, 86*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1427626): Remove this param once there's an 87*6777b538SAndroid Build Coastguard Worker // overload of `CreateHandler` that doesn't require it. 88*6777b538SAndroid Build Coastguard Worker async_get_default_dispatcher(), 89*6777b538SAndroid Build Coastguard Worker [](fidl::UnbindInfo info) {}), 90*6777b538SAndroid Build Coastguard Worker name) {} 91*6777b538SAndroid Build Coastguard Worker 92*6777b538SAndroid Build Coastguard Worker // Publishes a service in the specified |pseudo_dir|. |pseudo_dir| and |impl| 93*6777b538SAndroid Build Coastguard Worker // must outlive the binding. The service is unpublished on destruction. 94*6777b538SAndroid Build Coastguard Worker ScopedNaturalServiceBinding( 95*6777b538SAndroid Build Coastguard Worker vfs::PseudoDir* pseudo_dir, 96*6777b538SAndroid Build Coastguard Worker fidl::Server<Protocol>* impl, 97*6777b538SAndroid Build Coastguard Worker std::string_view name = fidl::DiscoverableProtocolName<Protocol>) 98*6777b538SAndroid Build Coastguard Worker : publisher_( 99*6777b538SAndroid Build Coastguard Worker pseudo_dir, 100*6777b538SAndroid Build Coastguard Worker bindings_.CreateHandler( 101*6777b538SAndroid Build Coastguard Worker impl, 102*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1427626): Remove this param once there's an 103*6777b538SAndroid Build Coastguard Worker // overload of `CreateHandler` that doesn't require it. 104*6777b538SAndroid Build Coastguard Worker async_get_default_dispatcher(), 105*6777b538SAndroid Build Coastguard Worker [](fidl::UnbindInfo info) {}), 106*6777b538SAndroid Build Coastguard Worker name) {} 107*6777b538SAndroid Build Coastguard Worker 108*6777b538SAndroid Build Coastguard Worker ScopedNaturalServiceBinding(const ScopedNaturalServiceBinding&) = delete; 109*6777b538SAndroid Build Coastguard Worker ScopedNaturalServiceBinding& operator=(const ScopedNaturalServiceBinding&) = 110*6777b538SAndroid Build Coastguard Worker delete; 111*6777b538SAndroid Build Coastguard Worker 112*6777b538SAndroid Build Coastguard Worker ~ScopedNaturalServiceBinding() = default; 113*6777b538SAndroid Build Coastguard Worker 114*6777b538SAndroid Build Coastguard Worker // Registers `on_last_client_callback` to be called every time the number of 115*6777b538SAndroid Build Coastguard Worker // connected clients drops to 0. SetOnLastClientCallback(base::RepeatingClosure on_last_client_callback)116*6777b538SAndroid Build Coastguard Worker void SetOnLastClientCallback(base::RepeatingClosure on_last_client_callback) { 117*6777b538SAndroid Build Coastguard Worker bindings_.set_empty_set_handler( 118*6777b538SAndroid Build Coastguard Worker [callback = std::move(on_last_client_callback)] { callback.Run(); }); 119*6777b538SAndroid Build Coastguard Worker } 120*6777b538SAndroid Build Coastguard Worker has_clients()121*6777b538SAndroid Build Coastguard Worker bool has_clients() const { return bindings_.size() != 0; } 122*6777b538SAndroid Build Coastguard Worker 123*6777b538SAndroid Build Coastguard Worker private: 124*6777b538SAndroid Build Coastguard Worker fidl::ServerBindingGroup<Protocol> bindings_; 125*6777b538SAndroid Build Coastguard Worker ScopedNaturalServicePublisher<Protocol> publisher_; 126*6777b538SAndroid Build Coastguard Worker }; 127*6777b538SAndroid Build Coastguard Worker 128*6777b538SAndroid Build Coastguard Worker // Scoped service binding which allows only a single client to be connected 129*6777b538SAndroid Build Coastguard Worker // at any time. By default a new connection will disconnect an existing client. 130*6777b538SAndroid Build Coastguard Worker enum class ScopedServiceBindingPolicy { 131*6777b538SAndroid Build Coastguard Worker kPreferNew, 132*6777b538SAndroid Build Coastguard Worker kPreferExisting, 133*6777b538SAndroid Build Coastguard Worker kConnectOnce 134*6777b538SAndroid Build Coastguard Worker }; 135*6777b538SAndroid Build Coastguard Worker 136*6777b538SAndroid Build Coastguard Worker template <typename Interface, 137*6777b538SAndroid Build Coastguard Worker ScopedServiceBindingPolicy Policy = 138*6777b538SAndroid Build Coastguard Worker ScopedServiceBindingPolicy::kPreferNew> 139*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT ScopedSingleClientServiceBinding { 140*6777b538SAndroid Build Coastguard Worker public: 141*6777b538SAndroid Build Coastguard Worker // |outgoing_directory| and |impl| must outlive the binding. 142*6777b538SAndroid Build Coastguard Worker ScopedSingleClientServiceBinding(sys::OutgoingDirectory* outgoing_directory, 143*6777b538SAndroid Build Coastguard Worker Interface* impl, 144*6777b538SAndroid Build Coastguard Worker std::string_view name = Interface::Name_) binding_(impl)145*6777b538SAndroid Build Coastguard Worker : binding_(impl) { 146*6777b538SAndroid Build Coastguard Worker publisher_.emplace( 147*6777b538SAndroid Build Coastguard Worker outgoing_directory, 148*6777b538SAndroid Build Coastguard Worker fit::bind_member(this, &ScopedSingleClientServiceBinding::BindClient), 149*6777b538SAndroid Build Coastguard Worker name); 150*6777b538SAndroid Build Coastguard Worker binding_.set_error_handler(fit::bind_member( 151*6777b538SAndroid Build Coastguard Worker this, &ScopedSingleClientServiceBinding::OnBindingEmpty)); 152*6777b538SAndroid Build Coastguard Worker } 153*6777b538SAndroid Build Coastguard Worker 154*6777b538SAndroid Build Coastguard Worker ScopedSingleClientServiceBinding(vfs::PseudoDir* publish_to, 155*6777b538SAndroid Build Coastguard Worker Interface* impl, 156*6777b538SAndroid Build Coastguard Worker std::string_view name = Interface::Name_) binding_(impl)157*6777b538SAndroid Build Coastguard Worker : binding_(impl) { 158*6777b538SAndroid Build Coastguard Worker publisher_.emplace( 159*6777b538SAndroid Build Coastguard Worker publish_to, 160*6777b538SAndroid Build Coastguard Worker fit::bind_member(this, &ScopedSingleClientServiceBinding::BindClient), 161*6777b538SAndroid Build Coastguard Worker name); 162*6777b538SAndroid Build Coastguard Worker binding_.set_error_handler(fit::bind_member( 163*6777b538SAndroid Build Coastguard Worker this, &ScopedSingleClientServiceBinding::OnBindingEmpty)); 164*6777b538SAndroid Build Coastguard Worker } 165*6777b538SAndroid Build Coastguard Worker 166*6777b538SAndroid Build Coastguard Worker ScopedSingleClientServiceBinding(const ScopedSingleClientServiceBinding&) = 167*6777b538SAndroid Build Coastguard Worker delete; 168*6777b538SAndroid Build Coastguard Worker ScopedSingleClientServiceBinding& operator=( 169*6777b538SAndroid Build Coastguard Worker const ScopedSingleClientServiceBinding&) = delete; 170*6777b538SAndroid Build Coastguard Worker 171*6777b538SAndroid Build Coastguard Worker ~ScopedSingleClientServiceBinding() = default; 172*6777b538SAndroid Build Coastguard Worker events()173*6777b538SAndroid Build Coastguard Worker typename Interface::EventSender_& events() { return binding_.events(); } 174*6777b538SAndroid Build Coastguard Worker 175*6777b538SAndroid Build Coastguard Worker // |on_last_client_callback| will be called the first time a client 176*6777b538SAndroid Build Coastguard Worker // disconnects. It is still possible for a client to connect after that point 177*6777b538SAndroid Build Coastguard Worker // if Policy is kPreferNew of kPreferExisting. SetOnLastClientCallback(base::OnceClosure on_last_client_callback)178*6777b538SAndroid Build Coastguard Worker void SetOnLastClientCallback(base::OnceClosure on_last_client_callback) { 179*6777b538SAndroid Build Coastguard Worker on_last_client_callback_ = std::move(on_last_client_callback); 180*6777b538SAndroid Build Coastguard Worker } 181*6777b538SAndroid Build Coastguard Worker has_clients()182*6777b538SAndroid Build Coastguard Worker bool has_clients() const { return binding_.is_bound(); } 183*6777b538SAndroid Build Coastguard Worker 184*6777b538SAndroid Build Coastguard Worker private: BindClient(fidl::InterfaceRequest<Interface> request)185*6777b538SAndroid Build Coastguard Worker void BindClient(fidl::InterfaceRequest<Interface> request) { 186*6777b538SAndroid Build Coastguard Worker if (Policy == ScopedServiceBindingPolicy::kPreferExisting && 187*6777b538SAndroid Build Coastguard Worker binding_.is_bound()) { 188*6777b538SAndroid Build Coastguard Worker return; 189*6777b538SAndroid Build Coastguard Worker } 190*6777b538SAndroid Build Coastguard Worker binding_.Bind(std::move(request)); 191*6777b538SAndroid Build Coastguard Worker if (Policy == ScopedServiceBindingPolicy::kConnectOnce) { 192*6777b538SAndroid Build Coastguard Worker publisher_.reset(); 193*6777b538SAndroid Build Coastguard Worker } 194*6777b538SAndroid Build Coastguard Worker } 195*6777b538SAndroid Build Coastguard Worker OnBindingEmpty(zx_status_t status)196*6777b538SAndroid Build Coastguard Worker void OnBindingEmpty(zx_status_t status) { 197*6777b538SAndroid Build Coastguard Worker if (on_last_client_callback_) { 198*6777b538SAndroid Build Coastguard Worker std::move(on_last_client_callback_).Run(); 199*6777b538SAndroid Build Coastguard Worker } 200*6777b538SAndroid Build Coastguard Worker } 201*6777b538SAndroid Build Coastguard Worker 202*6777b538SAndroid Build Coastguard Worker fidl::Binding<Interface> binding_; 203*6777b538SAndroid Build Coastguard Worker std::optional<ScopedServicePublisher<Interface>> publisher_; 204*6777b538SAndroid Build Coastguard Worker base::OnceClosure on_last_client_callback_; 205*6777b538SAndroid Build Coastguard Worker }; 206*6777b538SAndroid Build Coastguard Worker 207*6777b538SAndroid Build Coastguard Worker } // namespace base 208*6777b538SAndroid Build Coastguard Worker 209*6777b538SAndroid Build Coastguard Worker #endif // BASE_FUCHSIA_SCOPED_SERVICE_BINDING_H_ 210