Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Side by Side Diff: ipc/mojo/ipc_channel_mojo.cc

Issue 2069803003: Fold //ipc/mojo into //ipc. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mojo-ipc-deps
Patch Set: rebase Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ipc/mojo/ipc_channel_mojo.h ('k') | ipc/mojo/ipc_channel_mojo_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "ipc/mojo/ipc_channel_mojo.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <memory>
11 #include <utility>
12
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/command_line.h"
16 #include "base/lazy_instance.h"
17 #include "base/macros.h"
18 #include "base/memory/ptr_util.h"
19 #include "base/threading/thread_task_runner_handle.h"
20 #include "build/build_config.h"
21 #include "ipc/ipc_listener.h"
22 #include "ipc/ipc_logging.h"
23 #include "ipc/ipc_message_attachment_set.h"
24 #include "ipc/ipc_message_macros.h"
25 #include "ipc/mojo/ipc_mojo_bootstrap.h"
26 #include "ipc/mojo/ipc_mojo_handle_attachment.h"
27 #include "mojo/public/cpp/bindings/binding.h"
28 #include "mojo/public/cpp/system/platform_handle.h"
29
30 #if defined(OS_POSIX)
31 #include "ipc/ipc_platform_file_attachment_posix.h"
32 #endif
33
34 #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
42 namespace IPC {
43
44 namespace {
45
46 class MojoChannelFactory : public ChannelFactory {
47 public:
48 MojoChannelFactory(mojo::ScopedMessagePipeHandle handle, Channel::Mode mode)
49 : handle_(std::move(handle)), mode_(mode) {}
50
51 std::string GetName() const override { return ""; }
52
53 std::unique_ptr<Channel> BuildChannel(Listener* listener) override {
54 return ChannelMojo::Create(std::move(handle_), mode_, listener);
55 }
56
57 private:
58 mojo::ScopedMessagePipeHandle handle_;
59 const Channel::Mode mode_;
60
61 DISALLOW_COPY_AND_ASSIGN(MojoChannelFactory);
62 };
63
64 mojom::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
73 MojoResult WrapPlatformHandle(base::PlatformFile handle,
74 mojom::SerializedHandle::Type type,
75 mojom::SerializedHandlePtr* serialized) {
76 mojo::ScopedHandle wrapped_handle = mojo::WrapPlatformFile(handle);
77 if (!wrapped_handle.is_valid())
78 return MOJO_RESULT_UNKNOWN;
79
80 *serialized = CreateSerializedHandle(std::move(wrapped_handle), type);
81 return MOJO_RESULT_OK;
82 }
83
84 #if defined(OS_MACOSX)
85
86 MojoResult WrapMachPort(mach_port_t mach_port,
87 mojom::SerializedHandlePtr* serialized) {
88 MojoPlatformHandle platform_handle = {
89 sizeof(MojoPlatformHandle), MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT,
90 static_cast<uint64_t>(mach_port)
91 };
92
93 MojoHandle wrapped_handle;
94 MojoResult result = MojoWrapPlatformHandle(&platform_handle, &wrapped_handle);
95 if (result != MOJO_RESULT_OK)
96 return result;
97
98 *serialized = CreateSerializedHandle(
99 mojo::MakeScopedHandle(mojo::Handle(wrapped_handle)),
100 mojom::SerializedHandle::Type::MACH_PORT);
101 return MOJO_RESULT_OK;
102 }
103
104 #endif
105
106 #if defined(OS_POSIX)
107
108 base::ScopedFD TakeOrDupFile(internal::PlatformFileAttachment* attachment) {
109 return attachment->Owns() ? base::ScopedFD(attachment->TakePlatformFile())
110 : base::ScopedFD(dup(attachment->file()));
111 }
112
113 #endif
114
115 MojoResult WrapAttachmentImpl(MessageAttachment* attachment,
116 mojom::SerializedHandlePtr* serialized) {
117 if (attachment->GetType() == MessageAttachment::TYPE_MOJO_HANDLE) {
118 *serialized = CreateSerializedHandle(
119 static_cast<internal::MojoHandleAttachment&>(*attachment).TakeHandle(),
120 mojom::SerializedHandle::Type::MOJO_HANDLE);
121 return MOJO_RESULT_OK;
122 }
123 #if defined(OS_POSIX)
124 if (attachment->GetType() == MessageAttachment::TYPE_PLATFORM_FILE) {
125 // We dup() the handles in IPC::Message to transmit.
126 // IPC::MessageAttachmentSet has intricate lifecycle semantics
127 // of FDs, so just to dup()-and-own them is the safest option.
128 base::ScopedFD file = TakeOrDupFile(
129 static_cast<IPC::internal::PlatformFileAttachment*>(attachment));
130 if (!file.is_valid()) {
131 DPLOG(WARNING) << "Failed to dup FD to transmit.";
132 return MOJO_RESULT_UNKNOWN;
133 }
134
135 return WrapPlatformHandle(file.release(),
136 mojom::SerializedHandle::Type::PLATFORM_FILE,
137 serialized);
138 }
139 #endif
140 #if defined(OS_MACOSX)
141 DCHECK_EQ(attachment->GetType(),
142 MessageAttachment::TYPE_BROKERABLE_ATTACHMENT);
143 DCHECK_EQ(static_cast<BrokerableAttachment&>(*attachment).GetBrokerableType(),
144 BrokerableAttachment::MACH_PORT);
145 internal::MachPortAttachmentMac& mach_port_attachment =
146 static_cast<internal::MachPortAttachmentMac&>(*attachment);
147 MojoResult result = WrapMachPort(mach_port_attachment.get_mach_port(),
148 serialized);
149 mach_port_attachment.reset_mach_port_ownership();
150 return result;
151 #elif defined(OS_WIN)
152 DCHECK_EQ(attachment->GetType(),
153 MessageAttachment::TYPE_BROKERABLE_ATTACHMENT);
154 DCHECK_EQ(static_cast<BrokerableAttachment&>(*attachment).GetBrokerableType(),
155 BrokerableAttachment::WIN_HANDLE);
156 internal::HandleAttachmentWin& handle_attachment =
157 static_cast<internal::HandleAttachmentWin&>(*attachment);
158 MojoResult result = WrapPlatformHandle(
159 handle_attachment.get_handle(),
160 mojom::SerializedHandle::Type::WIN_HANDLE, serialized);
161 handle_attachment.reset_handle_ownership();
162 return result;
163 #else
164 NOTREACHED();
165 return MOJO_RESULT_UNKNOWN;
166 #endif // defined(OS_MACOSX)
167 }
168
169 MojoResult WrapAttachment(MessageAttachment* attachment,
170 mojo::Array<mojom::SerializedHandlePtr>* handles) {
171 mojom::SerializedHandlePtr serialized_handle;
172 MojoResult wrap_result = WrapAttachmentImpl(attachment, &serialized_handle);
173 if (wrap_result != MOJO_RESULT_OK) {
174 LOG(WARNING) << "Pipe failed to wrap handles. Closing: " << wrap_result;
175 return wrap_result;
176 }
177 handles->push_back(std::move(serialized_handle));
178 return MOJO_RESULT_OK;
179 }
180
181 MojoResult UnwrapAttachment(mojom::SerializedHandlePtr handle,
182 scoped_refptr<MessageAttachment>* attachment) {
183 if (handle->type == mojom::SerializedHandle::Type::MOJO_HANDLE) {
184 *attachment =
185 new IPC::internal::MojoHandleAttachment(std::move(handle->the_handle));
186 return MOJO_RESULT_OK;
187 }
188 MojoPlatformHandle platform_handle = { sizeof(MojoPlatformHandle), 0, 0 };
189 MojoResult unwrap_result = MojoUnwrapPlatformHandle(
190 handle->the_handle.release().value(), &platform_handle);
191 if (unwrap_result != MOJO_RESULT_OK)
192 return unwrap_result;
193 #if defined(OS_POSIX)
194 if (handle->type == mojom::SerializedHandle::Type::PLATFORM_FILE) {
195 base::PlatformFile file = base::kInvalidPlatformFile;
196 if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR)
197 file = static_cast<base::PlatformFile>(platform_handle.value);
198 *attachment = new internal::PlatformFileAttachment(file);
199 return MOJO_RESULT_OK;
200 }
201 #endif // defined(OS_POSIX)
202 #if defined(OS_MACOSX)
203 if (handle->type == mojom::SerializedHandle::Type::MACH_PORT) {
204 mach_port_t mach_port = MACH_PORT_NULL;
205 if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT)
206 mach_port = static_cast<mach_port_t>(platform_handle.value);
207 *attachment = new internal::MachPortAttachmentMac(
208 mach_port, internal::MachPortAttachmentMac::FROM_WIRE);
209 return MOJO_RESULT_OK;
210 }
211 #endif // defined(OS_MACOSX)
212 #if defined(OS_WIN)
213 if (handle->type == mojom::SerializedHandle::Type::WIN_HANDLE) {
214 base::PlatformFile handle = base::kInvalidPlatformFile;
215 if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE)
216 handle = reinterpret_cast<base::PlatformFile>(platform_handle.value);
217 *attachment = new internal::HandleAttachmentWin(
218 handle, internal::HandleAttachmentWin::FROM_WIRE);
219 return MOJO_RESULT_OK;
220 }
221 #endif // defined(OS_WIN)
222 NOTREACHED();
223 return MOJO_RESULT_UNKNOWN;
224 }
225
226 } // namespace
227
228 //------------------------------------------------------------------------------
229
230 // static
231 std::unique_ptr<ChannelMojo> ChannelMojo::Create(
232 mojo::ScopedMessagePipeHandle handle,
233 Mode mode,
234 Listener* listener) {
235 return base::WrapUnique(new ChannelMojo(std::move(handle), mode, listener));
236 }
237
238 // static
239 std::unique_ptr<ChannelFactory> ChannelMojo::CreateServerFactory(
240 mojo::ScopedMessagePipeHandle handle) {
241 return base::WrapUnique(
242 new MojoChannelFactory(std::move(handle), Channel::MODE_SERVER));
243 }
244
245 // static
246 std::unique_ptr<ChannelFactory> ChannelMojo::CreateClientFactory(
247 mojo::ScopedMessagePipeHandle handle) {
248 return base::WrapUnique(
249 new MojoChannelFactory(std::move(handle), Channel::MODE_CLIENT));
250 }
251
252 ChannelMojo::ChannelMojo(mojo::ScopedMessagePipeHandle handle,
253 Mode mode,
254 Listener* listener)
255 : pipe_(handle.get()),
256 listener_(listener),
257 waiting_connect_(true),
258 weak_factory_(this) {
259 // Create MojoBootstrap after all members are set as it touches
260 // ChannelMojo from a different thread.
261 bootstrap_ = MojoBootstrap::Create(std::move(handle), mode, this);
262 }
263
264 ChannelMojo::~ChannelMojo() {
265 Close();
266 }
267
268 bool ChannelMojo::Connect() {
269 WillConnect();
270 {
271 base::AutoLock lock(lock_);
272 DCHECK(!task_runner_);
273 task_runner_ = base::ThreadTaskRunnerHandle::Get();
274 DCHECK(!message_reader_);
275 }
276 bootstrap_->Connect();
277 return true;
278 }
279
280 void ChannelMojo::Close() {
281 std::unique_ptr<internal::MessagePipeReader, ReaderDeleter> reader;
282 {
283 base::AutoLock lock(lock_);
284 if (!message_reader_)
285 return;
286 // The reader's destructor may re-enter Close, so we swap it out first to
287 // avoid deadlock when freeing it below.
288 std::swap(message_reader_, reader);
289
290 // We might Close() before we Connect().
291 waiting_connect_ = false;
292 }
293
294 reader.reset();
295 }
296
297 // MojoBootstrap::Delegate implementation
298 void ChannelMojo::OnPipesAvailable(
299 mojom::ChannelAssociatedPtrInfo send_channel,
300 mojom::ChannelAssociatedRequest receive_channel,
301 int32_t peer_pid) {
302 InitMessageReader(std::move(send_channel), std::move(receive_channel),
303 peer_pid);
304 }
305
306 void ChannelMojo::OnBootstrapError() {
307 listener_->OnChannelError();
308 }
309
310 void ChannelMojo::InitMessageReader(mojom::ChannelAssociatedPtrInfo sender,
311 mojom::ChannelAssociatedRequest receiver,
312 base::ProcessId peer_pid) {
313 mojom::ChannelAssociatedPtr sender_ptr;
314 sender_ptr.Bind(std::move(sender));
315 std::unique_ptr<internal::MessagePipeReader, ChannelMojo::ReaderDeleter>
316 reader(new internal::MessagePipeReader(
317 pipe_, std::move(sender_ptr), std::move(receiver), peer_pid, this));
318
319 bool connected = true;
320 {
321 base::AutoLock lock(lock_);
322 for (size_t i = 0; i < pending_messages_.size(); ++i) {
323 if (!reader->Send(std::move(pending_messages_[i]))) {
324 LOG(ERROR) << "Failed to flush pending messages";
325 pending_messages_.clear();
326 connected = false;
327 break;
328 }
329 }
330
331 if (connected) {
332 // We set |message_reader_| here and won't get any |pending_messages_|
333 // hereafter. Although we might have some if there is an error, we don't
334 // care. They cannot be sent anyway.
335 message_reader_ = std::move(reader);
336 pending_messages_.clear();
337 waiting_connect_ = false;
338 }
339 }
340
341 if (connected)
342 listener_->OnChannelConnected(static_cast<int32_t>(GetPeerPID()));
343 else
344 OnPipeError();
345 }
346
347 void ChannelMojo::OnPipeError() {
348 DCHECK(task_runner_);
349 if (task_runner_->RunsTasksOnCurrentThread()) {
350 listener_->OnChannelError();
351 } else {
352 task_runner_->PostTask(
353 FROM_HERE,
354 base::Bind(&ChannelMojo::OnPipeError, weak_factory_.GetWeakPtr()));
355 }
356 }
357
358 bool ChannelMojo::Send(Message* message) {
359 bool sent = false;
360 {
361 base::AutoLock lock(lock_);
362 if (!message_reader_) {
363 pending_messages_.push_back(base::WrapUnique(message));
364 // Counts as OK before the connection is established, but it's an
365 // error otherwise.
366 return waiting_connect_;
367 }
368
369 sent = message_reader_->Send(base::WrapUnique(message));
370 }
371
372 if (!sent) {
373 OnPipeError();
374 return false;
375 }
376
377 return true;
378 }
379
380 bool ChannelMojo::IsSendThreadSafe() const {
381 return false;
382 }
383
384 base::ProcessId ChannelMojo::GetPeerPID() const {
385 base::AutoLock lock(lock_);
386 if (!message_reader_)
387 return base::kNullProcessId;
388
389 return message_reader_->GetPeerPid();
390 }
391
392 base::ProcessId ChannelMojo::GetSelfPID() const {
393 return bootstrap_->GetSelfPID();
394 }
395
396 void ChannelMojo::OnMessageReceived(const Message& message) {
397 TRACE_EVENT2("ipc,toplevel", "ChannelMojo::OnMessageReceived",
398 "class", IPC_MESSAGE_ID_CLASS(message.type()),
399 "line", IPC_MESSAGE_ID_LINE(message.type()));
400 if (AttachmentBroker* broker = AttachmentBroker::GetGlobal()) {
401 if (broker->OnMessageReceived(message))
402 return;
403 }
404 listener_->OnMessageReceived(message);
405 if (message.dispatch_error())
406 listener_->OnBadMessageReceived(message);
407 }
408
409 #if defined(OS_POSIX) && !defined(OS_NACL_SFI)
410 int ChannelMojo::GetClientFileDescriptor() const {
411 return -1;
412 }
413
414 base::ScopedFD ChannelMojo::TakeClientFileDescriptor() {
415 return base::ScopedFD(GetClientFileDescriptor());
416 }
417 #endif // defined(OS_POSIX) && !defined(OS_NACL_SFI)
418
419 // static
420 MojoResult ChannelMojo::ReadFromMessageAttachmentSet(
421 Message* message,
422 mojo::Array<mojom::SerializedHandlePtr>* handles) {
423 if (message->HasAttachments()) {
424 MessageAttachmentSet* set = message->attachment_set();
425 for (unsigned i = 0; i < set->num_non_brokerable_attachments(); ++i) {
426 MojoResult result = WrapAttachment(
427 set->GetNonBrokerableAttachmentAt(i).get(), handles);
428 if (result != MOJO_RESULT_OK) {
429 set->CommitAllDescriptors();
430 return result;
431 }
432 }
433 for (unsigned i = 0; i < set->num_brokerable_attachments(); ++i) {
434 MojoResult result =
435 WrapAttachment(set->GetBrokerableAttachmentAt(i).get(), handles);
436 if (result != MOJO_RESULT_OK) {
437 set->CommitAllDescriptors();
438 return result;
439 }
440 }
441 set->CommitAllDescriptors();
442 }
443 return MOJO_RESULT_OK;
444 }
445
446 // static
447 MojoResult ChannelMojo::WriteToMessageAttachmentSet(
448 mojo::Array<mojom::SerializedHandlePtr> handle_buffer,
449 Message* message) {
450 for (size_t i = 0; i < handle_buffer.size(); ++i) {
451 scoped_refptr<MessageAttachment> unwrapped_attachment;
452 MojoResult unwrap_result = UnwrapAttachment(std::move(handle_buffer[i]),
453 &unwrapped_attachment);
454 if (unwrap_result != MOJO_RESULT_OK) {
455 LOG(WARNING) << "Pipe failed to unwrap handles. Closing: "
456 << unwrap_result;
457 return unwrap_result;
458 }
459 DCHECK(unwrapped_attachment);
460
461 bool ok = message->attachment_set()->AddAttachment(
462 std::move(unwrapped_attachment));
463 DCHECK(ok);
464 if (!ok) {
465 LOG(ERROR) << "Failed to add new Mojo handle.";
466 return MOJO_RESULT_UNKNOWN;
467 }
468 }
469 return MOJO_RESULT_OK;
470 }
471
472 } // namespace IPC
OLDNEW
« no previous file with comments | « ipc/mojo/ipc_channel_mojo.h ('k') | ipc/mojo/ipc_channel_mojo_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698