OLD | NEW |
---|---|
(Empty) | |
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 <algorithm> // For |std::swap()|. | |
9 | |
10 #include "base/logging.h" | |
11 #include "base/macros.h" | |
12 #include "base/memory/ref_counted.h" | |
13 #include "base/memory/scoped_ptr.h" | |
14 #include "mojo/public/cpp/bindings/associated_group.h" | |
15 #include "mojo/public/cpp/bindings/callback.h" | |
16 #include "mojo/public/cpp/bindings/interface_ptr_info.h" | |
17 #include "mojo/public/cpp/bindings/lib/control_message_proxy.h" | |
18 #include "mojo/public/cpp/bindings/lib/filter_chain.h" | |
19 #include "mojo/public/cpp/bindings/lib/interface_endpoint_client.h" | |
20 #include "mojo/public/cpp/bindings/lib/interface_id.h" | |
21 #include "mojo/public/cpp/bindings/lib/message_header_validator.h" | |
22 #include "mojo/public/cpp/bindings/lib/multiplex_router.h" | |
23 #include "mojo/public/cpp/bindings/lib/router.h" | |
24 #include "mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.h" | |
25 | |
26 struct MojoAsyncWaiter; | |
27 | |
28 namespace mojo { | |
29 namespace internal { | |
30 | |
31 template <typename Interface, bool kUsesMultiplexRouter> | |
sky
2015/11/24 22:20:45
Same naming comment here.
yzshen1
2015/11/25 00:26:36
Done.
| |
32 class InterfacePtrState; | |
33 | |
34 template <typename Interface> | |
35 class InterfacePtrState<Interface, false> { | |
sky
2015/11/24 22:20:45
Again, please add descriptions for all classes.
yzshen1
2015/11/25 00:26:36
Done.
| |
36 public: | |
37 InterfacePtrState() | |
38 : proxy_(nullptr), router_(nullptr), waiter_(nullptr), version_(0u) {} | |
39 | |
40 ~InterfacePtrState() { | |
41 // Destruction order matters here. We delete |proxy_| first, even though | |
42 // |router_| may have a reference to it, so that destructors for any request | |
43 // callbacks still pending can interact with the InterfacePtr. | |
44 delete proxy_; | |
45 delete router_; | |
46 } | |
47 | |
48 Interface* instance() { | |
49 ConfigureProxyIfNecessary(); | |
50 | |
51 // This will be null if the object is not bound. | |
52 return proxy_; | |
53 } | |
54 | |
55 uint32_t version() const { return version_; } | |
56 | |
57 void QueryVersion(const Callback<void(uint32_t)>& callback) { | |
58 ConfigureProxyIfNecessary(); | |
59 | |
60 // It is safe to capture |this| because the callback won't be run after this | |
61 // object goes away. | |
62 auto callback_wrapper = [this, callback](uint32_t version) { | |
63 this->version_ = version; | |
64 callback.Run(version); | |
65 }; | |
66 | |
67 // Do a static cast in case the interface contains methods with the same | |
68 // name. | |
69 static_cast<ControlMessageProxy*>(proxy_)->QueryVersion(callback_wrapper); | |
sky
2015/11/24 22:20:45
How do you know the callback happens while this is
yzshen1
2015/11/25 00:26:36
If this object goes away, the callback is not call
| |
70 } | |
71 | |
72 void RequireVersion(uint32_t version) { | |
73 ConfigureProxyIfNecessary(); | |
74 | |
75 if (version <= version_) | |
76 return; | |
77 | |
78 version_ = version; | |
79 // Do a static cast in case the interface contains methods with the same | |
80 // name. | |
81 static_cast<ControlMessageProxy*>(proxy_)->RequireVersion(version); | |
82 } | |
83 | |
84 void Swap(InterfacePtrState* other) { | |
85 using std::swap; | |
86 swap(other->proxy_, proxy_); | |
87 swap(other->router_, router_); | |
88 handle_.swap(other->handle_); | |
89 swap(other->waiter_, waiter_); | |
90 swap(other->version_, version_); | |
91 } | |
92 | |
93 void Bind(InterfacePtrInfo<Interface> info, const MojoAsyncWaiter* waiter) { | |
94 DCHECK(!proxy_); | |
95 DCHECK(!router_); | |
96 DCHECK(!handle_.is_valid()); | |
97 DCHECK(!waiter_); | |
98 DCHECK_EQ(0u, version_); | |
99 DCHECK(info.is_valid()); | |
100 | |
101 handle_ = info.PassHandle(); | |
102 waiter_ = waiter; | |
103 version_ = info.version(); | |
104 } | |
105 | |
106 bool WaitForIncomingResponse() { | |
107 ConfigureProxyIfNecessary(); | |
108 | |
109 DCHECK(router_); | |
110 return router_->WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE); | |
111 } | |
112 | |
113 // After this method is called, the object is in an invalid state and | |
114 // shouldn't be reused. | |
115 InterfacePtrInfo<Interface> PassInterface() { | |
116 return InterfacePtrInfo<Interface>( | |
117 router_ ? router_->PassMessagePipe() : handle_.Pass(), version_); | |
118 } | |
119 | |
120 bool is_bound() const { return handle_.is_valid() || router_; } | |
121 | |
122 bool encountered_error() const { | |
123 return router_ ? router_->encountered_error() : false; | |
124 } | |
125 | |
126 void set_connection_error_handler(const Closure& error_handler) { | |
127 ConfigureProxyIfNecessary(); | |
128 | |
129 DCHECK(router_); | |
130 router_->set_connection_error_handler(error_handler); | |
131 } | |
132 | |
133 // Returns true if bound and awaiting a response to a message. | |
134 bool has_pending_callbacks() const { | |
135 return router_ && router_->has_pending_responders(); | |
136 } | |
137 | |
138 AssociatedGroup* associated_group() { return nullptr; } | |
139 | |
140 void EnableTestingMode() { | |
141 ConfigureProxyIfNecessary(); | |
142 router_->EnableTestingMode(); | |
143 } | |
144 | |
145 private: | |
146 using Proxy = typename Interface::Proxy_; | |
147 | |
148 void ConfigureProxyIfNecessary() { | |
149 // The proxy has been configured. | |
150 if (proxy_) { | |
151 DCHECK(router_); | |
152 return; | |
153 } | |
154 // The object hasn't been bound. | |
155 if (!waiter_) { | |
156 DCHECK(!handle_.is_valid()); | |
157 return; | |
158 } | |
159 | |
160 FilterChain filters; | |
161 filters.Append<MessageHeaderValidator>(); | |
162 filters.Append<typename Interface::ResponseValidator_>(); | |
163 | |
164 router_ = new Router(handle_.Pass(), filters.Pass(), waiter_); | |
165 waiter_ = nullptr; | |
166 | |
167 proxy_ = new Proxy(router_); | |
168 } | |
169 | |
170 Proxy* proxy_; | |
171 Router* router_; | |
172 | |
173 // |proxy_| and |router_| are not initialized until read/write with the | |
174 // message pipe handle is needed. |handle_| and |waiter_| are valid between | |
175 // the Bind() call and the initialization of |proxy_| and |router_|. | |
176 ScopedMessagePipeHandle handle_; | |
177 const MojoAsyncWaiter* waiter_; | |
178 | |
179 uint32_t version_; | |
180 | |
181 DISALLOW_COPY_AND_ASSIGN(InterfacePtrState); | |
182 }; | |
183 | |
184 template <typename Interface> | |
185 class InterfacePtrState<Interface, true> { | |
186 public: | |
187 InterfacePtrState() : waiter_(nullptr), version_(0u) {} | |
188 | |
189 ~InterfacePtrState() { | |
190 endpoint_client_.reset(); | |
191 proxy_.reset(); | |
192 if (router_) | |
193 router_->CloseMessagePipe(); | |
194 } | |
195 | |
196 Interface* instance() { | |
197 ConfigureProxyIfNecessary(); | |
198 | |
199 // This will be null if the object is not bound. | |
200 return proxy_.get(); | |
201 } | |
202 | |
203 uint32_t version() const { return version_; } | |
204 | |
205 void QueryVersion(const Callback<void(uint32_t)>& callback) { | |
206 ConfigureProxyIfNecessary(); | |
207 | |
208 // It is safe to capture |this| because the callback won't be run after this | |
209 // object goes away. | |
210 auto callback_wrapper = [this, callback](uint32_t version) { | |
211 this->version_ = version; | |
212 callback.Run(version); | |
213 }; | |
214 | |
215 // Do a static cast in case the interface contains methods with the same | |
216 // name. | |
217 static_cast<ControlMessageProxy*>(proxy_.get()) | |
218 ->QueryVersion(callback_wrapper); | |
219 } | |
220 | |
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 | |
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 swap(other->waiter_, waiter_); | |
240 swap(other->version_, version_); | |
241 } | |
242 | |
243 void Bind(InterfacePtrInfo<Interface> info, const MojoAsyncWaiter* waiter) { | |
244 DCHECK(!router_); | |
245 DCHECK(!endpoint_client_); | |
246 DCHECK(!proxy_); | |
247 DCHECK(!handle_.is_valid()); | |
248 DCHECK(!waiter_); | |
249 DCHECK_EQ(0u, version_); | |
250 DCHECK(info.is_valid()); | |
251 | |
252 handle_ = info.PassHandle(); | |
253 waiter_ = waiter; | |
254 version_ = info.version(); | |
255 } | |
256 | |
257 bool WaitForIncomingResponse() { | |
258 ConfigureProxyIfNecessary(); | |
259 | |
260 DCHECK(router_); | |
261 return router_->WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE); | |
262 } | |
263 | |
264 // After this method is called, the object is in an invalid state and | |
265 // shouldn't be reused. | |
266 InterfacePtrInfo<Interface> PassInterface() { | |
267 endpoint_client_.reset(); | |
268 proxy_.reset(); | |
269 return InterfacePtrInfo<Interface>( | |
270 router_ ? router_->PassMessagePipe() : handle_.Pass(), version_); | |
271 } | |
272 | |
273 bool is_bound() const { return handle_.is_valid() || endpoint_client_; } | |
274 | |
275 bool encountered_error() const { | |
276 return endpoint_client_ ? endpoint_client_->encountered_error() : false; | |
277 } | |
278 | |
279 void set_connection_error_handler(const Closure& error_handler) { | |
280 ConfigureProxyIfNecessary(); | |
281 | |
282 DCHECK(endpoint_client_); | |
283 endpoint_client_->set_connection_error_handler(error_handler); | |
284 } | |
285 | |
286 // Returns true if bound and awaiting a response to a message. | |
287 bool has_pending_callbacks() const { | |
288 return endpoint_client_ && endpoint_client_->has_pending_responders(); | |
289 } | |
290 | |
291 AssociatedGroup* associated_group() { | |
292 ConfigureProxyIfNecessary(); | |
293 return endpoint_client_->associated_group(); | |
294 } | |
295 | |
296 void EnableTestingMode() { | |
297 ConfigureProxyIfNecessary(); | |
298 router_->EnableTestingMode(); | |
299 } | |
300 | |
301 private: | |
302 using Proxy = typename Interface::Proxy_; | |
303 | |
304 void ConfigureProxyIfNecessary() { | |
305 // The proxy has been configured. | |
306 if (proxy_) { | |
307 DCHECK(router_); | |
308 DCHECK(endpoint_client_); | |
309 return; | |
310 } | |
311 // The object hasn't been bound. | |
312 if (!waiter_) { | |
313 DCHECK(!handle_.is_valid()); | |
314 return; | |
315 } | |
316 | |
317 router_ = new MultiplexRouter(true, handle_.Pass(), waiter_); | |
318 endpoint_client_.reset(new InterfaceEndpointClient( | |
319 router_->CreateLocalEndpointHandle(kMasterInterfaceId), nullptr, | |
320 make_scoped_ptr(new typename Interface::ResponseValidator_()))); | |
321 proxy_.reset(new Proxy(endpoint_client_.get(), endpoint_client_->router())); | |
322 | |
323 waiter_ = nullptr; | |
324 } | |
325 | |
326 scoped_refptr<MultiplexRouter> router_; | |
327 | |
328 scoped_ptr<InterfaceEndpointClient> endpoint_client_; | |
329 scoped_ptr<Proxy> proxy_; | |
330 | |
331 // |router_| (as well as other members above) is not initialized until | |
332 // read/write with the message pipe handle is needed. |handle_| and |waiter_| | |
333 // are valid between the Bind() call and the initialization of |router_|. | |
334 ScopedMessagePipeHandle handle_; | |
335 const MojoAsyncWaiter* waiter_; | |
336 | |
337 uint32_t version_; | |
338 | |
339 DISALLOW_COPY_AND_ASSIGN(InterfacePtrState); | |
340 }; | |
341 | |
342 } // namespace internal | |
343 } // namespace mojo | |
344 | |
345 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_STATE_H_ | |
OLD | NEW |