Home | History | Annotate | Download | only in embedder
      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 
     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.
     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.
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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)
    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.
    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 
    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