blob: 83327ec28dd351aca813807cb0fd25991befb420 [file] [log] [blame]
morrita@chromium.org15996aa2014-08-05 08:44:17 +09001// 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
amistry6555e692016-06-23 16:52:37 +09005#include "ipc/ipc_channel_mojo.h"
morrita@chromium.org15996aa2014-08-05 08:44:17 +09006
avi42ebda42015-12-22 11:39:04 +09007#include <stddef.h>
8#include <stdint.h>
danakjc3fb6c52016-04-23 13:21:09 +09009
dcheng0bdf3772015-11-19 16:00:20 +090010#include <memory>
dcheng6c1ffcf2015-12-28 11:24:50 +090011#include <utility>
dcheng0bdf3772015-11-19 16:00:20 +090012
morrita@chromium.org15996aa2014-08-05 08:44:17 +090013#include "base/bind.h"
14#include "base/bind_helpers.h"
jame76324e2015-10-03 06:01:28 +090015#include "base/command_line.h"
morrita@chromium.org15996aa2014-08-05 08:44:17 +090016#include "base/lazy_instance.h"
avi42ebda42015-12-22 11:39:04 +090017#include "base/macros.h"
danakjc3fb6c52016-04-23 13:21:09 +090018#include "base/memory/ptr_util.h"
rockota01dbc72016-07-23 06:18:07 +090019#include "base/process/process_handle.h"
gab0867a902016-05-12 03:51:11 +090020#include "base/threading/thread_task_runner_handle.h"
avi42ebda42015-12-22 11:39:04 +090021#include "build/build_config.h"
morrita@chromium.org15996aa2014-08-05 08:44:17 +090022#include "ipc/ipc_listener.h"
morrita24f34cd2014-12-18 04:01:40 +090023#include "ipc/ipc_logging.h"
morrita33a35902015-01-15 06:17:06 +090024#include "ipc/ipc_message_attachment_set.h"
morrita24f34cd2014-12-18 04:01:40 +090025#include "ipc/ipc_message_macros.h"
amistry6555e692016-06-23 16:52:37 +090026#include "ipc/ipc_mojo_bootstrap.h"
27#include "ipc/ipc_mojo_handle_attachment.h"
Ken Rockotb3a77c92017-09-14 13:23:41 +090028#include "ipc/native_handle_type_converters.h"
rockotaf32acb2015-11-13 10:33:59 +090029#include "mojo/public/cpp/bindings/binding.h"
amistryfe787b32016-06-09 13:08:12 +090030#include "mojo/public/cpp/system/platform_handle.h"
morrita@chromium.org15996aa2014-08-05 08:44:17 +090031
morrita@chromium.org15996aa2014-08-05 08:44:17 +090032namespace IPC {
33
34namespace {
35
morrita@chromium.org15996aa2014-08-05 08:44:17 +090036class MojoChannelFactory : public ChannelFactory {
37 public:
rockot37e7fa42016-07-20 13:28:32 +090038 MojoChannelFactory(
39 mojo::ScopedMessagePipeHandle handle,
40 Channel::Mode mode,
41 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner)
42 : handle_(std::move(handle)),
43 mode_(mode),
44 ipc_task_runner_(ipc_task_runner) {}
morrita@chromium.org15996aa2014-08-05 08:44:17 +090045
danakjc3fb6c52016-04-23 13:21:09 +090046 std::unique_ptr<Channel> BuildChannel(Listener* listener) override {
rockot37e7fa42016-07-20 13:28:32 +090047 return ChannelMojo::Create(
48 std::move(handle_), mode_, listener, ipc_task_runner_);
49 }
50
51 scoped_refptr<base::SingleThreadTaskRunner> GetIPCTaskRunner() override {
52 return ipc_task_runner_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090053 }
54
55 private:
sammc0bcbfc72016-03-10 15:28:35 +090056 mojo::ScopedMessagePipeHandle handle_;
sammc6194d972016-03-08 07:38:04 +090057 const Channel::Mode mode_;
rockot37e7fa42016-07-20 13:28:32 +090058 scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090059
sammc6194d972016-03-08 07:38:04 +090060 DISALLOW_COPY_AND_ASSIGN(MojoChannelFactory);
morrita88543a22014-10-28 05:10:25 +090061};
62
sammcb83485d2016-11-11 07:34:07 +090063base::ProcessId GetSelfPID() {
64#if defined(OS_LINUX)
65 if (int global_pid = Channel::GetGlobalPid())
66 return global_pid;
67#endif // OS_LINUX
68#if defined(OS_NACL)
69 return -1;
70#else
71 return base::GetCurrentProcId();
72#endif // defined(OS_NACL)
73}
74
rockotab992272015-05-12 07:53:22 +090075} // namespace
morrita@chromium.org15996aa2014-08-05 08:44:17 +090076
77//------------------------------------------------------------------------------
78
morrita@chromium.org15996aa2014-08-05 08:44:17 +090079// static
danakjc3fb6c52016-04-23 13:21:09 +090080std::unique_ptr<ChannelMojo> ChannelMojo::Create(
sammc0bcbfc72016-03-10 15:28:35 +090081 mojo::ScopedMessagePipeHandle handle,
82 Mode mode,
rockot37e7fa42016-07-20 13:28:32 +090083 Listener* listener,
84 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner) {
85 return base::WrapUnique(
86 new ChannelMojo(std::move(handle), mode, listener, ipc_task_runner));
morrita@chromium.org15996aa2014-08-05 08:44:17 +090087}
88
89// static
danakjc3fb6c52016-04-23 13:21:09 +090090std::unique_ptr<ChannelFactory> ChannelMojo::CreateServerFactory(
rockot37e7fa42016-07-20 13:28:32 +090091 mojo::ScopedMessagePipeHandle handle,
92 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner) {
Jeremy Romanbd20ea92017-08-30 02:43:43 +090093 return std::make_unique<MojoChannelFactory>(
riceacc524fe2016-09-05 14:06:18 +090094 std::move(handle), Channel::MODE_SERVER, ipc_task_runner);
morrita@chromium.org15996aa2014-08-05 08:44:17 +090095}
96
morrita7c48ab82014-09-24 06:16:00 +090097// static
danakjc3fb6c52016-04-23 13:21:09 +090098std::unique_ptr<ChannelFactory> ChannelMojo::CreateClientFactory(
rockot37e7fa42016-07-20 13:28:32 +090099 mojo::ScopedMessagePipeHandle handle,
100 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner) {
Jeremy Romanbd20ea92017-08-30 02:43:43 +0900101 return std::make_unique<MojoChannelFactory>(
riceacc524fe2016-09-05 14:06:18 +0900102 std::move(handle), Channel::MODE_CLIENT, ipc_task_runner);
morrita7c48ab82014-09-24 06:16:00 +0900103}
104
rockot37e7fa42016-07-20 13:28:32 +0900105ChannelMojo::ChannelMojo(
106 mojo::ScopedMessagePipeHandle handle,
107 Mode mode,
108 Listener* listener,
109 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner)
rockot7900d342017-02-09 17:40:15 +0900110 : task_runner_(ipc_task_runner),
111 pipe_(handle.get()),
112 listener_(listener),
113 weak_factory_(this) {
Wezd7f09fa2017-10-31 01:46:06 +0900114 weak_ptr_ = weak_factory_.GetWeakPtr();
rockot7900d342017-02-09 17:40:15 +0900115 bootstrap_ = MojoBootstrap::Create(std::move(handle), mode, ipc_task_runner);
116}
117
118void ChannelMojo::ForwardMessageFromThreadSafePtr(mojo::Message message) {
peary20b3a3c42017-05-19 09:37:15 +0900119 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot35d8b862017-02-10 06:25:20 +0900120 if (!message_reader_ || !message_reader_->sender().is_bound())
rockot7900d342017-02-09 17:40:15 +0900121 return;
122 message_reader_->sender().internal_state()->ForwardMessage(
123 std::move(message));
124}
125
126void ChannelMojo::ForwardMessageWithResponderFromThreadSafePtr(
127 mojo::Message message,
128 std::unique_ptr<mojo::MessageReceiver> responder) {
peary20b3a3c42017-05-19 09:37:15 +0900129 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot35d8b862017-02-10 06:25:20 +0900130 if (!message_reader_ || !message_reader_->sender().is_bound())
rockot7900d342017-02-09 17:40:15 +0900131 return;
132 message_reader_->sender().internal_state()->ForwardMessageWithResponder(
133 std::move(message), std::move(responder));
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900134}
135
136ChannelMojo::~ChannelMojo() {
peary20b3a3c42017-05-19 09:37:15 +0900137 DCHECK(task_runner_->RunsTasksInCurrentSequence());
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900138 Close();
morrita98b6e4a2014-09-26 12:20:48 +0900139}
morrita7c48ab82014-09-24 06:16:00 +0900140
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900141bool ChannelMojo::Connect() {
peary20b3a3c42017-05-19 09:37:15 +0900142 DCHECK(task_runner_->RunsTasksInCurrentSequence());
rockot7900d342017-02-09 17:40:15 +0900143
erikchen6b477672016-04-26 08:45:31 +0900144 WillConnect();
rockota01dbc72016-07-23 06:18:07 +0900145
rockot7900d342017-02-09 17:40:15 +0900146 mojom::ChannelAssociatedPtr sender;
147 mojom::ChannelAssociatedRequest receiver;
148 bootstrap_->Connect(&sender, &receiver);
rockota01dbc72016-07-23 06:18:07 +0900149
rockot7900d342017-02-09 17:40:15 +0900150 DCHECK(!message_reader_);
151 sender->SetPeerPid(GetSelfPID());
152 message_reader_.reset(new internal::MessagePipeReader(
153 pipe_, std::move(sender), std::move(receiver), this));
sammc6194d972016-03-08 07:38:04 +0900154 return true;
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900155}
156
rockote7c47902016-09-09 03:24:56 +0900157void ChannelMojo::Pause() {
158 bootstrap_->Pause();
159}
160
rockot685505b2016-09-07 03:35:57 +0900161void ChannelMojo::Unpause(bool flush) {
rockote7c47902016-09-09 03:24:56 +0900162 bootstrap_->Unpause();
rockot685505b2016-09-07 03:35:57 +0900163 if (flush)
164 Flush();
165}
166
167void ChannelMojo::Flush() {
168 bootstrap_->Flush();
169}
170
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900171void ChannelMojo::Close() {
rockota01dbc72016-07-23 06:18:07 +0900172 // NOTE: The MessagePipeReader's destructor may re-enter this function. Use
173 // caution when changing this method.
174 std::unique_ptr<internal::MessagePipeReader> reader =
175 std::move(message_reader_);
msramek12185ef2016-07-22 19:06:21 +0900176 reader.reset();
rockota01dbc72016-07-23 06:18:07 +0900177
178 base::AutoLock lock(associated_interface_lock_);
179 associated_interfaces_.clear();
sammc6194d972016-03-08 07:38:04 +0900180}
morrita5138bf52015-04-21 06:20:12 +0900181
rockot6e3d4922016-03-23 10:32:18 +0900182void ChannelMojo::OnPipeError() {
rockot121a4672016-03-25 13:49:18 +0900183 DCHECK(task_runner_);
peary20b3a3c42017-05-19 09:37:15 +0900184 if (task_runner_->RunsTasksInCurrentSequence()) {
rockot6e3d4922016-03-23 10:32:18 +0900185 listener_->OnChannelError();
186 } else {
Wezd7f09fa2017-10-31 01:46:06 +0900187 task_runner_->PostTask(FROM_HERE,
188 base::Bind(&ChannelMojo::OnPipeError, weak_ptr_));
rockot6e3d4922016-03-23 10:32:18 +0900189 }
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900190}
191
rockota01dbc72016-07-23 06:18:07 +0900192void ChannelMojo::OnAssociatedInterfaceRequest(
193 const std::string& name,
194 mojo::ScopedInterfaceEndpointHandle handle) {
195 GenericAssociatedInterfaceFactory factory;
196 {
197 base::AutoLock locker(associated_interface_lock_);
198 auto iter = associated_interfaces_.find(name);
199 if (iter != associated_interfaces_.end())
200 factory = iter->second;
msramek12185ef2016-07-22 19:06:21 +0900201 }
rockot262d5532016-07-22 12:53:59 +0900202
rockota01dbc72016-07-23 06:18:07 +0900203 if (!factory.is_null())
204 factory.Run(std::move(handle));
rockot065bc8f2016-09-15 09:08:59 +0900205 else
206 listener_->OnAssociatedInterfaceRequest(name, std::move(handle));
rockota01dbc72016-07-23 06:18:07 +0900207}
208
209bool ChannelMojo::Send(Message* message) {
210 std::unique_ptr<Message> scoped_message = base::WrapUnique(message);
211 if (!message_reader_)
212 return false;
213
amistry6dcfcf72016-07-12 06:33:28 +0900214 // Comment copied from ipc_channel_posix.cc:
215 // We can't close the pipe here, because calling OnChannelError may destroy
216 // this object, and that would be bad if we are called from Send(). Instead,
217 // we return false and hope the caller will close the pipe. If they do not,
218 // the pipe will still be closed next time OnFileCanReadWithoutBlocking is
219 // called.
220 //
221 // With Mojo, there's no OnFileCanReadWithoutBlocking, but we expect the
222 // pipe's connection error handler will be invoked in its place.
rockota01dbc72016-07-23 06:18:07 +0900223 return message_reader_->Send(std::move(scoped_message));
rockot6e3d4922016-03-23 10:32:18 +0900224}
225
rockota6edf832016-07-14 09:34:11 +0900226Channel::AssociatedInterfaceSupport*
227ChannelMojo::GetAssociatedInterfaceSupport() { return this; }
228
rockot7900d342017-02-09 17:40:15 +0900229std::unique_ptr<mojo::ThreadSafeForwarder<mojom::Channel>>
230ChannelMojo::CreateThreadSafeChannel() {
Jeremy Romanbd20ea92017-08-30 02:43:43 +0900231 return std::make_unique<mojo::ThreadSafeForwarder<mojom::Channel>>(
232 task_runner_,
Wezd7f09fa2017-10-31 01:46:06 +0900233 base::Bind(&ChannelMojo::ForwardMessageFromThreadSafePtr, weak_ptr_),
rockot7900d342017-02-09 17:40:15 +0900234 base::Bind(&ChannelMojo::ForwardMessageWithResponderFromThreadSafePtr,
Wezd7f09fa2017-10-31 01:46:06 +0900235 weak_ptr_),
yzshen8dc7bd72017-02-15 07:24:25 +0900236 *bootstrap_->GetAssociatedGroup());
rockot7900d342017-02-09 17:40:15 +0900237}
238
sammcb83485d2016-11-11 07:34:07 +0900239void ChannelMojo::OnPeerPidReceived(int32_t peer_pid) {
240 listener_->OnChannelConnected(peer_pid);
rockota01dbc72016-07-23 06:18:07 +0900241}
242
sammc6194d972016-03-08 07:38:04 +0900243void ChannelMojo::OnMessageReceived(const Message& message) {
morrita24f34cd2014-12-18 04:01:40 +0900244 TRACE_EVENT2("ipc,toplevel", "ChannelMojo::OnMessageReceived",
245 "class", IPC_MESSAGE_ID_CLASS(message.type()),
246 "line", IPC_MESSAGE_ID_LINE(message.type()));
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900247 listener_->OnMessageReceived(message);
248 if (message.dispatch_error())
249 listener_->OnBadMessageReceived(message);
250}
251
morrita42bda252014-09-12 04:06:29 +0900252// static
morrita33a35902015-01-15 06:17:06 +0900253MojoResult ChannelMojo::ReadFromMessageAttachmentSet(
morritaab207252014-09-25 05:11:45 +0900254 Message* message,
Ken Rockotb3a77c92017-09-14 13:23:41 +0900255 base::Optional<std::vector<mojo::native::SerializedHandlePtr>>* handles) {
yzshen8af798c2016-08-24 10:10:13 +0900256 DCHECK(!*handles);
257
258 MojoResult result = MOJO_RESULT_OK;
259 if (!message->HasAttachments())
260 return result;
261
Ken Rockotb3a77c92017-09-14 13:23:41 +0900262 std::vector<mojo::native::SerializedHandlePtr> output_handles;
yzshen8af798c2016-08-24 10:10:13 +0900263 MessageAttachmentSet* set = message->attachment_set();
264
sammc14583362016-11-23 12:17:35 +0900265 for (unsigned i = 0; result == MOJO_RESULT_OK && i < set->size(); ++i) {
Ken Rockotb3a77c92017-09-14 13:23:41 +0900266 auto attachment = set->GetAttachmentAt(i);
267 auto serialized_handle = mojo::native::SerializedHandle::New();
268 serialized_handle->the_handle = attachment->TakeMojoHandle();
269 serialized_handle->type =
270 mojo::ConvertTo<mojo::native::SerializedHandle::Type>(
271 attachment->GetType());
272 output_handles.emplace_back(std::move(serialized_handle));
morrita42bda252014-09-12 04:06:29 +0900273 }
yzshen8af798c2016-08-24 10:10:13 +0900274 set->CommitAllDescriptors();
275
276 if (!output_handles.empty())
277 *handles = std::move(output_handles);
278
279 return result;
morrita42bda252014-09-12 04:06:29 +0900280}
281
morrita1b52e4c2015-02-06 09:58:30 +0900282// static
283MojoResult ChannelMojo::WriteToMessageAttachmentSet(
Ken Rockotb3a77c92017-09-14 13:23:41 +0900284 base::Optional<std::vector<mojo::native::SerializedHandlePtr>> handles,
morrita1b52e4c2015-02-06 09:58:30 +0900285 Message* message) {
Ken Rockotb3a77c92017-09-14 13:23:41 +0900286 if (!handles)
yzshen8af798c2016-08-24 10:10:13 +0900287 return MOJO_RESULT_OK;
Ken Rockotb3a77c92017-09-14 13:23:41 +0900288 for (size_t i = 0; i < handles->size(); ++i) {
289 auto& handle = handles->at(i);
290 scoped_refptr<MessageAttachment> unwrapped_attachment =
291 MessageAttachment::CreateFromMojoHandle(
292 std::move(handle->the_handle),
293 mojo::ConvertTo<MessageAttachment::Type>(handle->type));
294 if (!unwrapped_attachment) {
295 DLOG(WARNING) << "Pipe failed to unwrap handles.";
296 return MOJO_RESULT_UNKNOWN;
sammc0bcbfc72016-03-10 15:28:35 +0900297 }
sammc0bcbfc72016-03-10 15:28:35 +0900298
morrita1b52e4c2015-02-06 09:58:30 +0900299 bool ok = message->attachment_set()->AddAttachment(
sammc0bcbfc72016-03-10 15:28:35 +0900300 std::move(unwrapped_attachment));
morrita1b52e4c2015-02-06 09:58:30 +0900301 DCHECK(ok);
302 if (!ok) {
morritada23c5d2015-03-17 07:40:51 +0900303 LOG(ERROR) << "Failed to add new Mojo handle.";
morrita1b52e4c2015-02-06 09:58:30 +0900304 return MOJO_RESULT_UNKNOWN;
305 }
306 }
morrita1b52e4c2015-02-06 09:58:30 +0900307 return MOJO_RESULT_OK;
308}
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900309
rockota6edf832016-07-14 09:34:11 +0900310void ChannelMojo::AddGenericAssociatedInterface(
311 const std::string& name,
312 const GenericAssociatedInterfaceFactory& factory) {
rockota01dbc72016-07-23 06:18:07 +0900313 base::AutoLock locker(associated_interface_lock_);
rockota6edf832016-07-14 09:34:11 +0900314 auto result = associated_interfaces_.insert({ name, factory });
315 DCHECK(result.second);
316}
317
318void ChannelMojo::GetGenericRemoteAssociatedInterface(
319 const std::string& name,
320 mojo::ScopedInterfaceEndpointHandle handle) {
yzshen91dd4642017-03-25 17:27:17 +0900321 if (message_reader_) {
rockota01dbc72016-07-23 06:18:07 +0900322 message_reader_->GetRemoteInterface(name, std::move(handle));
yzshen91dd4642017-03-25 17:27:17 +0900323 } else {
324 // Attach the associated interface to a disconnected pipe, so that the
325 // associated interface pointer can be used to make calls (which are
326 // dropped).
Balazs Engedy4522c122017-11-04 09:50:21 +0900327 mojo::AssociateWithDisconnectedPipe(std::move(handle));
yzshen91dd4642017-03-25 17:27:17 +0900328 }
rockota289bcc2016-07-15 01:37:14 +0900329}
330
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900331} // namespace IPC