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 ChannelHandle channel_handle
,
33 : delegate_(delegate
), channel_handle_(channel_handle
), mode_(mode
) {}
35 std::string
GetName() const override
{
36 return channel_handle_
.name
;
39 scoped_ptr
<Channel
> BuildChannel(Listener
* listener
) override
{
40 return ChannelMojo::Create(delegate_
, channel_handle_
, mode_
, listener
);
44 ChannelMojo::Delegate
* delegate_
;
45 ChannelHandle channel_handle_
;
49 //------------------------------------------------------------------------------
51 class ClientChannelMojo
: public ChannelMojo
,
53 public mojo::ErrorHandler
{
55 ClientChannelMojo(ChannelMojo::Delegate
* delegate
,
56 const ChannelHandle
& handle
,
58 ~ClientChannelMojo() override
;
59 // MojoBootstrap::Delegate implementation
60 void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle
) override
;
61 // mojo::ErrorHandler implementation
62 void OnConnectionError() override
;
63 // ClientChannel implementation
65 mojo::ScopedMessagePipeHandle pipe
,
67 const mojo::Callback
<void(int32_t)>& callback
) override
;
70 mojo::Binding
<ClientChannel
> binding_
;
72 DISALLOW_COPY_AND_ASSIGN(ClientChannelMojo
);
75 ClientChannelMojo::ClientChannelMojo(ChannelMojo::Delegate
* delegate
,
76 const ChannelHandle
& handle
,
78 : ChannelMojo(delegate
, handle
, Channel::MODE_CLIENT
, listener
),
82 ClientChannelMojo::~ClientChannelMojo() {
85 void ClientChannelMojo::OnPipeAvailable(
86 mojo::embedder::ScopedPlatformHandle handle
) {
87 binding_
.Bind(CreateMessagingPipe(handle
.Pass()));
90 void ClientChannelMojo::OnConnectionError() {
91 listener()->OnChannelError();
94 void ClientChannelMojo::Init(
95 mojo::ScopedMessagePipeHandle pipe
,
97 const mojo::Callback
<void(int32_t)>& callback
) {
98 InitMessageReader(pipe
.Pass(), static_cast<base::ProcessId
>(peer_pid
));
99 callback
.Run(GetSelfPID());
102 //------------------------------------------------------------------------------
104 class ServerChannelMojo
: public ChannelMojo
, public mojo::ErrorHandler
{
106 ServerChannelMojo(ChannelMojo::Delegate
* delegate
,
107 const ChannelHandle
& handle
,
109 ~ServerChannelMojo() override
;
111 // MojoBootstrap::Delegate implementation
112 void OnPipeAvailable(mojo::embedder::ScopedPlatformHandle handle
) override
;
113 // mojo::ErrorHandler implementation
114 void OnConnectionError() override
;
116 void Close() override
;
119 // ClientChannelClient implementation
120 void ClientChannelWasInitialized(int32_t peer_pid
);
122 mojo::InterfacePtr
<ClientChannel
> client_channel_
;
123 mojo::ScopedMessagePipeHandle message_pipe_
;
125 DISALLOW_COPY_AND_ASSIGN(ServerChannelMojo
);
128 ServerChannelMojo::ServerChannelMojo(ChannelMojo::Delegate
* delegate
,
129 const ChannelHandle
& handle
,
131 : ChannelMojo(delegate
, handle
, Channel::MODE_SERVER
, listener
) {
134 ServerChannelMojo::~ServerChannelMojo() {
138 void ServerChannelMojo::OnPipeAvailable(
139 mojo::embedder::ScopedPlatformHandle handle
) {
140 mojo::ScopedMessagePipeHandle peer
;
141 MojoResult create_result
=
142 mojo::CreateMessagePipe(nullptr, &message_pipe_
, &peer
);
143 if (create_result
!= MOJO_RESULT_OK
) {
144 LOG(WARNING
) << "mojo::CreateMessagePipe failed: " << create_result
;
145 listener()->OnChannelError();
149 client_channel_
.Bind(CreateMessagingPipe(handle
.Pass()));
150 client_channel_
.set_error_handler(this);
151 client_channel_
->Init(
153 static_cast<int32_t>(GetSelfPID()),
154 base::Bind(&ServerChannelMojo::ClientChannelWasInitialized
,
155 base::Unretained(this)));
158 void ServerChannelMojo::ClientChannelWasInitialized(int32_t peer_pid
) {
159 InitMessageReader(message_pipe_
.Pass(), peer_pid
);
162 void ServerChannelMojo::OnConnectionError() {
163 listener()->OnChannelError();
166 void ServerChannelMojo::Close() {
167 client_channel_
.reset();
168 message_pipe_
.reset();
169 ChannelMojo::Close();
172 #if defined(OS_POSIX) && !defined(OS_NACL)
174 base::ScopedFD
TakeOrDupFile(internal::PlatformFileAttachment
* attachment
) {
175 return attachment
->Owns() ? base::ScopedFD(attachment
->TakePlatformFile())
176 : base::ScopedFD(dup(attachment
->file()));
183 //------------------------------------------------------------------------------
185 void ChannelMojo::ChannelInfoDeleter::operator()(
186 mojo::embedder::ChannelInfo
* ptr
) const {
187 mojo::embedder::DestroyChannel(ptr
, base::Bind(&base::DoNothing
), nullptr);
190 //------------------------------------------------------------------------------
193 bool ChannelMojo::ShouldBeUsed() {
194 // TODO(morrita): Remove this if it sticks.
195 // ChannelMojo is currently disabled due to http://crbug.com/466814.
200 scoped_ptr
<ChannelMojo
> ChannelMojo::Create(ChannelMojo::Delegate
* delegate
,
201 const ChannelHandle
& channel_handle
,
203 Listener
* listener
) {
205 case Channel::MODE_CLIENT
:
206 return make_scoped_ptr(
207 new ClientChannelMojo(delegate
, channel_handle
, listener
));
208 case Channel::MODE_SERVER
:
209 return make_scoped_ptr(
210 new ServerChannelMojo(delegate
, channel_handle
, listener
));
218 scoped_ptr
<ChannelFactory
> ChannelMojo::CreateServerFactory(
219 ChannelMojo::Delegate
* delegate
,
220 const ChannelHandle
& channel_handle
) {
221 return make_scoped_ptr(
222 new MojoChannelFactory(delegate
, channel_handle
, Channel::MODE_SERVER
));
226 scoped_ptr
<ChannelFactory
> ChannelMojo::CreateClientFactory(
227 ChannelMojo::Delegate
* delegate
,
228 const ChannelHandle
& channel_handle
) {
229 return make_scoped_ptr(
230 new MojoChannelFactory(delegate
, channel_handle
, Channel::MODE_CLIENT
));
233 ChannelMojo::ChannelMojo(ChannelMojo::Delegate
* delegate
,
234 const ChannelHandle
& handle
,
239 peer_pid_(base::kNullProcessId
),
240 weak_factory_(this) {
241 // Create MojoBootstrap after all members are set as it touches
242 // ChannelMojo from a different thread.
243 bootstrap_
= MojoBootstrap::Create(handle
, mode
, this);
245 if (delegate
->GetIOTaskRunner() ==
246 base::MessageLoop::current()->message_loop_proxy()) {
247 InitDelegate(delegate
);
249 delegate
->GetIOTaskRunner()->PostTask(
252 &ChannelMojo::InitDelegate
, base::Unretained(this), delegate
));
257 ChannelMojo::~ChannelMojo() {
261 void ChannelMojo::InitDelegate(ChannelMojo::Delegate
* delegate
) {
263 new ScopedIPCSupport(base::MessageLoop::current()->task_runner()));
264 delegate_
= delegate
->ToWeakPtr();
265 delegate_
->OnChannelCreated(weak_factory_
.GetWeakPtr());
268 mojo::ScopedMessagePipeHandle
ChannelMojo::CreateMessagingPipe(
269 mojo::embedder::ScopedPlatformHandle handle
) {
270 DCHECK(!channel_info_
.get());
271 mojo::embedder::ChannelInfo
* channel_info
;
272 mojo::ScopedMessagePipeHandle pipe
=
273 mojo::embedder::CreateChannelOnIOThread(handle
.Pass(), &channel_info
);
274 channel_info_
.reset(channel_info
);
278 bool ChannelMojo::Connect() {
279 DCHECK(!message_reader_
);
280 return bootstrap_
->Connect();
283 void ChannelMojo::Close() {
284 message_reader_
.reset();
285 channel_info_
.reset();
286 ipc_support_
.reset();
289 void ChannelMojo::OnBootstrapError() {
290 listener_
->OnChannelError();
293 void ChannelMojo::InitMessageReader(mojo::ScopedMessagePipeHandle pipe
,
296 make_scoped_ptr(new internal::MessagePipeReader(pipe
.Pass(), this));
298 for (size_t i
= 0; i
< pending_messages_
.size(); ++i
) {
299 bool sent
= message_reader_
->Send(make_scoped_ptr(pending_messages_
[i
]));
300 pending_messages_
[i
] = nullptr;
302 pending_messages_
.clear();
303 listener_
->OnChannelError();
308 pending_messages_
.clear();
310 set_peer_pid(peer_pid
);
311 listener_
->OnChannelConnected(static_cast<int32_t>(GetPeerPID()));
313 message_reader_
->ReadMessagesThenWait();
316 void ChannelMojo::OnPipeClosed(internal::MessagePipeReader
* reader
) {
320 void ChannelMojo::OnPipeError(internal::MessagePipeReader
* reader
) {
321 listener_
->OnChannelError();
325 bool ChannelMojo::Send(Message
* message
) {
326 if (!message_reader_
) {
327 pending_messages_
.push_back(message
);
331 return message_reader_
->Send(make_scoped_ptr(message
));
334 base::ProcessId
ChannelMojo::GetPeerPID() const {
338 base::ProcessId
ChannelMojo::GetSelfPID() const {
339 return bootstrap_
->GetSelfPID();
342 void ChannelMojo::OnClientLaunched(base::ProcessHandle handle
) {
343 bootstrap_
->OnClientLaunched(handle
);
346 void ChannelMojo::OnMessageReceived(Message
& message
) {
347 TRACE_EVENT2("ipc,toplevel", "ChannelMojo::OnMessageReceived",
348 "class", IPC_MESSAGE_ID_CLASS(message
.type()),
349 "line", IPC_MESSAGE_ID_LINE(message
.type()));
350 listener_
->OnMessageReceived(message
);
351 if (message
.dispatch_error())
352 listener_
->OnBadMessageReceived(message
);
355 #if defined(OS_POSIX) && !defined(OS_NACL)
356 int ChannelMojo::GetClientFileDescriptor() const {
357 return bootstrap_
->GetClientFileDescriptor();
360 base::ScopedFD
ChannelMojo::TakeClientFileDescriptor() {
361 return bootstrap_
->TakeClientFileDescriptor();
363 #endif // defined(OS_POSIX) && !defined(OS_NACL)
366 MojoResult
ChannelMojo::ReadFromMessageAttachmentSet(
368 std::vector
<MojoHandle
>* handles
) {
369 // We dup() the handles in IPC::Message to transmit.
370 // IPC::MessageAttachmentSet has intricate lifecycle semantics
371 // of FDs, so just to dup()-and-own them is the safest option.
372 if (message
->HasAttachments()) {
373 MessageAttachmentSet
* set
= message
->attachment_set();
374 for (unsigned i
= 0; i
< set
->size(); ++i
) {
375 scoped_refptr
<MessageAttachment
> attachment
= set
->GetAttachmentAt(i
);
376 switch (attachment
->GetType()) {
377 case MessageAttachment::TYPE_PLATFORM_FILE
:
378 #if defined(OS_POSIX) && !defined(OS_NACL)
380 base::ScopedFD file
=
381 TakeOrDupFile(static_cast<IPC::internal::PlatformFileAttachment
*>(
383 if (!file
.is_valid()) {
384 DPLOG(WARNING
) << "Failed to dup FD to transmit.";
386 return MOJO_RESULT_UNKNOWN
;
389 MojoHandle wrapped_handle
;
390 MojoResult wrap_result
= CreatePlatformHandleWrapper(
391 mojo::embedder::ScopedPlatformHandle(
392 mojo::embedder::PlatformHandle(file
.release())),
394 if (MOJO_RESULT_OK
!= wrap_result
) {
395 LOG(WARNING
) << "Pipe failed to wrap handles. Closing: "
401 handles
->push_back(wrapped_handle
);
405 #endif // defined(OS_POSIX) && !defined(OS_NACL)
407 case MessageAttachment::TYPE_MOJO_HANDLE
: {
408 mojo::ScopedHandle handle
=
409 static_cast<IPC::internal::MojoHandleAttachment
*>(
410 attachment
.get())->TakeHandle();
411 handles
->push_back(handle
.release().value());
419 return MOJO_RESULT_OK
;
423 MojoResult
ChannelMojo::WriteToMessageAttachmentSet(
424 const std::vector
<MojoHandle
>& handle_buffer
,
426 for (size_t i
= 0; i
< handle_buffer
.size(); ++i
) {
427 bool ok
= message
->attachment_set()->AddAttachment(
428 new IPC::internal::MojoHandleAttachment(
429 mojo::MakeScopedHandle(mojo::Handle(handle_buffer
[i
]))));
432 LOG(ERROR
) << "Failed to add new Mojo handle.";
433 return MOJO_RESULT_UNKNOWN
;
437 return MOJO_RESULT_OK
;