• 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/core/embedder/embedder.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <string.h>
10 
11 #include <utility>
12 
13 #include "base/base_paths.h"
14 #include "base/bind.h"
15 #include "base/command_line.h"
16 #include "base/files/file.h"
17 #include "base/logging.h"
18 #include "base/macros.h"
19 #include "base/memory/ptr_util.h"
20 #include "base/memory/read_only_shared_memory_region.h"
21 #include "base/memory/unsafe_shared_memory_region.h"
22 #include "base/memory/writable_shared_memory_region.h"
23 #include "base/message_loop/message_loop.h"
24 #include "base/path_service.h"
25 #include "base/rand_util.h"
26 #include "base/run_loop.h"
27 #include "base/stl_util.h"
28 #include "base/strings/string_number_conversions.h"
29 #include "base/synchronization/waitable_event.h"
30 #include "base/test/test_timeouts.h"
31 #include "build/build_config.h"
32 #include "mojo/core/core.h"
33 #include "mojo/core/shared_buffer_dispatcher.h"
34 #include "mojo/core/test/mojo_test_base.h"
35 #include "mojo/core/test_utils.h"
36 #include "mojo/public/c/system/core.h"
37 #include "mojo/public/cpp/system/handle.h"
38 #include "mojo/public/cpp/system/message_pipe.h"
39 #include "mojo/public/cpp/system/platform_handle.h"
40 #include "mojo/public/cpp/system/wait.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42 
43 namespace mojo {
44 namespace core {
45 namespace {
46 
47 template <typename T>
CreateSharedBufferFromRegion(T && region,MojoHandle * handle)48 MojoResult CreateSharedBufferFromRegion(T&& region, MojoHandle* handle) {
49   scoped_refptr<SharedBufferDispatcher> buffer;
50   MojoResult result =
51       SharedBufferDispatcher::CreateFromPlatformSharedMemoryRegion(
52           T::TakeHandleForSerialization(std::move(region)), &buffer);
53   if (result != MOJO_RESULT_OK)
54     return result;
55 
56   *handle = Core::Get()->AddDispatcher(std::move(buffer));
57   return MOJO_RESULT_OK;
58 }
59 
60 template <typename T>
ExtractRegionFromSharedBuffer(MojoHandle handle,T * region)61 MojoResult ExtractRegionFromSharedBuffer(MojoHandle handle, T* region) {
62   scoped_refptr<Dispatcher> dispatcher =
63       Core::Get()->GetAndRemoveDispatcher(handle);
64   if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::SHARED_BUFFER)
65     return MOJO_RESULT_INVALID_ARGUMENT;
66 
67   auto* buffer = static_cast<SharedBufferDispatcher*>(dispatcher.get());
68   *region = T::Deserialize(buffer->PassPlatformSharedMemoryRegion());
69   return MOJO_RESULT_OK;
70 }
71 
72 // The multiprocess tests that use these don't compile on iOS.
73 #if !defined(OS_IOS)
74 const char kHelloWorld[] = "hello world";
75 const char kByeWorld[] = "bye world";
76 #endif
77 
78 using EmbedderTest = test::MojoTestBase;
79 
TEST_F(EmbedderTest,ChannelBasic)80 TEST_F(EmbedderTest, ChannelBasic) {
81   MojoHandle server_mp, client_mp;
82   CreateMessagePipe(&server_mp, &client_mp);
83 
84   const std::string kHello = "hello";
85 
86   // We can write to a message pipe handle immediately.
87   WriteMessage(server_mp, kHello);
88   EXPECT_EQ(kHello, ReadMessage(client_mp));
89 
90   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp));
91   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
92 }
93 
94 // Verifies that a MP with pending messages to be written can be sent and the
95 // pending messages aren't dropped.
TEST_F(EmbedderTest,SendMessagePipeWithWriteQueue)96 TEST_F(EmbedderTest, SendMessagePipeWithWriteQueue) {
97   MojoHandle server_mp, client_mp;
98   CreateMessagePipe(&server_mp, &client_mp);
99 
100   MojoHandle server_mp2, client_mp2;
101   CreateMessagePipe(&server_mp2, &client_mp2);
102 
103   static const size_t kNumMessages = 1001;
104   for (size_t i = 1; i <= kNumMessages; i++)
105     WriteMessage(client_mp2, std::string(i, 'A' + (i % 26)));
106 
107   // Now send client2.
108   WriteMessageWithHandles(server_mp, "hey", &client_mp2, 1);
109   client_mp2 = MOJO_HANDLE_INVALID;
110 
111   // Read client2 just so we can close it later.
112   EXPECT_EQ("hey", ReadMessageWithHandles(client_mp, &client_mp2, 1));
113   EXPECT_NE(MOJO_HANDLE_INVALID, client_mp2);
114 
115   // Now verify that all the messages that were written were sent correctly.
116   for (size_t i = 1; i <= kNumMessages; i++)
117     ASSERT_EQ(std::string(i, 'A' + (i % 26)), ReadMessage(server_mp2));
118 
119   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp2));
120   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp2));
121   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp));
122   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
123 }
124 
TEST_F(EmbedderTest,ChannelsHandlePassing)125 TEST_F(EmbedderTest, ChannelsHandlePassing) {
126   MojoHandle server_mp, client_mp;
127   CreateMessagePipe(&server_mp, &client_mp);
128   EXPECT_NE(server_mp, MOJO_HANDLE_INVALID);
129   EXPECT_NE(client_mp, MOJO_HANDLE_INVALID);
130 
131   MojoHandle h0, h1;
132   CreateMessagePipe(&h0, &h1);
133 
134   // Write a message to |h0| (attaching nothing).
135   const std::string kHello = "hello";
136   WriteMessage(h0, kHello);
137 
138   // Write one message to |server_mp|, attaching |h1|.
139   const std::string kWorld = "world!!!";
140   WriteMessageWithHandles(server_mp, kWorld, &h1, 1);
141   h1 = MOJO_HANDLE_INVALID;
142 
143   // Write another message to |h0|.
144   const std::string kFoo = "foo";
145   WriteMessage(h0, kFoo);
146 
147   // Wait for |client_mp| to become readable and read a message from it.
148   EXPECT_EQ(kWorld, ReadMessageWithHandles(client_mp, &h1, 1));
149   EXPECT_NE(h1, MOJO_HANDLE_INVALID);
150 
151   // Wait for |h1| to become readable and read a message from it.
152   EXPECT_EQ(kHello, ReadMessage(h1));
153 
154   // Wait for |h1| to become readable (again) and read its second message.
155   EXPECT_EQ(kFoo, ReadMessage(h1));
156 
157   // Write a message to |h1|.
158   const std::string kBarBaz = "barbaz";
159   WriteMessage(h1, kBarBaz);
160 
161   // Wait for |h0| to become readable and read a message from it.
162   EXPECT_EQ(kBarBaz, ReadMessage(h0));
163 
164   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(server_mp));
165   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(client_mp));
166   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(h0));
167   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(h1));
168 }
169 
170 // The sequence of messages sent is:
171 //       server_mp   client_mp   mp0         mp1         mp2         mp3
172 //   1.  "hello"
173 //   2.              "world!"
174 //   3.                          "FOO"
175 //   4.  "Bar"+mp1
176 //   5.  (close)
177 //   6.              (close)
178 //   7.                                                              "baz"
179 //   8.                                                              (closed)
180 //   9.                                      "quux"+mp2
181 //  10.                          (close)
182 //  11.                                      (wait/cl.)
183 //  12.                                                  (wait/cl.)
184 
185 #if !defined(OS_IOS)
186 
TEST_F(EmbedderTest,MultiprocessChannels)187 TEST_F(EmbedderTest, MultiprocessChannels) {
188   RunTestClient("MultiprocessChannelsClient", [&](MojoHandle server_mp) {
189     // 1. Write a message to |server_mp| (attaching nothing).
190     WriteMessage(server_mp, "hello");
191 
192     // 2. Read a message from |server_mp|.
193     EXPECT_EQ("world!", ReadMessage(server_mp));
194 
195     // 3. Create a new message pipe (endpoints |mp0| and |mp1|).
196     MojoHandle mp0, mp1;
197     CreateMessagePipe(&mp0, &mp1);
198 
199     // 4. Write something to |mp0|.
200     WriteMessage(mp0, "FOO");
201 
202     // 5. Write a message to |server_mp|, attaching |mp1|.
203     WriteMessageWithHandles(server_mp, "Bar", &mp1, 1);
204     mp1 = MOJO_HANDLE_INVALID;
205 
206     // 6. Read a message from |mp0|, which should have |mp2| attached.
207     MojoHandle mp2 = MOJO_HANDLE_INVALID;
208     EXPECT_EQ("quux", ReadMessageWithHandles(mp0, &mp2, 1));
209 
210     // 7. Read a message from |mp2|.
211     EXPECT_EQ("baz", ReadMessage(mp2));
212 
213     // 8. Close |mp0|.
214     ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp0));
215 
216     // 9. Tell the client to quit.
217     WriteMessage(server_mp, "quit");
218 
219     // 10. Wait on |mp2| (which should eventually fail) and then close it.
220     MojoHandleSignalsState state;
221     ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
222               WaitForSignals(mp2, MOJO_HANDLE_SIGNAL_READABLE, &state));
223     ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals);
224     ASSERT_FALSE(state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE);
225     ASSERT_FALSE(state.satisfiable_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
226 
227     ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp2));
228   });
229 }
230 
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessChannelsClient,EmbedderTest,client_mp)231 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessChannelsClient,
232                                   EmbedderTest,
233                                   client_mp) {
234   // 1. Read the first message from |client_mp|.
235   EXPECT_EQ("hello", ReadMessage(client_mp));
236 
237   // 2. Write a message to |client_mp| (attaching nothing).
238   WriteMessage(client_mp, "world!");
239 
240   // 4. Read a message from |client_mp|, which should have |mp1| attached.
241   MojoHandle mp1;
242   EXPECT_EQ("Bar", ReadMessageWithHandles(client_mp, &mp1, 1));
243 
244   // 5. Create a new message pipe (endpoints |mp2| and |mp3|).
245   MojoHandle mp2, mp3;
246   CreateMessagePipe(&mp2, &mp3);
247 
248   // 6. Write a message to |mp3|.
249   WriteMessage(mp3, "baz");
250 
251   // 7. Close |mp3|.
252   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp3));
253 
254   // 8. Write a message to |mp1|, attaching |mp2|.
255   WriteMessageWithHandles(mp1, "quux", &mp2, 1);
256   mp2 = MOJO_HANDLE_INVALID;
257 
258   // 9. Read a message from |mp1|.
259   EXPECT_EQ("FOO", ReadMessage(mp1));
260 
261   EXPECT_EQ("quit", ReadMessage(client_mp));
262 
263   // 10. Wait on |mp1| (which should eventually fail) and then close it.
264   MojoHandleSignalsState state;
265   ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
266             WaitForSignals(mp1, MOJO_HANDLE_SIGNAL_READABLE, &state));
267   ASSERT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, state.satisfied_signals);
268   ASSERT_FALSE(state.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE);
269   ASSERT_FALSE(state.satisfiable_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
270   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(mp1));
271 }
272 
TEST_F(EmbedderTest,MultiprocessBaseSharedMemory)273 TEST_F(EmbedderTest, MultiprocessBaseSharedMemory) {
274   RunTestClient("MultiprocessSharedMemoryClient", [&](MojoHandle server_mp) {
275     // 1. Create a shared memory region and wrap it as a Mojo object.
276     auto shared_memory = base::UnsafeSharedMemoryRegion::Create(123);
277     ASSERT_TRUE(shared_memory.IsValid());
278     MojoHandle sb1;
279     ASSERT_EQ(MOJO_RESULT_OK,
280               CreateSharedBufferFromRegion(shared_memory.Duplicate(), &sb1));
281 
282     // 2. Map |sb1| and write something into it.
283     char* buffer = nullptr;
284     ASSERT_EQ(MOJO_RESULT_OK, MojoMapBuffer(sb1, 0, 123, nullptr,
285                                             reinterpret_cast<void**>(&buffer)));
286     ASSERT_TRUE(buffer);
287     memcpy(buffer, kHelloWorld, sizeof(kHelloWorld));
288 
289     // 3. Duplicate |sb1| into |sb2| and pass to |server_mp|.
290     MojoHandle sb2 = MOJO_HANDLE_INVALID;
291     EXPECT_EQ(MOJO_RESULT_OK, MojoDuplicateBufferHandle(sb1, nullptr, &sb2));
292     EXPECT_NE(MOJO_HANDLE_INVALID, sb2);
293     WriteMessageWithHandles(server_mp, "hello", &sb2, 1);
294 
295     // 4. Read a message from |server_mp|.
296     EXPECT_EQ("bye", ReadMessage(server_mp));
297 
298     // 5. Expect that the contents of the shared buffer have changed.
299     EXPECT_EQ(kByeWorld, std::string(buffer));
300 
301     // 6. Map the original base::SharedMemory and expect it contains the
302     // expected value.
303     auto mapping = shared_memory.Map();
304     ASSERT_TRUE(mapping.IsValid());
305     EXPECT_EQ(kByeWorld, std::string(static_cast<char*>(mapping.memory())));
306 
307     ASSERT_EQ(MOJO_RESULT_OK, MojoClose(sb1));
308   });
309 }
310 
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessSharedMemoryClient,EmbedderTest,client_mp)311 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessSharedMemoryClient,
312                                   EmbedderTest,
313                                   client_mp) {
314   // 1. Read the first message from |client_mp|, which should have |sb1| which
315   // should be a shared buffer handle.
316   MojoHandle sb1;
317   EXPECT_EQ("hello", ReadMessageWithHandles(client_mp, &sb1, 1));
318 
319   // 2. Map |sb1|.
320   char* buffer = nullptr;
321   ASSERT_EQ(MOJO_RESULT_OK, MojoMapBuffer(sb1, 0, 123, nullptr,
322                                           reinterpret_cast<void**>(&buffer)));
323   ASSERT_TRUE(buffer);
324 
325   // 3. Ensure |buffer| contains the values we expect.
326   EXPECT_EQ(kHelloWorld, std::string(buffer));
327 
328   // 4. Write into |buffer| and send a message back.
329   memcpy(buffer, kByeWorld, sizeof(kByeWorld));
330   WriteMessage(client_mp, "bye");
331 
332   // 5. Extract the shared memory handle and ensure we can map it and read the
333   // contents.
334   base::UnsafeSharedMemoryRegion shared_memory;
335   ASSERT_EQ(MOJO_RESULT_OK, ExtractRegionFromSharedBuffer(sb1, &shared_memory));
336   auto mapping = shared_memory.Map();
337   ASSERT_TRUE(mapping.IsValid());
338   EXPECT_NE(buffer, mapping.memory());
339   EXPECT_EQ(kByeWorld, std::string(static_cast<char*>(mapping.memory())));
340 
341   // 6. Close |sb1|. Should fail because |ExtractRegionFromSharedBuffer()|
342   // should have closed the handle.
343   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(sb1));
344 }
345 
346 #if defined(OS_MACOSX)
347 
348 enum class HandleType {
349   POSIX,
350   MACH,
351 };
352 
353 const HandleType kTestHandleTypes[] = {
354     HandleType::MACH, HandleType::POSIX, HandleType::POSIX, HandleType::MACH,
355 };
356 
357 // Test that we can mix file descriptors and mach port handles.
TEST_F(EmbedderTest,MultiprocessMixMachAndFds)358 TEST_F(EmbedderTest, MultiprocessMixMachAndFds) {
359   const size_t kShmSize = 1234;
360   RunTestClient("MultiprocessMixMachAndFdsClient", [&](MojoHandle server_mp) {
361     // 1. Create fds or Mach objects and mojo handles from them.
362     MojoHandle platform_handles[base::size(kTestHandleTypes)];
363     for (size_t i = 0; i < base::size(kTestHandleTypes); i++) {
364       const auto type = kTestHandleTypes[i];
365       PlatformHandle scoped_handle;
366       if (type == HandleType::POSIX) {
367         // The easiest source of fds is opening /dev/null.
368         base::File file(base::FilePath("/dev/null"),
369                         base::File::FLAG_OPEN | base::File::FLAG_WRITE);
370         ASSERT_TRUE(file.IsValid());
371         scoped_handle = PlatformHandle(base::ScopedFD(file.TakePlatformFile()));
372         ASSERT_TRUE(scoped_handle.is_valid_fd());
373       } else {
374         auto shared_memory = base::UnsafeSharedMemoryRegion::Create(kShmSize);
375         ASSERT_TRUE(shared_memory.IsValid());
376         auto shm_handle =
377             base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
378                 std::move(shared_memory))
379                 .PassPlatformHandle();
380         scoped_handle = PlatformHandle(std::move(shm_handle));
381         ASSERT_TRUE(scoped_handle.is_valid_mach_port());
382       }
383       platform_handles[i] =
384           WrapPlatformHandle(std::move(scoped_handle)).release().value();
385     }
386 
387     // 2. Send all the handles to the child.
388     WriteMessageWithHandles(server_mp, "hello", platform_handles,
389                             base::size(kTestHandleTypes));
390 
391     // 3. Read a message from |server_mp|.
392     EXPECT_EQ("bye", ReadMessage(server_mp));
393   });
394 }
395 
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessMixMachAndFdsClient,EmbedderTest,client_mp)396 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MultiprocessMixMachAndFdsClient,
397                                   EmbedderTest,
398                                   client_mp) {
399   const int kNumHandles = base::size(kTestHandleTypes);
400   MojoHandle platform_handles[kNumHandles];
401 
402   // 1. Read from |client_mp|, which should have a message containing
403   // |kNumHandles| handles.
404   EXPECT_EQ("hello",
405             ReadMessageWithHandles(client_mp, platform_handles, kNumHandles));
406 
407   // 2. Extract each handle, and verify the type.
408   for (int i = 0; i < kNumHandles; i++) {
409     const auto type = kTestHandleTypes[i];
410     PlatformHandle scoped_handle =
411         UnwrapPlatformHandle(ScopedHandle(Handle(platform_handles[i])));
412     if (type == HandleType::POSIX) {
413       EXPECT_TRUE(scoped_handle.is_valid_fd());
414     } else {
415       EXPECT_TRUE(scoped_handle.is_valid_mach_port());
416     }
417   }
418 
419   // 3. Say bye!
420   WriteMessage(client_mp, "bye");
421 }
422 
423 #endif  // defined(OS_MACOSX)
424 
425 #endif  // !defined(OS_IOS)
426 
427 }  // namespace
428 }  // namespace core
429 }  // namespace mojo
430