• 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/sequenced_task_runner.h"
18 #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
19 #include "mojo/public/cpp/bindings/associated_interface_request.h"
20 #include "mojo/public/cpp/bindings/bindings_export.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   using Proxy = typename Interface::Proxy_;
36 
37   // Constructs an unbound AssociatedInterfacePtr.
AssociatedInterfacePtr()38   AssociatedInterfacePtr() {}
AssociatedInterfacePtr(decltype (nullptr))39   AssociatedInterfacePtr(decltype(nullptr)) {}
40 
AssociatedInterfacePtr(AssociatedInterfacePtr && other)41   AssociatedInterfacePtr(AssociatedInterfacePtr&& other) {
42     internal_state_.Swap(&other.internal_state_);
43   }
44 
AssociatedInterfacePtr(PtrInfoType && info)45   explicit AssociatedInterfacePtr(PtrInfoType&& info) { Bind(std::move(info)); }
46 
47   AssociatedInterfacePtr& operator=(AssociatedInterfacePtr&& other) {
48     reset();
49     internal_state_.Swap(&other.internal_state_);
50     return *this;
51   }
52 
53   // Assigning nullptr to this class causes it to closes the associated
54   // interface (if any) and returns the pointer to the unbound state.
decltype(nullptr)55   AssociatedInterfacePtr& operator=(decltype(nullptr)) {
56     reset();
57     return *this;
58   }
59 
~AssociatedInterfacePtr()60   ~AssociatedInterfacePtr() {}
61 
62   // Sets up this object as the client side of an associated interface.
63   // Calling with an invalid |info| has the same effect as reset(). In this
64   // case, the AssociatedInterfacePtr is not considered as bound.
65   //
66   // Optionally, |runner| is a SequencedTaskRunner bound to the current sequence
67   // on which all callbacks and connection error notifications will be
68   // dispatched. It is only useful to specify this to use a different
69   // SequencedTaskRunner than SequencedTaskRunnerHandle::Get().
70   //
71   // NOTE: The corresponding AssociatedInterfaceRequest must be sent over
72   // another interface before using this object to make calls. Please see the
73   // comments of MakeRequest(AssociatedInterfacePtr<Interface>*) for more
74   // details.
75   void Bind(AssociatedInterfacePtrInfo<Interface> info,
76             scoped_refptr<base::SequencedTaskRunner> runner = nullptr) {
77     reset();
78 
79     if (info.is_valid())
80       internal_state_.Bind(std::move(info), std::move(runner));
81   }
82 
is_bound()83   bool is_bound() const { return internal_state_.is_bound(); }
84 
get()85   Proxy* get() const { return internal_state_.instance(); }
86 
87   // Functions like a pointer to Interface. Must already be bound.
88   Proxy* operator->() const { return get(); }
89   Proxy& operator*() const { return *get(); }
90 
91   // Returns the version number of the interface that the remote side supports.
version()92   uint32_t version() const { return internal_state_.version(); }
93 
94   // Queries the max version that the remote side supports. On completion, the
95   // result will be returned as the input of |callback|. The version number of
96   // this object will also be updated.
QueryVersion(const base::Callback<void (uint32_t)> & callback)97   void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
98     internal_state_.QueryVersion(callback);
99   }
100 
101   // If the remote side doesn't support the specified version, it will close the
102   // associated interface asynchronously. This does nothing if it's already
103   // known that the remote side supports the specified version, i.e., if
104   // |version <= this->version()|.
105   //
106   // After calling RequireVersion() with a version not supported by the remote
107   // side, all subsequent calls to interface methods will be ignored.
RequireVersion(uint32_t version)108   void RequireVersion(uint32_t version) {
109     internal_state_.RequireVersion(version);
110   }
111 
112   // Sends a message on the underlying message pipe and runs the current
113   // message loop until its response is received. This can be used in tests to
114   // verify that no message was sent on a message pipe in response to some
115   // stimulus.
FlushForTesting()116   void FlushForTesting() { internal_state_.FlushForTesting(); }
117 
118   // Closes the associated interface (if any) and returns the pointer to the
119   // unbound state.
reset()120   void reset() {
121     State doomed;
122     internal_state_.Swap(&doomed);
123   }
124 
125   // Similar to the method above, but also specifies a disconnect reason.
ResetWithReason(uint32_t custom_reason,const std::string & description)126   void ResetWithReason(uint32_t custom_reason, const std::string& description) {
127     if (internal_state_.is_bound())
128       internal_state_.CloseWithReason(custom_reason, description);
129     reset();
130   }
131 
132   // Indicates whether an error has been encountered. If true, method calls made
133   // on this interface will be dropped (and may already have been dropped).
encountered_error()134   bool encountered_error() const { return internal_state_.encountered_error(); }
135 
136   // Registers a handler to receive error notifications.
137   //
138   // This method may only be called after the AssociatedInterfacePtr has been
139   // bound.
set_connection_error_handler(base::OnceClosure error_handler)140   void set_connection_error_handler(base::OnceClosure error_handler) {
141     internal_state_.set_connection_error_handler(std::move(error_handler));
142   }
143 
set_connection_error_with_reason_handler(ConnectionErrorWithReasonCallback error_handler)144   void set_connection_error_with_reason_handler(
145       ConnectionErrorWithReasonCallback error_handler) {
146     internal_state_.set_connection_error_with_reason_handler(
147         std::move(error_handler));
148   }
149 
150   // Unbinds and returns the associated interface pointer information which
151   // could be used to setup an AssociatedInterfacePtr again. This method may be
152   // used to move the proxy to a different sequence.
153   //
154   // It is an error to call PassInterface() while there are pending responses.
155   // TODO: fix this restriction, it's not always obvious when there is a
156   // pending response.
PassInterface()157   AssociatedInterfacePtrInfo<Interface> PassInterface() {
158     DCHECK(!internal_state_.has_pending_callbacks());
159     State state;
160     internal_state_.Swap(&state);
161 
162     return state.PassInterface();
163   }
164 
165   // DO NOT USE. Exposed only for internal use and for testing.
internal_state()166   internal::AssociatedInterfacePtrState<Interface>* internal_state() {
167     return &internal_state_;
168   }
169 
170   // Allow AssociatedInterfacePtr<> to be used in boolean expressions.
171   explicit operator bool() const { return internal_state_.is_bound(); }
172 
173  private:
174   typedef internal::AssociatedInterfacePtrState<Interface> State;
175   mutable State internal_state_;
176 
177   DISALLOW_COPY_AND_ASSIGN(AssociatedInterfacePtr);
178 };
179 
180 // Creates an associated interface. The returned request is supposed to be sent
181 // over another interface (either associated or non-associated).
182 //
183 // NOTE: |ptr| must NOT be used to make calls before the request is sent.
184 // Violating that will lead to crash. On the other hand, as soon as the request
185 // is sent, |ptr| is usable. There is no need to wait until the request is bound
186 // to an implementation at the remote side.
187 template <typename Interface>
188 AssociatedInterfaceRequest<Interface> MakeRequest(
189     AssociatedInterfacePtr<Interface>* ptr,
190     scoped_refptr<base::SequencedTaskRunner> runner = nullptr) {
191   AssociatedInterfacePtrInfo<Interface> ptr_info;
192   auto request = MakeRequest(&ptr_info);
193   ptr->Bind(std::move(ptr_info), std::move(runner));
194   return request;
195 }
196 
197 // Creates an associated interface. One of the two endpoints is supposed to be
198 // sent over another interface (either associated or non-associated); while the
199 // other is used locally.
200 //
201 // NOTE: If |ptr_info| is used locally and bound to an AssociatedInterfacePtr,
202 // the interface pointer must NOT be used to make calls before the request is
203 // sent. Please see NOTE of the previous function for more details.
204 template <typename Interface>
MakeRequest(AssociatedInterfacePtrInfo<Interface> * ptr_info)205 AssociatedInterfaceRequest<Interface> MakeRequest(
206     AssociatedInterfacePtrInfo<Interface>* ptr_info) {
207   ScopedInterfaceEndpointHandle handle0;
208   ScopedInterfaceEndpointHandle handle1;
209   ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&handle0,
210                                                               &handle1);
211 
212   ptr_info->set_handle(std::move(handle0));
213   ptr_info->set_version(0);
214 
215   return AssociatedInterfaceRequest<Interface>(std::move(handle1));
216 }
217 
218 // Like MakeRequest() above, but it creates a dedicated message pipe. The
219 // returned request can be bound directly to an implementation, without being
220 // first passed through a message pipe endpoint.
221 //
222 // This function has two main uses:
223 //
224 //  * In testing, where the returned request is bound to e.g. a mock and there
225 //    are no other interfaces involved.
226 //
227 //  * When discarding messages sent on an interface, which can be done by
228 //    discarding the returned request.
229 template <typename Interface>
MakeRequestAssociatedWithDedicatedPipe(AssociatedInterfacePtr<Interface> * ptr)230 AssociatedInterfaceRequest<Interface> MakeRequestAssociatedWithDedicatedPipe(
231     AssociatedInterfacePtr<Interface>* ptr) {
232   MessagePipe pipe;
233   scoped_refptr<internal::MultiplexRouter> router0 =
234       new internal::MultiplexRouter(
235           std::move(pipe.handle0), internal::MultiplexRouter::MULTI_INTERFACE,
236           false, base::SequencedTaskRunnerHandle::Get());
237   scoped_refptr<internal::MultiplexRouter> router1 =
238       new internal::MultiplexRouter(
239           std::move(pipe.handle1), internal::MultiplexRouter::MULTI_INTERFACE,
240           true, base::SequencedTaskRunnerHandle::Get());
241 
242   ScopedInterfaceEndpointHandle endpoint0, endpoint1;
243   ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(&endpoint0,
244                                                               &endpoint1);
245   InterfaceId id = router1->AssociateInterface(std::move(endpoint0));
246   endpoint0 = router0->CreateLocalEndpointHandle(id);
247 
248   ptr->Bind(AssociatedInterfacePtrInfo<Interface>(std::move(endpoint0),
249                                                   Interface::Version_));
250   return AssociatedInterfaceRequest<Interface>(std::move(endpoint1));
251 }
252 
253 // |handle| is supposed to be the request of an associated interface. This
254 // method associates the interface with a dedicated, disconnected message pipe.
255 // That way, the corresponding associated interface pointer of |handle| can
256 // safely make calls (although those calls are silently dropped).
257 MOJO_CPP_BINDINGS_EXPORT void AssociateWithDisconnectedPipe(
258     ScopedInterfaceEndpointHandle handle);
259 
260 }  // namespace mojo
261 
262 #endif  // MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_INTERFACE_PTR_H_
263