1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ipc/mojo/ipc_mojo_bootstrap.h"
7 #include "base/logging.h"
8 #include "base/process/process_handle.h"
9 #include "ipc/ipc_message_utils.h"
10 #include "ipc/ipc_platform_file.h"
11 #include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
17 // MojoBootstrap for the server process. You should create the instance
18 // using MojoBootstrap::Create().
19 class MojoServerBootstrap
: public MojoBootstrap
{
21 MojoServerBootstrap();
23 void OnClientLaunched(base::ProcessHandle process
) override
;
26 void SendClientPipe();
27 void SendClientPipeIfReady();
29 // Listener implementations
30 bool OnMessageReceived(const Message
& message
) override
;
31 void OnChannelConnected(int32 peer_pid
) override
;
33 mojo::embedder::ScopedPlatformHandle server_pipe_
;
34 base::ProcessHandle client_process_
;
37 DISALLOW_COPY_AND_ASSIGN(MojoServerBootstrap
);
40 MojoServerBootstrap::MojoServerBootstrap()
41 : client_process_(base::kNullProcessHandle
), connected_(false) {
44 void MojoServerBootstrap::SendClientPipe() {
45 DCHECK_EQ(state(), STATE_INITIALIZED
);
46 DCHECK_NE(client_process_
, base::kNullProcessHandle
);
49 mojo::embedder::PlatformChannelPair channel_pair
;
50 server_pipe_
= channel_pair
.PassServerHandle();
51 PlatformFileForTransit client_pipe
= GetFileHandleForProcess(
53 channel_pair
.PassClientHandle().release().fd
,
55 channel_pair
.PassClientHandle().release().handle
,
59 if (client_pipe
== IPC::InvalidPlatformFileForTransit()) {
61 // GetFileHandleForProcess() only fails on Windows.
64 DLOG(WARNING
) << "Failed to translate file handle for client process.";
69 scoped_ptr
<Message
> message(new Message());
70 ParamTraits
<PlatformFileForTransit
>::Write(message
.get(), client_pipe
);
71 Send(message
.release());
73 set_state(STATE_WAITING_ACK
);
76 void MojoServerBootstrap::SendClientPipeIfReady() {
77 // Is the client launched?
78 if (client_process_
== base::kNullProcessHandle
)
80 // Has the bootstrap channel been made?
86 void MojoServerBootstrap::OnClientLaunched(base::ProcessHandle process
) {
90 DCHECK_EQ(state(), STATE_INITIALIZED
);
91 DCHECK_NE(process
, base::kNullProcessHandle
);
92 client_process_
= process
;
93 SendClientPipeIfReady();
96 void MojoServerBootstrap::OnChannelConnected(int32 peer_pid
) {
97 DCHECK_EQ(state(), STATE_INITIALIZED
);
99 SendClientPipeIfReady();
102 bool MojoServerBootstrap::OnMessageReceived(const Message
&) {
103 if (state() != STATE_WAITING_ACK
) {
104 set_state(STATE_ERROR
);
105 LOG(ERROR
) << "Got inconsistent message from client.";
109 set_state(STATE_READY
);
110 CHECK(server_pipe_
.is_valid());
111 delegate()->OnPipeAvailable(
112 mojo::embedder::ScopedPlatformHandle(server_pipe_
.release()));
117 // MojoBootstrap for client processes. You should create the instance
118 // using MojoBootstrap::Create().
119 class MojoClientBootstrap
: public MojoBootstrap
{
121 MojoClientBootstrap();
123 void OnClientLaunched(base::ProcessHandle process
) override
;
126 // Listener implementations
127 bool OnMessageReceived(const Message
& message
) override
;
128 void OnChannelConnected(int32 peer_pid
) override
;
130 DISALLOW_COPY_AND_ASSIGN(MojoClientBootstrap
);
133 MojoClientBootstrap::MojoClientBootstrap() {
136 bool MojoClientBootstrap::OnMessageReceived(const Message
& message
) {
137 if (state() != STATE_INITIALIZED
) {
138 set_state(STATE_ERROR
);
139 LOG(ERROR
) << "Got inconsistent message from server.";
143 PlatformFileForTransit pipe
;
144 PickleIterator
iter(message
);
145 if (!ParamTraits
<PlatformFileForTransit
>::Read(&message
, &iter
, &pipe
)) {
146 DLOG(WARNING
) << "Failed to read a file handle from bootstrap channel.";
147 message
.set_dispatch_error();
153 set_state(STATE_READY
);
154 delegate()->OnPipeAvailable(
155 mojo::embedder::ScopedPlatformHandle(mojo::embedder::PlatformHandle(
156 PlatformFileForTransitToPlatformFile(pipe
))));
161 void MojoClientBootstrap::OnClientLaunched(base::ProcessHandle process
) {
162 // This notification should happen only on server processes.
166 void MojoClientBootstrap::OnChannelConnected(int32 peer_pid
) {
174 scoped_ptr
<MojoBootstrap
> MojoBootstrap::Create(ChannelHandle handle
,
176 Delegate
* delegate
) {
177 CHECK(mode
== Channel::MODE_CLIENT
|| mode
== Channel::MODE_SERVER
);
178 scoped_ptr
<MojoBootstrap
> self
=
179 mode
== Channel::MODE_CLIENT
180 ? scoped_ptr
<MojoBootstrap
>(new MojoClientBootstrap())
181 : scoped_ptr
<MojoBootstrap
>(new MojoServerBootstrap());
182 scoped_ptr
<Channel
> bootstrap_channel
=
183 Channel::Create(handle
, mode
, self
.get());
184 self
->Init(bootstrap_channel
.Pass(), delegate
);
188 MojoBootstrap::MojoBootstrap() : delegate_(NULL
), state_(STATE_INITIALIZED
) {
191 MojoBootstrap::~MojoBootstrap() {
194 void MojoBootstrap::Init(scoped_ptr
<Channel
> channel
, Delegate
* delegate
) {
195 channel_
= channel
.Pass();
196 delegate_
= delegate
;
199 bool MojoBootstrap::Connect() {
200 return channel_
->Connect();
203 base::ProcessId
MojoBootstrap::GetSelfPID() const {
204 return channel_
->GetSelfPID();
207 void MojoBootstrap::OnBadMessageReceived(const Message
& message
) {
211 void MojoBootstrap::OnChannelError() {
212 if (state_
== STATE_READY
|| state_
== STATE_ERROR
)
214 DLOG(WARNING
) << "Detected error on Mojo bootstrap channel.";
218 void MojoBootstrap::Fail() {
219 set_state(STATE_ERROR
);
220 delegate()->OnBootstrapError();
223 bool MojoBootstrap::HasFailed() const {
224 return state() == STATE_ERROR
;
227 bool MojoBootstrap::Send(Message
* message
) {
228 return channel_
->Send(message
);
231 #if defined(OS_POSIX) && !defined(OS_NACL)
232 int MojoBootstrap::GetClientFileDescriptor() const {
233 return channel_
->GetClientFileDescriptor();
236 base::ScopedFD
MojoBootstrap::TakeClientFileDescriptor() {
237 return channel_
->TakeClientFileDescriptor();
239 #endif // defined(OS_POSIX) && !defined(OS_NACL)