• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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