| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "mojo/edk/system/ipc_support.h" |
| |
| #include "base/logging.h" |
| #include "mojo/edk/embedder/master_process_delegate.h" |
| #include "mojo/edk/embedder/slave_process_delegate.h" |
| #include "mojo/edk/system/channel_manager.h" |
| #include "mojo/edk/system/master_connection_manager.h" |
| #include "mojo/edk/system/message_pipe_dispatcher.h" |
| #include "mojo/edk/system/slave_connection_manager.h" |
| |
| namespace mojo { |
| namespace system { |
| |
| IPCSupport::IPCSupport( |
| embedder::PlatformSupport* platform_support, |
| embedder::ProcessType process_type, |
| scoped_refptr<base::TaskRunner> delegate_thread_task_runner, |
| embedder::ProcessDelegate* process_delegate, |
| scoped_refptr<base::TaskRunner> io_thread_task_runner, |
| embedder::ScopedPlatformHandle platform_handle) |
| : process_type_(process_type), |
| delegate_thread_task_runner_(delegate_thread_task_runner.Pass()), |
| process_delegate_(process_delegate), |
| io_thread_task_runner_(io_thread_task_runner.Pass()) { |
| DCHECK(delegate_thread_task_runner_); |
| DCHECK(io_thread_task_runner_); |
| |
| switch (process_type_) { |
| case embedder::ProcessType::UNINITIALIZED: |
| CHECK(false); |
| break; |
| case embedder::ProcessType::NONE: |
| DCHECK(!platform_handle.is_valid()); // We wouldn't do anything with it. |
| // Nothing to do. |
| break; |
| case embedder::ProcessType::MASTER: |
| DCHECK(!platform_handle.is_valid()); // We wouldn't do anything with it. |
| connection_manager_.reset( |
| new system::MasterConnectionManager(platform_support)); |
| static_cast<system::MasterConnectionManager*>(connection_manager_.get()) |
| ->Init( |
| delegate_thread_task_runner_, |
| static_cast<embedder::MasterProcessDelegate*>(process_delegate_)); |
| break; |
| case embedder::ProcessType::SLAVE: |
| connection_manager_.reset( |
| new system::SlaveConnectionManager(platform_support)); |
| static_cast<system::SlaveConnectionManager*>(connection_manager_.get()) |
| ->Init( |
| delegate_thread_task_runner_, |
| static_cast<embedder::SlaveProcessDelegate*>(process_delegate_), |
| platform_handle.Pass()); |
| break; |
| } |
| |
| channel_manager_.reset(new ChannelManager( |
| platform_support, io_thread_task_runner_, connection_manager_.get())); |
| } |
| |
| IPCSupport::~IPCSupport() { |
| DCHECK_EQ(process_type_, embedder::ProcessType::UNINITIALIZED); |
| } |
| |
| void IPCSupport::ShutdownOnIOThread() { |
| DCHECK_NE(process_type_, embedder::ProcessType::UNINITIALIZED); |
| |
| channel_manager_->ShutdownOnIOThread(); |
| channel_manager_.reset(); |
| |
| if (connection_manager_) { |
| connection_manager_->Shutdown(); |
| connection_manager_.reset(); |
| } |
| |
| io_thread_task_runner_ = nullptr; |
| process_delegate_ = nullptr; |
| delegate_thread_task_runner_ = nullptr; |
| process_type_ = embedder::ProcessType::UNINITIALIZED; |
| } |
| |
| ConnectionIdentifier IPCSupport::GenerateConnectionIdentifier() { |
| return connection_manager()->GenerateConnectionIdentifier(); |
| } |
| |
| scoped_refptr<system::MessagePipeDispatcher> IPCSupport::ConnectToSlave( |
| const ConnectionIdentifier& connection_id, |
| embedder::SlaveInfo slave_info, |
| embedder::ScopedPlatformHandle platform_handle, |
| const base::Closure& callback, |
| scoped_refptr<base::TaskRunner> callback_thread_task_runner, |
| ChannelId* channel_id) { |
| DCHECK(channel_id); |
| |
| // We rely on |ChannelId| and |ProcessIdentifier| being identical types. |
| // TODO(vtl): Use std::is_same instead when we are allowed to (C++11 library). |
| static_assert(sizeof(ChannelId) == sizeof(ProcessIdentifier), |
| "ChannelId and ProcessIdentifier types don't match"); |
| |
| embedder::ScopedPlatformHandle platform_connection_handle = |
| ConnectToSlaveInternal(connection_id, slave_info, platform_handle.Pass(), |
| channel_id); |
| return channel_manager()->CreateChannel( |
| *channel_id, platform_connection_handle.Pass(), callback, |
| callback_thread_task_runner); |
| } |
| |
| scoped_refptr<system::MessagePipeDispatcher> IPCSupport::ConnectToMaster( |
| const ConnectionIdentifier& connection_id, |
| const base::Closure& callback, |
| scoped_refptr<base::TaskRunner> callback_thread_task_runner, |
| ChannelId* channel_id) { |
| DCHECK(channel_id); |
| |
| // TODO(vtl): Use std::is_same instead when we are allowed to (C++11 library). |
| static_assert(sizeof(ChannelId) == sizeof(ProcessIdentifier), |
| "ChannelId and ProcessIdentifier types don't match"); |
| embedder::ScopedPlatformHandle platform_connection_handle = |
| ConnectToMasterInternal(connection_id); |
| *channel_id = kMasterProcessIdentifier; |
| return channel_manager()->CreateChannel( |
| *channel_id, platform_connection_handle.Pass(), callback, |
| callback_thread_task_runner); |
| } |
| |
| embedder::ScopedPlatformHandle IPCSupport::ConnectToSlaveInternal( |
| const ConnectionIdentifier& connection_id, |
| embedder::SlaveInfo slave_info, |
| embedder::ScopedPlatformHandle platform_handle, |
| ProcessIdentifier* slave_process_identifier) { |
| DCHECK(slave_process_identifier); |
| DCHECK_EQ(process_type_, embedder::ProcessType::MASTER); |
| |
| *slave_process_identifier = |
| static_cast<system::MasterConnectionManager*>(connection_manager()) |
| ->AddSlaveAndBootstrap(slave_info, platform_handle.Pass(), |
| connection_id); |
| |
| system::ProcessIdentifier peer_id = system::kInvalidProcessIdentifier; |
| bool is_first; |
| embedder::ScopedPlatformHandle platform_connection_handle; |
| CHECK_EQ(connection_manager()->Connect(connection_id, &peer_id, &is_first, |
| &platform_connection_handle), |
| ConnectionManager::Result::SUCCESS_CONNECT_NEW_CONNECTION); |
| DCHECK_EQ(peer_id, *slave_process_identifier); |
| DCHECK(platform_connection_handle.is_valid()); |
| return platform_connection_handle; |
| } |
| |
| embedder::ScopedPlatformHandle IPCSupport::ConnectToMasterInternal( |
| const ConnectionIdentifier& connection_id) { |
| DCHECK_EQ(process_type_, embedder::ProcessType::SLAVE); |
| |
| system::ProcessIdentifier peer_id = system::kInvalidProcessIdentifier; |
| bool is_first; |
| embedder::ScopedPlatformHandle platform_connection_handle; |
| CHECK_EQ(connection_manager()->Connect(connection_id, &peer_id, &is_first, |
| &platform_connection_handle), |
| ConnectionManager::Result::SUCCESS_CONNECT_NEW_CONNECTION); |
| DCHECK_EQ(peer_id, system::kMasterProcessIdentifier); |
| DCHECK(platform_connection_handle.is_valid()); |
| return platform_connection_handle; |
| } |
| |
| } // namespace system |
| } // namespace mojo |