// 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 #include #include #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 class StrongAssociatedBinding; template using StrongAssociatedBindingPtr = base::WeakPtr>; // 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::Create() (see below) or the helper // MakeStrongAssociatedBinding function: // // mojo::MakeStrongAssociatedBinding(base::MakeUnique(), // std::move(foo_request)); // template class StrongAssociatedBinding { public: // 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 Create( std::unique_ptr impl, AssociatedInterfaceRequest 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(const base::Closure& error_handler) { DCHECK(binding_.is_bound()); connection_error_handler_ = error_handler; connection_error_with_reason_handler_.Reset(); } void set_connection_error_with_reason_handler( const ConnectionErrorWithReasonCallback& error_handler) { DCHECK(binding_.is_bound()); connection_error_with_reason_handler_ = 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(); } private: StrongAssociatedBinding(std::unique_ptr impl, AssociatedInterfaceRequest 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_.is_null()) connection_error_handler_.Run(); else if (!connection_error_with_reason_handler_.is_null()) connection_error_with_reason_handler_.Run(custom_reason, description); Close(); } std::unique_ptr impl_; base::Closure connection_error_handler_; ConnectionErrorWithReasonCallback connection_error_with_reason_handler_; AssociatedBinding binding_; base::WeakPtrFactory weak_factory_; DISALLOW_COPY_AND_ASSIGN(StrongAssociatedBinding); }; template StrongAssociatedBindingPtr MakeStrongAssociatedBinding( std::unique_ptr impl, AssociatedInterfaceRequest request) { return StrongAssociatedBinding::Create(std::move(impl), std::move(request)); } } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_STRONG_ASSOCIATED_BINDING_H_