| // Copyright 2016 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 MOJO_PUBLIC_CPP_BINDINGS_STRONG_ASSOCIATED_BINDING_H_ |
| #define MOJO_PUBLIC_CPP_BINDINGS_STRONG_ASSOCIATED_BINDING_H_ |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/memory/weak_ptr.h" |
| #include "mojo/public/cpp/bindings/associated_binding.h" |
| #include "mojo/public/cpp/bindings/associated_interface_request.h" |
| #include "mojo/public/cpp/bindings/connection_error_callback.h" |
| #include "mojo/public/cpp/system/core.h" |
| |
| namespace mojo { |
| |
| template <typename Interface> |
| class StrongAssociatedBinding; |
| |
| template <typename Interface> |
| using StrongAssociatedBindingPtr = |
| base::WeakPtr<StrongAssociatedBinding<Interface>>; |
| |
| // This connects an interface implementation strongly to an associated pipe. |
| // When a connection error is detected the implementation is deleted. If the |
| // task runner that a StrongAssociatedBinding is bound on is stopped, the |
| // connection error handler will not be invoked and the implementation will not |
| // be deleted. |
| // |
| // To use, call StrongAssociatedBinding<T>::Create() (see below) or the helper |
| // MakeStrongAssociatedBinding function: |
| // |
| // mojo::MakeStrongAssociatedBinding(std::make_unique<FooImpl>(), |
| // std::move(foo_request)); |
| // |
| template <typename Interface> |
| class StrongAssociatedBinding { |
| public: |
| using ImplPointerType = |
| typename AssociatedBinding<Interface>::ImplPointerType; |
| |
| // Create a new StrongAssociatedBinding instance. The instance owns itself, |
| // cleaning up only in the event of a pipe connection error. Returns a WeakPtr |
| // to the new StrongAssociatedBinding instance. |
| static StrongAssociatedBindingPtr<Interface> Create( |
| std::unique_ptr<Interface> impl, |
| AssociatedInterfaceRequest<Interface> request) { |
| StrongAssociatedBinding* binding = |
| new StrongAssociatedBinding(std::move(impl), std::move(request)); |
| return binding->weak_factory_.GetWeakPtr(); |
| } |
| |
| // Note: The error handler must not delete the interface implementation. |
| // |
| // This method may only be called after this StrongAssociatedBinding has been |
| // bound to a message pipe. |
| void set_connection_error_handler(base::OnceClosure error_handler) { |
| DCHECK(binding_.is_bound()); |
| connection_error_handler_ = std::move(error_handler); |
| connection_error_with_reason_handler_.Reset(); |
| } |
| |
| void set_connection_error_with_reason_handler( |
| ConnectionErrorWithReasonCallback error_handler) { |
| DCHECK(binding_.is_bound()); |
| connection_error_with_reason_handler_ = std::move(error_handler); |
| connection_error_handler_.Reset(); |
| } |
| |
| // Forces the binding to close. This destroys the StrongBinding instance. |
| void Close() { delete this; } |
| |
| Interface* impl() { return impl_.get(); } |
| |
| // Sends a message on the underlying message pipe and runs the current |
| // message loop until its response is received. This can be used in tests to |
| // verify that no message was sent on a message pipe in response to some |
| // stimulus. |
| void FlushForTesting() { binding_.FlushForTesting(); } |
| |
| // Allows test code to swap the interface implementation. |
| ImplPointerType SwapImplForTesting(ImplPointerType new_impl) { |
| return binding_.SwapImplForTesting(new_impl); |
| } |
| |
| private: |
| StrongAssociatedBinding(std::unique_ptr<Interface> impl, |
| AssociatedInterfaceRequest<Interface> request) |
| : impl_(std::move(impl)), |
| binding_(impl_.get(), std::move(request)), |
| weak_factory_(this) { |
| binding_.set_connection_error_with_reason_handler(base::Bind( |
| &StrongAssociatedBinding::OnConnectionError, base::Unretained(this))); |
| } |
| |
| ~StrongAssociatedBinding() {} |
| |
| void OnConnectionError(uint32_t custom_reason, |
| const std::string& description) { |
| if (connection_error_handler_) { |
| std::move(connection_error_handler_).Run(); |
| } else if (connection_error_with_reason_handler_) { |
| std::move(connection_error_with_reason_handler_) |
| .Run(custom_reason, description); |
| } |
| Close(); |
| } |
| |
| std::unique_ptr<Interface> impl_; |
| base::OnceClosure connection_error_handler_; |
| ConnectionErrorWithReasonCallback connection_error_with_reason_handler_; |
| AssociatedBinding<Interface> binding_; |
| base::WeakPtrFactory<StrongAssociatedBinding> weak_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(StrongAssociatedBinding); |
| }; |
| |
| template <typename Interface, typename Impl> |
| StrongAssociatedBindingPtr<Interface> MakeStrongAssociatedBinding( |
| std::unique_ptr<Impl> impl, |
| AssociatedInterfaceRequest<Interface> request) { |
| return StrongAssociatedBinding<Interface>::Create(std::move(impl), |
| std::move(request)); |
| } |
| |
| } // namespace mojo |
| |
| #endif // MOJO_PUBLIC_CPP_BINDINGS_STRONG_ASSOCIATED_BINDING_H_ |