OLD | NEW |
| (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 | |
OLD | NEW |