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_INTERFACE_PTR_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
7
8 #include <stdint.h>
9
10 #include <string>
11 #include <utility>
12
13 #include "base/callback.h"
14 #include "base/logging.h"
15 #include "base/macros.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
20 #include "mojo/public/cpp/bindings/associated_interface_request.h"
21 #include "mojo/public/cpp/bindings/connection_error_callback.h"
22 #include "mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h"
23 #include "mojo/public/cpp/bindings/lib/multiplex_router.h"
24 #include "mojo/public/cpp/system/message_pipe.h"
25
26 namespace mojo {
27
28 // Represents the client side of an associated interface. It is similar to
29 // InterfacePtr, except that it doesn't own a message pipe handle.
30 template <typename Interface>
31 class AssociatedInterfacePtr {
32 public:
33 using InterfaceType = Interface;
34 using PtrInfoType = AssociatedInterfacePtrInfo<Interface>;
35
36 // Constructs an unbound AssociatedInterfacePtr.
AssociatedInterfacePtr()37 AssociatedInterfacePtr() {}
AssociatedInterfacePtr(decltype (nullptr))38 AssociatedInterfacePtr(decltype(nullptr)) {}
39
AssociatedInterfacePtr(AssociatedInterfacePtr && other)40 AssociatedInterfacePtr(AssociatedInterfacePtr&& other) {
41 internal_state_.Swap(&other.internal_state_);
42 }
43
44 AssociatedInterfacePtr& operator=(AssociatedInterfacePtr&& other) {
45 reset();
46 internal_state_.Swap(&other.internal_state_);
47 return *this;
48 }
49
50 // Assigning nullptr to this class causes it to closes the associated
51 // interface (if any) and returns the pointer to the unbound state.
decltype(nullptr)52 AssociatedInterfacePtr& operator=(decltype(nullptr)) {
53 reset();
54 return *this;
55 }
56
~AssociatedInterfacePtr()57 ~AssociatedInterfacePtr() {}
58
59 // Sets up this object as the client side of an associated interface.
60 // Calling with an invalid |info| has the same effect as reset(). In this
61 // case, the AssociatedInterfacePtr is not considered as bound.
62 //
63 // |runner| must belong to the same thread. It will be used to dispatch all
64 // callbacks and connection error notification. It is useful when you attach
65 // multiple task runners to a single thread for the purposes of task
66 // scheduling.
67 //
68 // NOTE: The corresponding AssociatedInterfaceRequest must be sent over
69 // another interface before using this object to make calls. Please see the
70 // comments of MakeRequest(AssociatedInterfacePtr<Interface>*) for more
71 // details.
72 void Bind(AssociatedInterfacePtrInfo<Interface> info,
73 scoped_refptr<base::SingleThreadTaskRunner> runner =
74 base::ThreadTaskRunnerHandle::Get()) {
75 reset();
76
77 if (info.is_valid())
78 internal_state_.Bind(std::move(info), std::move(runner));
79 }
80
is_bound()81 bool is_bound() const { return internal_state_.is_bound(); }
82
get()83 Interface* get() const { return internal_state_.instance(); }
84
85 // Functions like a pointer to Interface. Must already be bound.
86 Interface* operator->() const { return get(); }
87 Interface& operator*() const { return *get(); }
88
89 // Returns the version number of the interface that the remote side supports.
version()90 uint32_t version() const { return internal_state_.version(); }
91
92 // Queries the max version that the remote side supports. On completion, the
93 // result will be returned as the input of |callback|. The version number of
94 // this object will also be updated.
QueryVersion(const base::Callback<void (uint32_t)> & callback)95 void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
96 internal_state_.QueryVersion(callback);
97 }
98
99 // If the remote side doesn't support the specified version, it will close the
100 // associated interface asynchronously. This does nothing if it's already
101 // known that the remote side supports the specified version, i.e., if
102 // |version <= this->version()|.
103 //
104 // After calling RequireVersion() with a version not supported by the remote
105 // side, all subsequent calls to interface methods will be ignored.
RequireVersion(uint32_t version)106 void RequireVersion(uint32_t version) {
107 internal_state_.RequireVersion(version);
108 }
109
110 // Sends a message on the underlying message pipe and runs the current
111 // message loop until its response is received. This can be used in tests to
112 // verify that no message was sent on a message pipe in response to some
113 // stimulus.
FlushForTesting()114 void FlushForTesting() { internal_state_.FlushForTesting(); }
115
116 // Closes the associated interface (if any) and returns the pointer to the
117 // unbound state.
reset()118 void reset() {
119 State doomed;
120 internal_state_.Swap(&doomed);
121 }
122
123 // Similar to the method above, but also specifies a disconnect reason.
ResetWithReason(uint32_t custom_reason,const std::string & description)124 void ResetWithReason(uint32_t custom_reason, const std::string& description) {
125 if (internal_state_.is_bound())
126 internal_state_.CloseWithReason(custom_reason, description);
127 reset();
128 }
129
130 // Indicates whether an error has been encountered. If true, method calls made
131 // on this interface will be dropped (and may already have been dropped).
encountered_error()132 bool encountered_error() const { return internal_state_.encountered_error(); }
133
134 // Registers a handler to receive error notifications.
135 //
136 // This method may only be called after the AssociatedInterfacePtr has been
137 // bound.
set_connection_error_handler(const base::Closure & error_handler)138 void set_connection_error_handler(const base::Closure& error_handler) {
139 internal_state_.set_connection_error_handler(error_handler);
140 }
141
set_connection_error_with_reason_handler(const ConnectionErrorWithReasonCallback & error_handler)142 void set_connection_error_with_reason_handler(
143 const ConnectionErrorWithReasonCallback& error_handler) {
144 internal_state_.set_connection_error_with_reason_handler(error_handler);
145 }
146
147 // Unbinds and returns the associated interface pointer information which
148 // could be used to setup an AssociatedInterfacePtr again. This method may be
149 // used to move the proxy to a different thread.
150 //
151 // It is an error to call PassInterface() while there are pending responses.
152 // TODO: fix this restriction, it's not always obvious when there is a
153 // pending response.
PassInterface()154 AssociatedInterfacePtrInfo<Interface> PassInterface() {
155 DCHECK(!internal_state_.has_pending_callbacks());
156 State state;
157 internal_state_.Swap(&state);
158
159 return state.PassInterface();
160 }
161
162 // DO NOT USE. Exposed only for internal use and for testing.
internal_state()163 internal::AssociatedInterfacePtrState<Interface>* internal_state() {
164 return &internal_state_;
165 }
166
167 // Allow AssociatedInterfacePtr<> to be used in boolean expressions, but not
168 // implicitly convertible to a real bool (which is dangerous).
169 private:
170 // TODO(dcheng): Use an explicit conversion operator.
171 typedef internal::AssociatedInterfacePtrState<Interface>
172 AssociatedInterfacePtr::*Testable;
173
174 public:
Testable()175 operator Testable() const {
176 return internal_state_.is_bound() ? &AssociatedInterfacePtr::internal_state_
177 : nullptr;
178 }
179
180 private:
181 // Forbid the == and != operators explicitly, otherwise AssociatedInterfacePtr
182 // will be converted to Testable to do == or != comparison.
183 template <typename T>
184 bool operator==(const AssociatedInterfacePtr<T>& other) const = delete;
185 template <typename T>
186 bool operator!=(const AssociatedInterfacePtr<T>& other) const = delete;
187
188 typedef internal::AssociatedInterfacePtrState<Interface> State;
189 mutable State internal_state_;
190
191 DISALLOW_COPY_AND_ASSIGN(AssociatedInterfacePtr);
192 };
193
194 // Creates an associated interface. The returned request is supposed to be sent
195 // over another interface (either associated or non-associated).
196 //
197 // NOTE: |ptr| must NOT be used to make calls before the request is sent.
198 // Violating that will lead to crash. On the other hand, as soon as the request
199 // is sent, |ptr| is usable. There is no need to wait until the request is bound
200 // to an implementation at the remote side.
201 template <typename Interface>
202 AssociatedInterfaceRequest<Interface> MakeRequest(
203 AssociatedInterfacePtr<Interface>* ptr,
204 scoped_refptr<base::SingleThreadTaskRunner> runner =
205 base::ThreadTaskRunnerHandle::Get()) {
206 AssociatedInterfacePtrInfo<Interface> ptr_info;
207 auto request = MakeRequest(&ptr_info);
208 ptr->Bind(std::move(ptr_info), std::move(runner));
209 return request;
210 }
211
212 // Creates an associated interface. One of the two endpoints is supposed to be
213 // sent over another interface (either associated or non-associated); while the
214 // other is used locally.
215 //
216 // NOTE: If |ptr_info| is used locally and bound to an AssociatedInterfacePtr,
217 // the interface pointer must NOT be used to make calls before the request is
218 // sent. Please see NOTE of the previous function for more details.
219 template <typename Interface>
MakeRequest(AssociatedInterfacePtrInfo<Interface> * ptr_info)220 AssociatedInterfaceRequest<Interface> MakeRequest(
221 AssociatedInterfacePtrInfo<Interface>* ptr_info) {
222 ScopedInterfaceEndpointHandle handle0;
223 ScopedInterfaceEndpointHandle handle1;
224 ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&handle0,
225 &handle1);
226
227 ptr_info->set_handle(std::move(handle0));
228 ptr_info->set_version(0);
229
230 AssociatedInterfaceRequest<Interface> request;
231 request.Bind(std::move(handle1));
232 return request;
233 }
234
235 // Like |GetProxy|, but the interface is never associated with any other
236 // interface. The returned request can be bound directly to the corresponding
237 // associated interface implementation, without first passing it through a
238 // message pipe endpoint.
239 //
240 // This function has two main uses:
241 //
242 // * In testing, where the returned request is bound to e.g. a mock and there
243 // are no other interfaces involved.
244 //
245 // * When discarding messages sent on an interface, which can be done by
246 // discarding the returned request.
247 template <typename Interface>
GetIsolatedProxy(AssociatedInterfacePtr<Interface> * ptr)248 AssociatedInterfaceRequest<Interface> GetIsolatedProxy(
249 AssociatedInterfacePtr<Interface>* ptr) {
250 MessagePipe pipe;
251 scoped_refptr<internal::MultiplexRouter> router0 =
252 new internal::MultiplexRouter(std::move(pipe.handle0),
253 internal::MultiplexRouter::MULTI_INTERFACE,
254 false, base::ThreadTaskRunnerHandle::Get());
255 scoped_refptr<internal::MultiplexRouter> router1 =
256 new internal::MultiplexRouter(std::move(pipe.handle1),
257 internal::MultiplexRouter::MULTI_INTERFACE,
258 true, base::ThreadTaskRunnerHandle::Get());
259
260 ScopedInterfaceEndpointHandle endpoint0, endpoint1;
261 ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&endpoint0,
262 &endpoint1);
263 InterfaceId id = router1->AssociateInterface(std::move(endpoint0));
264 endpoint0 = router0->CreateLocalEndpointHandle(id);
265
266 ptr->Bind(AssociatedInterfacePtrInfo<Interface>(std::move(endpoint0),
267 Interface::Version_));
268
269 AssociatedInterfaceRequest<Interface> request;
270 request.Bind(std::move(endpoint1));
271 return request;
272 }
273
274 // Creates an associated interface proxy in its own AssociatedGroup.
275 // TODO(yzshen): Rename GetIsolatedProxy() to MakeIsolatedRequest(), and change
276 // all callsites of this function to directly use that.
277 template <typename Interface>
MakeRequestForTesting(AssociatedInterfacePtr<Interface> * ptr)278 AssociatedInterfaceRequest<Interface> MakeRequestForTesting(
279 AssociatedInterfacePtr<Interface>* ptr) {
280 return GetIsolatedProxy(ptr);
281 }
282
283 } // namespace mojo
284
285 #endif // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
286