| // 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 <type_traits> |
| #include <utility> |
| |
| #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" |
| |
| using mojo::platform::PlatformHandleWatcher; |
| using mojo::platform::ScopedPlatformHandle; |
| using mojo::platform::TaskRunner; |
| using mojo::util::RefPtr; |
| |
| namespace mojo { |
| namespace system { |
| |
| IPCSupport::IPCSupport(embedder::PlatformSupport* platform_support, |
| embedder::ProcessType process_type, |
| RefPtr<TaskRunner>&& delegate_thread_task_runner, |
| embedder::ProcessDelegate* process_delegate, |
| RefPtr<TaskRunner>&& io_task_runner, |
| PlatformHandleWatcher* io_watcher, |
| ScopedPlatformHandle platform_handle) |
| : process_type_(process_type), |
| delegate_thread_task_runner_(std::move(delegate_thread_task_runner)), |
| process_delegate_(process_delegate), |
| io_task_runner_(std::move(io_task_runner)), |
| io_watcher_(io_watcher) { |
| DCHECK(delegate_thread_task_runner_); |
| DCHECK(io_task_runner_); |
| DCHECK(io_watcher_); |
| |
| 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_.Clone(), |
| 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_.Clone(), |
| static_cast<embedder::SlaveProcessDelegate*>(process_delegate_), |
| platform_handle.Pass()); |
| break; |
| } |
| |
| channel_manager_.reset( |
| new ChannelManager(platform_support, io_task_runner_.Clone(), io_watcher_, |
| 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_watcher_ = nullptr; |
| io_task_runner_ = nullptr; |
| process_delegate_ = nullptr; |
| delegate_thread_task_runner_ = nullptr; |
| process_type_ = embedder::ProcessType::UNINITIALIZED; |
| } |
| |
| ConnectionIdentifier IPCSupport::GenerateConnectionIdentifier() { |
| return connection_manager()->GenerateConnectionIdentifier(); |
| } |
| |
| RefPtr<MessagePipeDispatcher> IPCSupport::ConnectToSlave( |
| const ConnectionIdentifier& connection_id, |
| embedder::SlaveInfo slave_info, |
| ScopedPlatformHandle platform_handle, |
| std::function<void()>&& callback, |
| RefPtr<TaskRunner>&& callback_thread_task_runner, |
| ChannelId* channel_id) { |
| DCHECK(channel_id); |
| |
| // We rely on |ChannelId| and |ProcessIdentifier| being identical types. |
| static_assert(std::is_same<ChannelId, ProcessIdentifier>::value, |
| "ChannelId and ProcessIdentifier types don't match"); |
| |
| ScopedPlatformHandle platform_connection_handle = ConnectToSlaveInternal( |
| connection_id, slave_info, platform_handle.Pass(), channel_id); |
| return channel_manager()->CreateChannel( |
| *channel_id, platform_connection_handle.Pass(), std::move(callback), |
| std::move(callback_thread_task_runner)); |
| } |
| |
| RefPtr<MessagePipeDispatcher> IPCSupport::ConnectToMaster( |
| const ConnectionIdentifier& connection_id, |
| std::function<void()>&& callback, |
| RefPtr<TaskRunner>&& callback_thread_task_runner, |
| ChannelId* channel_id) { |
| DCHECK(channel_id); |
| |
| static_assert(std::is_same<ChannelId, ProcessIdentifier>::value, |
| "ChannelId and ProcessIdentifier types don't match"); |
| ScopedPlatformHandle platform_connection_handle = |
| ConnectToMasterInternal(connection_id); |
| *channel_id = kMasterProcessIdentifier; |
| return channel_manager()->CreateChannel( |
| *channel_id, platform_connection_handle.Pass(), std::move(callback), |
| std::move(callback_thread_task_runner)); |
| } |
| |
| ScopedPlatformHandle IPCSupport::ConnectToSlaveInternal( |
| const ConnectionIdentifier& connection_id, |
| embedder::SlaveInfo slave_info, |
| 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; |
| 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; |
| } |
| |
| ScopedPlatformHandle IPCSupport::ConnectToMasterInternal( |
| const ConnectionIdentifier& connection_id) { |
| DCHECK_EQ(process_type_, embedder::ProcessType::SLAVE); |
| |
| system::ProcessIdentifier peer_id = system::kInvalidProcessIdentifier; |
| bool is_first; |
| 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 |