scoped_service_binding.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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 <utility>
  7. #include <lib/fidl/cpp/binding.h>
  8. #include <lib/fidl/cpp/binding_set.h>
  9. #include <lib/fidl/cpp/interface_request.h>
  10. #include <lib/zx/channel.h>
  11. #include "base/base_export.h"
  12. #include "base/callback.h"
  13. #include "base/fuchsia/scoped_service_publisher.h"
  14. #include "third_party/abseil-cpp/absl/types/optional.h"
  15. namespace sys {
  16. class OutgoingDirectory;
  17. } // namespace sys
  18. namespace vfs {
  19. class PseudoDir;
  20. } // namespace vfs
  21. namespace base {
  22. template <typename Interface>
  23. class BASE_EXPORT ScopedServiceBinding {
  24. public:
  25. // Published a public service in the specified |outgoing_directory|.
  26. // |outgoing_directory| and |impl| must outlive the binding.
  27. ScopedServiceBinding(sys::OutgoingDirectory* outgoing_directory,
  28. Interface* impl, base::StringPiece name = Interface::Name_)
  29. : publisher_(outgoing_directory, bindings_.GetHandler(impl), name) {}
  30. // Publishes a service in the specified |pseudo_dir|. |pseudo_dir| and |impl|
  31. // must outlive the binding.
  32. ScopedServiceBinding(vfs::PseudoDir* pseudo_dir, Interface* impl,
  33. base::StringPiece name = Interface::Name_)
  34. : publisher_(pseudo_dir, bindings_.GetHandler(impl), name) {}
  35. ScopedServiceBinding(const ScopedServiceBinding&) = delete;
  36. ScopedServiceBinding& operator=(const ScopedServiceBinding&) = delete;
  37. ~ScopedServiceBinding() = default;
  38. // |on_last_client_callback| will be called every time the number of connected
  39. // clients drops to 0.
  40. void SetOnLastClientCallback(base::RepeatingClosure on_last_client_callback) {
  41. bindings_.set_empty_set_handler(
  42. [callback = std::move(on_last_client_callback)] { callback.Run(); });
  43. }
  44. bool has_clients() const { return bindings_.size() != 0; }
  45. private:
  46. fidl::BindingSet<Interface> bindings_;
  47. ScopedServicePublisher<Interface> publisher_;
  48. };
  49. // Scoped service binding which allows only a single client to be connected
  50. // at any time. By default a new connection will disconnect an existing client.
  51. enum class ScopedServiceBindingPolicy {
  52. kPreferNew,
  53. kPreferExisting,
  54. kConnectOnce
  55. };
  56. template <typename Interface,
  57. ScopedServiceBindingPolicy Policy =
  58. ScopedServiceBindingPolicy::kPreferNew>
  59. class BASE_EXPORT ScopedSingleClientServiceBinding {
  60. public:
  61. // |outgoing_directory| and |impl| must outlive the binding.
  62. ScopedSingleClientServiceBinding(sys::OutgoingDirectory* outgoing_directory,
  63. Interface* impl,
  64. base::StringPiece name = Interface::Name_)
  65. : binding_(impl) {
  66. publisher_.emplace(
  67. outgoing_directory,
  68. fit::bind_member(this, &ScopedSingleClientServiceBinding::BindClient),
  69. name);
  70. binding_.set_error_handler(fit::bind_member(
  71. this, &ScopedSingleClientServiceBinding::OnBindingEmpty));
  72. }
  73. ScopedSingleClientServiceBinding(const ScopedSingleClientServiceBinding&) =
  74. delete;
  75. ScopedSingleClientServiceBinding& operator=(
  76. const ScopedSingleClientServiceBinding&) = delete;
  77. ~ScopedSingleClientServiceBinding() = default;
  78. typename Interface::EventSender_& events() { return binding_.events(); }
  79. // |on_last_client_callback| will be called the first time a client
  80. // disconnects. It is still possible for a client to connect after that point
  81. // if Policy is kPreferNew of kPreferExisting.
  82. void SetOnLastClientCallback(base::OnceClosure on_last_client_callback) {
  83. on_last_client_callback_ = std::move(on_last_client_callback);
  84. }
  85. bool has_clients() const { return binding_.is_bound(); }
  86. private:
  87. void BindClient(fidl::InterfaceRequest<Interface> request) {
  88. if (Policy == ScopedServiceBindingPolicy::kPreferExisting &&
  89. binding_.is_bound()) {
  90. return;
  91. }
  92. binding_.Bind(std::move(request));
  93. if (Policy == ScopedServiceBindingPolicy::kConnectOnce) {
  94. publisher_.reset();
  95. }
  96. }
  97. void OnBindingEmpty(zx_status_t status) {
  98. if (on_last_client_callback_) {
  99. std::move(on_last_client_callback_).Run();
  100. }
  101. }
  102. fidl::Binding<Interface> binding_;
  103. absl::optional<ScopedServicePublisher<Interface>> publisher_;
  104. base::OnceClosure on_last_client_callback_;
  105. };
  106. } // namespace base
  107. #endif // BASE_FUCHSIA_SCOPED_SERVICE_BINDING_H_