ipc_support.cc 6.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
// 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;
143
  bool is_first;
144
  embedder::ScopedPlatformHandle platform_connection_handle;
145
  CHECK_EQ(connection_manager()->Connect(connection_id, &peer_id, &is_first,
146 147
                                         &platform_connection_handle),
           ConnectionManager::Result::SUCCESS_CONNECT_NEW_CONNECTION);
148 149 150 151 152 153 154 155 156
  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);

157 158
  system::ProcessIdentifier peer_id = system::kInvalidProcessIdentifier;
  bool is_first;
159
  embedder::ScopedPlatformHandle platform_connection_handle;
160
  CHECK_EQ(connection_manager()->Connect(connection_id, &peer_id, &is_first,
161 162
                                         &platform_connection_handle),
           ConnectionManager::Result::SUCCESS_CONNECT_NEW_CONNECTION);
163 164 165 166 167 168 169
  DCHECK_EQ(peer_id, system::kMasterProcessIdentifier);
  DCHECK(platform_connection_handle.is_valid());
  return platform_connection_handle;
}

}  // namespace system
}  // namespace mojo