1 // Copyright 2014 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 5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_ 6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_ 7 8 #include <stdint.h> 9 10 #include <algorithm> // For |std::swap()|. 11 #include <memory> 12 #include <string> 13 #include <utility> 14 15 #include "base/bind.h" 16 #include "base/callback_forward.h" 17 #include "base/logging.h" 18 #include "base/macros.h" 19 #include "base/memory/ptr_util.h" 20 #include "base/memory/ref_counted.h" 21 #include "base/sequenced_task_runner.h" 22 #include "mojo/public/cpp/bindings/associated_group.h" 23 #include "mojo/public/cpp/bindings/bindings_export.h" 24 #include "mojo/public/cpp/bindings/connection_error_callback.h" 25 #include "mojo/public/cpp/bindings/filter_chain.h" 26 #include "mojo/public/cpp/bindings/interface_endpoint_client.h" 27 #include "mojo/public/cpp/bindings/interface_id.h" 28 #include "mojo/public/cpp/bindings/interface_ptr_info.h" 29 #include "mojo/public/cpp/bindings/lib/multiplex_router.h" 30 #include "mojo/public/cpp/bindings/message_header_validator.h" 31 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" 32 33 namespace mojo { 34 namespace internal { 35 36 class MOJO_CPP_BINDINGS_EXPORT InterfacePtrStateBase { 37 public: 38 InterfacePtrStateBase(); 39 ~InterfacePtrStateBase(); 40 41 MessagePipeHandle handle() const { 42 return router_ ? router_->handle() : handle_.get(); 43 } 44 45 uint32_t version() const { return version_; } 46 47 bool is_bound() const { return handle_.is_valid() || endpoint_client_; } 48 49 bool encountered_error() const { 50 return endpoint_client_ ? endpoint_client_->encountered_error() : false; 51 } 52 53 bool HasAssociatedInterfaces() const { 54 return router_ ? router_->HasAssociatedEndpoints() : false; 55 } 56 57 // Returns true if bound and awaiting a response to a message. 58 bool has_pending_callbacks() const { 59 return endpoint_client_ && endpoint_client_->has_pending_responders(); 60 } 61 62 protected: 63 InterfaceEndpointClient* endpoint_client() const { 64 return endpoint_client_.get(); 65 } 66 MultiplexRouter* router() const { return router_.get(); } 67 68 void QueryVersion(const base::Callback<void(uint32_t)>& callback); 69 void RequireVersion(uint32_t version); 70 void Swap(InterfacePtrStateBase* other); 71 void Bind(ScopedMessagePipeHandle handle, 72 uint32_t version, 73 scoped_refptr<base::SequencedTaskRunner> task_runner); 74 75 ScopedMessagePipeHandle PassMessagePipe() { 76 endpoint_client_.reset(); 77 return router_ ? router_->PassMessagePipe() : std::move(handle_); 78 } 79 80 bool InitializeEndpointClient( 81 bool passes_associated_kinds, 82 bool has_sync_methods, 83 std::unique_ptr<MessageReceiver> payload_validator); 84 85 private: 86 void OnQueryVersion(const base::Callback<void(uint32_t)>& callback, 87 uint32_t version); 88 89 scoped_refptr<MultiplexRouter> router_; 90 91 std::unique_ptr<InterfaceEndpointClient> endpoint_client_; 92 93 // |router_| (as well as other members above) is not initialized until 94 // read/write with the message pipe handle is needed. |handle_| is valid 95 // between the Bind() call and the initialization of |router_|. 96 ScopedMessagePipeHandle handle_; 97 scoped_refptr<base::SequencedTaskRunner> runner_; 98 99 uint32_t version_ = 0; 100 101 DISALLOW_COPY_AND_ASSIGN(InterfacePtrStateBase); 102 }; 103 104 template <typename Interface> 105 class InterfacePtrState : public InterfacePtrStateBase { 106 public: 107 using Proxy = typename Interface::Proxy_; 108 109 InterfacePtrState() = default; 110 ~InterfacePtrState() = default; 111 112 Proxy* instance() { 113 ConfigureProxyIfNecessary(); 114 115 // This will be null if the object is not bound. 116 return proxy_.get(); 117 } 118 119 void QueryVersion(const base::Callback<void(uint32_t)>& callback) { 120 ConfigureProxyIfNecessary(); 121 InterfacePtrStateBase::QueryVersion(callback); 122 } 123 124 void RequireVersion(uint32_t version) { 125 ConfigureProxyIfNecessary(); 126 InterfacePtrStateBase::RequireVersion(version); 127 } 128 129 void FlushForTesting() { 130 ConfigureProxyIfNecessary(); 131 endpoint_client()->FlushForTesting(); 132 } 133 134 void CloseWithReason(uint32_t custom_reason, const std::string& description) { 135 ConfigureProxyIfNecessary(); 136 endpoint_client()->CloseWithReason(custom_reason, description); 137 } 138 139 void Swap(InterfacePtrState* other) { 140 using std::swap; 141 swap(other->proxy_, proxy_); 142 InterfacePtrStateBase::Swap(other); 143 } 144 145 void Bind(InterfacePtrInfo<Interface> info, 146 scoped_refptr<base::SequencedTaskRunner> runner) { 147 DCHECK(!proxy_); 148 InterfacePtrStateBase::Bind(info.PassHandle(), info.version(), 149 std::move(runner)); 150 } 151 152 // After this method is called, the object is in an invalid state and 153 // shouldn't be reused. 154 InterfacePtrInfo<Interface> PassInterface() { 155 proxy_.reset(); 156 return InterfacePtrInfo<Interface>(PassMessagePipe(), version()); 157 } 158 159 void set_connection_error_handler(base::OnceClosure error_handler) { 160 ConfigureProxyIfNecessary(); 161 162 DCHECK(endpoint_client()); 163 endpoint_client()->set_connection_error_handler(std::move(error_handler)); 164 } 165 166 void set_connection_error_with_reason_handler( 167 ConnectionErrorWithReasonCallback error_handler) { 168 ConfigureProxyIfNecessary(); 169 170 DCHECK(endpoint_client()); 171 endpoint_client()->set_connection_error_with_reason_handler( 172 std::move(error_handler)); 173 } 174 175 AssociatedGroup* associated_group() { 176 ConfigureProxyIfNecessary(); 177 return endpoint_client()->associated_group(); 178 } 179 180 void EnableTestingMode() { 181 ConfigureProxyIfNecessary(); 182 router()->EnableTestingMode(); 183 } 184 185 void ForwardMessage(Message message) { 186 ConfigureProxyIfNecessary(); 187 endpoint_client()->Accept(&message); 188 } 189 190 void ForwardMessageWithResponder(Message message, 191 std::unique_ptr<MessageReceiver> responder) { 192 ConfigureProxyIfNecessary(); 193 endpoint_client()->AcceptWithResponder(&message, std::move(responder)); 194 } 195 196 void RaiseError() { 197 ConfigureProxyIfNecessary(); 198 endpoint_client()->RaiseError(); 199 } 200 201 private: 202 void ConfigureProxyIfNecessary() { 203 // The proxy has been configured. 204 if (proxy_) { 205 DCHECK(router()); 206 DCHECK(endpoint_client()); 207 return; 208 } 209 210 if (InitializeEndpointClient( 211 Interface::PassesAssociatedKinds_, Interface::HasSyncMethods_, 212 std::make_unique<typename Interface::ResponseValidator_>())) { 213 router()->SetMasterInterfaceName(Interface::Name_); 214 proxy_ = std::make_unique<Proxy>(endpoint_client()); 215 } 216 } 217 218 std::unique_ptr<Proxy> proxy_; 219 220 DISALLOW_COPY_AND_ASSIGN(InterfacePtrState); 221 }; 222 223 } // namespace internal 224 } // namespace mojo 225 226 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_ 227