1 // Copyright 2015 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_ASSOCIATED_BINDING_H_ 6 #define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_BINDING_H_ 7 8 #include <memory> 9 #include <utility> 10 11 #include "base/bind.h" 12 #include "base/callback.h" 13 #include "base/macros.h" 14 #include "base/memory/ptr_util.h" 15 #include "base/memory/ref_counted.h" 16 #include "base/single_thread_task_runner.h" 17 #include "base/threading/thread_task_runner_handle.h" 18 #include "mojo/public/cpp/bindings/associated_group.h" 19 #include "mojo/public/cpp/bindings/associated_group_controller.h" 20 #include "mojo/public/cpp/bindings/associated_interface_request.h" 21 #include "mojo/public/cpp/bindings/interface_endpoint_client.h" 22 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h" 23 24 namespace mojo { 25 26 // Represents the implementation side of an associated interface. It is similar 27 // to Binding, except that it doesn't own a message pipe handle. 28 // 29 // When you bind this class to a request, optionally you can specify a 30 // base::SingleThreadTaskRunner. This task runner must belong to the same 31 // thread. It will be used to dispatch incoming method calls and connection 32 // error notification. It is useful when you attach multiple task runners to a 33 // single thread for the purposes of task scheduling. Please note that incoming 34 // synchrounous method calls may not be run from this task runner, when they 35 // reenter outgoing synchrounous calls on the same thread. 36 template <typename Interface> 37 class AssociatedBinding { 38 public: 39 // Constructs an incomplete associated binding that will use the 40 // implementation |impl|. It may be completed with a subsequent call to the 41 // |Bind| method. Does not take ownership of |impl|, which must outlive this 42 // object. AssociatedBinding(Interface * impl)43 explicit AssociatedBinding(Interface* impl) : impl_(impl) { 44 stub_.set_sink(impl_); 45 } 46 47 // Constructs a completed associated binding of |impl|. The output |ptr_info| 48 // should be passed through the message pipe endpoint referred to by 49 // |associated_group| to setup the corresponding asssociated interface 50 // pointer. |impl| must outlive this object. 51 AssociatedBinding(Interface* impl, 52 AssociatedInterfacePtrInfo<Interface>* ptr_info, 53 AssociatedGroup* associated_group, 54 scoped_refptr<base::SingleThreadTaskRunner> runner = 55 base::ThreadTaskRunnerHandle::Get()) AssociatedBinding(impl)56 : AssociatedBinding(impl) { 57 Bind(ptr_info, associated_group, std::move(runner)); 58 } 59 60 // Constructs a completed associated binding of |impl|. |impl| must outlive 61 // the binding. 62 AssociatedBinding(Interface* impl, 63 AssociatedInterfaceRequest<Interface> request, 64 scoped_refptr<base::SingleThreadTaskRunner> runner = 65 base::ThreadTaskRunnerHandle::Get()) AssociatedBinding(impl)66 : AssociatedBinding(impl) { 67 Bind(std::move(request), std::move(runner)); 68 } 69 ~AssociatedBinding()70 ~AssociatedBinding() {} 71 72 // Creates an associated inteface and sets up this object as the 73 // implementation side. The output |ptr_info| should be passed through the 74 // message pipe endpoint referred to by |associated_group| to setup the 75 // corresponding asssociated interface pointer. 76 void Bind(AssociatedInterfacePtrInfo<Interface>* ptr_info, 77 AssociatedGroup* associated_group, 78 scoped_refptr<base::SingleThreadTaskRunner> runner = 79 base::ThreadTaskRunnerHandle::Get()) { 80 AssociatedInterfaceRequest<Interface> request; 81 associated_group->CreateAssociatedInterface(AssociatedGroup::WILL_PASS_PTR, 82 ptr_info, &request); 83 Bind(std::move(request), std::move(runner)); 84 } 85 86 // Sets up this object as the implementation side of an associated interface. 87 void Bind(AssociatedInterfaceRequest<Interface> request, 88 scoped_refptr<base::SingleThreadTaskRunner> runner = 89 base::ThreadTaskRunnerHandle::Get()) { 90 ScopedInterfaceEndpointHandle handle = request.PassHandle(); 91 92 DCHECK(handle.is_local()) 93 << "The AssociatedInterfaceRequest is supposed to be used at the " 94 << "other side of the message pipe."; 95 96 if (!handle.is_valid() || !handle.is_local()) { 97 endpoint_client_.reset(); 98 return; 99 } 100 101 endpoint_client_.reset(new InterfaceEndpointClient( 102 std::move(handle), &stub_, 103 base::WrapUnique(new typename Interface::RequestValidator_()), 104 Interface::HasSyncMethods_, std::move(runner))); 105 endpoint_client_->set_connection_error_handler( 106 base::Bind(&AssociatedBinding::RunConnectionErrorHandler, 107 base::Unretained(this))); 108 109 stub_.serialization_context()->group_controller = 110 endpoint_client_->group_controller(); 111 } 112 113 // Closes the associated interface. Puts this object into a state where it can 114 // be rebound. Close()115 void Close() { 116 DCHECK(endpoint_client_); 117 endpoint_client_.reset(); 118 connection_error_handler_.Reset(); 119 } 120 121 // Unbinds and returns the associated interface request so it can be 122 // used in another context, such as on another thread or with a different 123 // implementation. Puts this object into a state where it can be rebound. Unbind()124 AssociatedInterfaceRequest<Interface> Unbind() { 125 DCHECK(endpoint_client_); 126 127 AssociatedInterfaceRequest<Interface> request; 128 request.Bind(endpoint_client_->PassHandle()); 129 130 endpoint_client_.reset(); 131 connection_error_handler_.Reset(); 132 133 return request; 134 } 135 136 // Sets an error handler that will be called if a connection error occurs. 137 // 138 // This method may only be called after this AssociatedBinding has been bound 139 // to a message pipe. The error handler will be reset when this 140 // AssociatedBinding is unbound or closed. set_connection_error_handler(const base::Closure & error_handler)141 void set_connection_error_handler(const base::Closure& error_handler) { 142 DCHECK(is_bound()); 143 connection_error_handler_ = error_handler; 144 } 145 146 // Returns the interface implementation that was previously specified. impl()147 Interface* impl() { return impl_; } 148 149 // Indicates whether the associated binding has been completed. is_bound()150 bool is_bound() const { return !!endpoint_client_; } 151 152 // Returns the associated group that this object belongs to. Returns null if 153 // the object is not bound. associated_group()154 AssociatedGroup* associated_group() { 155 return endpoint_client_ ? endpoint_client_->associated_group() : nullptr; 156 } 157 158 private: RunConnectionErrorHandler()159 void RunConnectionErrorHandler() { 160 if (!connection_error_handler_.is_null()) 161 connection_error_handler_.Run(); 162 } 163 164 std::unique_ptr<InterfaceEndpointClient> endpoint_client_; 165 166 typename Interface::Stub_ stub_; 167 Interface* impl_; 168 base::Closure connection_error_handler_; 169 170 DISALLOW_COPY_AND_ASSIGN(AssociatedBinding); 171 }; 172 173 } // namespace mojo 174 175 #endif // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_BINDING_H_ 176