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"
7 #include "base/base_paths.h"
8 #include "base/files/file.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/path_service.h"
11 #include "base/pickle.h"
12 #include "base/threading/thread.h"
13 #include "ipc/ipc_message.h"
14 #include "ipc/ipc_test_base.h"
15 #include "ipc/ipc_test_channel_listener.h"
16 #include "ipc/mojo/ipc_channel_mojo_host.h"
17 #include "ipc/mojo/ipc_mojo_handle_attachment.h"
18 #include "ipc/mojo/ipc_mojo_message_helper.h"
21 #include "base/file_descriptor_posix.h"
22 #include "ipc/ipc_platform_file_attachment_posix.h"
27 class ListenerThatExpectsOK
: public IPC::Listener
{
29 ListenerThatExpectsOK()
30 : received_ok_(false) {}
32 ~ListenerThatExpectsOK() override
{}
34 bool OnMessageReceived(const IPC::Message
& message
) override
{
35 PickleIterator
iter(message
);
36 std::string should_be_ok
;
37 EXPECT_TRUE(iter
.ReadString(&should_be_ok
));
38 EXPECT_EQ(should_be_ok
, "OK");
40 base::MessageLoop::current()->Quit();
44 void OnChannelError() override
{
45 // The connection should be healthy while the listener is waiting
46 // message. An error can occur after that because the peer
51 static void SendOK(IPC::Sender
* sender
) {
52 IPC::Message
* message
= new IPC::Message(
53 0, 2, IPC::Message::PRIORITY_NORMAL
);
54 message
->WriteString(std::string("OK"));
55 ASSERT_TRUE(sender
->Send(message
));
64 explicit ChannelClient(IPC::Listener
* listener
, const char* name
) {
65 channel_
= IPC::ChannelMojo::Create(NULL
,
66 IPCTestBase::GetChannelName(name
),
67 IPC::Channel::MODE_CLIENT
,
72 CHECK(channel_
->Connect());
75 IPC::ChannelMojo
* channel() const { return channel_
.get(); }
78 base::MessageLoopForIO main_message_loop_
;
79 scoped_ptr
<IPC::ChannelMojo
> channel_
;
82 class IPCChannelMojoTest
: public IPCTestBase
{
84 scoped_ptr
<IPC::ChannelFactory
> CreateChannelFactory(
85 const IPC::ChannelHandle
& handle
,
86 base::TaskRunner
* runner
) override
{
87 host_
.reset(new IPC::ChannelMojoHost(task_runner()));
88 return IPC::ChannelMojo::CreateServerFactory(host_
->channel_delegate(),
92 bool DidStartClient() override
{
93 bool ok
= IPCTestBase::DidStartClient();
95 host_
->OnClientLaunched(client_process().Handle());
100 scoped_ptr
<IPC::ChannelMojoHost
> host_
;
104 class TestChannelListenerWithExtraExpectations
105 : public IPC::TestChannelListener
{
107 TestChannelListenerWithExtraExpectations()
108 : is_connected_called_(false) {
111 void OnChannelConnected(int32 peer_pid
) override
{
112 IPC::TestChannelListener::OnChannelConnected(peer_pid
);
113 EXPECT_TRUE(base::kNullProcessId
!= peer_pid
);
114 is_connected_called_
= true;
117 bool is_connected_called() const { return is_connected_called_
; }
120 bool is_connected_called_
;
123 TEST_F(IPCChannelMojoTest
, ConnectedFromClient
) {
124 Init("IPCChannelMojoTestClient");
126 // Set up IPC channel and start client.
127 TestChannelListenerWithExtraExpectations listener
;
128 CreateChannel(&listener
);
129 listener
.Init(sender());
130 ASSERT_TRUE(ConnectChannel());
131 ASSERT_TRUE(StartClient());
133 IPC::TestChannelListener::SendOneMessage(
134 sender(), "hello from parent");
136 base::MessageLoop::current()->Run();
137 EXPECT_TRUE(base::kNullProcessId
!= this->channel()->GetPeerPID());
139 this->channel()->Close();
141 EXPECT_TRUE(WaitForClientShutdown());
142 EXPECT_TRUE(listener
.is_connected_called());
143 EXPECT_TRUE(listener
.HasSentAll());
148 // A long running process that connects to us
149 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestClient
) {
150 TestChannelListenerWithExtraExpectations listener
;
151 ChannelClient
client(&listener
, "IPCChannelMojoTestClient");
153 listener
.Init(client
.channel());
155 IPC::TestChannelListener::SendOneMessage(
156 client
.channel(), "hello from child");
157 base::MessageLoop::current()->Run();
158 EXPECT_TRUE(listener
.is_connected_called());
159 EXPECT_TRUE(listener
.HasSentAll());
164 class ListenerExpectingErrors
: public IPC::Listener
{
166 ListenerExpectingErrors()
167 : has_error_(false) {
170 void OnChannelConnected(int32 peer_pid
) override
{
171 base::MessageLoop::current()->Quit();
174 bool OnMessageReceived(const IPC::Message
& message
) override
{ return true; }
176 void OnChannelError() override
{
178 base::MessageLoop::current()->Quit();
181 bool has_error() const { return has_error_
; }
188 class IPCChannelMojoErrorTest
: public IPCTestBase
{
190 scoped_ptr
<IPC::ChannelFactory
> CreateChannelFactory(
191 const IPC::ChannelHandle
& handle
,
192 base::TaskRunner
* runner
) override
{
193 host_
.reset(new IPC::ChannelMojoHost(task_runner()));
194 return IPC::ChannelMojo::CreateServerFactory(host_
->channel_delegate(),
198 bool DidStartClient() override
{
199 bool ok
= IPCTestBase::DidStartClient();
201 host_
->OnClientLaunched(client_process().Handle());
206 scoped_ptr
<IPC::ChannelMojoHost
> host_
;
209 class ListenerThatQuits
: public IPC::Listener
{
211 ListenerThatQuits() {
214 bool OnMessageReceived(const IPC::Message
& message
) override
{
218 void OnChannelConnected(int32 peer_pid
) override
{
219 base::MessageLoop::current()->Quit();
223 // A long running process that connects to us.
224 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoErraticTestClient
) {
225 ListenerThatQuits listener
;
226 ChannelClient
client(&listener
, "IPCChannelMojoErraticTestClient");
229 base::MessageLoop::current()->Run();
234 TEST_F(IPCChannelMojoErrorTest
, SendFailWithPendingMessages
) {
235 Init("IPCChannelMojoErraticTestClient");
237 // Set up IPC channel and start client.
238 ListenerExpectingErrors listener
;
239 CreateChannel(&listener
);
240 ASSERT_TRUE(ConnectChannel());
242 // This matches a value in mojo/edk/system/constants.h
243 const int kMaxMessageNumBytes
= 4 * 1024 * 1024;
244 std::string
overly_large_data(kMaxMessageNumBytes
, '*');
245 // This messages are queued as pending.
246 for (size_t i
= 0; i
< 10; ++i
) {
247 IPC::TestChannelListener::SendOneMessage(
248 sender(), overly_large_data
.c_str());
251 ASSERT_TRUE(StartClient());
252 base::MessageLoop::current()->Run();
254 this->channel()->Close();
256 EXPECT_TRUE(WaitForClientShutdown());
257 EXPECT_TRUE(listener
.has_error());
262 struct TestingMessagePipe
{
263 TestingMessagePipe() {
264 EXPECT_EQ(MOJO_RESULT_OK
, mojo::CreateMessagePipe(nullptr, &self
, &peer
));
267 mojo::ScopedMessagePipeHandle self
;
268 mojo::ScopedMessagePipeHandle peer
;
271 class HandleSendingHelper
{
273 static std::string
GetSendingFileContent() { return "Hello"; }
275 static void WritePipe(IPC::Message
* message
, TestingMessagePipe
* pipe
) {
276 std::string content
= HandleSendingHelper::GetSendingFileContent();
277 EXPECT_EQ(MOJO_RESULT_OK
,
278 mojo::WriteMessageRaw(pipe
->self
.get(), &content
[0],
279 static_cast<uint32_t>(content
.size()),
282 IPC::MojoMessageHelper::WriteMessagePipeTo(message
, pipe
->peer
.Pass()));
285 static void WritePipeThenSend(IPC::Sender
* sender
, TestingMessagePipe
* pipe
) {
286 IPC::Message
* message
=
287 new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL
);
288 WritePipe(message
, pipe
);
289 ASSERT_TRUE(sender
->Send(message
));
292 static void ReadReceivedPipe(const IPC::Message
& message
,
293 PickleIterator
* iter
) {
294 mojo::ScopedMessagePipeHandle pipe
;
296 IPC::MojoMessageHelper::ReadMessagePipeFrom(&message
, iter
, &pipe
));
297 std::string
content(GetSendingFileContent().size(), ' ');
299 uint32_t num_bytes
= static_cast<uint32_t>(content
.size());
300 EXPECT_EQ(MOJO_RESULT_OK
,
301 mojo::ReadMessageRaw(pipe
.get(), &content
[0], &num_bytes
, nullptr,
303 EXPECT_EQ(content
, GetSendingFileContent());
306 #if defined(OS_POSIX)
307 static base::FilePath
GetSendingFilePath() {
309 bool ok
= PathService::Get(base::DIR_CACHE
, &path
);
311 return path
.Append("ListenerThatExpectsFile.txt");
314 static void WriteFile(IPC::Message
* message
, base::File
& file
) {
315 std::string content
= GetSendingFileContent();
316 file
.WriteAtCurrentPos(content
.data(), content
.size());
318 message
->WriteAttachment(new IPC::internal::PlatformFileAttachment(
319 base::ScopedFD(file
.TakePlatformFile())));
322 static void WriteFileThenSend(IPC::Sender
* sender
, base::File
& file
) {
323 IPC::Message
* message
=
324 new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL
);
325 WriteFile(message
, file
);
326 ASSERT_TRUE(sender
->Send(message
));
329 static void WriteFileAndPipeThenSend(IPC::Sender
* sender
,
331 TestingMessagePipe
* pipe
) {
332 IPC::Message
* message
=
333 new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL
);
334 WriteFile(message
, file
);
335 WritePipe(message
, pipe
);
336 ASSERT_TRUE(sender
->Send(message
));
339 static void ReadReceivedFile(const IPC::Message
& message
,
340 PickleIterator
* iter
) {
342 scoped_refptr
<IPC::MessageAttachment
> attachment
;
343 EXPECT_TRUE(message
.ReadAttachment(iter
, &attachment
));
344 base::File
file(attachment
->TakePlatformFile());
345 std::string
content(GetSendingFileContent().size(), ' ');
346 file
.Read(0, &content
[0], content
.size());
347 EXPECT_EQ(content
, GetSendingFileContent());
352 class ListenerThatExpectsMessagePipe
: public IPC::Listener
{
354 ListenerThatExpectsMessagePipe() : sender_(NULL
) {}
356 ~ListenerThatExpectsMessagePipe() override
{}
358 bool OnMessageReceived(const IPC::Message
& message
) override
{
359 PickleIterator
iter(message
);
360 HandleSendingHelper::ReadReceivedPipe(message
, &iter
);
361 base::MessageLoop::current()->Quit();
362 ListenerThatExpectsOK::SendOK(sender_
);
366 void OnChannelError() override
{ NOTREACHED(); }
368 void set_sender(IPC::Sender
* sender
) { sender_
= sender
; }
371 IPC::Sender
* sender_
;
374 TEST_F(IPCChannelMojoTest
, SendMessagePipe
) {
375 Init("IPCChannelMojoTestSendMessagePipeClient");
377 ListenerThatExpectsOK listener
;
378 CreateChannel(&listener
);
379 ASSERT_TRUE(ConnectChannel());
380 ASSERT_TRUE(StartClient());
382 TestingMessagePipe pipe
;
383 HandleSendingHelper::WritePipeThenSend(channel(), &pipe
);
385 base::MessageLoop::current()->Run();
386 this->channel()->Close();
388 EXPECT_TRUE(WaitForClientShutdown());
392 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendMessagePipeClient
) {
393 ListenerThatExpectsMessagePipe listener
;
394 ChannelClient
client(&listener
, "IPCChannelMojoTestSendPlatformHandleClient");
396 listener
.set_sender(client
.channel());
398 base::MessageLoop::current()->Run();
404 class IPCChannelMojoDeadHandleTest
: public IPCTestBase
{
406 virtual scoped_ptr
<IPC::ChannelFactory
> CreateChannelFactory(
407 const IPC::ChannelHandle
& handle
,
408 base::TaskRunner
* runner
) override
{
409 host_
.reset(new IPC::ChannelMojoHost(task_runner()));
410 return IPC::ChannelMojo::CreateServerFactory(host_
->channel_delegate(),
414 virtual bool DidStartClient() override
{
415 IPCTestBase::DidStartClient();
416 const base::ProcessHandle client
= client_process().Handle();
417 // Forces GetFileHandleForProcess() fail. It happens occasionally
418 // in production, so we should exercise it somehow.
419 // TODO(morrita): figure out how to safely test this.
420 // ::CloseHandle(client);
421 host_
->OnClientLaunched(client
);
426 scoped_ptr
<IPC::ChannelMojoHost
> host_
;
429 TEST_F(IPCChannelMojoDeadHandleTest
, InvalidClientHandle
) {
430 // Any client type is fine as it is going to be killed anyway.
431 Init("IPCChannelMojoTestDoNothingClient");
433 // Set up IPC channel and start client.
434 ListenerExpectingErrors listener
;
435 CreateChannel(&listener
);
436 ASSERT_TRUE(ConnectChannel());
438 ASSERT_TRUE(StartClient());
439 base::MessageLoop::current()->Run();
441 this->channel()->Close();
443 // WaitForClientShutdown() fails as client_hanadle() is already
445 EXPECT_FALSE(WaitForClientShutdown());
446 EXPECT_TRUE(listener
.has_error());
451 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestDoNothingClient
) {
452 ListenerThatQuits listener
;
453 ChannelClient
client(&listener
, "IPCChannelMojoTestDoNothingClient");
456 // Quits without running the message loop as this client won't
457 // receive any messages from the server.
463 #if defined(OS_POSIX)
464 class ListenerThatExpectsFile
: public IPC::Listener
{
466 ListenerThatExpectsFile()
469 ~ListenerThatExpectsFile() override
{}
471 bool OnMessageReceived(const IPC::Message
& message
) override
{
472 PickleIterator
iter(message
);
473 HandleSendingHelper::ReadReceivedFile(message
, &iter
);
474 base::MessageLoop::current()->Quit();
475 ListenerThatExpectsOK::SendOK(sender_
);
479 void OnChannelError() override
{
483 void set_sender(IPC::Sender
* sender
) { sender_
= sender
; }
486 IPC::Sender
* sender_
;
490 TEST_F(IPCChannelMojoTest
, SendPlatformHandle
) {
491 Init("IPCChannelMojoTestSendPlatformHandleClient");
493 ListenerThatExpectsOK listener
;
494 CreateChannel(&listener
);
495 ASSERT_TRUE(ConnectChannel());
496 ASSERT_TRUE(StartClient());
498 base::File
file(HandleSendingHelper::GetSendingFilePath(),
499 base::File::FLAG_CREATE_ALWAYS
| base::File::FLAG_WRITE
|
500 base::File::FLAG_READ
);
501 HandleSendingHelper::WriteFileThenSend(channel(), file
);
502 base::MessageLoop::current()->Run();
504 this->channel()->Close();
506 EXPECT_TRUE(WaitForClientShutdown());
510 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendPlatformHandleClient
) {
511 ListenerThatExpectsFile listener
;
512 ChannelClient
client(
513 &listener
, "IPCChannelMojoTestSendPlatformHandleClient");
515 listener
.set_sender(client
.channel());
517 base::MessageLoop::current()->Run();
522 class ListenerThatExpectsFileAndPipe
: public IPC::Listener
{
524 ListenerThatExpectsFileAndPipe() : sender_(NULL
) {}
526 ~ListenerThatExpectsFileAndPipe() override
{}
528 bool OnMessageReceived(const IPC::Message
& message
) override
{
529 PickleIterator
iter(message
);
530 HandleSendingHelper::ReadReceivedFile(message
, &iter
);
531 HandleSendingHelper::ReadReceivedPipe(message
, &iter
);
532 base::MessageLoop::current()->Quit();
533 ListenerThatExpectsOK::SendOK(sender_
);
537 void OnChannelError() override
{ NOTREACHED(); }
539 void set_sender(IPC::Sender
* sender
) { sender_
= sender
; }
542 IPC::Sender
* sender_
;
545 TEST_F(IPCChannelMojoTest
, SendPlatformHandleAndPipe
) {
546 Init("IPCChannelMojoTestSendPlatformHandleAndPipeClient");
548 ListenerThatExpectsOK listener
;
549 CreateChannel(&listener
);
550 ASSERT_TRUE(ConnectChannel());
551 ASSERT_TRUE(StartClient());
553 base::File
file(HandleSendingHelper::GetSendingFilePath(),
554 base::File::FLAG_CREATE_ALWAYS
| base::File::FLAG_WRITE
|
555 base::File::FLAG_READ
);
556 TestingMessagePipe pipe
;
557 HandleSendingHelper::WriteFileAndPipeThenSend(channel(), file
, &pipe
);
559 base::MessageLoop::current()->Run();
560 this->channel()->Close();
562 EXPECT_TRUE(WaitForClientShutdown());
566 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
567 IPCChannelMojoTestSendPlatformHandleAndPipeClient
) {
568 ListenerThatExpectsFileAndPipe listener
;
569 ChannelClient
client(&listener
,
570 "IPCChannelMojoTestSendPlatformHandleAndPipeClient");
572 listener
.set_sender(client
.channel());
574 base::MessageLoop::current()->Run();