OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ipc/ipc_mojo_bootstrap.h" | 5 #include "ipc/ipc_mojo_bootstrap.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | |
9 #include <map> | |
10 #include <memory> | |
8 #include <utility> | 11 #include <utility> |
9 | 12 |
10 #include "base/callback.h" | 13 #include "base/callback.h" |
11 #include "base/logging.h" | 14 #include "base/logging.h" |
12 #include "base/macros.h" | 15 #include "base/macros.h" |
13 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
14 #include "base/process/process_handle.h" | 17 #include "base/process/process_handle.h" |
18 #include "base/single_thread_task_runner.h" | |
19 #include "base/stl_util.h" | |
20 #include "base/synchronization/lock.h" | |
21 #include "base/threading/thread_task_runner_handle.h" | |
15 #include "build/build_config.h" | 22 #include "build/build_config.h" |
16 #include "ipc/ipc_message_utils.h" | 23 #include "ipc/ipc_message_utils.h" |
17 #include "ipc/ipc_platform_file.h" | 24 #include "ipc/ipc_platform_file.h" |
25 #include "mojo/public/cpp/bindings/associated_group.h" | |
26 #include "mojo/public/cpp/bindings/associated_group_controller.h" | |
18 #include "mojo/public/cpp/bindings/binding.h" | 27 #include "mojo/public/cpp/bindings/binding.h" |
28 #include "mojo/public/cpp/bindings/connector.h" | |
29 #include "mojo/public/cpp/bindings/interface_endpoint_client.h" | |
30 #include "mojo/public/cpp/bindings/interface_endpoint_controller.h" | |
31 #include "mojo/public/cpp/bindings/interface_id.h" | |
32 #include "mojo/public/cpp/bindings/message_header_validator.h" | |
33 #include "mojo/public/cpp/bindings/pipe_control_message_handler.h" | |
34 #include "mojo/public/cpp/bindings/pipe_control_message_handler_delegate.h" | |
35 #include "mojo/public/cpp/bindings/pipe_control_message_proxy.h" | |
19 | 36 |
20 namespace IPC { | 37 namespace IPC { |
21 | 38 |
22 namespace { | 39 namespace { |
23 | 40 |
41 class ChannelAssociatedGroupController | |
42 : public mojo::AssociatedGroupController, | |
43 public mojo::MessageReceiver, | |
44 public mojo::PipeControlMessageHandlerDelegate { | |
45 public: | |
46 ChannelAssociatedGroupController(bool set_interface_id_namespace_bit, | |
47 mojo::ScopedMessagePipeHandle handle) | |
48 : mojo::AssociatedGroupController(base::ThreadTaskRunnerHandle::Get()), | |
49 task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
50 id_namespace_mask_(set_interface_id_namespace_bit ? | |
51 mojo::kInterfaceIdNamespaceMask : 0), | |
52 associated_group_(CreateAssociatedGroup()), | |
53 connector_(std::move(handle), mojo::Connector::SINGLE_THREADED_SEND, | |
54 base::ThreadTaskRunnerHandle::Get()), | |
55 header_validator_( | |
56 "IPC::mojom::Bootstrap [master] MessageHeaderValidator", this), | |
57 control_message_handler_(this), | |
58 control_message_proxy_(&connector_) { | |
59 connector_.set_incoming_receiver(&header_validator_); | |
60 connector_.set_connection_error_handler( | |
61 base::Bind(&ChannelAssociatedGroupController::OnPipeError, | |
62 base::Unretained(this))); | |
63 control_message_handler_.SetDescription( | |
64 "IPC::mojom::Bootstrap [master] PipeControlMessageHandler"); | |
65 } | |
66 | |
67 mojo::AssociatedGroup* associated_group() { return associated_group_.get(); } | |
68 | |
69 void ShutDown() { | |
70 DCHECK(thread_checker_.CalledOnValidThread()); | |
71 connector_.CloseMessagePipe(); | |
72 OnPipeError(); | |
73 associated_group_.reset(); | |
74 } | |
75 | |
76 void SetProxyTaskRunner( | |
77 scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner) { | |
78 proxy_task_runner_ = proxy_task_runner; | |
79 } | |
80 | |
81 // mojo::AssociatedGroupController: | |
82 void CreateEndpointHandlePair( | |
83 mojo::ScopedInterfaceEndpointHandle* local_endpoint, | |
84 mojo::ScopedInterfaceEndpointHandle* remote_endpoint) override { | |
85 base::AutoLock locker(lock_); | |
86 uint32_t id = 0; | |
87 do { | |
88 if (next_interface_id_ >= mojo::kInterfaceIdNamespaceMask) | |
89 next_interface_id_ = 1; | |
90 id = (next_interface_id_++) | id_namespace_mask_; | |
91 } while (ContainsKey(endpoints_, id)); | |
92 | |
93 Endpoint* endpoint = new Endpoint(this, id); | |
94 if (encountered_error_) | |
95 endpoint->set_peer_closed(); | |
96 endpoints_.insert({ id, endpoint }); | |
97 | |
98 *local_endpoint = CreateScopedInterfaceEndpointHandle(id, true); | |
99 *remote_endpoint = CreateScopedInterfaceEndpointHandle(id, false); | |
100 } | |
101 | |
102 mojo::ScopedInterfaceEndpointHandle CreateLocalEndpointHandle( | |
103 mojo::InterfaceId id) override { | |
104 if (!mojo::IsValidInterfaceId(id)) | |
105 return mojo::ScopedInterfaceEndpointHandle(); | |
106 | |
107 base::AutoLock locker(lock_); | |
108 bool inserted = false; | |
109 Endpoint* endpoint = FindOrInsertEndpoint(id, &inserted); | |
110 if (inserted && encountered_error_) | |
111 endpoint->set_peer_closed(); | |
112 | |
113 return CreateScopedInterfaceEndpointHandle(id, true); | |
114 } | |
115 | |
116 void CloseEndpointHandle(mojo::InterfaceId id, bool is_local) override { | |
117 if (!mojo::IsValidInterfaceId(id)) | |
118 return; | |
119 | |
120 base::AutoLock locker(lock_); | |
121 if (!is_local) { | |
122 DCHECK(ContainsKey(endpoints_, id)); | |
123 DCHECK(!mojo::IsMasterInterfaceId(id)); | |
124 control_message_proxy_.NotifyEndpointClosedBeforeSent(id); | |
125 return; | |
126 } | |
127 | |
128 DCHECK(ContainsKey(endpoints_, id)); | |
129 Endpoint* endpoint = endpoints_[id].get(); | |
130 DCHECK(!endpoint->client()); | |
131 DCHECK(!endpoint->closed()); | |
132 MarkClosedAndMaybeRemove(endpoint); | |
133 | |
134 if (!mojo::IsMasterInterfaceId(id)) | |
135 control_message_proxy_.NotifyPeerEndpointClosed(id); | |
136 } | |
137 | |
138 mojo::InterfaceEndpointController* AttachEndpointClient( | |
139 const mojo::ScopedInterfaceEndpointHandle& handle, | |
140 mojo::InterfaceEndpointClient* client, | |
141 scoped_refptr<base::SingleThreadTaskRunner> runner) override { | |
142 const mojo::InterfaceId id = handle.id(); | |
143 | |
144 DCHECK(mojo::IsValidInterfaceId(id)); | |
145 DCHECK(client); | |
146 | |
147 base::AutoLock locker(lock_); | |
148 DCHECK(ContainsKey(endpoints_, id)); | |
149 | |
150 Endpoint* endpoint = endpoints_[id].get(); | |
151 endpoint->AttachClient(client, std::move(runner)); | |
152 | |
153 if (endpoint->peer_closed()) | |
154 NotifyEndpointOfError(endpoint, true /* force_async */); | |
155 | |
156 return endpoint; | |
157 } | |
158 | |
159 void DetachEndpointClient( | |
160 const mojo::ScopedInterfaceEndpointHandle& handle) override { | |
161 const mojo::InterfaceId id = handle.id(); | |
162 | |
163 DCHECK(mojo::IsValidInterfaceId(id)); | |
164 | |
165 base::AutoLock locker(lock_); | |
166 DCHECK(ContainsKey(endpoints_, id)); | |
167 | |
168 Endpoint* endpoint = endpoints_[id].get(); | |
169 endpoint->DetachClient(); | |
170 } | |
171 | |
172 void RaiseError() override { | |
173 if (task_runner_->BelongsToCurrentThread()) { | |
174 connector_.RaiseError(); | |
175 } else { | |
176 task_runner_->PostTask( | |
177 FROM_HERE, | |
178 base::Bind(&ChannelAssociatedGroupController::RaiseError, this)); | |
179 } | |
180 } | |
181 | |
182 private: | |
183 class Endpoint; | |
184 friend class Endpoint; | |
185 | |
186 class Endpoint : public base::RefCountedThreadSafe<Endpoint>, | |
187 public mojo::InterfaceEndpointController { | |
188 public: | |
189 Endpoint(ChannelAssociatedGroupController* controller, mojo::InterfaceId id) | |
190 : controller_(controller), id_(id) {} | |
191 | |
192 mojo::InterfaceId id() const { return id_; } | |
193 | |
194 bool closed() const { | |
195 controller_->lock_.AssertAcquired(); | |
196 return closed_; | |
197 } | |
198 | |
199 void set_closed() { | |
200 controller_->lock_.AssertAcquired(); | |
201 closed_ = true; | |
202 } | |
203 | |
204 bool peer_closed() const { | |
205 controller_->lock_.AssertAcquired(); | |
206 return peer_closed_; | |
207 } | |
208 | |
209 void set_peer_closed() { | |
210 controller_->lock_.AssertAcquired(); | |
211 peer_closed_ = true; | |
212 } | |
213 | |
214 base::SingleThreadTaskRunner* task_runner() const { | |
215 return task_runner_.get(); | |
216 } | |
217 | |
218 mojo::InterfaceEndpointClient* client() const { | |
219 controller_->lock_.AssertAcquired(); | |
220 return client_; | |
221 } | |
222 | |
223 void AttachClient(mojo::InterfaceEndpointClient* client, | |
224 scoped_refptr<base::SingleThreadTaskRunner> runner) { | |
225 controller_->lock_.AssertAcquired(); | |
226 DCHECK(!client_); | |
227 DCHECK(!closed_); | |
228 DCHECK(runner->BelongsToCurrentThread()); | |
229 | |
230 task_runner_ = std::move(runner); | |
231 client_ = client; | |
232 } | |
233 | |
234 void DetachClient() { | |
235 controller_->lock_.AssertAcquired(); | |
236 DCHECK(client_); | |
237 DCHECK(task_runner_->BelongsToCurrentThread()); | |
238 DCHECK(!closed_); | |
239 | |
240 task_runner_ = nullptr; | |
241 client_ = nullptr; | |
242 } | |
243 | |
244 // mojo::InterfaceEndpointController: | |
245 bool SendMessage(mojo::Message* message) override { | |
246 DCHECK(task_runner_->BelongsToCurrentThread()); | |
247 message->set_interface_id(id_); | |
248 return controller_->SendMessage(message); | |
249 } | |
250 | |
251 void AllowWokenUpBySyncWatchOnSameThread() override { | |
252 DCHECK(task_runner_->BelongsToCurrentThread()); | |
253 | |
254 // TODO(rockot): Implement sync waiting. | |
255 NOTREACHED(); | |
256 } | |
257 | |
258 bool SyncWatch(const bool* should_stop) override { | |
259 DCHECK(task_runner_->BelongsToCurrentThread()); | |
260 | |
261 // It's not legal to make sync calls from the master endpoint's thread, | |
262 // and in fact they must only happen from the proxy task runner. | |
263 DCHECK(!controller_->task_runner_->BelongsToCurrentThread()); | |
264 DCHECK(controller_->proxy_task_runner_->BelongsToCurrentThread()); | |
265 | |
266 // TODO(rockot): Implement sync waiting. | |
267 NOTREACHED(); | |
268 return false; | |
269 } | |
270 | |
271 private: | |
272 friend class base::RefCountedThreadSafe<Endpoint>; | |
273 | |
274 ~Endpoint() override {} | |
275 | |
276 ChannelAssociatedGroupController* const controller_; | |
277 const mojo::InterfaceId id_; | |
278 | |
279 bool closed_ = false; | |
280 bool peer_closed_ = false; | |
281 mojo::InterfaceEndpointClient* client_ = nullptr; | |
282 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | |
283 | |
284 DISALLOW_COPY_AND_ASSIGN(Endpoint); | |
285 }; | |
286 | |
287 ~ChannelAssociatedGroupController() override { | |
288 base::AutoLock locker(lock_); | |
289 | |
290 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) { | |
291 Endpoint* endpoint = iter->second.get(); | |
292 ++iter; | |
293 | |
294 DCHECK(endpoint->closed()); | |
295 MarkClosedAndMaybeRemove(endpoint); | |
yzshen1
2016/07/13 17:53:27
I think it should be MarkPeerClosed, right?
Ken Rockot(use gerrit already)
2016/07/13 17:58:56
Gah! Fixed.
| |
296 } | |
297 | |
298 DCHECK(endpoints_.empty()); | |
299 } | |
300 | |
301 bool SendMessage(mojo::Message* message) { | |
302 if (task_runner_->BelongsToCurrentThread()) { | |
303 DCHECK(thread_checker_.CalledOnValidThread()); | |
304 return connector_.Accept(message); | |
305 } else { | |
306 // We always post tasks to the master endpoint thread when called from the | |
307 // proxy thread in order to simulate IPC::ChannelProxy::Send behavior. | |
308 DCHECK(proxy_task_runner_ && | |
309 proxy_task_runner_->BelongsToCurrentThread()); | |
310 std::unique_ptr<mojo::Message> passed_message(new mojo::Message); | |
311 message->MoveTo(passed_message.get()); | |
312 task_runner_->PostTask( | |
313 FROM_HERE, | |
314 base::Bind( | |
315 &ChannelAssociatedGroupController::SendMessageOnMasterThread, | |
316 this, base::Passed(&passed_message))); | |
317 return true; | |
318 } | |
319 } | |
320 | |
321 void SendMessageOnMasterThread(std::unique_ptr<mojo::Message> message) { | |
322 DCHECK(thread_checker_.CalledOnValidThread()); | |
323 if (!SendMessage(message.get())) | |
324 RaiseError(); | |
325 } | |
326 | |
327 void OnPipeError() { | |
328 DCHECK(thread_checker_.CalledOnValidThread()); | |
329 | |
330 // We keep |this| alive here because it's possible for the notifications | |
331 // below to release all other references. | |
332 scoped_refptr<ChannelAssociatedGroupController> keepalive(this); | |
333 | |
334 base::AutoLock locker(lock_); | |
335 encountered_error_ = true; | |
336 | |
337 std::vector<scoped_refptr<Endpoint>> endpoints_to_notify; | |
338 for (auto iter = endpoints_.begin(); iter != endpoints_.end();) { | |
339 Endpoint* endpoint = iter->second.get(); | |
340 ++iter; | |
341 | |
342 if (endpoint->client()) | |
343 endpoints_to_notify.push_back(endpoint); | |
344 | |
345 MarkPeerClosedAndMaybeRemove(endpoint); | |
346 } | |
347 | |
348 for (auto& endpoint : endpoints_to_notify) { | |
349 // Because an notification may in turn detach any endpoint, we have to | |
350 // check each client again here. | |
351 if (endpoint->client()) | |
352 NotifyEndpointOfError(endpoint.get(), false /* force_async */); | |
353 } | |
354 } | |
355 | |
356 void NotifyEndpointOfError(Endpoint* endpoint, bool force_async) { | |
357 lock_.AssertAcquired(); | |
358 DCHECK(endpoint->task_runner() && endpoint->client()); | |
359 if (endpoint->task_runner()->BelongsToCurrentThread() && !force_async) { | |
360 mojo::InterfaceEndpointClient* client = endpoint->client(); | |
361 | |
362 base::AutoUnlock unlocker(lock_); | |
363 client->NotifyError(); | |
364 } else { | |
365 endpoint->task_runner()->PostTask( | |
366 FROM_HERE, | |
367 base::Bind(&ChannelAssociatedGroupController | |
368 ::NotifyEndpointOfErrorOnEndpointThread, this, | |
369 make_scoped_refptr(endpoint))); | |
370 } | |
371 } | |
372 | |
373 void NotifyEndpointOfErrorOnEndpointThread(scoped_refptr<Endpoint> endpoint) { | |
374 base::AutoLock locker(lock_); | |
375 if (!endpoint->client()) | |
376 return; | |
377 DCHECK(endpoint->task_runner()->BelongsToCurrentThread()); | |
378 NotifyEndpointOfError(endpoint.get(), false /* force_async */); | |
379 } | |
380 | |
381 void MarkClosedAndMaybeRemove(Endpoint* endpoint) { | |
382 lock_.AssertAcquired(); | |
383 endpoint->set_closed(); | |
384 if (endpoint->closed() && endpoint->peer_closed()) | |
385 endpoints_.erase(endpoint->id()); | |
386 } | |
387 | |
388 void MarkPeerClosedAndMaybeRemove(Endpoint* endpoint) { | |
389 lock_.AssertAcquired(); | |
390 endpoint->set_peer_closed(); | |
391 if (endpoint->closed() && endpoint->peer_closed()) | |
392 endpoints_.erase(endpoint->id()); | |
393 } | |
394 | |
395 Endpoint* FindOrInsertEndpoint(mojo::InterfaceId id, bool* inserted) { | |
396 lock_.AssertAcquired(); | |
397 DCHECK(!inserted || !*inserted); | |
398 | |
399 auto iter = endpoints_.find(id); | |
400 if (iter != endpoints_.end()) | |
401 return iter->second.get(); | |
402 | |
403 Endpoint* endpoint = new Endpoint(this, id); | |
404 endpoints_.insert({ id, endpoint }); | |
405 if (inserted) | |
406 *inserted = true; | |
407 return endpoint; | |
408 } | |
409 | |
410 // mojo::MessageReceiver: | |
411 bool Accept(mojo::Message* message) override { | |
412 DCHECK(thread_checker_.CalledOnValidThread()); | |
413 | |
414 if (mojo::PipeControlMessageHandler::IsPipeControlMessage(message)) { | |
415 if (!control_message_handler_.Accept(message)) | |
416 RaiseError(); | |
417 return true; | |
418 } | |
419 | |
420 mojo::InterfaceId id = message->interface_id(); | |
421 DCHECK(mojo::IsValidInterfaceId(id)); | |
422 | |
423 base::AutoLock locker(lock_); | |
424 bool inserted = false; | |
425 Endpoint* endpoint = FindOrInsertEndpoint(id, &inserted); | |
426 if (inserted) { | |
427 MarkClosedAndMaybeRemove(endpoint); | |
428 if (!mojo::IsMasterInterfaceId(id)) | |
429 control_message_proxy_.NotifyPeerEndpointClosed(id); | |
430 return true; | |
431 } | |
432 | |
433 if (endpoint->closed()) | |
434 return true; | |
435 | |
436 mojo::InterfaceEndpointClient* client = endpoint->client(); | |
437 if (!client || !endpoint->task_runner()->BelongsToCurrentThread()) { | |
438 // No client has been bound yet or the client runs tasks on another | |
439 // thread. We assume the other thread must always be the one on which | |
440 // |proxy_task_runner_| runs tasks, since that's the only valid scenario. | |
441 // | |
442 // If the client is not yet bound, it must be bound by the time this task | |
443 // runs or else it's programmer error. | |
444 DCHECK(proxy_task_runner_); | |
445 CHECK(false); | |
446 std::unique_ptr<mojo::Message> passed_message(new mojo::Message); | |
447 message->MoveTo(passed_message.get()); | |
448 proxy_task_runner_->PostTask( | |
449 FROM_HERE, | |
450 base::Bind(&ChannelAssociatedGroupController::AcceptOnProxyThread, | |
451 this, base::Passed(&passed_message))); | |
452 return true; | |
453 } | |
454 | |
455 // We do not expect to receive sync responses on the master endpoint thread. | |
456 // If it's happening, it's a bug. | |
457 DCHECK(!message->has_flag(mojo::Message::kFlagIsSync)); | |
458 | |
459 bool result = false; | |
460 { | |
461 base::AutoUnlock unlocker(lock_); | |
462 result = client->HandleIncomingMessage(message); | |
463 } | |
464 | |
465 if (!result) | |
466 RaiseError(); | |
467 | |
468 return true; | |
469 } | |
470 | |
471 void AcceptOnProxyThread(std::unique_ptr<mojo::Message> message) { | |
472 DCHECK(proxy_task_runner_->BelongsToCurrentThread()); | |
473 | |
474 // TODO(rockot): Implement this. | |
475 NOTREACHED(); | |
476 } | |
477 | |
478 // mojo::PipeControlMessageHandlerDelegate: | |
479 bool OnPeerAssociatedEndpointClosed(mojo::InterfaceId id) override { | |
480 DCHECK(thread_checker_.CalledOnValidThread()); | |
481 | |
482 if (mojo::IsMasterInterfaceId(id)) | |
483 return false; | |
484 | |
485 base::AutoLock locker(lock_); | |
486 scoped_refptr<Endpoint> endpoint = FindOrInsertEndpoint(id, nullptr); | |
487 if (!endpoint->peer_closed()) { | |
488 if (endpoint->client()) | |
489 NotifyEndpointOfError(endpoint.get(), false /* force_async */); | |
490 MarkPeerClosedAndMaybeRemove(endpoint.get()); | |
491 } | |
492 | |
493 return true; | |
494 } | |
495 | |
496 bool OnAssociatedEndpointClosedBeforeSent(mojo::InterfaceId id) override { | |
497 DCHECK(thread_checker_.CalledOnValidThread()); | |
498 | |
499 if (mojo::IsMasterInterfaceId(id)) | |
500 return false; | |
501 | |
502 base::AutoLock locker(lock_); | |
503 Endpoint* endpoint = FindOrInsertEndpoint(id, nullptr); | |
504 DCHECK(!endpoint->closed()); | |
505 MarkClosedAndMaybeRemove(endpoint); | |
506 control_message_proxy_.NotifyPeerEndpointClosed(id); | |
507 return true; | |
508 } | |
509 | |
510 // Checked in places which must be run on the master endpoint's thread. | |
511 base::ThreadChecker thread_checker_; | |
512 | |
513 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | |
514 scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_; | |
515 const uint32_t id_namespace_mask_; | |
516 std::unique_ptr<mojo::AssociatedGroup> associated_group_; | |
517 mojo::Connector connector_; | |
518 mojo::MessageHeaderValidator header_validator_; | |
519 mojo::PipeControlMessageHandler control_message_handler_; | |
520 | |
521 // Guards the fields below for thread-safe access. | |
522 base::Lock lock_; | |
523 | |
524 bool encountered_error_ = false; | |
525 uint32_t next_interface_id_ = 1; | |
526 std::map<uint32_t, scoped_refptr<Endpoint>> endpoints_; | |
527 mojo::PipeControlMessageProxy control_message_proxy_; | |
528 | |
529 DISALLOW_COPY_AND_ASSIGN(ChannelAssociatedGroupController); | |
530 }; | |
531 | |
532 class BootstrapMasterProxy { | |
533 public: | |
534 BootstrapMasterProxy() {} | |
535 ~BootstrapMasterProxy() { | |
536 endpoint_client_.reset(); | |
537 proxy_.reset(); | |
538 if (controller_) | |
539 controller_->ShutDown(); | |
540 } | |
541 | |
542 void Bind(mojo::ScopedMessagePipeHandle handle) { | |
543 DCHECK(!controller_); | |
544 controller_ = new ChannelAssociatedGroupController(true, std::move(handle)); | |
545 endpoint_client_.reset(new mojo::InterfaceEndpointClient( | |
546 controller_->CreateLocalEndpointHandle(mojo::kMasterInterfaceId), | |
547 nullptr, | |
548 base::MakeUnique<typename mojom::Bootstrap::ResponseValidator_>(), | |
549 false, base::ThreadTaskRunnerHandle::Get())); | |
550 proxy_.reset(new mojom::BootstrapProxy(endpoint_client_.get())); | |
551 proxy_->serialization_context()->group_controller = controller_; | |
552 } | |
553 | |
554 void set_connection_error_handler(const base::Closure& handler) { | |
555 DCHECK(endpoint_client_); | |
556 endpoint_client_->set_connection_error_handler(handler); | |
557 } | |
558 | |
559 mojo::AssociatedGroup* associated_group() { | |
560 DCHECK(controller_); | |
561 return controller_->associated_group(); | |
562 } | |
563 | |
564 mojom::Bootstrap* operator->() { | |
565 DCHECK(proxy_); | |
566 return proxy_.get(); | |
567 } | |
568 | |
569 private: | |
570 std::unique_ptr<mojom::BootstrapProxy> proxy_; | |
571 scoped_refptr<ChannelAssociatedGroupController> controller_; | |
572 std::unique_ptr<mojo::InterfaceEndpointClient> endpoint_client_; | |
573 | |
574 DISALLOW_COPY_AND_ASSIGN(BootstrapMasterProxy); | |
575 }; | |
576 | |
577 class BootstrapMasterBinding { | |
578 public: | |
579 explicit BootstrapMasterBinding(mojom::Bootstrap* impl) { | |
580 stub_.set_sink(impl); | |
581 } | |
582 | |
583 ~BootstrapMasterBinding() { | |
584 endpoint_client_.reset(); | |
585 if (controller_) | |
586 controller_->ShutDown(); | |
587 } | |
588 | |
589 void set_connection_error_handler(const base::Closure& handler) { | |
590 DCHECK(endpoint_client_); | |
591 endpoint_client_->set_connection_error_handler(handler); | |
592 } | |
593 | |
594 void Bind(mojo::ScopedMessagePipeHandle handle) { | |
595 DCHECK(!controller_); | |
596 controller_ = | |
597 new ChannelAssociatedGroupController(false, std::move(handle)); | |
598 stub_.serialization_context()->group_controller = controller_; | |
599 | |
600 endpoint_client_.reset(new mojo::InterfaceEndpointClient( | |
601 controller_->CreateLocalEndpointHandle(mojo::kMasterInterfaceId), | |
602 &stub_, | |
603 base::MakeUnique<typename mojom::Bootstrap::RequestValidator_>(), | |
604 false, base::ThreadTaskRunnerHandle::Get())); | |
605 } | |
606 | |
607 private: | |
608 mojom::BootstrapStub stub_; | |
609 scoped_refptr<ChannelAssociatedGroupController> controller_; | |
610 std::unique_ptr<mojo::InterfaceEndpointClient> endpoint_client_; | |
611 | |
612 DISALLOW_COPY_AND_ASSIGN(BootstrapMasterBinding); | |
613 }; | |
614 | |
24 // MojoBootstrap for the server process. You should create the instance | 615 // MojoBootstrap for the server process. You should create the instance |
25 // using MojoBootstrap::Create(). | 616 // using MojoBootstrap::Create(). |
26 class MojoServerBootstrap : public MojoBootstrap { | 617 class MojoServerBootstrap : public MojoBootstrap { |
27 public: | 618 public: |
28 MojoServerBootstrap(); | 619 MojoServerBootstrap(); |
29 | 620 |
30 private: | 621 private: |
31 // MojoBootstrap implementation. | 622 // MojoBootstrap implementation. |
32 void Connect() override; | 623 void Connect() override; |
33 | 624 |
34 void OnInitDone(int32_t peer_pid); | 625 void OnInitDone(int32_t peer_pid); |
35 | 626 |
36 mojom::BootstrapPtr bootstrap_; | 627 BootstrapMasterProxy bootstrap_; |
37 IPC::mojom::ChannelAssociatedPtrInfo send_channel_; | 628 IPC::mojom::ChannelAssociatedPtrInfo send_channel_; |
38 IPC::mojom::ChannelAssociatedRequest receive_channel_request_; | 629 IPC::mojom::ChannelAssociatedRequest receive_channel_request_; |
39 | 630 |
40 DISALLOW_COPY_AND_ASSIGN(MojoServerBootstrap); | 631 DISALLOW_COPY_AND_ASSIGN(MojoServerBootstrap); |
41 }; | 632 }; |
42 | 633 |
43 MojoServerBootstrap::MojoServerBootstrap() = default; | 634 MojoServerBootstrap::MojoServerBootstrap() = default; |
44 | 635 |
45 void MojoServerBootstrap::Connect() { | 636 void MojoServerBootstrap::Connect() { |
46 DCHECK_EQ(state(), STATE_INITIALIZED); | 637 DCHECK_EQ(state(), STATE_INITIALIZED); |
47 | 638 |
48 bootstrap_.Bind(mojom::BootstrapPtrInfo(TakeHandle(), 0)); | 639 bootstrap_.Bind(TakeHandle()); |
49 bootstrap_.set_connection_error_handler( | 640 bootstrap_.set_connection_error_handler( |
50 base::Bind(&MojoServerBootstrap::Fail, base::Unretained(this))); | 641 base::Bind(&MojoServerBootstrap::Fail, base::Unretained(this))); |
51 | 642 |
52 IPC::mojom::ChannelAssociatedRequest send_channel_request; | 643 IPC::mojom::ChannelAssociatedRequest send_channel_request; |
53 IPC::mojom::ChannelAssociatedPtrInfo receive_channel; | 644 IPC::mojom::ChannelAssociatedPtrInfo receive_channel; |
54 | 645 |
55 bootstrap_.associated_group()->CreateAssociatedInterface( | 646 bootstrap_.associated_group()->CreateAssociatedInterface( |
56 mojo::AssociatedGroup::WILL_PASS_REQUEST, &send_channel_, | 647 mojo::AssociatedGroup::WILL_PASS_REQUEST, &send_channel_, |
57 &send_channel_request); | 648 &send_channel_request); |
58 bootstrap_.associated_group()->CreateAssociatedInterface( | 649 bootstrap_.associated_group()->CreateAssociatedInterface( |
(...skipping 30 matching lines...) Expand all Loading... | |
89 private: | 680 private: |
90 // MojoBootstrap implementation. | 681 // MojoBootstrap implementation. |
91 void Connect() override; | 682 void Connect() override; |
92 | 683 |
93 // mojom::Bootstrap implementation. | 684 // mojom::Bootstrap implementation. |
94 void Init(mojom::ChannelAssociatedRequest receive_channel, | 685 void Init(mojom::ChannelAssociatedRequest receive_channel, |
95 mojom::ChannelAssociatedPtrInfo send_channel, | 686 mojom::ChannelAssociatedPtrInfo send_channel, |
96 int32_t peer_pid, | 687 int32_t peer_pid, |
97 const InitCallback& callback) override; | 688 const InitCallback& callback) override; |
98 | 689 |
99 mojo::Binding<mojom::Bootstrap> binding_; | 690 BootstrapMasterBinding binding_; |
100 | 691 |
101 DISALLOW_COPY_AND_ASSIGN(MojoClientBootstrap); | 692 DISALLOW_COPY_AND_ASSIGN(MojoClientBootstrap); |
102 }; | 693 }; |
103 | 694 |
104 MojoClientBootstrap::MojoClientBootstrap() : binding_(this) {} | 695 MojoClientBootstrap::MojoClientBootstrap() : binding_(this) {} |
105 | 696 |
106 void MojoClientBootstrap::Connect() { | 697 void MojoClientBootstrap::Connect() { |
107 binding_.Bind(TakeHandle()); | 698 binding_.Bind(TakeHandle()); |
108 binding_.set_connection_error_handler( | 699 binding_.set_connection_error_handler( |
109 base::Bind(&MojoClientBootstrap::Fail, base::Unretained(this))); | 700 base::Bind(&MojoClientBootstrap::Fail, base::Unretained(this))); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
169 | 760 |
170 bool MojoBootstrap::HasFailed() const { | 761 bool MojoBootstrap::HasFailed() const { |
171 return state() == STATE_ERROR; | 762 return state() == STATE_ERROR; |
172 } | 763 } |
173 | 764 |
174 mojo::ScopedMessagePipeHandle MojoBootstrap::TakeHandle() { | 765 mojo::ScopedMessagePipeHandle MojoBootstrap::TakeHandle() { |
175 return std::move(handle_); | 766 return std::move(handle_); |
176 } | 767 } |
177 | 768 |
178 } // namespace IPC | 769 } // namespace IPC |
OLD | NEW |