blob: 97e99c194d77118ad753d3e653c69dcd41bd5407 [file] [log] [blame]
// 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