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 <utility> 13 14 #include "base/bind.h" 15 #include "base/callback_forward.h" 16 #include "base/logging.h" 17 #include "base/macros.h" 18 #include "base/memory/ptr_util.h" 19 #include "base/memory/ref_counted.h" 20 #include "base/single_thread_task_runner.h" 21 #include "mojo/public/cpp/bindings/associated_group.h" 22 #include "mojo/public/cpp/bindings/interface_endpoint_client.h" 23 #include "mojo/public/cpp/bindings/interface_id.h" 24 #include "mojo/public/cpp/bindings/interface_ptr_info.h" 25 #include "mojo/public/cpp/bindings/lib/control_message_proxy.h" 26 #include "mojo/public/cpp/bindings/lib/filter_chain.h" 27 #include "mojo/public/cpp/bindings/lib/multiplex_router.h" 28 #include "mojo/public/cpp/bindings/lib/router.h" 29 #include "mojo/public/cpp/bindings/message_header_validator.h" 30 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" 31 32 namespace mojo { 33 namespace internal { 34 35 template <typename Interface, bool use_multiplex_router> 36 class InterfacePtrState; 37 38 // Uses a single-threaded, dedicated router. If |Interface| doesn't have any 39 // methods to pass associated interface pointers or requests, there won't be 40 // multiple interfaces running on the underlying message pipe. In that case, we 41 // can use this specialization to reduce cost. 42 template <typename Interface> 43 class InterfacePtrState<Interface, false> { 44 public: InterfacePtrState()45 InterfacePtrState() : proxy_(nullptr), router_(nullptr), version_(0u) {} 46 ~InterfacePtrState()47 ~InterfacePtrState() { 48 // Destruction order matters here. We delete |proxy_| first, even though 49 // |router_| may have a reference to it, so that destructors for any request 50 // callbacks still pending can interact with the InterfacePtr. 51 delete proxy_; 52 delete router_; 53 } 54 instance()55 Interface* instance() { 56 ConfigureProxyIfNecessary(); 57 58 // This will be null if the object is not bound. 59 return proxy_; 60 } 61 version()62 uint32_t version() const { return version_; } 63 QueryVersion(const base::Callback<void (uint32_t)> & callback)64 void QueryVersion(const base::Callback<void(uint32_t)>& callback) { 65 ConfigureProxyIfNecessary(); 66 67 // Do a static cast in case the interface contains methods with the same 68 // name. It is safe to capture |this| because the callback won't be run 69 // after this object goes away. 70 static_cast<ControlMessageProxy*>(proxy_)->QueryVersion( 71 base::Bind(&InterfacePtrState::OnQueryVersion, base::Unretained(this), 72 callback)); 73 } 74 RequireVersion(uint32_t version)75 void RequireVersion(uint32_t version) { 76 ConfigureProxyIfNecessary(); 77 78 if (version <= version_) 79 return; 80 81 version_ = version; 82 // Do a static cast in case the interface contains methods with the same 83 // name. 84 static_cast<ControlMessageProxy*>(proxy_)->RequireVersion(version); 85 } 86 Swap(InterfacePtrState * other)87 void Swap(InterfacePtrState* other) { 88 using std::swap; 89 swap(other->proxy_, proxy_); 90 swap(other->router_, router_); 91 handle_.swap(other->handle_); 92 runner_.swap(other->runner_); 93 swap(other->version_, version_); 94 } 95 Bind(InterfacePtrInfo<Interface> info,scoped_refptr<base::SingleThreadTaskRunner> runner)96 void Bind(InterfacePtrInfo<Interface> info, 97 scoped_refptr<base::SingleThreadTaskRunner> runner) { 98 DCHECK(!proxy_); 99 DCHECK(!router_); 100 DCHECK(!handle_.is_valid()); 101 DCHECK_EQ(0u, version_); 102 DCHECK(info.is_valid()); 103 104 handle_ = info.PassHandle(); 105 version_ = info.version(); 106 runner_ = std::move(runner); 107 } 108 HasAssociatedInterfaces()109 bool HasAssociatedInterfaces() const { return false; } 110 111 // After this method is called, the object is in an invalid state and 112 // shouldn't be reused. PassInterface()113 InterfacePtrInfo<Interface> PassInterface() { 114 return InterfacePtrInfo<Interface>( 115 router_ ? router_->PassMessagePipe() : std::move(handle_), version_); 116 } 117 is_bound()118 bool is_bound() const { return handle_.is_valid() || router_; } 119 encountered_error()120 bool encountered_error() const { 121 return router_ ? router_->encountered_error() : false; 122 } 123 set_connection_error_handler(const base::Closure & error_handler)124 void set_connection_error_handler(const base::Closure& error_handler) { 125 ConfigureProxyIfNecessary(); 126 127 DCHECK(router_); 128 router_->set_connection_error_handler(error_handler); 129 } 130 131 // Returns true if bound and awaiting a response to a message. has_pending_callbacks()132 bool has_pending_callbacks() const { 133 return router_ && router_->has_pending_responders(); 134 } 135 associated_group()136 AssociatedGroup* associated_group() { return nullptr; } 137 EnableTestingMode()138 void EnableTestingMode() { 139 ConfigureProxyIfNecessary(); 140 router_->EnableTestingMode(); 141 } 142 143 private: 144 using Proxy = typename Interface::Proxy_; 145 ConfigureProxyIfNecessary()146 void ConfigureProxyIfNecessary() { 147 // The proxy has been configured. 148 if (proxy_) { 149 DCHECK(router_); 150 return; 151 } 152 // The object hasn't been bound. 153 if (!handle_.is_valid()) 154 return; 155 156 FilterChain filters; 157 filters.Append<MessageHeaderValidator>(Interface::Name_); 158 filters.Append<typename Interface::ResponseValidator_>(); 159 160 router_ = new Router(std::move(handle_), std::move(filters), false, 161 std::move(runner_)); 162 163 proxy_ = new Proxy(router_); 164 } 165 OnQueryVersion(const base::Callback<void (uint32_t)> & callback,uint32_t version)166 void OnQueryVersion(const base::Callback<void(uint32_t)>& callback, 167 uint32_t version) { 168 version_ = version; 169 callback.Run(version); 170 } 171 172 Proxy* proxy_; 173 Router* router_; 174 175 // |proxy_| and |router_| are not initialized until read/write with the 176 // message pipe handle is needed. |handle_| is valid between the Bind() call 177 // and the initialization of |proxy_| and |router_|. 178 ScopedMessagePipeHandle handle_; 179 scoped_refptr<base::SingleThreadTaskRunner> runner_; 180 181 uint32_t version_; 182 183 DISALLOW_COPY_AND_ASSIGN(InterfacePtrState); 184 }; 185 186 // Uses a multiplexing router. If |Interface| has methods to pass associated 187 // interface pointers or requests, this specialization should be used. 188 template <typename Interface> 189 class InterfacePtrState<Interface, true> { 190 public: InterfacePtrState()191 InterfacePtrState() : version_(0u) {} 192 ~InterfacePtrState()193 ~InterfacePtrState() { 194 endpoint_client_.reset(); 195 proxy_.reset(); 196 if (router_) 197 router_->CloseMessagePipe(); 198 } 199 instance()200 Interface* instance() { 201 ConfigureProxyIfNecessary(); 202 203 // This will be null if the object is not bound. 204 return proxy_.get(); 205 } 206 version()207 uint32_t version() const { return version_; } 208 QueryVersion(const base::Callback<void (uint32_t)> & callback)209 void QueryVersion(const base::Callback<void(uint32_t)>& callback) { 210 ConfigureProxyIfNecessary(); 211 212 213 // Do a static cast in case the interface contains methods with the same 214 // name. It is safe to capture |this| because the callback won't be run 215 // after this object goes away. 216 static_cast<ControlMessageProxy*>(proxy_.get())->QueryVersion( 217 base::Bind(&InterfacePtrState::OnQueryVersion, base::Unretained(this), 218 callback)); 219 } 220 RequireVersion(uint32_t version)221 void RequireVersion(uint32_t version) { 222 ConfigureProxyIfNecessary(); 223 224 if (version <= version_) 225 return; 226 227 version_ = version; 228 // Do a static cast in case the interface contains methods with the same 229 // name. 230 static_cast<ControlMessageProxy*>(proxy_.get())->RequireVersion(version); 231 } 232 Swap(InterfacePtrState * other)233 void Swap(InterfacePtrState* other) { 234 using std::swap; 235 swap(other->router_, router_); 236 swap(other->endpoint_client_, endpoint_client_); 237 swap(other->proxy_, proxy_); 238 handle_.swap(other->handle_); 239 runner_.swap(other->runner_); 240 swap(other->version_, version_); 241 } 242 Bind(InterfacePtrInfo<Interface> info,scoped_refptr<base::SingleThreadTaskRunner> runner)243 void Bind(InterfacePtrInfo<Interface> info, 244 scoped_refptr<base::SingleThreadTaskRunner> runner) { 245 DCHECK(!router_); 246 DCHECK(!endpoint_client_); 247 DCHECK(!proxy_); 248 DCHECK(!handle_.is_valid()); 249 DCHECK_EQ(0u, version_); 250 DCHECK(info.is_valid()); 251 252 handle_ = info.PassHandle(); 253 version_ = info.version(); 254 runner_ = std::move(runner); 255 } 256 HasAssociatedInterfaces()257 bool HasAssociatedInterfaces() const { 258 return router_ ? router_->HasAssociatedEndpoints() : false; 259 } 260 261 // After this method is called, the object is in an invalid state and 262 // shouldn't be reused. PassInterface()263 InterfacePtrInfo<Interface> PassInterface() { 264 endpoint_client_.reset(); 265 proxy_.reset(); 266 return InterfacePtrInfo<Interface>( 267 router_ ? router_->PassMessagePipe() : std::move(handle_), version_); 268 } 269 is_bound()270 bool is_bound() const { return handle_.is_valid() || endpoint_client_; } 271 encountered_error()272 bool encountered_error() const { 273 return endpoint_client_ ? endpoint_client_->encountered_error() : false; 274 } 275 set_connection_error_handler(const base::Closure & error_handler)276 void set_connection_error_handler(const base::Closure& error_handler) { 277 ConfigureProxyIfNecessary(); 278 279 DCHECK(endpoint_client_); 280 endpoint_client_->set_connection_error_handler(error_handler); 281 } 282 283 // Returns true if bound and awaiting a response to a message. has_pending_callbacks()284 bool has_pending_callbacks() const { 285 return endpoint_client_ && endpoint_client_->has_pending_responders(); 286 } 287 associated_group()288 AssociatedGroup* associated_group() { 289 ConfigureProxyIfNecessary(); 290 return endpoint_client_->associated_group(); 291 } 292 EnableTestingMode()293 void EnableTestingMode() { 294 ConfigureProxyIfNecessary(); 295 router_->EnableTestingMode(); 296 } 297 298 private: 299 using Proxy = typename Interface::Proxy_; 300 ConfigureProxyIfNecessary()301 void ConfigureProxyIfNecessary() { 302 // The proxy has been configured. 303 if (proxy_) { 304 DCHECK(router_); 305 DCHECK(endpoint_client_); 306 return; 307 } 308 // The object hasn't been bound. 309 if (!handle_.is_valid()) 310 return; 311 312 router_ = new MultiplexRouter(true, std::move(handle_), runner_); 313 router_->SetMasterInterfaceName(Interface::Name_); 314 endpoint_client_.reset(new InterfaceEndpointClient( 315 router_->CreateLocalEndpointHandle(kMasterInterfaceId), nullptr, 316 base::WrapUnique(new typename Interface::ResponseValidator_()), false, 317 std::move(runner_))); 318 proxy_.reset(new Proxy(endpoint_client_.get())); 319 proxy_->serialization_context()->group_controller = 320 endpoint_client_->group_controller(); 321 } 322 OnQueryVersion(const base::Callback<void (uint32_t)> & callback,uint32_t version)323 void OnQueryVersion(const base::Callback<void(uint32_t)>& callback, 324 uint32_t version) { 325 version_ = version; 326 callback.Run(version); 327 } 328 329 scoped_refptr<MultiplexRouter> router_; 330 331 std::unique_ptr<InterfaceEndpointClient> endpoint_client_; 332 std::unique_ptr<Proxy> proxy_; 333 334 // |router_| (as well as other members above) is not initialized until 335 // read/write with the message pipe handle is needed. |handle_| is valid 336 // between the Bind() call and the initialization of |router_|. 337 ScopedMessagePipeHandle handle_; 338 scoped_refptr<base::SingleThreadTaskRunner> runner_; 339 340 uint32_t version_; 341 342 DISALLOW_COPY_AND_ASSIGN(InterfacePtrState); 343 }; 344 345 } // namespace internal 346 } // namespace mojo 347 348 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_ 349