blob: 1f05d268f18864eab3a55f1f7908a9f948b767cd [file] [log] [blame]
[email protected]64860882014-08-04 23:44:171// 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.
4
5#include "ipc/mojo/ipc_channel_mojo.h"
6
avi246998d82015-12-22 02:39:047#include <stddef.h>
8#include <stdint.h>
danakj03de39b22016-04-23 04:21:099
dcheng0917ec42015-11-19 07:00:2010#include <memory>
dchenge48600452015-12-28 02:24:5011#include <utility>
dcheng0917ec42015-11-19 07:00:2012
[email protected]64860882014-08-04 23:44:1713#include "base/bind.h"
14#include "base/bind_helpers.h"
jam76bcf0c2015-10-02 21:01:2815#include "base/command_line.h"
[email protected]64860882014-08-04 23:44:1716#include "base/lazy_instance.h"
avi246998d82015-12-22 02:39:0417#include "base/macros.h"
danakj03de39b22016-04-23 04:21:0918#include "base/memory/ptr_util.h"
rockotdbb3bb6b2015-05-11 22:53:2219#include "base/thread_task_runner_handle.h"
avi246998d82015-12-22 02:39:0420#include "build/build_config.h"
[email protected]64860882014-08-04 23:44:1721#include "ipc/ipc_listener.h"
morrita7126b7a2014-12-17 19:01:4022#include "ipc/ipc_logging.h"
morrita4b5c28e22015-01-14 21:17:0623#include "ipc/ipc_message_attachment_set.h"
morrita7126b7a2014-12-17 19:01:4024#include "ipc/ipc_message_macros.h"
morrita54f6f80c2014-09-23 21:16:0025#include "ipc/mojo/ipc_mojo_bootstrap.h"
morrita81b17e02015-02-06 00:58:3026#include "ipc/mojo/ipc_mojo_handle_attachment.h"
rockotc637caf9b2016-02-10 09:57:0827#include "mojo/edk/embedder/embedder.h"
rockot85dce0862015-11-13 01:33:5928#include "mojo/public/cpp/bindings/binding.h"
[email protected]64860882014-08-04 23:44:1729
morrita1aa788c2015-01-31 05:45:4230#if defined(OS_POSIX) && !defined(OS_NACL)
31#include "ipc/ipc_platform_file_attachment_posix.h"
32#endif
33
sammc57ed9f982016-03-10 06:28:3534#if defined(OS_MACOSX)
35#include "ipc/mach_port_attachment_mac.h"
36#endif
37
38#if defined(OS_WIN)
39#include "ipc/handle_attachment_win.h"
40#endif
41
[email protected]64860882014-08-04 23:44:1742namespace IPC {
43
44namespace {
45
[email protected]64860882014-08-04 23:44:1746class MojoChannelFactory : public ChannelFactory {
47 public:
sammc57ed9f982016-03-10 06:28:3548 MojoChannelFactory(mojo::ScopedMessagePipeHandle handle, Channel::Mode mode)
49 : handle_(std::move(handle)), mode_(mode) {}
[email protected]64860882014-08-04 23:44:1750
sammc57ed9f982016-03-10 06:28:3551 std::string GetName() const override { return ""; }
[email protected]64860882014-08-04 23:44:1752
danakj03de39b22016-04-23 04:21:0953 std::unique_ptr<Channel> BuildChannel(Listener* listener) override {
sammc57ed9f982016-03-10 06:28:3554 return ChannelMojo::Create(std::move(handle_), mode_, listener);
[email protected]64860882014-08-04 23:44:1755 }
56
57 private:
sammc57ed9f982016-03-10 06:28:3558 mojo::ScopedMessagePipeHandle handle_;
sammce4d0abd2016-03-07 22:38:0459 const Channel::Mode mode_;
[email protected]64860882014-08-04 23:44:1760
sammce4d0abd2016-03-07 22:38:0461 DISALLOW_COPY_AND_ASSIGN(MojoChannelFactory);
morritaf8f92dcd2014-10-27 20:10:2562};
63
sammc57ed9f982016-03-10 06:28:3564mojom::SerializedHandlePtr CreateSerializedHandle(
65 mojo::ScopedHandle handle,
66 mojom::SerializedHandle::Type type) {
67 mojom::SerializedHandlePtr serialized_handle = mojom::SerializedHandle::New();
68 serialized_handle->the_handle = std::move(handle);
69 serialized_handle->type = type;
70 return serialized_handle;
71}
72
73MojoResult WrapPlatformHandle(mojo::edk::ScopedPlatformHandle handle,
74 mojom::SerializedHandle::Type type,
75 mojom::SerializedHandlePtr* serialized) {
76 MojoHandle wrapped_handle;
77 MojoResult wrap_result = mojo::edk::CreatePlatformHandleWrapper(
78 std::move(handle), &wrapped_handle);
79 if (wrap_result != MOJO_RESULT_OK)
80 return wrap_result;
81
82 *serialized = CreateSerializedHandle(
83 mojo::MakeScopedHandle(mojo::Handle(wrapped_handle)), type);
84 return MOJO_RESULT_OK;
85}
86
morrita98ac98f2015-02-25 02:55:0487#if defined(OS_POSIX) && !defined(OS_NACL)
88
89base::ScopedFD TakeOrDupFile(internal::PlatformFileAttachment* attachment) {
90 return attachment->Owns() ? base::ScopedFD(attachment->TakePlatformFile())
91 : base::ScopedFD(dup(attachment->file()));
92}
93
94#endif
95
sammc57ed9f982016-03-10 06:28:3596MojoResult WrapAttachmentImpl(MessageAttachment* attachment,
97 mojom::SerializedHandlePtr* serialized) {
98 if (attachment->GetType() == MessageAttachment::TYPE_MOJO_HANDLE) {
99 *serialized = CreateSerializedHandle(
100 static_cast<internal::MojoHandleAttachment&>(*attachment).TakeHandle(),
101 mojom::SerializedHandle::Type::MOJO_HANDLE);
102 return MOJO_RESULT_OK;
103 }
104#if defined(OS_POSIX) && !defined(OS_NACL)
105 if (attachment->GetType() == MessageAttachment::TYPE_PLATFORM_FILE) {
106 // We dup() the handles in IPC::Message to transmit.
107 // IPC::MessageAttachmentSet has intricate lifecycle semantics
108 // of FDs, so just to dup()-and-own them is the safest option.
109 base::ScopedFD file = TakeOrDupFile(
110 static_cast<IPC::internal::PlatformFileAttachment*>(attachment));
111 if (!file.is_valid()) {
112 DPLOG(WARNING) << "Failed to dup FD to transmit.";
113 return MOJO_RESULT_UNKNOWN;
114 }
115
116 return WrapPlatformHandle(mojo::edk::ScopedPlatformHandle(
117 mojo::edk::PlatformHandle(file.release())),
118 mojom::SerializedHandle::Type::MOJO_HANDLE,
119 serialized);
120 }
121#endif
122#if defined(OS_MACOSX)
123 DCHECK_EQ(attachment->GetType(),
124 MessageAttachment::TYPE_BROKERABLE_ATTACHMENT);
125 DCHECK_EQ(static_cast<BrokerableAttachment&>(*attachment).GetBrokerableType(),
126 BrokerableAttachment::MACH_PORT);
127 internal::MachPortAttachmentMac& mach_port_attachment =
128 static_cast<internal::MachPortAttachmentMac&>(*attachment);
129 MojoResult result = WrapPlatformHandle(
130 mojo::edk::ScopedPlatformHandle(
131 mojo::edk::PlatformHandle(mach_port_attachment.get_mach_port())),
132 mojom::SerializedHandle::Type::MACH_PORT, serialized);
133 mach_port_attachment.reset_mach_port_ownership();
134 return result;
135#elif defined(OS_WIN)
136 DCHECK_EQ(attachment->GetType(),
137 MessageAttachment::TYPE_BROKERABLE_ATTACHMENT);
138 DCHECK_EQ(static_cast<BrokerableAttachment&>(*attachment).GetBrokerableType(),
139 BrokerableAttachment::WIN_HANDLE);
140 internal::HandleAttachmentWin& handle_attachment =
141 static_cast<internal::HandleAttachmentWin&>(*attachment);
142 MojoResult result = WrapPlatformHandle(
143 mojo::edk::ScopedPlatformHandle(
144 mojo::edk::PlatformHandle(handle_attachment.get_handle())),
145 mojom::SerializedHandle::Type::WIN_HANDLE, serialized);
146 handle_attachment.reset_handle_ownership();
147 return result;
148#else
149 NOTREACHED();
150 return MOJO_RESULT_UNKNOWN;
151#endif // defined(OS_MACOSX)
152}
153
154MojoResult WrapAttachment(MessageAttachment* attachment,
155 mojo::Array<mojom::SerializedHandlePtr>* handles) {
156 mojom::SerializedHandlePtr serialized_handle;
157 MojoResult wrap_result = WrapAttachmentImpl(attachment, &serialized_handle);
158 if (wrap_result != MOJO_RESULT_OK) {
159 LOG(WARNING) << "Pipe failed to wrap handles. Closing: " << wrap_result;
160 return wrap_result;
161 }
162 handles->push_back(std::move(serialized_handle));
163 return MOJO_RESULT_OK;
164}
165
166MojoResult UnwrapAttachment(mojom::SerializedHandlePtr handle,
167 scoped_refptr<MessageAttachment>* attachment) {
168 if (handle->type == mojom::SerializedHandle::Type::MOJO_HANDLE) {
169 *attachment =
170 new IPC::internal::MojoHandleAttachment(std::move(handle->the_handle));
171 return MOJO_RESULT_OK;
172 }
173 mojo::edk::ScopedPlatformHandle platform_handle;
174 MojoResult unwrap_result = mojo::edk::PassWrappedPlatformHandle(
175 handle->the_handle.release().value(), &platform_handle);
176 if (unwrap_result != MOJO_RESULT_OK)
177 return unwrap_result;
178#if defined(OS_MACOSX)
179 if (handle->type == mojom::SerializedHandle::Type::MACH_PORT &&
180 platform_handle.get().type == mojo::edk::PlatformHandle::Type::MACH) {
181 *attachment = new internal::MachPortAttachmentMac(
182 platform_handle.release().port,
183 internal::MachPortAttachmentMac::FROM_WIRE);
184 return MOJO_RESULT_OK;
185 }
186#endif // defined(OS_MACOSX)
187#if defined(OS_WIN)
188 if (handle->type == mojom::SerializedHandle::Type::WIN_HANDLE) {
189 *attachment = new internal::HandleAttachmentWin(
190 platform_handle.release().handle,
191 internal::HandleAttachmentWin::FROM_WIRE);
192 return MOJO_RESULT_OK;
193 }
194#endif // defined(OS_WIN)
195 NOTREACHED();
196 return MOJO_RESULT_UNKNOWN;
197}
198
rockotdbb3bb6b2015-05-11 22:53:22199} // namespace
[email protected]64860882014-08-04 23:44:17200
201//------------------------------------------------------------------------------
202
[email protected]64860882014-08-04 23:44:17203// static
danakj03de39b22016-04-23 04:21:09204std::unique_ptr<ChannelMojo> ChannelMojo::Create(
sammc57ed9f982016-03-10 06:28:35205 mojo::ScopedMessagePipeHandle handle,
206 Mode mode,
207 Listener* listener) {
danakj03de39b22016-04-23 04:21:09208 return base::WrapUnique(new ChannelMojo(std::move(handle), mode, listener));
[email protected]64860882014-08-04 23:44:17209}
210
211// static
danakj03de39b22016-04-23 04:21:09212std::unique_ptr<ChannelFactory> ChannelMojo::CreateServerFactory(
sammc57ed9f982016-03-10 06:28:35213 mojo::ScopedMessagePipeHandle handle) {
danakj03de39b22016-04-23 04:21:09214 return base::WrapUnique(
sammc57ed9f982016-03-10 06:28:35215 new MojoChannelFactory(std::move(handle), Channel::MODE_SERVER));
[email protected]64860882014-08-04 23:44:17216}
217
morrita54f6f80c2014-09-23 21:16:00218// static
danakj03de39b22016-04-23 04:21:09219std::unique_ptr<ChannelFactory> ChannelMojo::CreateClientFactory(
sammc57ed9f982016-03-10 06:28:35220 mojo::ScopedMessagePipeHandle handle) {
danakj03de39b22016-04-23 04:21:09221 return base::WrapUnique(
sammc57ed9f982016-03-10 06:28:35222 new MojoChannelFactory(std::move(handle), Channel::MODE_CLIENT));
morrita54f6f80c2014-09-23 21:16:00223}
224
sammc57ed9f982016-03-10 06:28:35225ChannelMojo::ChannelMojo(mojo::ScopedMessagePipeHandle handle,
morrita3b41d6c2014-09-11 19:06:29226 Mode mode,
erikchen30dc2812015-09-24 03:26:38227 Listener* listener)
rockotc18f64f2016-03-25 04:49:18228 : pipe_(handle.get()),
rockot506f92fa22016-03-23 01:32:18229 listener_(listener),
230 waiting_connect_(true),
231 weak_factory_(this) {
morrita54f6f80c2014-09-23 21:16:00232 // Create MojoBootstrap after all members are set as it touches
233 // ChannelMojo from a different thread.
sammc57ed9f982016-03-10 06:28:35234 bootstrap_ = MojoBootstrap::Create(std::move(handle), mode, this);
[email protected]64860882014-08-04 23:44:17235}
236
237ChannelMojo::~ChannelMojo() {
238 Close();
morritae9453ea2014-09-26 03:20:48239}
morrita54f6f80c2014-09-23 21:16:00240
[email protected]64860882014-08-04 23:44:17241bool ChannelMojo::Connect() {
erikchen90971902016-04-25 23:45:31242 WillConnect();
rockot506f92fa22016-03-23 01:32:18243 base::AutoLock lock(lock_);
rockotc18f64f2016-03-25 04:49:18244 DCHECK(!task_runner_);
245 task_runner_ = base::ThreadTaskRunnerHandle::Get();
[email protected]64860882014-08-04 23:44:17246 DCHECK(!message_reader_);
sammce4d0abd2016-03-07 22:38:04247 bootstrap_->Connect();
248 return true;
[email protected]64860882014-08-04 23:44:17249}
250
251void ChannelMojo::Close() {
danakj03de39b22016-04-23 04:21:09252 std::unique_ptr<internal::MessagePipeReader, ReaderDeleter> reader;
rockot506f92fa22016-03-23 01:32:18253 {
254 base::AutoLock lock(lock_);
255 if (!message_reader_)
256 return;
257 // The reader's destructor may re-enter Close, so we swap it out first to
258 // avoid deadlock when freeing it below.
259 std::swap(message_reader_, reader);
260
261 // We might Close() before we Connect().
262 waiting_connect_ = false;
263 }
264
265 reader.reset();
sammce4d0abd2016-03-07 22:38:04266}
morritab4472142015-04-20 21:20:12267
sammce4d0abd2016-03-07 22:38:04268// MojoBootstrap::Delegate implementation
269void ChannelMojo::OnPipesAvailable(
270 mojom::ChannelAssociatedPtrInfo send_channel,
271 mojom::ChannelAssociatedRequest receive_channel,
272 int32_t peer_pid) {
sammc57ed9f982016-03-10 06:28:35273 InitMessageReader(std::move(send_channel), std::move(receive_channel),
274 peer_pid);
[email protected]64860882014-08-04 23:44:17275}
276
morrita54f6f80c2014-09-23 21:16:00277void ChannelMojo::OnBootstrapError() {
278 listener_->OnChannelError();
279}
280
sammce4d0abd2016-03-07 22:38:04281void ChannelMojo::InitMessageReader(mojom::ChannelAssociatedPtrInfo sender,
sammc57ed9f982016-03-10 06:28:35282 mojom::ChannelAssociatedRequest receiver,
283 base::ProcessId peer_pid) {
284 mojom::ChannelAssociatedPtr sender_ptr;
285 sender_ptr.Bind(std::move(sender));
danakj03de39b22016-04-23 04:21:09286 std::unique_ptr<internal::MessagePipeReader, ChannelMojo::ReaderDeleter>
287 reader(new internal::MessagePipeReader(
288 pipe_, std::move(sender_ptr), std::move(receiver), peer_pid, this));
morritab4472142015-04-20 21:20:12289
rockot506f92fa22016-03-23 01:32:18290 bool connected = true;
291 {
292 base::AutoLock lock(lock_);
293 for (size_t i = 0; i < pending_messages_.size(); ++i) {
294 if (!reader->Send(std::move(pending_messages_[i]))) {
295 LOG(ERROR) << "Failed to flush pending messages";
296 pending_messages_.clear();
297 connected = false;
298 break;
299 }
300 }
301
302 if (connected) {
303 // We set |message_reader_| here and won't get any |pending_messages_|
304 // hereafter. Although we might have some if there is an error, we don't
305 // care. They cannot be sent anyway.
306 message_reader_ = std::move(reader);
sammce4d0abd2016-03-07 22:38:04307 pending_messages_.clear();
rockot506f92fa22016-03-23 01:32:18308 waiting_connect_ = false;
morrita0a24cfc92014-09-16 03:20:48309 }
morritab4472142015-04-20 21:20:12310 }
[email protected]64860882014-08-04 23:44:17311
rockot506f92fa22016-03-23 01:32:18312 if (connected)
313 listener_->OnChannelConnected(static_cast<int32_t>(GetPeerPID()));
314 else
315 OnPipeError();
[email protected]64860882014-08-04 23:44:17316}
317
rockot506f92fa22016-03-23 01:32:18318void ChannelMojo::OnPipeError() {
rockotc18f64f2016-03-25 04:49:18319 DCHECK(task_runner_);
rockot506f92fa22016-03-23 01:32:18320 if (task_runner_->RunsTasksOnCurrentThread()) {
321 listener_->OnChannelError();
322 } else {
323 task_runner_->PostTask(
324 FROM_HERE,
325 base::Bind(&ChannelMojo::OnPipeError, weak_factory_.GetWeakPtr()));
326 }
[email protected]64860882014-08-04 23:44:17327}
328
[email protected]64860882014-08-04 23:44:17329bool ChannelMojo::Send(Message* message) {
rockot506f92fa22016-03-23 01:32:18330 base::AutoLock lock(lock_);
[email protected]64860882014-08-04 23:44:17331 if (!message_reader_) {
danakj03de39b22016-04-23 04:21:09332 pending_messages_.push_back(base::WrapUnique(message));
morrita17137e62015-06-23 22:29:36333 // Counts as OK before the connection is established, but it's an
334 // error otherwise.
335 return waiting_connect_;
[email protected]64860882014-08-04 23:44:17336 }
337
danakj03de39b22016-04-23 04:21:09338 if (!message_reader_->Send(base::WrapUnique(message))) {
rockot506f92fa22016-03-23 01:32:18339 OnPipeError();
340 return false;
341 }
342
343 return true;
344}
345
346bool ChannelMojo::IsSendThreadSafe() const {
347 return true;
[email protected]64860882014-08-04 23:44:17348}
349
350base::ProcessId ChannelMojo::GetPeerPID() const {
rockot506f92fa22016-03-23 01:32:18351 base::AutoLock lock(lock_);
sammc57ed9f982016-03-10 06:28:35352 if (!message_reader_)
353 return base::kNullProcessId;
354
355 return message_reader_->GetPeerPid();
[email protected]64860882014-08-04 23:44:17356}
357
358base::ProcessId ChannelMojo::GetSelfPID() const {
morrita0bd20bd2015-02-25 20:11:27359 return bootstrap_->GetSelfPID();
[email protected]64860882014-08-04 23:44:17360}
361
sammce4d0abd2016-03-07 22:38:04362void ChannelMojo::OnMessageReceived(const Message& message) {
morrita7126b7a2014-12-17 19:01:40363 TRACE_EVENT2("ipc,toplevel", "ChannelMojo::OnMessageReceived",
364 "class", IPC_MESSAGE_ID_CLASS(message.type()),
365 "line", IPC_MESSAGE_ID_LINE(message.type()));
sammc57ed9f982016-03-10 06:28:35366 if (AttachmentBroker* broker = AttachmentBroker::GetGlobal()) {
367 if (broker->OnMessageReceived(message))
368 return;
369 }
[email protected]64860882014-08-04 23:44:17370 listener_->OnMessageReceived(message);
371 if (message.dispatch_error())
372 listener_->OnBadMessageReceived(message);
373}
374
375#if defined(OS_POSIX) && !defined(OS_NACL)
376int ChannelMojo::GetClientFileDescriptor() const {
sammce4d0abd2016-03-07 22:38:04377 return -1;
[email protected]64860882014-08-04 23:44:17378}
379
morritaa409ccc2014-10-20 23:53:25380base::ScopedFD ChannelMojo::TakeClientFileDescriptor() {
sammce4d0abd2016-03-07 22:38:04381 return base::ScopedFD(GetClientFileDescriptor());
[email protected]64860882014-08-04 23:44:17382}
morrita81b17e02015-02-06 00:58:30383#endif // defined(OS_POSIX) && !defined(OS_NACL)
morrita3b41d6c2014-09-11 19:06:29384
385// static
morrita4b5c28e22015-01-14 21:17:06386MojoResult ChannelMojo::ReadFromMessageAttachmentSet(
morrita96693852014-09-24 20:11:45387 Message* message,
sammc57ed9f982016-03-10 06:28:35388 mojo::Array<mojom::SerializedHandlePtr>* handles) {
morrita1aa788c2015-01-31 05:45:42389 if (message->HasAttachments()) {
morrita81b17e02015-02-06 00:58:30390 MessageAttachmentSet* set = message->attachment_set();
erikchenae6d3212015-10-10 02:43:49391 for (unsigned i = 0; i < set->num_non_brokerable_attachments(); ++i) {
sammc57ed9f982016-03-10 06:28:35392 MojoResult result = WrapAttachment(
393 set->GetNonBrokerableAttachmentAt(i).get(), handles);
394 if (result != MOJO_RESULT_OK) {
395 set->CommitAllDescriptors();
396 return result;
morrita81b17e02015-02-06 00:58:30397 }
morrita3b41d6c2014-09-11 19:06:29398 }
sammc57ed9f982016-03-10 06:28:35399 for (unsigned i = 0; i < set->num_brokerable_attachments(); ++i) {
400 MojoResult result =
401 WrapAttachment(set->GetBrokerableAttachmentAt(i).get(), handles);
402 if (result != MOJO_RESULT_OK) {
403 set->CommitAllDescriptors();
404 return result;
405 }
406 }
erikchenae6d3212015-10-10 02:43:49407 set->CommitAllDescriptors();
morrita3b41d6c2014-09-11 19:06:29408 }
morrita3b41d6c2014-09-11 19:06:29409 return MOJO_RESULT_OK;
410}
411
morrita81b17e02015-02-06 00:58:30412// static
413MojoResult ChannelMojo::WriteToMessageAttachmentSet(
sammc57ed9f982016-03-10 06:28:35414 mojo::Array<mojom::SerializedHandlePtr> handle_buffer,
morrita81b17e02015-02-06 00:58:30415 Message* message) {
416 for (size_t i = 0; i < handle_buffer.size(); ++i) {
sammc57ed9f982016-03-10 06:28:35417 scoped_refptr<MessageAttachment> unwrapped_attachment;
418 MojoResult unwrap_result = UnwrapAttachment(std::move(handle_buffer[i]),
419 &unwrapped_attachment);
420 if (unwrap_result != MOJO_RESULT_OK) {
421 LOG(WARNING) << "Pipe failed to unwrap handles. Closing: "
422 << unwrap_result;
423 return unwrap_result;
424 }
425 DCHECK(unwrapped_attachment);
426
morrita81b17e02015-02-06 00:58:30427 bool ok = message->attachment_set()->AddAttachment(
sammc57ed9f982016-03-10 06:28:35428 std::move(unwrapped_attachment));
morrita81b17e02015-02-06 00:58:30429 DCHECK(ok);
430 if (!ok) {
morritaa3889aa2015-03-16 22:40:51431 LOG(ERROR) << "Failed to add new Mojo handle.";
morrita81b17e02015-02-06 00:58:30432 return MOJO_RESULT_UNKNOWN;
433 }
434 }
morrita81b17e02015-02-06 00:58:30435 return MOJO_RESULT_OK;
436}
[email protected]64860882014-08-04 23:44:17437
438} // namespace IPC