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