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_channel_mojo.h"
8 #include "base/bind_helpers.h"
9 #include "base/lazy_instance.h"
10 #include "ipc/ipc_listener.h"
11 #include "ipc/ipc_logging.h"
12 #include "ipc/ipc_message_attachment_set.h"
13 #include "ipc/ipc_message_macros.h"
14 #include "ipc/mojo/client_channel.mojom.h"
15 #include "ipc/mojo/ipc_mojo_bootstrap.h"
16 #include "ipc/mojo/ipc_mojo_handle_attachment.h"
17 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
18 #include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
20 #if defined(OS_POSIX) && !defined(OS_NACL)
21 #include "ipc/ipc_platform_file_attachment_posix.h"
28 class MojoChannelFactory
: public ChannelFactory
{
30 MojoChannelFactory(ChannelMojo::Delegate
* delegate
,
31 scoped_refptr
<base::TaskRunner
> io_runner
,
32 ChannelHandle channel_handle
,
34 : delegate_(delegate
),
35 io_runner_(io_runner
),
36 channel_handle_(channel_handle
),
39 std::string
GetName() const override
{
40 return channel_handle_
.name
;
43 scoped_ptr
<Channel
> BuildChannel(Listener
* listener
) override
{
44 return ChannelMojo::Create(delegate_
, io_runner_
, channel_handle_
, mode_
,
49 ChannelMojo::Delegate
* delegate_
;
50 scoped_refptr
<base::TaskRunner
> io_runner_
;
51 ChannelHandle channel_handle_
;
55 //------------------------------------------------------------------------------
57 class ClientChannelMojo
: public ChannelMojo
,
59 public mojo::ErrorHandler
{
61 ClientChannelMojo(ChannelMojo::Delegate
* delegate
,
62 scoped_refptr
<base::TaskRunner
> io_runner
,
63 const ChannelHandle
& handle
,
65 ~ClientChannelMojo() override
;
66 // MojoBootstrap::Delegate implementation
67 void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle
) override
;
68 // mojo::ErrorHandler implementation
69 void OnConnectionError() override
;
70 // ClientChannel implementation
72 mojo::ScopedMessagePipeHandle pipe
,
74 const mojo::Callback
<void(int32_t)>& callback
) override
;
77 mojo::Binding
<ClientChannel
> binding_
;
79 DISALLOW_COPY_AND_ASSIGN(ClientChannelMojo
);
82 ClientChannelMojo::ClientChannelMojo(ChannelMojo::Delegate
* delegate
,
83 scoped_refptr
<base::TaskRunner
> io_runner
,
84 const ChannelHandle
& handle
,
86 : ChannelMojo(delegate
, io_runner
, handle
, Channel::MODE_CLIENT
, listener
),
90 ClientChannelMojo::~ClientChannelMojo() {
93 void ClientChannelMojo::OnPipeAvailable(
94 mojo::embedder::ScopedPlatformHandle handle
) {
95 binding_
.Bind(CreateMessagingPipe(handle
.Pass()));
98 void ClientChannelMojo::OnConnectionError() {
99 listener()->OnChannelError();
102 void ClientChannelMojo::Init(
103 mojo::ScopedMessagePipeHandle pipe
,
105 const mojo::Callback
<void(int32_t)>& callback
) {
106 InitMessageReader(pipe
.Pass(), static_cast<base::ProcessId
>(peer_pid
));
107 callback
.Run(GetSelfPID());
110 //------------------------------------------------------------------------------
112 class ServerChannelMojo
: public ChannelMojo
, public mojo::ErrorHandler
{
114 ServerChannelMojo(ChannelMojo::Delegate
* delegate
,
115 scoped_refptr
<base::TaskRunner
> io_runner
,
116 const ChannelHandle
& handle
,
118 ~ServerChannelMojo() override
;
120 // MojoBootstrap::Delegate implementation
121 void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle
) override
;
122 // mojo::ErrorHandler implementation
123 void OnConnectionError() override
;
125 void Close() override
;
128 // ClientChannelClient implementation
129 void ClientChannelWasInitialized(int32_t peer_pid
);
131 mojo::InterfacePtr
<ClientChannel
> client_channel_
;
132 mojo::ScopedMessagePipeHandle message_pipe_
;
134 DISALLOW_COPY_AND_ASSIGN(ServerChannelMojo
);
137 ServerChannelMojo::ServerChannelMojo(ChannelMojo::Delegate
* delegate
,
138 scoped_refptr
<base::TaskRunner
> io_runner
,
139 const ChannelHandle
& handle
,
141 : ChannelMojo(delegate
, io_runner
, handle
, Channel::MODE_SERVER
, listener
) {
144 ServerChannelMojo::~ServerChannelMojo() {
148 void ServerChannelMojo::OnPipeAvailable(
149 mojo::embedder::ScopedPlatformHandle handle
) {
150 mojo::ScopedMessagePipeHandle peer
;
151 MojoResult create_result
=
152 mojo::CreateMessagePipe(nullptr, &message_pipe_
, &peer
);
153 if (create_result
!= MOJO_RESULT_OK
) {
154 LOG(WARNING
) << "mojo::CreateMessagePipe failed: " << create_result
;
155 listener()->OnChannelError();
159 client_channel_
.Bind(CreateMessagingPipe(handle
.Pass()));
160 client_channel_
.set_error_handler(this);
161 client_channel_
->Init(
163 static_cast<int32_t>(GetSelfPID()),
164 base::Bind(&ServerChannelMojo::ClientChannelWasInitialized
,
165 base::Unretained(this)));
168 void ServerChannelMojo::ClientChannelWasInitialized(int32_t peer_pid
) {
169 InitMessageReader(message_pipe_
.Pass(), peer_pid
);
172 void ServerChannelMojo::OnConnectionError() {
173 listener()->OnChannelError();
176 void ServerChannelMojo::Close() {
177 client_channel_
.reset();
178 message_pipe_
.reset();
179 ChannelMojo::Close();
182 #if defined(OS_POSIX) && !defined(OS_NACL)
184 base::ScopedFD
TakeOrDupFile(internal::PlatformFileAttachment
* attachment
) {
185 return attachment
->Owns() ? base::ScopedFD(attachment
->TakePlatformFile())
186 : base::ScopedFD(dup(attachment
->file()));
193 //------------------------------------------------------------------------------
195 void ChannelMojo::ChannelInfoDeleter::operator()(
196 mojo::embedder::ChannelInfo
* ptr
) const {
197 mojo::embedder::DestroyChannelOnIOThread(ptr
);
200 //------------------------------------------------------------------------------
203 bool ChannelMojo::ShouldBeUsed() {
204 // TODO(morrita): Remove this if it sticks.
209 scoped_ptr
<ChannelMojo
> ChannelMojo::Create(
210 ChannelMojo::Delegate
* delegate
,
211 scoped_refptr
<base::TaskRunner
> io_runner
,
212 const ChannelHandle
& channel_handle
,
214 Listener
* listener
) {
216 case Channel::MODE_CLIENT
:
217 return make_scoped_ptr(
218 new ClientChannelMojo(delegate
, io_runner
, channel_handle
, listener
));
219 case Channel::MODE_SERVER
:
220 return make_scoped_ptr(
221 new ServerChannelMojo(delegate
, io_runner
, channel_handle
, listener
));
229 scoped_ptr
<ChannelFactory
> ChannelMojo::CreateServerFactory(
230 ChannelMojo::Delegate
* delegate
,
231 scoped_refptr
<base::TaskRunner
> io_runner
,
232 const ChannelHandle
& channel_handle
) {
233 return make_scoped_ptr(new MojoChannelFactory(
234 delegate
, io_runner
, channel_handle
, Channel::MODE_SERVER
));
238 scoped_ptr
<ChannelFactory
> ChannelMojo::CreateClientFactory(
239 ChannelMojo::Delegate
* delegate
,
240 scoped_refptr
<base::TaskRunner
> io_runner
,
241 const ChannelHandle
& channel_handle
) {
242 return make_scoped_ptr(new MojoChannelFactory(
243 delegate
, io_runner
, channel_handle
, Channel::MODE_CLIENT
));
246 ChannelMojo::ChannelMojo(ChannelMojo::Delegate
* delegate
,
247 scoped_refptr
<base::TaskRunner
> io_runner
,
248 const ChannelHandle
& handle
,
253 peer_pid_(base::kNullProcessId
),
254 weak_factory_(this) {
255 // Create MojoBootstrap after all members are set as it touches
256 // ChannelMojo from a different thread.
257 bootstrap_
= MojoBootstrap::Create(handle
, mode
, this);
258 if (io_runner
== base::MessageLoop::current()->message_loop_proxy()) {
259 InitOnIOThread(delegate
);
261 io_runner
->PostTask(FROM_HERE
,
262 base::Bind(&ChannelMojo::InitOnIOThread
,
263 base::Unretained(this), delegate
));
267 ChannelMojo::~ChannelMojo() {
271 void ChannelMojo::InitOnIOThread(ChannelMojo::Delegate
* delegate
) {
273 new ScopedIPCSupport(base::MessageLoop::current()->task_runner()));
276 delegate_
= delegate
->ToWeakPtr();
277 delegate_
->OnChannelCreated(weak_factory_
.GetWeakPtr());
280 mojo::ScopedMessagePipeHandle
ChannelMojo::CreateMessagingPipe(
281 mojo::embedder::ScopedPlatformHandle handle
) {
282 DCHECK(!channel_info_
.get());
283 mojo::embedder::ChannelInfo
* channel_info
;
284 mojo::ScopedMessagePipeHandle pipe
=
285 mojo::embedder::CreateChannelOnIOThread(handle
.Pass(), &channel_info
);
286 channel_info_
.reset(channel_info
);
290 bool ChannelMojo::Connect() {
291 DCHECK(!message_reader_
);
292 return bootstrap_
->Connect();
295 void ChannelMojo::Close() {
296 message_reader_
.reset();
297 channel_info_
.reset();
298 ipc_support_
.reset();
301 void ChannelMojo::OnBootstrapError() {
302 listener_
->OnChannelError();
305 void ChannelMojo::InitMessageReader(mojo::ScopedMessagePipeHandle pipe
,
308 make_scoped_ptr(new internal::MessagePipeReader(pipe
.Pass(), this));
310 for (size_t i
= 0; i
< pending_messages_
.size(); ++i
) {
311 bool sent
= message_reader_
->Send(make_scoped_ptr(pending_messages_
[i
]));
312 pending_messages_
[i
] = nullptr;
314 pending_messages_
.clear();
315 listener_
->OnChannelError();
320 pending_messages_
.clear();
322 set_peer_pid(peer_pid
);
323 listener_
->OnChannelConnected(static_cast<int32_t>(GetPeerPID()));
325 message_reader_
->ReadMessagesThenWait();
328 void ChannelMojo::OnPipeClosed(internal::MessagePipeReader
* reader
) {
332 void ChannelMojo::OnPipeError(internal::MessagePipeReader
* reader
) {
333 listener_
->OnChannelError();
337 bool ChannelMojo::Send(Message
* message
) {
338 if (!message_reader_
) {
339 pending_messages_
.push_back(message
);
343 return message_reader_
->Send(make_scoped_ptr(message
));
346 base::ProcessId
ChannelMojo::GetPeerPID() const {
350 base::ProcessId
ChannelMojo::GetSelfPID() const {
351 return bootstrap_
->GetSelfPID();
354 void ChannelMojo::OnClientLaunched(base::ProcessHandle handle
) {
355 bootstrap_
->OnClientLaunched(handle
);
358 void ChannelMojo::OnMessageReceived(Message
& message
) {
359 TRACE_EVENT2("ipc,toplevel", "ChannelMojo::OnMessageReceived",
360 "class", IPC_MESSAGE_ID_CLASS(message
.type()),
361 "line", IPC_MESSAGE_ID_LINE(message
.type()));
362 listener_
->OnMessageReceived(message
);
363 if (message
.dispatch_error())
364 listener_
->OnBadMessageReceived(message
);
367 #if defined(OS_POSIX) && !defined(OS_NACL)
368 int ChannelMojo::GetClientFileDescriptor() const {
369 return bootstrap_
->GetClientFileDescriptor();
372 base::ScopedFD
ChannelMojo::TakeClientFileDescriptor() {
373 return bootstrap_
->TakeClientFileDescriptor();
375 #endif // defined(OS_POSIX) && !defined(OS_NACL)
378 MojoResult
ChannelMojo::ReadFromMessageAttachmentSet(
380 std::vector
<MojoHandle
>* handles
) {
381 // We dup() the handles in IPC::Message to transmit.
382 // IPC::MessageAttachmentSet has intricate lifecycle semantics
383 // of FDs, so just to dup()-and-own them is the safest option.
384 if (message
->HasAttachments()) {
385 MessageAttachmentSet
* set
= message
->attachment_set();
386 for (unsigned i
= 0; i
< set
->size(); ++i
) {
387 scoped_refptr
<MessageAttachment
> attachment
= set
->GetAttachmentAt(i
);
388 switch (attachment
->GetType()) {
389 case MessageAttachment::TYPE_PLATFORM_FILE
:
390 #if defined(OS_POSIX) && !defined(OS_NACL)
392 base::ScopedFD file
=
393 TakeOrDupFile(static_cast<IPC::internal::PlatformFileAttachment
*>(
395 if (!file
.is_valid()) {
396 DPLOG(WARNING
) << "Failed to dup FD to transmit.";
398 return MOJO_RESULT_UNKNOWN
;
401 MojoHandle wrapped_handle
;
402 MojoResult wrap_result
= CreatePlatformHandleWrapper(
403 mojo::embedder::ScopedPlatformHandle(
404 mojo::embedder::PlatformHandle(file
.release())),
406 if (MOJO_RESULT_OK
!= wrap_result
) {
407 LOG(WARNING
) << "Pipe failed to wrap handles. Closing: "
413 handles
->push_back(wrapped_handle
);
417 #endif // defined(OS_POSIX) && !defined(OS_NACL)
419 case MessageAttachment::TYPE_MOJO_HANDLE
: {
420 mojo::ScopedHandle handle
=
421 static_cast<IPC::internal::MojoHandleAttachment
*>(
422 attachment
.get())->TakeHandle();
423 handles
->push_back(handle
.release().value());
431 return MOJO_RESULT_OK
;
435 MojoResult
ChannelMojo::WriteToMessageAttachmentSet(
436 const std::vector
<MojoHandle
>& handle_buffer
,
438 for (size_t i
= 0; i
< handle_buffer
.size(); ++i
) {
439 bool ok
= message
->attachment_set()->AddAttachment(
440 new IPC::internal::MojoHandleAttachment(
441 mojo::MakeScopedHandle(mojo::Handle(handle_buffer
[i
]))));
444 LOG(ERROR
) << "Failed to add new Mojo handle.";
445 return MOJO_RESULT_UNKNOWN
;
449 return MOJO_RESULT_OK
;