xref: /aosp_15_r20/external/cronet/base/fuchsia/scoped_service_binding.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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