summaryrefslogtreecommitdiffstats
path: root/ipc/mojo
diff options
context:
space:
mode:
authormorrita <morrita@chromium.org>2014-09-23 14:16:00 -0700
committerCommit bot <commit-bot@chromium.org>2014-09-23 21:16:28 +0000
commit54f6f80c3623a6fb9d3049b6f5e0e23b1d76c34d (patch)
treed5188994206cd43ae680f6e7325ec5c45075b9da /ipc/mojo
parentde9555146d87d2daf5e2e1da425d46b8efc06415 (diff)
downloadchromium_src-54f6f80c3623a6fb9d3049b6f5e0e23b1d76c34d.zip
chromium_src-54f6f80c3623a6fb9d3049b6f5e0e23b1d76c34d.tar.gz
chromium_src-54f6f80c3623a6fb9d3049b6f5e0e23b1d76c34d.tar.bz2
IPC::ChannelMojo: Introduce IPC::MojoBootstrap for Windows
ChannelMojo doesn't work on Windows with existing implementaion and this CL fixes it. On Windows, ChannelHandle isn't immediately usable: The handle has to be activated through ConnectNamedPipe() windows API, which is done in its own Connect() handlshaking phase. ChannelMojo didn't Connect() underlying channel and took the ChannelHandle over so the handle wasn't activated. Instead of hijacking underlying ChannelHandle, this CL actually Connect()s underlying channel, creates a pipe on the server side, send one side of the pipe to the client process, and use the pipe for the MessagePipe initialization. These initialization task is encapsulated behind new MojoBootstrap class. ChannelMojo creates MojoBootstrap class to get the PlatformHandle which is already activated and usable. BUG=377980 TEST=ipc_mojo_bootstrap_unittest.cc, ipc_channel_mojo_unittest.cc R=viettrungluu@chromium.org, darin@chromium.org, yzshen@chromium.org Review URL: https://codereview.chromium.org/553283002 Cr-Commit-Position: refs/heads/master@{#296248}
Diffstat (limited to 'ipc/mojo')
-rw-r--r--ipc/mojo/BUILD.gn5
-rw-r--r--ipc/mojo/ipc_channel_mojo.cc139
-rw-r--r--ipc/mojo/ipc_channel_mojo.h43
-rw-r--r--ipc/mojo/ipc_channel_mojo_host.cc47
-rw-r--r--ipc/mojo/ipc_channel_mojo_host.h49
-rw-r--r--ipc/mojo/ipc_channel_mojo_unittest.cc65
-rw-r--r--ipc/mojo/ipc_mojo.gyp5
-rw-r--r--ipc/mojo/ipc_mojo_bootstrap.cc205
-rw-r--r--ipc/mojo/ipc_mojo_bootstrap.h82
-rw-r--r--ipc/mojo/ipc_mojo_bootstrap_unittest.cc86
-rw-r--r--ipc/mojo/ipc_mojo_perftest.cc22
11 files changed, 629 insertions, 119 deletions
diff --git a/ipc/mojo/BUILD.gn b/ipc/mojo/BUILD.gn
index 743a320..27c9cd9 100644
--- a/ipc/mojo/BUILD.gn
+++ b/ipc/mojo/BUILD.gn
@@ -6,8 +6,12 @@ component("mojo") {
sources = [
"ipc_channel_mojo.cc",
"ipc_channel_mojo.h",
+ "ipc_channel_mojo_host.cc",
+ "ipc_channel_mojo_host.h",
"ipc_channel_mojo_readers.cc",
"ipc_channel_mojo_readers.h",
+ "ipc_mojo_bootstrap.cc",
+ "ipc_mojo_bootstrap.h",
"ipc_message_pipe_reader.cc",
"ipc_message_pipe_reader.h",
]
@@ -27,6 +31,7 @@ component("mojo") {
test("ipc_mojo_unittests") {
sources = [
"ipc_channel_mojo_unittest.cc",
+ "ipc_mojo_bootstrap_unittest.cc",
"run_all_unittests.cc",
]
diff --git a/ipc/mojo/ipc_channel_mojo.cc b/ipc/mojo/ipc_channel_mojo.cc
index 71c373e..e61a90e 100644
--- a/ipc/mojo/ipc_channel_mojo.cc
+++ b/ipc/mojo/ipc_channel_mojo.cc
@@ -8,7 +8,9 @@
#include "base/bind_helpers.h"
#include "base/lazy_instance.h"
#include "ipc/ipc_listener.h"
+#include "ipc/mojo/ipc_channel_mojo_host.h"
#include "ipc/mojo/ipc_channel_mojo_readers.h"
+#include "ipc/mojo/ipc_mojo_bootstrap.h"
#include "mojo/embedder/embedder.h"
#if defined(OS_POSIX) && !defined(OS_NACL)
@@ -19,70 +21,28 @@ namespace IPC {
namespace {
-// IPC::Listener for bootstrap channels.
-// It should never receive any message.
-class NullListener : public Listener {
- public:
- virtual bool OnMessageReceived(const Message&) OVERRIDE {
- NOTREACHED();
- return false;
- }
-
- virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
- NOTREACHED();
- }
-
- virtual void OnChannelError() OVERRIDE {
- NOTREACHED();
- }
-
- virtual void OnBadMessageReceived(const Message& message) OVERRIDE {
- NOTREACHED();
- }
-};
-
-base::LazyInstance<NullListener> g_null_listener = LAZY_INSTANCE_INITIALIZER;
-
class MojoChannelFactory : public ChannelFactory {
public:
- MojoChannelFactory(
- ChannelHandle channel_handle,
- Channel::Mode mode,
- scoped_refptr<base::TaskRunner> io_thread_task_runner)
- : channel_handle_(channel_handle),
- mode_(mode),
- io_thread_task_runner_(io_thread_task_runner) {
- }
+ MojoChannelFactory(ChannelMojoHost* host,
+ ChannelHandle channel_handle,
+ Channel::Mode mode)
+ : host_(host), channel_handle_(channel_handle), mode_(mode) {}
virtual std::string GetName() const OVERRIDE {
return channel_handle_.name;
}
virtual scoped_ptr<Channel> BuildChannel(Listener* listener) OVERRIDE {
- return ChannelMojo::Create(
- channel_handle_,
- mode_,
- listener,
- io_thread_task_runner_).PassAs<Channel>();
+ return ChannelMojo::Create(host_, channel_handle_, mode_, listener)
+ .PassAs<Channel>();
}
private:
+ ChannelMojoHost* host_;
ChannelHandle channel_handle_;
Channel::Mode mode_;
- scoped_refptr<base::TaskRunner> io_thread_task_runner_;
};
-mojo::embedder::PlatformHandle ToPlatformHandle(
- const ChannelHandle& handle) {
-#if defined(OS_POSIX) && !defined(OS_NACL)
- return mojo::embedder::PlatformHandle(handle.socket.fd);
-#elif defined(OS_WIN)
- return mojo::embedder::PlatformHandle(handle.pipe.handle);
-#else
-#error "Unsupported Platform!"
-#endif
-}
-
} // namespace
//------------------------------------------------------------------------------
@@ -95,53 +55,59 @@ void ChannelMojo::ChannelInfoDeleter::operator()(
//------------------------------------------------------------------------------
// static
-scoped_ptr<ChannelMojo> ChannelMojo::Create(
- const ChannelHandle &channel_handle, Mode mode, Listener* listener,
- scoped_refptr<base::TaskRunner> io_thread_task_runner) {
+scoped_ptr<ChannelMojo> ChannelMojo::Create(ChannelMojoHost* host,
+ const ChannelHandle& channel_handle,
+ Mode mode,
+ Listener* listener) {
+ return make_scoped_ptr(new ChannelMojo(host, channel_handle, mode, listener));
+}
+
+// static
+scoped_ptr<ChannelFactory> ChannelMojo::CreateServerFactory(
+ ChannelMojoHost* host,
+ const ChannelHandle& channel_handle) {
return make_scoped_ptr(
- new ChannelMojo(channel_handle, mode, listener, io_thread_task_runner));
+ new MojoChannelFactory(host, channel_handle, Channel::MODE_SERVER))
+ .PassAs<ChannelFactory>();
}
// static
-scoped_ptr<ChannelFactory> ChannelMojo::CreateFactory(
- const ChannelHandle &channel_handle, Mode mode,
- scoped_refptr<base::TaskRunner> io_thread_task_runner) {
+scoped_ptr<ChannelFactory> ChannelMojo::CreateClientFactory(
+ const ChannelHandle& channel_handle) {
return make_scoped_ptr(
- new MojoChannelFactory(
- channel_handle, mode,
- io_thread_task_runner)).PassAs<ChannelFactory>();
+ new MojoChannelFactory(NULL, channel_handle, Channel::MODE_CLIENT))
+ .PassAs<ChannelFactory>();
}
-ChannelMojo::ChannelMojo(const ChannelHandle& channel_handle,
+ChannelMojo::ChannelMojo(ChannelMojoHost* host,
+ const ChannelHandle& handle,
Mode mode,
- Listener* listener,
- scoped_refptr<base::TaskRunner> io_thread_task_runner)
- : bootstrap_(
- Channel::Create(channel_handle, mode, g_null_listener.Pointer())),
+ Listener* listener)
+ : host_(host),
mode_(mode),
listener_(listener),
peer_pid_(base::kNullProcessId),
weak_factory_(this) {
- if (base::MessageLoopProxy::current() == io_thread_task_runner.get()) {
- InitOnIOThread();
- } else {
- io_thread_task_runner->PostTask(FROM_HERE,
- base::Bind(&ChannelMojo::InitOnIOThread,
- weak_factory_.GetWeakPtr()));
- }
+ // Create MojoBootstrap after all members are set as it touches
+ // ChannelMojo from a different thread.
+ bootstrap_ = MojoBootstrap::Create(handle, mode, this);
+ if (host_)
+ host_->OnChannelCreated(this);
}
ChannelMojo::~ChannelMojo() {
Close();
+
+ if (host_)
+ host_->OnChannelDestroyed();
}
-void ChannelMojo::InitOnIOThread() {
+void ChannelMojo::InitControlReader(
+ mojo::embedder::ScopedPlatformHandle handle) {
+ DCHECK(base::MessageLoopForIO::IsCurrent());
mojo::embedder::ChannelInfo* channel_info;
mojo::ScopedMessagePipeHandle control_pipe =
- mojo::embedder::CreateChannelOnIOThread(
- mojo::embedder::ScopedPlatformHandle(
- ToPlatformHandle(bootstrap_->TakePipeHandle())),
- &channel_info);
+ mojo::embedder::CreateChannelOnIOThread(handle.Pass(), &channel_info);
channel_info_.reset(channel_info);
switch (mode_) {
@@ -161,7 +127,8 @@ void ChannelMojo::InitOnIOThread() {
bool ChannelMojo::Connect() {
DCHECK(!message_reader_);
- return control_reader_->Connect();
+ DCHECK(!control_reader_);
+ return bootstrap_->Connect();
}
void ChannelMojo::Close() {
@@ -170,6 +137,15 @@ void ChannelMojo::Close() {
channel_info_.reset();
}
+void ChannelMojo::OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle) {
+ InitControlReader(handle.Pass());
+ control_reader_->Connect();
+}
+
+void ChannelMojo::OnBootstrapError() {
+ listener_->OnChannelError();
+}
+
void ChannelMojo::OnConnected(mojo::ScopedMessagePipeHandle pipe) {
message_reader_ =
make_scoped_ptr(new internal::MessageReader(pipe.Pass(), this));
@@ -212,11 +188,16 @@ base::ProcessId ChannelMojo::GetPeerPID() const {
}
base::ProcessId ChannelMojo::GetSelfPID() const {
- return bootstrap_->GetSelfPID();
+ return base::GetCurrentProcId();
}
ChannelHandle ChannelMojo::TakePipeHandle() {
- return bootstrap_->TakePipeHandle();
+ NOTREACHED();
+ return ChannelHandle();
+}
+
+void ChannelMojo::OnClientLaunched(base::ProcessHandle handle) {
+ bootstrap_->OnClientLaunched(handle);
}
void ChannelMojo::OnMessageReceived(Message& message) {
diff --git a/ipc/mojo/ipc_channel_mojo.h b/ipc/mojo/ipc_channel_mojo.h
index 22c56a9..9964a8f 100644
--- a/ipc/mojo/ipc_channel_mojo.h
+++ b/ipc/mojo/ipc_channel_mojo.h
@@ -14,6 +14,7 @@
#include "ipc/ipc_channel_factory.h"
#include "ipc/ipc_export.h"
#include "ipc/mojo/ipc_message_pipe_reader.h"
+#include "ipc/mojo/ipc_mojo_bootstrap.h"
#include "mojo/public/cpp/system/core.h"
namespace mojo {
@@ -31,6 +32,8 @@ class ClientControlReader;
class MessageReader;
}
+class ChannelMojoHost;
+
// Mojo-based IPC::Channel implementation over a platform handle.
//
// ChannelMojo builds Mojo MessagePipe using underlying pipe given by
@@ -55,21 +58,31 @@ class MessageReader;
// TODO(morrita): Add APIs to create extra MessagePipes to let
// Mojo-based objects talk over this Channel.
//
-class IPC_MOJO_EXPORT ChannelMojo : public Channel {
+class IPC_MOJO_EXPORT ChannelMojo : public Channel,
+ public MojoBootstrap::Delegate {
public:
// Create ChannelMojo. A bootstrap channel is created as well.
- static scoped_ptr<ChannelMojo> Create(
- const ChannelHandle &channel_handle, Mode mode, Listener* listener,
- scoped_refptr<base::TaskRunner> io_thread_task_runner);
+ // |host| must not be null.
+ static scoped_ptr<ChannelMojo> Create(ChannelMojoHost* host,
+ const ChannelHandle& channel_handle,
+ Mode mode,
+ Listener* listener);
// Create a factory object for ChannelMojo.
// The factory is used to create Mojo-based ChannelProxy family.
- static scoped_ptr<ChannelFactory> CreateFactory(
- const ChannelHandle &channel_handle, Mode mode,
- scoped_refptr<base::TaskRunner> io_thread_task_runner);
+ // |host| must not be null.
+ static scoped_ptr<ChannelFactory> CreateServerFactory(
+ ChannelMojoHost* host,
+ const ChannelHandle& channel_handle);
+
+ static scoped_ptr<ChannelFactory> CreateClientFactory(
+ const ChannelHandle& channel_handle);
virtual ~ChannelMojo();
+ // ChannelMojoHost tells the client handle using this API.
+ void OnClientLaunched(base::ProcessHandle handle);
+
// Channel implementation
virtual bool Connect() OVERRIDE;
virtual void Close() OVERRIDE;
@@ -92,6 +105,11 @@ class IPC_MOJO_EXPORT ChannelMojo : public Channel {
#endif // defined(OS_POSIX) && !defined(OS_NACL)
+ // MojoBootstrapDelegate implementation
+ virtual void OnPipeAvailable(
+ mojo::embedder::ScopedPlatformHandle handle) OVERRIDE;
+ virtual void OnBootstrapError() OVERRIDE;
+
// Called from MessagePipeReader implementations
void OnMessageReceived(Message& message);
void OnConnected(mojo::ScopedMessagePipeHandle pipe);
@@ -100,10 +118,10 @@ class IPC_MOJO_EXPORT ChannelMojo : public Channel {
void set_peer_pid(base::ProcessId pid) { peer_pid_ = pid; }
protected:
- ChannelMojo(const ChannelHandle& channel_handle,
+ ChannelMojo(ChannelMojoHost* host,
+ const ChannelHandle& channel_handle,
Mode mode,
- Listener* listener,
- scoped_refptr<base::TaskRunner> io_thread_task_runner);
+ Listener* listener);
private:
struct ChannelInfoDeleter {
@@ -115,9 +133,10 @@ class IPC_MOJO_EXPORT ChannelMojo : public Channel {
// notifications invoked by them.
typedef internal::MessagePipeReader::DelayedDeleter ReaderDeleter;
- void InitOnIOThread();
+ void InitControlReader(mojo::embedder::ScopedPlatformHandle handle);
- scoped_ptr<Channel> bootstrap_;
+ scoped_ptr<MojoBootstrap> bootstrap_;
+ ChannelMojoHost* const host_;
Mode mode_;
Listener* listener_;
base::ProcessId peer_pid_;
diff --git a/ipc/mojo/ipc_channel_mojo_host.cc b/ipc/mojo/ipc_channel_mojo_host.cc
new file mode 100644
index 0000000..4318a15
--- /dev/null
+++ b/ipc/mojo/ipc_channel_mojo_host.cc
@@ -0,0 +1,47 @@
+// Copyright 2014 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 "ipc/mojo/ipc_channel_mojo_host.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "ipc/mojo/ipc_channel_mojo.h"
+
+namespace IPC {
+
+ChannelMojoHost::ChannelMojoHost(scoped_refptr<base::TaskRunner> task_runner)
+ : weak_factory_(this), task_runner_(task_runner), channel_(NULL) {
+}
+
+ChannelMojoHost::~ChannelMojoHost() {
+}
+
+void ChannelMojoHost::OnClientLaunched(base::ProcessHandle process) {
+ if (task_runner_ == base::MessageLoop::current()->message_loop_proxy()) {
+ InvokeOnClientLaunched(process);
+ } else {
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&ChannelMojoHost::InvokeOnClientLaunched,
+ weak_factory_.GetWeakPtr(),
+ process));
+ }
+}
+
+void ChannelMojoHost::InvokeOnClientLaunched(base::ProcessHandle process) {
+ if (!channel_)
+ return;
+ channel_->OnClientLaunched(process);
+}
+
+void ChannelMojoHost::OnChannelCreated(ChannelMojo* channel) {
+ DCHECK(channel_ == NULL);
+ channel_ = channel;
+}
+
+void ChannelMojoHost::OnChannelDestroyed() {
+ DCHECK(channel_ != NULL);
+ channel_ = NULL;
+}
+
+} // namespace IPC
diff --git a/ipc/mojo/ipc_channel_mojo_host.h b/ipc/mojo/ipc_channel_mojo_host.h
new file mode 100644
index 0000000..e0d94be
--- /dev/null
+++ b/ipc/mojo/ipc_channel_mojo_host.h
@@ -0,0 +1,49 @@
+// Copyright 2014 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.
+
+#ifndef IPC_IPC_CHANNEL_MOJO_HOST_H_
+#define IPC_IPC_CHANNEL_MOJO_HOST_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/process/process_handle.h"
+#include "ipc/ipc_export.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace IPC {
+
+class ChannelMojo;
+
+// Through ChannelMojoHost, ChannelMojo gets extra information that
+// its client provides, including the child process's process handle. Every
+// server process that uses ChannelMojo must have a ChannelMojoHost
+// instance and call OnClientLaunched().
+class IPC_MOJO_EXPORT ChannelMojoHost {
+ public:
+ explicit ChannelMojoHost(scoped_refptr<base::TaskRunner> task_runner);
+ ~ChannelMojoHost();
+
+ void OnClientLaunched(base::ProcessHandle process);
+
+ private:
+ friend class ChannelMojo;
+
+ void OnChannelCreated(ChannelMojo* channel);
+ void OnChannelDestroyed();
+
+ void InvokeOnClientLaunched(base::ProcessHandle process);
+
+ base::WeakPtrFactory<ChannelMojoHost> weak_factory_;
+ scoped_refptr<base::TaskRunner> task_runner_;
+ ChannelMojo* channel_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChannelMojoHost);
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_CHANNEL_MOJO_HOST_H_
diff --git a/ipc/mojo/ipc_channel_mojo_unittest.cc b/ipc/mojo/ipc_channel_mojo_unittest.cc
index 2b9a954..0763533 100644
--- a/ipc/mojo/ipc_channel_mojo_unittest.cc
+++ b/ipc/mojo/ipc_channel_mojo_unittest.cc
@@ -13,6 +13,7 @@
#include "ipc/ipc_message.h"
#include "ipc/ipc_test_base.h"
#include "ipc/ipc_test_channel_listener.h"
+#include "ipc/mojo/ipc_channel_mojo_host.h"
#include "ipc/mojo/ipc_channel_mojo_readers.h"
#if defined(OS_POSIX)
@@ -59,9 +60,10 @@ class ListenerThatExpectsOK : public IPC::Listener {
class ChannelClient {
public:
explicit ChannelClient(IPC::Listener* listener, const char* name) {
- channel_ = IPC::ChannelMojo::Create(
- IPCTestBase::GetChannelName(name), IPC::Channel::MODE_CLIENT, listener,
- main_message_loop_.message_loop_proxy());
+ channel_ = IPC::ChannelMojo::Create(NULL,
+ IPCTestBase::GetChannelName(name),
+ IPC::Channel::MODE_CLIENT,
+ listener);
}
void Connect() {
@@ -71,8 +73,8 @@ class ChannelClient {
IPC::ChannelMojo* channel() const { return channel_.get(); }
private:
- scoped_ptr<IPC::ChannelMojo> channel_;
base::MessageLoopForIO main_message_loop_;
+ scoped_ptr<IPC::ChannelMojo> channel_;
};
class IPCChannelMojoTest : public IPCTestBase {
@@ -80,9 +82,19 @@ class IPCChannelMojoTest : public IPCTestBase {
virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
const IPC::ChannelHandle& handle,
base::TaskRunner* runner) OVERRIDE {
- return IPC::ChannelMojo::CreateFactory(
- handle, IPC::Channel::MODE_SERVER, runner);
+ host_.reset(new IPC::ChannelMojoHost(task_runner()));
+ return IPC::ChannelMojo::CreateServerFactory(host_.get(), handle);
+ }
+
+ virtual bool DidStartClient() OVERRIDE {
+ bool ok = IPCTestBase::DidStartClient();
+ DCHECK(ok);
+ host_->OnClientLaunched(client_process());
+ return ok;
}
+
+ private:
+ scoped_ptr<IPC::ChannelMojoHost> host_;
};
@@ -149,13 +161,12 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestClient) {
// Close given handle before use to simulate an error.
class ErraticChannelMojo : public IPC::ChannelMojo {
public:
- ErraticChannelMojo(
- const IPC::ChannelHandle& channel_handle,
- IPC::Channel::Mode mode,
- IPC::Listener* listener,
- scoped_refptr<base::TaskRunner> runner)
- : ChannelMojo(channel_handle, mode, listener, runner) {
- }
+ ErraticChannelMojo(IPC::ChannelMojoHost* host,
+ const IPC::ChannelHandle& channel_handle,
+ IPC::Channel::Mode mode,
+ IPC::Listener* listener,
+ scoped_refptr<base::TaskRunner> runner)
+ : ChannelMojo(host, channel_handle, mode, listener) {}
virtual void OnConnected(mojo::ScopedMessagePipeHandle pipe) {
MojoClose(pipe.get().value());
@@ -166,11 +177,10 @@ class ErraticChannelMojo : public IPC::ChannelMojo {
// Exists to create ErraticChannelMojo.
class ErraticChannelFactory : public IPC::ChannelFactory {
public:
- explicit ErraticChannelFactory(
- const IPC::ChannelHandle& handle,
- base::TaskRunner* runner)
- : handle_(handle), runner_(runner) {
- }
+ explicit ErraticChannelFactory(IPC::ChannelMojoHost* host,
+ const IPC::ChannelHandle& handle,
+ base::TaskRunner* runner)
+ : host_(host), handle_(handle), runner_(runner) {}
virtual std::string GetName() const OVERRIDE {
return "";
@@ -178,12 +188,12 @@ class ErraticChannelFactory : public IPC::ChannelFactory {
virtual scoped_ptr<IPC::Channel> BuildChannel(
IPC::Listener* listener) OVERRIDE {
- return scoped_ptr<IPC::Channel>(
- new ErraticChannelMojo(
- handle_, IPC::Channel::MODE_SERVER, listener, runner_));
+ return scoped_ptr<IPC::Channel>(new ErraticChannelMojo(
+ host_, handle_, IPC::Channel::MODE_SERVER, listener, runner_));
}
private:
+ IPC::ChannelMojoHost* host_;
IPC::ChannelHandle handle_;
scoped_refptr<base::TaskRunner> runner_;
};
@@ -215,9 +225,20 @@ class IPCChannelMojoErrorTest : public IPCTestBase {
virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
const IPC::ChannelHandle& handle,
base::TaskRunner* runner) OVERRIDE {
+ host_.reset(new IPC::ChannelMojoHost(task_runner()));
return scoped_ptr<IPC::ChannelFactory>(
- new ErraticChannelFactory(handle, runner));
+ new ErraticChannelFactory(host_.get(), handle, runner));
+ }
+
+ virtual bool DidStartClient() OVERRIDE {
+ bool ok = IPCTestBase::DidStartClient();
+ DCHECK(ok);
+ host_->OnClientLaunched(client_process());
+ return ok;
}
+
+ private:
+ scoped_ptr<IPC::ChannelMojoHost> host_;
};
class ListenerThatQuits : public IPC::Listener {
diff --git a/ipc/mojo/ipc_mojo.gyp b/ipc/mojo/ipc_mojo.gyp
index c4ead0a..e4bdd20 100644
--- a/ipc/mojo/ipc_mojo.gyp
+++ b/ipc/mojo/ipc_mojo.gyp
@@ -28,8 +28,12 @@
'sources': [
'ipc_channel_mojo.cc',
'ipc_channel_mojo.h',
+ 'ipc_channel_mojo_host.cc',
+ 'ipc_channel_mojo_host.h',
'ipc_channel_mojo_readers.cc',
'ipc_channel_mojo_readers.h',
+ 'ipc_mojo_bootstrap.cc',
+ 'ipc_mojo_bootstrap.h',
'ipc_message_pipe_reader.cc',
'ipc_message_pipe_reader.h',
],
@@ -62,6 +66,7 @@
'sources': [
'run_all_unittests.cc',
'ipc_channel_mojo_unittest.cc',
+ 'ipc_mojo_bootstrap_unittest.cc',
],
'conditions': [
],
diff --git a/ipc/mojo/ipc_mojo_bootstrap.cc b/ipc/mojo/ipc_mojo_bootstrap.cc
new file mode 100644
index 0000000..0082fb8
--- /dev/null
+++ b/ipc/mojo/ipc_mojo_bootstrap.cc
@@ -0,0 +1,205 @@
+// Copyright 2014 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 "ipc/mojo/ipc_mojo_bootstrap.h"
+
+#include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "ipc/ipc_message_utils.h"
+#include "ipc/ipc_platform_file.h"
+#include "mojo/embedder/platform_channel_pair.h"
+
+namespace IPC {
+
+namespace {
+
+// MojoBootstrap for the server process. You should create the instance
+// using MojoBootstrap::Create().
+class IPC_MOJO_EXPORT MojoServerBootstrap : public MojoBootstrap {
+ public:
+ MojoServerBootstrap();
+
+ virtual void OnClientLaunched(base::ProcessHandle process) OVERRIDE;
+
+ private:
+ void SendClientPipe();
+ void SendClientPipeIfReady();
+
+ // Listener implementations
+ virtual bool OnMessageReceived(const Message& message) OVERRIDE;
+ virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
+
+ mojo::embedder::ScopedPlatformHandle server_pipe_;
+ base::ProcessHandle client_process_;
+ bool connected_;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoServerBootstrap);
+};
+
+MojoServerBootstrap::MojoServerBootstrap()
+ : client_process_(base::kNullProcessHandle), connected_(false) {
+}
+
+void MojoServerBootstrap::SendClientPipe() {
+ DCHECK_EQ(state(), STATE_INITIALIZED);
+ DCHECK_NE(client_process_, base::kNullProcessHandle);
+ DCHECK(connected_);
+
+ mojo::embedder::PlatformChannelPair channel_pair;
+ server_pipe_ = channel_pair.PassServerHandle();
+ PlatformFileForTransit client_pipe = GetFileHandleForProcess(
+#if defined(OS_POSIX)
+ channel_pair.PassClientHandle().release().fd,
+#else
+ channel_pair.PassClientHandle().release().handle,
+#endif
+ client_process_,
+ true);
+ CHECK(client_pipe != IPC::InvalidPlatformFileForTransit());
+ scoped_ptr<Message> message(new Message());
+ ParamTraits<PlatformFileForTransit>::Write(message.get(), client_pipe);
+ Send(message.release());
+
+ set_state(STATE_WAITING_ACK);
+}
+
+void MojoServerBootstrap::SendClientPipeIfReady() {
+ // Is the client launched?
+ if (client_process_ == base::kNullProcessHandle)
+ return;
+ // Has the bootstrap channel been made?
+ if (!connected_)
+ return;
+ SendClientPipe();
+}
+
+void MojoServerBootstrap::OnClientLaunched(base::ProcessHandle process) {
+ DCHECK_EQ(state(), STATE_INITIALIZED);
+ DCHECK_NE(process, base::kNullProcessHandle);
+ client_process_ = process;
+ SendClientPipeIfReady();
+}
+
+void MojoServerBootstrap::OnChannelConnected(int32 peer_pid) {
+ DCHECK_EQ(state(), STATE_INITIALIZED);
+ connected_ = true;
+ SendClientPipeIfReady();
+}
+
+bool MojoServerBootstrap::OnMessageReceived(const Message&) {
+ DCHECK_EQ(state(), STATE_WAITING_ACK);
+ set_state(STATE_READY);
+
+ delegate()->OnPipeAvailable(
+ mojo::embedder::ScopedPlatformHandle(server_pipe_.release()));
+
+ return true;
+}
+
+// MojoBootstrap for client processes. You should create the instance
+// using MojoBootstrap::Create().
+class IPC_MOJO_EXPORT MojoClientBootstrap : public MojoBootstrap {
+ public:
+ MojoClientBootstrap();
+
+ virtual void OnClientLaunched(base::ProcessHandle process) OVERRIDE;
+
+ private:
+ // Listener implementations
+ virtual bool OnMessageReceived(const Message& message) OVERRIDE;
+ virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoClientBootstrap);
+};
+
+MojoClientBootstrap::MojoClientBootstrap() {
+}
+
+bool MojoClientBootstrap::OnMessageReceived(const Message& message) {
+ PlatformFileForTransit pipe;
+ PickleIterator iter(message);
+ if (!ParamTraits<PlatformFileForTransit>::Read(&message, &iter, &pipe)) {
+ DLOG(WARNING) << "Failed to read a file handle from bootstrap channel.";
+ message.set_dispatch_error();
+ return false;
+ }
+
+ // Sends ACK back.
+ Send(new Message());
+ set_state(STATE_READY);
+ delegate()->OnPipeAvailable(
+ mojo::embedder::ScopedPlatformHandle(mojo::embedder::PlatformHandle(
+ PlatformFileForTransitToPlatformFile(pipe))));
+
+ return true;
+}
+
+void MojoClientBootstrap::OnClientLaunched(base::ProcessHandle process) {
+ // This notification should happen only on server processes.
+ NOTREACHED();
+}
+
+void MojoClientBootstrap::OnChannelConnected(int32 peer_pid) {
+}
+
+} // namespace
+
+// MojoBootstrap
+
+// static
+scoped_ptr<MojoBootstrap> MojoBootstrap::Create(ChannelHandle handle,
+ Channel::Mode mode,
+ Delegate* delegate) {
+ CHECK(mode == Channel::MODE_CLIENT || mode == Channel::MODE_SERVER);
+ scoped_ptr<MojoBootstrap> self =
+ mode == Channel::MODE_CLIENT
+ ? scoped_ptr<MojoBootstrap>(new MojoClientBootstrap())
+ : scoped_ptr<MojoBootstrap>(new MojoServerBootstrap());
+ scoped_ptr<Channel> bootstrap_channel =
+ Channel::Create(handle, mode, self.get());
+ self->Init(bootstrap_channel.Pass(), delegate);
+ return self.Pass();
+}
+
+MojoBootstrap::MojoBootstrap() : delegate_(NULL), state_(STATE_INITIALIZED) {
+}
+
+MojoBootstrap::~MojoBootstrap() {
+}
+
+void MojoBootstrap::Init(scoped_ptr<Channel> channel, Delegate* delegate) {
+ channel_ = channel.Pass();
+ delegate_ = delegate;
+}
+
+bool MojoBootstrap::Connect() {
+ return channel_->Connect();
+}
+
+void MojoBootstrap::OnBadMessageReceived(const Message& message) {
+ delegate_->OnBootstrapError();
+}
+
+void MojoBootstrap::OnChannelError() {
+ if (state_ == STATE_READY)
+ return;
+ DLOG(WARNING) << "Detected error on Mojo bootstrap channel.";
+ delegate()->OnBootstrapError();
+}
+
+bool MojoBootstrap::Send(Message* message) {
+ return channel_->Send(message);
+}
+
+#if defined(OS_POSIX) && !defined(OS_NACL)
+int MojoBootstrap::GetClientFileDescriptor() const {
+ return channel_->GetClientFileDescriptor();
+}
+
+int MojoBootstrap::TakeClientFileDescriptor() {
+ return channel_->TakeClientFileDescriptor();
+}
+#endif // defined(OS_POSIX) && !defined(OS_NACL)
+
+} // namespace IPC
diff --git a/ipc/mojo/ipc_mojo_bootstrap.h b/ipc/mojo/ipc_mojo_bootstrap.h
new file mode 100644
index 0000000..a099af9
--- /dev/null
+++ b/ipc/mojo/ipc_mojo_bootstrap.h
@@ -0,0 +1,82 @@
+// Copyright 2014 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.
+
+#ifndef IPC_MOJO_IPC_MOJO_BOOTSTRAP_H_
+#define IPC_MOJO_IPC_MOJO_BOOTSTRAP_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/process/process_handle.h"
+#include "ipc/ipc_channel.h"
+#include "ipc/ipc_listener.h"
+#include "mojo/embedder/scoped_platform_handle.h"
+
+namespace IPC {
+
+// MojoBootstrap establishes a bootstrap pipe between two processes in
+// Chrome. It creates a native IPC::Channel first, then sends one
+// side of a newly created pipe to peer process. The pipe is intended
+// to be wrapped by Mojo MessagePipe.
+//
+// Clients should implement MojoBootstrapDelegate to get the pipe
+// from MojoBootstrap object. It should also tell the client process handle
+// using OnClientLaunched().
+//
+// This lives on IO thread other than Create(), which can be called from
+// UI thread as Channel::Create() can be.
+class IPC_MOJO_EXPORT MojoBootstrap : public Listener {
+ public:
+ class Delegate {
+ public:
+ virtual void OnPipeAvailable(
+ mojo::embedder::ScopedPlatformHandle handle) = 0;
+ virtual void OnBootstrapError() = 0;
+ };
+
+ // Create the MojoBootstrap instance.
+ // Instead of creating IPC::Channel, passs its ChannelHandle as |handle|,
+ // mode as |mode|. The result is notified to passed |delegate|.
+ static scoped_ptr<MojoBootstrap> Create(ChannelHandle handle,
+ Channel::Mode mode,
+ Delegate* delegate);
+
+ MojoBootstrap();
+ virtual ~MojoBootstrap();
+
+ // Start the handshake over the underlying platform channel.
+ bool Connect();
+
+ // Each client should call this once the process handle becomes known.
+ virtual void OnClientLaunched(base::ProcessHandle process) = 0;
+
+#if defined(OS_POSIX) && !defined(OS_NACL)
+ int GetClientFileDescriptor() const;
+ int TakeClientFileDescriptor();
+#endif // defined(OS_POSIX) && !defined(OS_NACL)
+
+ protected:
+ enum State { STATE_INITIALIZED, STATE_WAITING_ACK, STATE_READY };
+
+ Delegate* delegate() const { return delegate_; }
+ bool Send(Message* message);
+
+ State state() const { return state_; }
+ void set_state(State state) { state_ = state; }
+
+ private:
+ void Init(scoped_ptr<Channel> channel, Delegate* delegate);
+
+ // Listener implementations
+ virtual void OnBadMessageReceived(const Message& message) OVERRIDE;
+ virtual void OnChannelError() OVERRIDE;
+
+ scoped_ptr<Channel> channel_;
+ Delegate* delegate_;
+ State state_;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoBootstrap);
+};
+
+} // namespace IPC
+
+#endif // IPC_MOJO_IPC_MOJO_BOOTSTRAP_H_
diff --git a/ipc/mojo/ipc_mojo_bootstrap_unittest.cc b/ipc/mojo/ipc_mojo_bootstrap_unittest.cc
new file mode 100644
index 0000000..207c060
--- /dev/null
+++ b/ipc/mojo/ipc_mojo_bootstrap_unittest.cc
@@ -0,0 +1,86 @@
+// Copyright 2014 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 "ipc/mojo/ipc_mojo_bootstrap.h"
+
+#include "base/base_paths.h"
+#include "base/files/file.h"
+#include "base/message_loop/message_loop.h"
+#include "ipc/ipc_test_base.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#endif
+
+namespace {
+
+class IPCMojoBootstrapTest : public IPCTestBase {
+ protected:
+};
+
+class TestingDelegate : public IPC::MojoBootstrap::Delegate {
+ public:
+ TestingDelegate() : passed_(false) {}
+
+ virtual void OnPipeAvailable(
+ mojo::embedder::ScopedPlatformHandle handle) OVERRIDE;
+ virtual void OnBootstrapError() OVERRIDE;
+
+ bool passed() const { return passed_; }
+
+ private:
+ bool passed_;
+};
+
+void TestingDelegate::OnPipeAvailable(
+ mojo::embedder::ScopedPlatformHandle handle) {
+ passed_ = true;
+ base::MessageLoop::current()->Quit();
+}
+
+void TestingDelegate::OnBootstrapError() {
+ base::MessageLoop::current()->Quit();
+}
+
+TEST_F(IPCMojoBootstrapTest, Connect) {
+ Init("IPCMojoBootstrapTestClient");
+
+ TestingDelegate delegate;
+ scoped_ptr<IPC::MojoBootstrap> bootstrap = IPC::MojoBootstrap::Create(
+ GetTestChannelHandle(), IPC::Channel::MODE_SERVER, &delegate);
+
+ ASSERT_TRUE(bootstrap->Connect());
+#if defined(OS_POSIX)
+ ASSERT_TRUE(StartClientWithFD(bootstrap->GetClientFileDescriptor()));
+#else
+ ASSERT_TRUE(StartClient());
+#endif
+ bootstrap->OnClientLaunched(client_process());
+
+ base::MessageLoop::current()->Run();
+
+ EXPECT_TRUE(delegate.passed());
+ EXPECT_TRUE(WaitForClientShutdown());
+}
+
+// A long running process that connects to us.
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCMojoBootstrapTestClient) {
+ base::MessageLoopForIO main_message_loop;
+
+ TestingDelegate delegate;
+ scoped_ptr<IPC::MojoBootstrap> bootstrap = IPC::MojoBootstrap::Create(
+ IPCTestBase::GetChannelName("IPCMojoBootstrapTestClient"),
+ IPC::Channel::MODE_CLIENT,
+ &delegate);
+
+ bootstrap->Connect();
+
+ base::MessageLoop::current()->Run();
+
+ EXPECT_TRUE(delegate.passed());
+
+ return 0;
+}
+
+} // namespace
diff --git a/ipc/mojo/ipc_mojo_perftest.cc b/ipc/mojo/ipc_mojo_perftest.cc
index d433703..576f13e 100644
--- a/ipc/mojo/ipc_mojo_perftest.cc
+++ b/ipc/mojo/ipc_mojo_perftest.cc
@@ -5,6 +5,7 @@
#include "base/lazy_instance.h"
#include "ipc/ipc_perftest_support.h"
#include "ipc/mojo/ipc_channel_mojo.h"
+#include "ipc/mojo/ipc_channel_mojo_host.h"
#include "mojo/embedder/test_embedder.h"
namespace {
@@ -31,8 +32,15 @@ public:
virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
const IPC::ChannelHandle& handle,
base::TaskRunner* runner) OVERRIDE {
- return IPC::ChannelMojo::CreateFactory(
- handle, IPC::Channel::MODE_SERVER, runner);
+ host_.reset(new IPC::ChannelMojoHost(task_runner()));
+ return IPC::ChannelMojo::CreateServerFactory(host_.get(), handle);
+ }
+
+ virtual bool DidStartClient() OVERRIDE {
+ bool ok = IPCTestBase::DidStartClient();
+ DCHECK(ok);
+ host_->OnClientLaunched(client_process());
+ return ok;
}
void set_io_thread_task_runner(base::TaskRunner* runner) {
@@ -41,6 +49,7 @@ public:
private:
base::TaskRunner* io_thread_task_runner_;
+ scoped_ptr<IPC::ChannelMojoHost> host_;
};
MojoChannelPerfTest::MojoChannelPerfTest()
@@ -73,10 +82,11 @@ MojoTestClient::MojoTestClient() {
scoped_ptr<IPC::Channel> MojoTestClient::CreateChannel(
IPC::Listener* listener) {
- return scoped_ptr<IPC::Channel>(IPC::ChannelMojo::Create(
- IPCTestBase::GetChannelName("PerformanceClient"),
- IPC::Channel::MODE_CLIENT, listener,
- task_runner()));
+ return scoped_ptr<IPC::Channel>(
+ IPC::ChannelMojo::Create(NULL,
+ IPCTestBase::GetChannelName("PerformanceClient"),
+ IPC::Channel::MODE_CLIENT,
+ listener));
}
MULTIPROCESS_IPC_TEST_CLIENT_MAIN(PerformanceClient) {