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