scoped_service_binding.h 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_FUCHSIA_SCOPED_SERVICE_BINDING_H_
  5. #define BASE_FUCHSIA_SCOPED_SERVICE_BINDING_H_
  6. #include <lib/fidl/cpp/binding.h>
  7. #include <lib/fidl/cpp/binding_set.h>
  8. #include <lib/zx/channel.h>
  9. #include "base/base_export.h"
  10. #include "base/callback.h"
  11. namespace sys {
  12. class OutgoingDirectory;
  13. } // namespace sys
  14. namespace vfs {
  15. class PseudoDir;
  16. } // namespace vfs
  17. namespace base {
  18. namespace fuchsia {
  19. namespace internal {
  20. class BASE_EXPORT ScopedServiceBindingBase {
  21. public:
  22. explicit ScopedServiceBindingBase(sys::OutgoingDirectory* outgoing_directory);
  23. explicit ScopedServiceBindingBase(vfs::PseudoDir* pseudo_dir);
  24. ~ScopedServiceBindingBase();
  25. protected:
  26. // Same type as vfs::Service::Connector, so the value can be passed directly
  27. // to vfs::Service.
  28. using Connector =
  29. fit::function<void(zx::channel channel, async_dispatcher_t* dispatcher)>;
  30. void RegisterService(const char* service_name, Connector connector);
  31. void UnregisterService(const char* service_name);
  32. private:
  33. vfs::PseudoDir* const pseudo_dir_ = nullptr;
  34. };
  35. } // namespace internal
  36. template <typename Interface>
  37. class ScopedServiceBinding : public internal::ScopedServiceBindingBase {
  38. public:
  39. // Published a public service in the specified |outgoing_directory|.
  40. // |outgoing_directory| and |impl| must outlive the binding.
  41. ScopedServiceBinding(sys::OutgoingDirectory* outgoing_directory,
  42. Interface* impl)
  43. : ScopedServiceBindingBase(outgoing_directory), impl_(impl) {
  44. RegisterService(Interface::Name_,
  45. fit::bind_member(this, &ScopedServiceBinding::BindClient));
  46. }
  47. // Publishes a service in the specified |pseudo_dir|. |pseudo_dir| and |impl|
  48. // must outlive the binding.
  49. ScopedServiceBinding(vfs::PseudoDir* pseudo_dir, Interface* impl)
  50. : ScopedServiceBindingBase(pseudo_dir), impl_(impl) {
  51. RegisterService(Interface::Name_,
  52. fit::bind_member(this, &ScopedServiceBinding::BindClient));
  53. }
  54. ~ScopedServiceBinding() { UnregisterService(Interface::Name_); }
  55. void SetOnLastClientCallback(base::OnceClosure on_last_client_callback) {
  56. on_last_client_callback_ = std::move(on_last_client_callback);
  57. bindings_.set_empty_set_handler(
  58. fit::bind_member(this, &ScopedServiceBinding::OnBindingSetEmpty));
  59. }
  60. bool has_clients() const { return bindings_.size() != 0; }
  61. private:
  62. void BindClient(zx::channel channel, async_dispatcher_t* dispatcher) {
  63. bindings_.AddBinding(impl_,
  64. fidl::InterfaceRequest<Interface>(std::move(channel)),
  65. dispatcher);
  66. }
  67. void OnBindingSetEmpty() {
  68. bindings_.set_empty_set_handler(nullptr);
  69. std::move(on_last_client_callback_).Run();
  70. }
  71. sys::OutgoingDirectory* const directory_ = nullptr;
  72. vfs::PseudoDir* const pseudo_dir_ = nullptr;
  73. Interface* const impl_;
  74. fidl::BindingSet<Interface> bindings_;
  75. base::OnceClosure on_last_client_callback_;
  76. DISALLOW_COPY_AND_ASSIGN(ScopedServiceBinding);
  77. };
  78. // Scoped service binding which allows only a single client to be connected
  79. // at any time. By default a new connection will disconnect an existing client.
  80. enum class ScopedServiceBindingPolicy { kPreferNew, kPreferExisting };
  81. template <typename Interface,
  82. ScopedServiceBindingPolicy Policy =
  83. ScopedServiceBindingPolicy::kPreferNew>
  84. class ScopedSingleClientServiceBinding
  85. : public internal::ScopedServiceBindingBase {
  86. public:
  87. // |outgoing_directory| and |impl| must outlive the binding.
  88. ScopedSingleClientServiceBinding(sys::OutgoingDirectory* outgoing_directory,
  89. Interface* impl)
  90. : ScopedServiceBindingBase(outgoing_directory), binding_(impl) {
  91. RegisterService(
  92. Interface::Name_,
  93. fit::bind_member(this, &ScopedSingleClientServiceBinding::BindClient));
  94. }
  95. ~ScopedSingleClientServiceBinding() { UnregisterService(Interface::Name_); }
  96. typename Interface::EventSender_& events() { return binding_.events(); }
  97. void SetOnLastClientCallback(base::OnceClosure on_last_client_callback) {
  98. on_last_client_callback_ = std::move(on_last_client_callback);
  99. binding_.set_error_handler(fit::bind_member(
  100. this, &ScopedSingleClientServiceBinding::OnBindingEmpty));
  101. }
  102. bool has_clients() const { return binding_.is_bound(); }
  103. private:
  104. void BindClient(zx::channel channel, async_dispatcher_t* dispatcher) {
  105. if (Policy == ScopedServiceBindingPolicy::kPreferExisting &&
  106. binding_.is_bound()) {
  107. return;
  108. }
  109. binding_.Bind(fidl::InterfaceRequest<Interface>(std::move(channel)),
  110. dispatcher);
  111. }
  112. void OnBindingEmpty(zx_status_t status) {
  113. binding_.set_error_handler(nullptr);
  114. std::move(on_last_client_callback_).Run();
  115. }
  116. fidl::Binding<Interface> binding_;
  117. base::OnceClosure on_last_client_callback_;
  118. DISALLOW_COPY_AND_ASSIGN(ScopedSingleClientServiceBinding);
  119. };
  120. } // namespace fuchsia
  121. } // namespace base
  122. #endif // BASE_FUCHSIA_SCOPED_SERVICE_BINDING_H_