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 "mojo/edk/embedder/embedder.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <string.h>
10
11 #include <utility>
12
13 #include "base/bind.h"
14 #include "base/command_line.h"
15 #include "base/files/file.h"
16 #include "base/logging.h"
17 #include "base/macros.h"
18 #include "base/memory/shared_memory.h"
19 #include "base/message_loop/message_loop.h"
20 #include "base/process/process_handle.h"
21 #include "base/synchronization/waitable_event.h"
22 #include "base/test/test_timeouts.h"
23 #include "mojo/edk/embedder/platform_channel_pair.h"
24 #include "mojo/edk/embedder/test_embedder.h"
25 #include "mojo/edk/system/test_utils.h"
26 #include "mojo/edk/test/mojo_test_base.h"
27 #include "mojo/public/c/system/core.h"
28 #include "mojo/public/cpp/system/handle.h"
29 #include "mojo/public/cpp/system/message_pipe.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31
32 namespace mojo {
33 namespace edk {
34 namespace {
35
36 const MojoHandleSignals kSignalReadadableWritable =
37 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE;
38
39 const MojoHandleSignals kSignalAll = MOJO_HANDLE_SIGNAL_READABLE |
40 MOJO_HANDLE_SIGNAL_WRITABLE |
41 MOJO_HANDLE_SIGNAL_PEER_CLOSED;
42
43 // The multiprocess tests that use these don't compile on iOS.
44 #if !defined(OS_IOS)
45 const char kHelloWorld[] = "hello world";
46 const char kByeWorld[] = "bye world";
47 #endif
48
49 using EmbedderTest = test::MojoTestBase;
50
TEST_F(EmbedderTest,ChannelBasic)51 TEST_F(EmbedderTest, ChannelBasic) {
52 MojoHandle server_mp, client_mp;
53 CreateMessagePipe(&server_mp, &client_mp);
54
55 const std::string kHello = "hello";
56
57 // We can write to a message pipe handle immediately.
58 WriteMessage(server_mp, kHello);
59 EXPECT_EQ(kHello, ReadMessage(client_mp));
60
61 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp));
62 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
63 }
64
65 // Test sending a MP which has read messages out of the OS pipe but which have
66 // not been consumed using MojoReadMessage yet.
TEST_F(EmbedderTest,SendReadableMessagePipe)67 TEST_F(EmbedderTest, SendReadableMessagePipe) {
68 MojoHandle server_mp, client_mp;
69 CreateMessagePipe(&server_mp, &client_mp);
70
71 MojoHandle server_mp2, client_mp2;
72 CreateMessagePipe(&server_mp2, &client_mp2);
73
74 // Write to server2 and wait for client2 to be readable before sending it.
75 // client2's MessagePipeDispatcher will have the message below in its
76 // message_queue_. For extra measures, also verify that this pending message
77 // can contain a message pipe.
78 MojoHandle server_mp3, client_mp3;
79 CreateMessagePipe(&server_mp3, &client_mp3);
80
81 const std::string kHello = "hello";
82 WriteMessageWithHandles(server_mp2, kHello, &client_mp3, 1);
83
84 MojoHandleSignalsState state;
85 ASSERT_EQ(MOJO_RESULT_OK, MojoWait(client_mp2, MOJO_HANDLE_SIGNAL_READABLE,
86 MOJO_DEADLINE_INDEFINITE, &state));
87 ASSERT_EQ(kSignalReadadableWritable, state.satisfied_signals);
88 ASSERT_EQ(kSignalAll, state.satisfiable_signals);
89
90 // Now send client2
91 WriteMessageWithHandles(server_mp, kHello, &client_mp2, 1);
92
93 MojoHandle port;
94 std::string message = ReadMessageWithHandles(client_mp, &port, 1);
95 EXPECT_EQ(kHello, message);
96
97 client_mp2 = port;
98 message = ReadMessageWithHandles(client_mp2, &client_mp3, 1);
99 EXPECT_EQ(kHello, message);
100
101 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp3));
102 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp3));
103 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp2));
104 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp2));
105 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp));
106 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
107 }
108
109 // Verifies that a MP with pending messages to be written can be sent and the
110 // pending messages aren't dropped.
TEST_F(EmbedderTest,SendMessagePipeWithWriteQueue)111 TEST_F(EmbedderTest, SendMessagePipeWithWriteQueue) {
112 MojoHandle server_mp, client_mp;
113 CreateMessagePipe(&server_mp, &client_mp);
114
115 MojoHandle server_mp2, client_mp2;
116 CreateMessagePipe(&server_mp2, &client_mp2);
117
118 static const size_t kNumMessages = 1001;
119 for (size_t i = 1; i <= kNumMessages; i++)
120 WriteMessage(client_mp2, std::string(i, 'A' + (i % 26)));
121
122 // Now send client2.
123 WriteMessageWithHandles(server_mp, "hey", &client_mp2, 1);
124 client_mp2 = MOJO_HANDLE_INVALID;
125
126 // Read client2 just so we can close it later.
127 EXPECT_EQ("hey", ReadMessageWithHandles(client_mp, &client_mp2, 1));
128 EXPECT_NE(MOJO_HANDLE_INVALID, client_mp2);
129
130 // Now verify that all the messages that were written were sent correctly.
131 for (size_t i = 1; i <= kNumMessages; i++)
132 ASSERT_EQ(std::string(i, 'A' + (i % 26)), ReadMessage(server_mp2));
133
134 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp2));
135 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp2));
136 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp));
137 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
138 }
139
TEST_F(EmbedderTest,ChannelsHandlePassing)140 TEST_F(EmbedderTest, ChannelsHandlePassing) {
141 MojoHandle server_mp, client_mp;
142 CreateMessagePipe(&server_mp, &client_mp);
143 EXPECT_NE(server_mp, MOJO_HANDLE_INVALID);
144 EXPECT_NE(client_mp, MOJO_HANDLE_INVALID);
145
146 MojoHandle h0, h1;
147 CreateMessagePipe(&h0, &h1);
148
149 // Write a message to |h0| (attaching nothing).
150 const std::string kHello = "hello";
151 WriteMessage(h0, kHello);
152
153 // Write one message to |server_mp|, attaching |h1|.
154 const std::string kWorld = "world!!!";
155 WriteMessageWithHandles(server_mp, kWorld, &h1, 1);
156 h1 = MOJO_HANDLE_INVALID;
157
158 // Write another message to |h0|.
159 const std::string kFoo = "foo";
160 WriteMessage(h0, kFoo);
161
162 // Wait for |client_mp| to become readable and read a message from it.
163 EXPECT_EQ(kWorld, ReadMessageWithHandles(client_mp, &h1, 1));
164 EXPECT_NE(h1, MOJO_HANDLE_INVALID);
165
166 // Wait for |h1| to become readable and read a message from it.
167 EXPECT_EQ(kHello, ReadMessage(h1));
168
169 // Wait for |h1| to become readable (again) and read its second message.
170 EXPECT_EQ(kFoo, ReadMessage(h1));
171
172 // Write a message to |h1|.
173 const std::string kBarBaz = "barbaz";
174 WriteMessage(h1, kBarBaz);
175
176 // Wait for |h0| to become readable and read a message from it.
177 EXPECT_EQ(kBarBaz, ReadMessage(h0));
178
179 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp));
180 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
181 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(h0));
182 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(h1));
183 }
184
TEST_F(EmbedderTest,PipeSetup)185 TEST_F(EmbedderTest, PipeSetup) {
186 std::string child_token = GenerateRandomToken();
187 std::string pipe_token = GenerateRandomToken();
188
189 ScopedMessagePipeHandle parent_mp =
190 CreateParentMessagePipe(pipe_token, child_token);
191 ScopedMessagePipeHandle child_mp =
192 CreateChildMessagePipe(pipe_token);
193
194 const std::string kHello = "hello";
195 WriteMessage(parent_mp.get().value(), kHello);
196
197 EXPECT_EQ(kHello, ReadMessage(child_mp.get().value()));
198 }
199
TEST_F(EmbedderTest,PipeSetup_LaunchDeath)200 TEST_F(EmbedderTest, PipeSetup_LaunchDeath) {
201 PlatformChannelPair pair;
202
203 std::string child_token = GenerateRandomToken();
204 std::string pipe_token = GenerateRandomToken();
205
206 ScopedMessagePipeHandle parent_mp =
207 CreateParentMessagePipe(pipe_token, child_token);
208 ChildProcessLaunched(base::GetCurrentProcessHandle(), pair.PassServerHandle(),
209 child_token);
210
211 // Close the remote end, simulating child death before the child connects to
212 // the reserved port.
213 ignore_result(pair.PassClientHandle());
214
215 EXPECT_EQ(MOJO_RESULT_OK, MojoWait(parent_mp.get().value(),
216 MOJO_HANDLE_SIGNAL_PEER_CLOSED,
217 MOJO_DEADLINE_INDEFINITE,
218 nullptr));
219 }
220
TEST_F(EmbedderTest,PipeSetup_LaunchFailure)221 TEST_F(EmbedderTest, PipeSetup_LaunchFailure) {
222 PlatformChannelPair pair;
223
224 std::string child_token = GenerateRandomToken();
225 std::string pipe_token = GenerateRandomToken();
226
227 ScopedMessagePipeHandle parent_mp =
228 CreateParentMessagePipe(pipe_token, child_token);
229
230 ChildProcessLaunchFailed(child_token);
231 EXPECT_EQ(MOJO_RESULT_OK, MojoWait(parent_mp.get().value(),
232 MOJO_HANDLE_SIGNAL_PEER_CLOSED,
233 MOJO_DEADLINE_INDEFINITE,
234 nullptr));
235 }
236
237 // The sequence of messages sent is:
238 // server_mp client_mp mp0 mp1 mp2 mp3
239 // 1. "hello"
240 // 2. "world!"
241 // 3. "FOO"
242 // 4. "Bar"+mp1
243 // 5. (close)
244 // 6. (close)
245 // 7. "baz"
246 // 8. (closed)
247 // 9. "quux"+mp2
248 // 10. (close)
249 // 11. (wait/cl.)
250 // 12. (wait/cl.)
251
252 #if !defined(OS_IOS)
253
TEST_F(EmbedderTest,MultiprocessChannels)254 TEST_F(EmbedderTest, MultiprocessChannels) {
255 RUN_CHILD_ON_PIPE(MultiprocessChannelsClient, server_mp)
256 // 1. Write a message to |server_mp| (attaching nothing).
257 WriteMessage(server_mp, "hello");
258
259 // 2. Read a message from |server_mp|.
260 EXPECT_EQ("world!", ReadMessage(server_mp));
261
262 // 3. Create a new message pipe (endpoints |mp0| and |mp1|).
263 MojoHandle mp0, mp1;
264 CreateMessagePipe(&mp0, &mp1);
265
266 // 4. Write something to |mp0|.
267 WriteMessage(mp0, "FOO");
268
269 // 5. Write a message to |server_mp|, attaching |mp1|.
270 WriteMessageWithHandles(server_mp, "Bar", &mp1, 1);
271 mp1 = MOJO_HANDLE_INVALID;
272
273 // 6. Read a message from |mp0|, which should have |mp2| attached.
274 MojoHandle mp2 = MOJO_HANDLE_INVALID;
275 EXPECT_EQ("quux", ReadMessageWithHandles(mp0, &mp2, 1));
276
277 // 7. Read a message from |mp2|.
278 EXPECT_EQ("baz", ReadMessage(mp2));
279
280 // 8. Close |mp0|.
281 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp0));
282
283 // 9. Tell the client to quit.
284 WriteMessage(server_mp, "quit");
285
286 // 10. Wait on |mp2| (which should eventually fail) and then close it.
287 MojoHandleSignalsState state;
288 ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
289 MojoWait(mp2, MOJO_HANDLE_SIGNAL_READABLE,
290 MOJO_DEADLINE_INDEFINITE,
291 &state));
292 ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals);
293 ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals);
294
295 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp2));
296 END_CHILD()
297 }
298
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessChannelsClient,EmbedderTest,client_mp)299 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessChannelsClient, EmbedderTest,
300 client_mp) {
301 // 1. Read the first message from |client_mp|.
302 EXPECT_EQ("hello", ReadMessage(client_mp));
303
304 // 2. Write a message to |client_mp| (attaching nothing).
305 WriteMessage(client_mp, "world!");
306
307 // 4. Read a message from |client_mp|, which should have |mp1| attached.
308 MojoHandle mp1;
309 EXPECT_EQ("Bar", ReadMessageWithHandles(client_mp, &mp1, 1));
310
311 // 5. Create a new message pipe (endpoints |mp2| and |mp3|).
312 MojoHandle mp2, mp3;
313 CreateMessagePipe(&mp2, &mp3);
314
315 // 6. Write a message to |mp3|.
316 WriteMessage(mp3, "baz");
317
318 // 7. Close |mp3|.
319 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp3));
320
321 // 8. Write a message to |mp1|, attaching |mp2|.
322 WriteMessageWithHandles(mp1, "quux", &mp2, 1);
323 mp2 = MOJO_HANDLE_INVALID;
324
325 // 9. Read a message from |mp1|.
326 EXPECT_EQ("FOO", ReadMessage(mp1));
327
328 EXPECT_EQ("quit", ReadMessage(client_mp));
329
330 // 10. Wait on |mp1| (which should eventually fail) and then close it.
331 MojoHandleSignalsState state;
332 ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
333 MojoWait(mp1, MOJO_HANDLE_SIGNAL_READABLE,
334 MOJO_DEADLINE_INDEFINITE, &state));
335 ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals);
336 ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfiable_signals);
337 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp1));
338 }
339
TEST_F(EmbedderTest,MultiprocessBaseSharedMemory)340 TEST_F(EmbedderTest, MultiprocessBaseSharedMemory) {
341 RUN_CHILD_ON_PIPE(MultiprocessSharedMemoryClient, server_mp)
342 // 1. Create a base::SharedMemory object and create a mojo shared buffer
343 // from it.
344 base::SharedMemoryCreateOptions options;
345 options.size = 123;
346 base::SharedMemory shared_memory;
347 ASSERT_TRUE(shared_memory.Create(options));
348 base::SharedMemoryHandle shm_handle = base::SharedMemory::DuplicateHandle(
349 shared_memory.handle());
350 MojoHandle sb1;
351 ASSERT_EQ(MOJO_RESULT_OK,
352 CreateSharedBufferWrapper(shm_handle, 123, false, &sb1));
353
354 // 2. Map |sb1| and write something into it.
355 char* buffer = nullptr;
356 ASSERT_EQ(MOJO_RESULT_OK,
357 MojoMapBuffer(sb1, 0, 123, reinterpret_cast<void**>(&buffer), 0));
358 ASSERT_TRUE(buffer);
359 memcpy(buffer, kHelloWorld, sizeof(kHelloWorld));
360
361 // 3. Duplicate |sb1| into |sb2| and pass to |server_mp|.
362 MojoHandle sb2 = MOJO_HANDLE_INVALID;
363 EXPECT_EQ(MOJO_RESULT_OK, MojoDuplicateBufferHandle(sb1, 0, &sb2));
364 EXPECT_NE(MOJO_HANDLE_INVALID, sb2);
365 WriteMessageWithHandles(server_mp, "hello", &sb2, 1);
366
367 // 4. Read a message from |server_mp|.
368 EXPECT_EQ("bye", ReadMessage(server_mp));
369
370 // 5. Expect that the contents of the shared buffer have changed.
371 EXPECT_EQ(kByeWorld, std::string(buffer));
372
373 // 6. Map the original base::SharedMemory and expect it contains the
374 // expected value.
375 ASSERT_TRUE(shared_memory.Map(123));
376 EXPECT_EQ(kByeWorld,
377 std::string(static_cast<char*>(shared_memory.memory())));
378
379 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(sb1));
380 END_CHILD()
381 }
382
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessSharedMemoryClient,EmbedderTest,client_mp)383 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessSharedMemoryClient, EmbedderTest,
384 client_mp) {
385 // 1. Read the first message from |client_mp|, which should have |sb1| which
386 // should be a shared buffer handle.
387 MojoHandle sb1;
388 EXPECT_EQ("hello", ReadMessageWithHandles(client_mp, &sb1, 1));
389
390 // 2. Map |sb1|.
391 char* buffer = nullptr;
392 ASSERT_EQ(MOJO_RESULT_OK,
393 MojoMapBuffer(sb1, 0, 123, reinterpret_cast<void**>(&buffer), 0));
394 ASSERT_TRUE(buffer);
395
396 // 3. Ensure |buffer| contains the values we expect.
397 EXPECT_EQ(kHelloWorld, std::string(buffer));
398
399 // 4. Write into |buffer| and send a message back.
400 memcpy(buffer, kByeWorld, sizeof(kByeWorld));
401 WriteMessage(client_mp, "bye");
402
403 // 5. Extract the shared memory handle and ensure we can map it and read the
404 // contents.
405 base::SharedMemoryHandle shm_handle;
406 ASSERT_EQ(MOJO_RESULT_OK,
407 PassSharedMemoryHandle(sb1, &shm_handle, nullptr, nullptr));
408 base::SharedMemory shared_memory(shm_handle, false);
409 ASSERT_TRUE(shared_memory.Map(123));
410 EXPECT_NE(buffer, shared_memory.memory());
411 EXPECT_EQ(kByeWorld, std::string(static_cast<char*>(shared_memory.memory())));
412
413 // 6. Close |sb1|. Should fail because |PassSharedMemoryHandle()| should have
414 // closed the handle.
415 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(sb1));
416 }
417
418 #if defined(OS_MACOSX) && !defined(OS_IOS)
TEST_F(EmbedderTest,MultiprocessMachSharedMemory)419 TEST_F(EmbedderTest, MultiprocessMachSharedMemory) {
420 RUN_CHILD_ON_PIPE(MultiprocessSharedMemoryClient, server_mp)
421 // 1. Create a Mach base::SharedMemory object and create a mojo shared
422 // buffer from it.
423 base::SharedMemoryCreateOptions options;
424 options.size = 123;
425 base::SharedMemory shared_memory;
426 ASSERT_TRUE(shared_memory.Create(options));
427 base::SharedMemoryHandle shm_handle = base::SharedMemory::DuplicateHandle(
428 shared_memory.handle());
429 MojoHandle sb1;
430 ASSERT_EQ(MOJO_RESULT_OK,
431 CreateSharedBufferWrapper(shm_handle, 123, false, &sb1));
432
433 // 2. Map |sb1| and write something into it.
434 char* buffer = nullptr;
435 ASSERT_EQ(MOJO_RESULT_OK,
436 MojoMapBuffer(sb1, 0, 123, reinterpret_cast<void**>(&buffer), 0));
437 ASSERT_TRUE(buffer);
438 memcpy(buffer, kHelloWorld, sizeof(kHelloWorld));
439
440 // 3. Duplicate |sb1| into |sb2| and pass to |server_mp|.
441 MojoHandle sb2 = MOJO_HANDLE_INVALID;
442 EXPECT_EQ(MOJO_RESULT_OK, MojoDuplicateBufferHandle(sb1, 0, &sb2));
443 EXPECT_NE(MOJO_HANDLE_INVALID, sb2);
444 WriteMessageWithHandles(server_mp, "hello", &sb2, 1);
445
446 // 4. Read a message from |server_mp|.
447 EXPECT_EQ("bye", ReadMessage(server_mp));
448
449 // 5. Expect that the contents of the shared buffer have changed.
450 EXPECT_EQ(kByeWorld, std::string(buffer));
451
452 // 6. Map the original base::SharedMemory and expect it contains the
453 // expected value.
454 ASSERT_TRUE(shared_memory.Map(123));
455 EXPECT_EQ(kByeWorld,
456 std::string(static_cast<char*>(shared_memory.memory())));
457
458 ASSERT_EQ(MOJO_RESULT_OK, MojoClose(sb1));
459 END_CHILD()
460 }
461
462 enum class HandleType {
463 POSIX,
464 MACH,
465 MACH_NULL,
466 };
467
468 const HandleType kTestHandleTypes[] = {
469 HandleType::MACH,
470 HandleType::MACH_NULL,
471 HandleType::POSIX,
472 HandleType::POSIX,
473 HandleType::MACH,
474 };
475
476 // Test that we can mix file descriptors and mach port handles.
TEST_F(EmbedderTest,MultiprocessMixMachAndFds)477 TEST_F(EmbedderTest, MultiprocessMixMachAndFds) {
478 const size_t kShmSize = 1234;
479 RUN_CHILD_ON_PIPE(MultiprocessMixMachAndFdsClient, server_mp)
480 // 1. Create fds or Mach objects and mojo handles from them.
481 MojoHandle platform_handles[arraysize(kTestHandleTypes)];
482 for (size_t i = 0; i < arraysize(kTestHandleTypes); i++) {
483 const auto type = kTestHandleTypes[i];
484 ScopedPlatformHandle scoped_handle;
485 if (type == HandleType::POSIX) {
486 // The easiest source of fds is opening /dev/null.
487 base::File file(base::FilePath("/dev/null"),
488 base::File::FLAG_OPEN | base::File::FLAG_WRITE);
489 ASSERT_TRUE(file.IsValid());
490 scoped_handle.reset(PlatformHandle(file.TakePlatformFile()));
491 EXPECT_EQ(PlatformHandle::Type::POSIX, scoped_handle.get().type);
492 } else if (type == HandleType::MACH_NULL) {
493 scoped_handle.reset(PlatformHandle(
494 static_cast<mach_port_t>(MACH_PORT_NULL)));
495 EXPECT_EQ(PlatformHandle::Type::MACH, scoped_handle.get().type);
496 } else {
497 base::SharedMemoryCreateOptions options;
498 options.size = kShmSize;
499 base::SharedMemory shared_memory;
500 ASSERT_TRUE(shared_memory.Create(options));
501 base::SharedMemoryHandle shm_handle =
502 base::SharedMemory::DuplicateHandle(shared_memory.handle());
503 scoped_handle.reset(PlatformHandle(shm_handle.GetMemoryObject()));
504 EXPECT_EQ(PlatformHandle::Type::MACH, scoped_handle.get().type);
505 }
506 ASSERT_EQ(MOJO_RESULT_OK, CreatePlatformHandleWrapper(
507 std::move(scoped_handle), platform_handles + i));
508 }
509
510 // 2. Send all the handles to the child.
511 WriteMessageWithHandles(server_mp, "hello", platform_handles,
512 arraysize(kTestHandleTypes));
513
514 // 3. Read a message from |server_mp|.
515 EXPECT_EQ("bye", ReadMessage(server_mp));
516 END_CHILD()
517 }
518
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessMixMachAndFdsClient,EmbedderTest,client_mp)519 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessMixMachAndFdsClient, EmbedderTest,
520 client_mp) {
521 const int kNumHandles = arraysize(kTestHandleTypes);
522 MojoHandle platform_handles[kNumHandles];
523
524 // 1. Read from |client_mp|, which should have a message containing
525 // |kNumHandles| handles.
526 EXPECT_EQ("hello",
527 ReadMessageWithHandles(client_mp, platform_handles, kNumHandles));
528
529 // 2. Extract each handle, and verify the type.
530 for (int i = 0; i < kNumHandles; i++) {
531 const auto type = kTestHandleTypes[i];
532 ScopedPlatformHandle scoped_handle;
533 ASSERT_EQ(MOJO_RESULT_OK,
534 PassWrappedPlatformHandle(platform_handles[i], &scoped_handle));
535 if (type == HandleType::POSIX) {
536 EXPECT_NE(0, scoped_handle.get().handle);
537 EXPECT_EQ(PlatformHandle::Type::POSIX, scoped_handle.get().type);
538 } else if (type == HandleType::MACH_NULL) {
539 EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL),
540 scoped_handle.get().port);
541 EXPECT_EQ(PlatformHandle::Type::MACH, scoped_handle.get().type);
542 } else {
543 EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL),
544 scoped_handle.get().port);
545 EXPECT_EQ(PlatformHandle::Type::MACH, scoped_handle.get().type);
546 }
547 }
548
549 // 3. Say bye!
550 WriteMessage(client_mp, "bye");
551 }
552
553 #endif // defined(OS_MACOSX) && !defined(OS_IOS)
554
555 // TODO(vtl): Test immediate write & close.
556 // TODO(vtl): Test broken-connection cases.
557
558 #endif // !defined(OS_IOS)
559
560 } // namespace
561 } // namespace edk
562 } // namespace mojo
563