• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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