blob: cefa29e08af85d1172b41e906529547e9be7c031 [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
5#include "ipc/mojo/ipc_channel_mojo.h"
6
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"
morrita7c48ab82014-09-24 06:16:00 +090016#include "ipc/mojo/ipc_channel_mojo_host.h"
morritafa3ab752014-09-16 12:20:48 +090017#include "ipc/mojo/ipc_channel_mojo_readers.h"
morrita@chromium.org15996aa2014-08-05 08:44:17 +090018
19#if defined(OS_POSIX)
20#include "base/file_descriptor_posix.h"
21#endif
22
23namespace {
24
25class ListenerThatExpectsOK : public IPC::Listener {
26 public:
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090027 ListenerThatExpectsOK()
28 : received_ok_(false) {}
morrita@chromium.org15996aa2014-08-05 08:44:17 +090029
dcheng9b01d242014-10-22 03:02:42 +090030 virtual ~ListenerThatExpectsOK() {}
morrita@chromium.org15996aa2014-08-05 08:44:17 +090031
dcheng9b01d242014-10-22 03:02:42 +090032 virtual bool OnMessageReceived(const IPC::Message& message) override {
morrita@chromium.org15996aa2014-08-05 08:44:17 +090033 PickleIterator iter(message);
34 std::string should_be_ok;
35 EXPECT_TRUE(iter.ReadString(&should_be_ok));
36 EXPECT_EQ(should_be_ok, "OK");
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090037 received_ok_ = true;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090038 base::MessageLoop::current()->Quit();
39 return true;
40 }
41
dcheng9b01d242014-10-22 03:02:42 +090042 virtual void OnChannelError() override {
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090043 // The connection should be healthy while the listener is waiting
44 // message. An error can occur after that because the peer
45 // process dies.
46 DCHECK(received_ok_);
morrita@chromium.org15996aa2014-08-05 08:44:17 +090047 }
48
49 static void SendOK(IPC::Sender* sender) {
50 IPC::Message* message = new IPC::Message(
51 0, 2, IPC::Message::PRIORITY_NORMAL);
52 message->WriteString(std::string("OK"));
53 ASSERT_TRUE(sender->Send(message));
54 }
morrita@chromium.orge2bbe782014-08-09 06:45:13 +090055
56 private:
57 bool received_ok_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090058};
59
morrita@chromium.org15996aa2014-08-05 08:44:17 +090060class ChannelClient {
61 public:
62 explicit ChannelClient(IPC::Listener* listener, const char* name) {
morrita7c48ab82014-09-24 06:16:00 +090063 channel_ = IPC::ChannelMojo::Create(NULL,
64 IPCTestBase::GetChannelName(name),
65 IPC::Channel::MODE_CLIENT,
66 listener);
morrita@chromium.org15996aa2014-08-05 08:44:17 +090067 }
68
69 void Connect() {
70 CHECK(channel_->Connect());
71 }
72
73 IPC::ChannelMojo* channel() const { return channel_.get(); }
74
75 private:
morrita@chromium.org15996aa2014-08-05 08:44:17 +090076 base::MessageLoopForIO main_message_loop_;
morrita7c48ab82014-09-24 06:16:00 +090077 scoped_ptr<IPC::ChannelMojo> channel_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090078};
79
80class IPCChannelMojoTest : public IPCTestBase {
morrita@chromium.org15996aa2014-08-05 08:44:17 +090081 protected:
dcheng9b01d242014-10-22 03:02:42 +090082 virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
morritaab779702014-09-10 04:35:24 +090083 const IPC::ChannelHandle& handle,
mostynbd41cdbb2014-10-07 16:17:16 +090084 base::TaskRunner* runner) override {
morrita7c48ab82014-09-24 06:16:00 +090085 host_.reset(new IPC::ChannelMojoHost(task_runner()));
morrita98b6e4a2014-09-26 12:20:48 +090086 return IPC::ChannelMojo::CreateServerFactory(host_->channel_delegate(),
87 handle);
morrita@chromium.org15996aa2014-08-05 08:44:17 +090088 }
morrita7c48ab82014-09-24 06:16:00 +090089
dcheng9b01d242014-10-22 03:02:42 +090090 virtual bool DidStartClient() override {
morrita7c48ab82014-09-24 06:16:00 +090091 bool ok = IPCTestBase::DidStartClient();
92 DCHECK(ok);
93 host_->OnClientLaunched(client_process());
94 return ok;
95 }
96
97 private:
98 scoped_ptr<IPC::ChannelMojoHost> host_;
morrita@chromium.org15996aa2014-08-05 08:44:17 +090099};
100
101
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900102class TestChannelListenerWithExtraExpectations
103 : public IPC::TestChannelListener {
104 public:
105 TestChannelListenerWithExtraExpectations()
106 : is_connected_called_(false) {
107 }
108
dcheng9b01d242014-10-22 03:02:42 +0900109 virtual void OnChannelConnected(int32 peer_pid) override {
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900110 IPC::TestChannelListener::OnChannelConnected(peer_pid);
111 EXPECT_TRUE(base::kNullProcessId != peer_pid);
112 is_connected_called_ = true;
113 }
114
115 bool is_connected_called() const { return is_connected_called_; }
116
117 private:
118 bool is_connected_called_;
119};
120
121TEST_F(IPCChannelMojoTest, ConnectedFromClient) {
122 Init("IPCChannelMojoTestClient");
123
124 // Set up IPC channel and start client.
125 TestChannelListenerWithExtraExpectations listener;
morritaab779702014-09-10 04:35:24 +0900126 CreateChannel(&listener);
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900127 listener.Init(sender());
128 ASSERT_TRUE(ConnectChannel());
129 ASSERT_TRUE(StartClient());
130
131 IPC::TestChannelListener::SendOneMessage(
132 sender(), "hello from parent");
133
134 base::MessageLoop::current()->Run();
135 EXPECT_TRUE(base::kNullProcessId != this->channel()->GetPeerPID());
136
137 this->channel()->Close();
138
139 EXPECT_TRUE(WaitForClientShutdown());
140 EXPECT_TRUE(listener.is_connected_called());
141 EXPECT_TRUE(listener.HasSentAll());
142
143 DestroyChannel();
144}
145
146// A long running process that connects to us
147MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestClient) {
148 TestChannelListenerWithExtraExpectations listener;
149 ChannelClient client(&listener, "IPCChannelMojoTestClient");
150 client.Connect();
151 listener.Init(client.channel());
152
153 IPC::TestChannelListener::SendOneMessage(
154 client.channel(), "hello from child");
155 base::MessageLoop::current()->Run();
156 EXPECT_TRUE(listener.is_connected_called());
157 EXPECT_TRUE(listener.HasSentAll());
158
159 return 0;
160}
161
morritafa3ab752014-09-16 12:20:48 +0900162class ListenerExpectingErrors : public IPC::Listener {
163 public:
164 ListenerExpectingErrors()
165 : has_error_(false) {
166 }
167
dcheng9b01d242014-10-22 03:02:42 +0900168 virtual void OnChannelConnected(int32 peer_pid) override {
morrita26b6d752014-09-25 08:38:44 +0900169 base::MessageLoop::current()->Quit();
170 }
171
dcheng9b01d242014-10-22 03:02:42 +0900172 virtual bool OnMessageReceived(const IPC::Message& message) override {
173 return true;
174 }
morritafa3ab752014-09-16 12:20:48 +0900175
dcheng9b01d242014-10-22 03:02:42 +0900176 virtual void OnChannelError() override {
morritafa3ab752014-09-16 12:20:48 +0900177 has_error_ = true;
178 base::MessageLoop::current()->Quit();
179 }
180
181 bool has_error() const { return has_error_; }
182
183 private:
184 bool has_error_;
185};
186
187
188class IPCChannelMojoErrorTest : public IPCTestBase {
189 protected:
dcheng9b01d242014-10-22 03:02:42 +0900190 virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
morritafa3ab752014-09-16 12:20:48 +0900191 const IPC::ChannelHandle& handle,
mostynbd41cdbb2014-10-07 16:17:16 +0900192 base::TaskRunner* runner) override {
morrita7c48ab82014-09-24 06:16:00 +0900193 host_.reset(new IPC::ChannelMojoHost(task_runner()));
morrita98b6e4a2014-09-26 12:20:48 +0900194 return IPC::ChannelMojo::CreateServerFactory(host_->channel_delegate(),
195 handle);
morritafa3ab752014-09-16 12:20:48 +0900196 }
morrita7c48ab82014-09-24 06:16:00 +0900197
dcheng9b01d242014-10-22 03:02:42 +0900198 virtual bool DidStartClient() override {
morrita7c48ab82014-09-24 06:16:00 +0900199 bool ok = IPCTestBase::DidStartClient();
200 DCHECK(ok);
201 host_->OnClientLaunched(client_process());
202 return ok;
203 }
204
205 private:
206 scoped_ptr<IPC::ChannelMojoHost> host_;
morritafa3ab752014-09-16 12:20:48 +0900207};
208
209class ListenerThatQuits : public IPC::Listener {
210 public:
211 ListenerThatQuits() {
212 }
213
dcheng9b01d242014-10-22 03:02:42 +0900214 virtual bool OnMessageReceived(const IPC::Message& message) override {
215 return true;
216 }
morritafa3ab752014-09-16 12:20:48 +0900217
dcheng9b01d242014-10-22 03:02:42 +0900218 virtual void OnChannelConnected(int32 peer_pid) override {
morritafa3ab752014-09-16 12:20:48 +0900219 base::MessageLoop::current()->Quit();
220 }
221};
222
223// A long running process that connects to us.
224MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoErraticTestClient) {
225 ListenerThatQuits listener;
226 ChannelClient client(&listener, "IPCChannelMojoErraticTestClient");
227 client.Connect();
228
229 base::MessageLoop::current()->Run();
230
231 return 0;
232}
233
morrita26b6d752014-09-25 08:38:44 +0900234TEST_F(IPCChannelMojoErrorTest, SendFailWithPendingMessages) {
morritafa3ab752014-09-16 12:20:48 +0900235 Init("IPCChannelMojoErraticTestClient");
236
237 // Set up IPC channel and start client.
238 ListenerExpectingErrors listener;
239 CreateChannel(&listener);
240 ASSERT_TRUE(ConnectChannel());
241
jamesr8dddfa22014-10-03 13:26:48 +0900242 // This matches a value in mojo/edk/system/constants.h
morrita26b6d752014-09-25 08:38:44 +0900243 const int kMaxMessageNumBytes = 4 * 1024 * 1024;
244 std::string overly_large_data(kMaxMessageNumBytes, '*');
morritafa3ab752014-09-16 12:20:48 +0900245 // This messages are queued as pending.
morrita26b6d752014-09-25 08:38:44 +0900246 for (size_t i = 0; i < 10; ++i) {
morritafa3ab752014-09-16 12:20:48 +0900247 IPC::TestChannelListener::SendOneMessage(
morrita26b6d752014-09-25 08:38:44 +0900248 sender(), overly_large_data.c_str());
morritafa3ab752014-09-16 12:20:48 +0900249 }
250
251 ASSERT_TRUE(StartClient());
252 base::MessageLoop::current()->Run();
253
254 this->channel()->Close();
255
256 EXPECT_TRUE(WaitForClientShutdown());
257 EXPECT_TRUE(listener.has_error());
258
259 DestroyChannel();
260}
261
morrita7767a0d2014-10-16 03:50:19 +0900262#if defined(OS_WIN)
263class IPCChannelMojoDeadHandleTest : public IPCTestBase {
264 protected:
265 virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory(
266 const IPC::ChannelHandle& handle,
267 base::TaskRunner* runner) override {
268 host_.reset(new IPC::ChannelMojoHost(task_runner()));
269 return IPC::ChannelMojo::CreateServerFactory(host_->channel_delegate(),
270 handle);
271 }
272
273 virtual bool DidStartClient() override {
274 IPCTestBase::DidStartClient();
275 base::ProcessHandle client = client_process();
276 // Forces GetFileHandleForProcess() fail. It happens occasionally
277 // in production, so we should exercise it somehow.
278 ::CloseHandle(client);
279 host_->OnClientLaunched(client);
280 return true;
281 }
282
283 private:
284 scoped_ptr<IPC::ChannelMojoHost> host_;
285};
286
287TEST_F(IPCChannelMojoDeadHandleTest, InvalidClientHandle) {
288 // Any client type is fine as it is going to be killed anyway.
289 Init("IPCChannelMojoTestDoNothingClient");
290
291 // Set up IPC channel and start client.
292 ListenerExpectingErrors listener;
293 CreateChannel(&listener);
294 ASSERT_TRUE(ConnectChannel());
295
296 ASSERT_TRUE(StartClient());
297 base::MessageLoop::current()->Run();
298
299 this->channel()->Close();
300
301 // WaitForClientShutdown() fails as client_hanadle() is already
302 // closed.
303 EXPECT_FALSE(WaitForClientShutdown());
304 EXPECT_TRUE(listener.has_error());
305
306 DestroyChannel();
307}
308
309MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestDoNothingClient) {
310 ListenerThatQuits listener;
311 ChannelClient client(&listener, "IPCChannelMojoTestDoNothingClient");
312 client.Connect();
313
314 // Quits without running the message loop as this client won't
315 // receive any messages from the server.
316
317 return 0;
318}
319#endif
morritafa3ab752014-09-16 12:20:48 +0900320
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900321#if defined(OS_POSIX)
322class ListenerThatExpectsFile : public IPC::Listener {
323 public:
324 ListenerThatExpectsFile()
325 : sender_(NULL) {}
326
dcheng9b01d242014-10-22 03:02:42 +0900327 virtual ~ListenerThatExpectsFile() {}
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900328
dcheng9b01d242014-10-22 03:02:42 +0900329 virtual bool OnMessageReceived(const IPC::Message& message) override {
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900330 PickleIterator iter(message);
morritaab207252014-09-25 05:11:45 +0900331
332 base::ScopedFD fd;
333 EXPECT_TRUE(message.ReadFile(&iter, &fd));
334 base::File file(fd.release());
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900335 std::string content(GetSendingFileContent().size(), ' ');
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900336 file.Read(0, &content[0], content.size());
337 EXPECT_EQ(content, GetSendingFileContent());
338 base::MessageLoop::current()->Quit();
339 ListenerThatExpectsOK::SendOK(sender_);
340 return true;
341 }
342
dcheng9b01d242014-10-22 03:02:42 +0900343 virtual void OnChannelError() override {
344 NOTREACHED();
345 }
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900346
347 static std::string GetSendingFileContent() {
348 return "Hello";
349 }
350
351 static base::FilePath GetSendingFilePath() {
352 base::FilePath path;
353 bool ok = PathService::Get(base::DIR_CACHE, &path);
354 EXPECT_TRUE(ok);
355 return path.Append("ListenerThatExpectsFile.txt");
356 }
357
358 static void WriteAndSendFile(IPC::Sender* sender, base::File& file) {
359 std::string content = GetSendingFileContent();
360 file.WriteAtCurrentPos(content.data(), content.size());
361 file.Flush();
362 IPC::Message* message = new IPC::Message(
363 0, 2, IPC::Message::PRIORITY_NORMAL);
morritaab207252014-09-25 05:11:45 +0900364 message->WriteFile(base::ScopedFD(file.TakePlatformFile()));
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900365 ASSERT_TRUE(sender->Send(message));
366 }
367
368 void set_sender(IPC::Sender* sender) { sender_ = sender; }
369
370 private:
371 IPC::Sender* sender_;
372};
373
374
375TEST_F(IPCChannelMojoTest, SendPlatformHandle) {
376 Init("IPCChannelMojoTestSendPlatformHandleClient");
377
378 ListenerThatExpectsOK listener;
morritaab779702014-09-10 04:35:24 +0900379 CreateChannel(&listener);
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900380 ASSERT_TRUE(ConnectChannel());
381 ASSERT_TRUE(StartClient());
382
383 base::File file(ListenerThatExpectsFile::GetSendingFilePath(),
384 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE |
385 base::File::FLAG_READ);
386 ListenerThatExpectsFile::WriteAndSendFile(channel(), file);
387 base::MessageLoop::current()->Run();
388
389 this->channel()->Close();
390
391 EXPECT_TRUE(WaitForClientShutdown());
392 DestroyChannel();
393}
394
395MULTIPROCESS_IPC_TEST_CLIENT_MAIN(IPCChannelMojoTestSendPlatformHandleClient) {
396 ListenerThatExpectsFile listener;
397 ChannelClient client(
398 &listener, "IPCChannelMojoTestSendPlatformHandleClient");
399 client.Connect();
400 listener.set_sender(client.channel());
401
402 base::MessageLoop::current()->Run();
403
404 return 0;
405}
406#endif
407
408} // namespace