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 MarkPeerClosedAndMaybeRemove(endpoint); |
| 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 |