• 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_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