// Copyright 2014 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_LIB_INTERFACE_PTR_STATE_H_ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_ #include #include // For |std::swap()|. #include #include #include #include "base/bind.h" #include "base/callback_forward.h" #include "base/logging.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" #include "base/sequenced_task_runner.h" #include "mojo/public/cpp/bindings/associated_group.h" #include "mojo/public/cpp/bindings/bindings_export.h" #include "mojo/public/cpp/bindings/connection_error_callback.h" #include "mojo/public/cpp/bindings/filter_chain.h" #include "mojo/public/cpp/bindings/interface_endpoint_client.h" #include "mojo/public/cpp/bindings/interface_id.h" #include "mojo/public/cpp/bindings/interface_ptr_info.h" #include "mojo/public/cpp/bindings/lib/multiplex_router.h" #include "mojo/public/cpp/bindings/message_header_validator.h" #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" namespace mojo { namespace internal { class MOJO_CPP_BINDINGS_EXPORT InterfacePtrStateBase { public: InterfacePtrStateBase(); ~InterfacePtrStateBase(); MessagePipeHandle handle() const { return router_ ? router_->handle() : handle_.get(); } uint32_t version() const { return version_; } bool is_bound() const { return handle_.is_valid() || endpoint_client_; } bool encountered_error() const { return endpoint_client_ ? endpoint_client_->encountered_error() : false; } bool HasAssociatedInterfaces() const { return router_ ? router_->HasAssociatedEndpoints() : false; } // Returns true if bound and awaiting a response to a message. bool has_pending_callbacks() const { return endpoint_client_ && endpoint_client_->has_pending_responders(); } protected: InterfaceEndpointClient* endpoint_client() const { return endpoint_client_.get(); } MultiplexRouter* router() const { return router_.get(); } void QueryVersion(const base::Callback& callback); void RequireVersion(uint32_t version); void Swap(InterfacePtrStateBase* other); void Bind(ScopedMessagePipeHandle handle, uint32_t version, scoped_refptr task_runner); ScopedMessagePipeHandle PassMessagePipe() { endpoint_client_.reset(); return router_ ? router_->PassMessagePipe() : std::move(handle_); } bool InitializeEndpointClient( bool passes_associated_kinds, bool has_sync_methods, std::unique_ptr payload_validator); private: void OnQueryVersion(const base::Callback& callback, uint32_t version); scoped_refptr router_; std::unique_ptr endpoint_client_; // |router_| (as well as other members above) is not initialized until // read/write with the message pipe handle is needed. |handle_| is valid // between the Bind() call and the initialization of |router_|. ScopedMessagePipeHandle handle_; scoped_refptr runner_; uint32_t version_ = 0; DISALLOW_COPY_AND_ASSIGN(InterfacePtrStateBase); }; template class InterfacePtrState : public InterfacePtrStateBase { public: using Proxy = typename Interface::Proxy_; InterfacePtrState() = default; ~InterfacePtrState() = default; Proxy* instance() { ConfigureProxyIfNecessary(); // This will be null if the object is not bound. return proxy_.get(); } void QueryVersion(const base::Callback& callback) { ConfigureProxyIfNecessary(); InterfacePtrStateBase::QueryVersion(callback); } void RequireVersion(uint32_t version) { ConfigureProxyIfNecessary(); InterfacePtrStateBase::RequireVersion(version); } void FlushForTesting() { ConfigureProxyIfNecessary(); endpoint_client()->FlushForTesting(); } void CloseWithReason(uint32_t custom_reason, const std::string& description) { ConfigureProxyIfNecessary(); endpoint_client()->CloseWithReason(custom_reason, description); } void Swap(InterfacePtrState* other) { using std::swap; swap(other->proxy_, proxy_); InterfacePtrStateBase::Swap(other); } void Bind(InterfacePtrInfo info, scoped_refptr runner) { DCHECK(!proxy_); InterfacePtrStateBase::Bind(info.PassHandle(), info.version(), std::move(runner)); } // After this method is called, the object is in an invalid state and // shouldn't be reused. InterfacePtrInfo PassInterface() { proxy_.reset(); return InterfacePtrInfo(PassMessagePipe(), version()); } void set_connection_error_handler(base::OnceClosure error_handler) { ConfigureProxyIfNecessary(); DCHECK(endpoint_client()); endpoint_client()->set_connection_error_handler(std::move(error_handler)); } void set_connection_error_with_reason_handler( ConnectionErrorWithReasonCallback error_handler) { ConfigureProxyIfNecessary(); DCHECK(endpoint_client()); endpoint_client()->set_connection_error_with_reason_handler( std::move(error_handler)); } AssociatedGroup* associated_group() { ConfigureProxyIfNecessary(); return endpoint_client()->associated_group(); } void EnableTestingMode() { ConfigureProxyIfNecessary(); router()->EnableTestingMode(); } void ForwardMessage(Message message) { ConfigureProxyIfNecessary(); endpoint_client()->Accept(&message); } void ForwardMessageWithResponder(Message message, std::unique_ptr responder) { ConfigureProxyIfNecessary(); endpoint_client()->AcceptWithResponder(&message, std::move(responder)); } void RaiseError() { ConfigureProxyIfNecessary(); endpoint_client()->RaiseError(); } private: void ConfigureProxyIfNecessary() { // The proxy has been configured. if (proxy_) { DCHECK(router()); DCHECK(endpoint_client()); return; } if (InitializeEndpointClient( Interface::PassesAssociatedKinds_, Interface::HasSyncMethods_, std::make_unique())) { router()->SetMasterInterfaceName(Interface::Name_); proxy_ = std::make_unique(endpoint_client()); } } std::unique_ptr proxy_; DISALLOW_COPY_AND_ASSIGN(InterfacePtrState); }; } // namespace internal } // namespace mojo #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_