1 // Copyright 2015 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 <string.h>
6
7 #include <string>
8 #include <utility>
9
10 #include "base/logging.h"
11 #include "base/memory/shared_memory.h"
12 #include "base/strings/string_piece.h"
13 #include "build/build_config.h"
14 #include "mojo/core/core.h"
15 #include "mojo/core/shared_buffer_dispatcher.h"
16 #include "mojo/core/test/mojo_test_base.h"
17 #include "mojo/public/c/system/types.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace mojo {
21 namespace core {
22 namespace {
23
24 using SharedBufferTest = test::MojoTestBase;
25
TEST_F(SharedBufferTest,CreateSharedBuffer)26 TEST_F(SharedBufferTest, CreateSharedBuffer) {
27 const std::string message = "hello";
28 MojoHandle h = CreateBuffer(message.size());
29 WriteToBuffer(h, 0, message);
30 ExpectBufferContents(h, 0, message);
31 }
32
TEST_F(SharedBufferTest,DuplicateSharedBuffer)33 TEST_F(SharedBufferTest, DuplicateSharedBuffer) {
34 const std::string message = "hello";
35 MojoHandle h = CreateBuffer(message.size());
36 WriteToBuffer(h, 0, message);
37
38 MojoHandle dupe = DuplicateBuffer(h, false);
39 ExpectBufferContents(dupe, 0, message);
40 }
41
TEST_F(SharedBufferTest,PassSharedBufferLocal)42 TEST_F(SharedBufferTest, PassSharedBufferLocal) {
43 const std::string message = "hello";
44 MojoHandle h = CreateBuffer(message.size());
45 WriteToBuffer(h, 0, message);
46
47 MojoHandle dupe = DuplicateBuffer(h, false);
48 MojoHandle p0, p1;
49 CreateMessagePipe(&p0, &p1);
50
51 WriteMessageWithHandles(p0, "...", &dupe, 1);
52 EXPECT_EQ("...", ReadMessageWithHandles(p1, &dupe, 1));
53
54 ExpectBufferContents(dupe, 0, message);
55 }
56
57 #if !defined(OS_IOS)
58
59 // Reads a single message with a shared buffer handle, maps the buffer, copies
60 // the message contents into it, then exits.
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CopyToBufferClient,SharedBufferTest,h)61 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CopyToBufferClient, SharedBufferTest, h) {
62 MojoHandle b;
63 std::string message = ReadMessageWithHandles(h, &b, 1);
64 WriteToBuffer(b, 0, message);
65
66 EXPECT_EQ("quit", ReadMessage(h));
67 }
68
TEST_F(SharedBufferTest,PassSharedBufferCrossProcess)69 TEST_F(SharedBufferTest, PassSharedBufferCrossProcess) {
70 const std::string message = "hello";
71 MojoHandle b = CreateBuffer(message.size());
72
73 RunTestClient("CopyToBufferClient", [&](MojoHandle h) {
74 MojoHandle dupe = DuplicateBuffer(b, false);
75 WriteMessageWithHandles(h, message, &dupe, 1);
76 WriteMessage(h, "quit");
77 });
78
79 ExpectBufferContents(b, 0, message);
80 }
81
82 // Creates a new buffer, maps it, writes a message contents to it, unmaps it,
83 // and finally passes it back to the parent.
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateBufferClient,SharedBufferTest,h)84 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateBufferClient, SharedBufferTest, h) {
85 std::string message = ReadMessage(h);
86 MojoHandle b = CreateBuffer(message.size());
87 WriteToBuffer(b, 0, message);
88 WriteMessageWithHandles(h, "have a buffer", &b, 1);
89
90 EXPECT_EQ("quit", ReadMessage(h));
91 }
92
TEST_F(SharedBufferTest,PassSharedBufferFromChild)93 TEST_F(SharedBufferTest, PassSharedBufferFromChild) {
94 const std::string message = "hello";
95 MojoHandle b;
96 RunTestClient("CreateBufferClient", [&](MojoHandle h) {
97 WriteMessage(h, message);
98 ReadMessageWithHandles(h, &b, 1);
99 WriteMessage(h, "quit");
100 });
101
102 ExpectBufferContents(b, 0, message);
103 }
104
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndPassBuffer,SharedBufferTest,h)105 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndPassBuffer, SharedBufferTest, h) {
106 // Receive a pipe handle over the primordial pipe. This will be connected to
107 // another child process.
108 MojoHandle other_child;
109 std::string message = ReadMessageWithHandles(h, &other_child, 1);
110
111 // Create a new shared buffer.
112 MojoHandle b = CreateBuffer(message.size());
113
114 // Send a copy of the buffer to the parent and the other child.
115 MojoHandle dupe = DuplicateBuffer(b, false);
116 WriteMessageWithHandles(h, "", &b, 1);
117 WriteMessageWithHandles(other_child, "", &dupe, 1);
118
119 EXPECT_EQ("quit", ReadMessage(h));
120 }
121
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceiveAndEditBuffer,SharedBufferTest,h)122 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceiveAndEditBuffer, SharedBufferTest, h) {
123 // Receive a pipe handle over the primordial pipe. This will be connected to
124 // another child process (running CreateAndPassBuffer).
125 MojoHandle other_child;
126 std::string message = ReadMessageWithHandles(h, &other_child, 1);
127
128 // Receive a shared buffer from the other child.
129 MojoHandle b;
130 ReadMessageWithHandles(other_child, &b, 1);
131
132 // Write the message from the parent into the buffer and exit.
133 WriteToBuffer(b, 0, message);
134 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
135 EXPECT_EQ("quit", ReadMessage(h));
136 }
137
TEST_F(SharedBufferTest,PassSharedBufferFromChildToChild)138 TEST_F(SharedBufferTest, PassSharedBufferFromChildToChild) {
139 const std::string message = "hello";
140 MojoHandle p0, p1;
141 CreateMessagePipe(&p0, &p1);
142
143 MojoHandle b;
144 RunTestClient("CreateAndPassBuffer", [&](MojoHandle h0) {
145 RunTestClient("ReceiveAndEditBuffer", [&](MojoHandle h1) {
146 // Send one end of the pipe to each child. The first child will create
147 // and pass a buffer to the second child and back to us. The second child
148 // will write our message into the buffer.
149 WriteMessageWithHandles(h0, message, &p0, 1);
150 WriteMessageWithHandles(h1, message, &p1, 1);
151
152 // Receive the buffer back from the first child.
153 ReadMessageWithHandles(h0, &b, 1);
154
155 WriteMessage(h1, "quit");
156 });
157 WriteMessage(h0, "quit");
158 });
159
160 // The second child should have written this message.
161 ExpectBufferContents(b, 0, message);
162 }
163
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndPassBufferParent,SharedBufferTest,parent)164 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndPassBufferParent,
165 SharedBufferTest,
166 parent) {
167 RunTestClient("CreateAndPassBuffer", [&](MojoHandle child) {
168 // Read a pipe from the parent and forward it to our child.
169 MojoHandle pipe;
170 std::string message = ReadMessageWithHandles(parent, &pipe, 1);
171
172 WriteMessageWithHandles(child, message, &pipe, 1);
173
174 // Read a buffer handle from the child and pass it back to the parent.
175 MojoHandle buffer;
176 EXPECT_EQ("", ReadMessageWithHandles(child, &buffer, 1));
177 WriteMessageWithHandles(parent, "", &buffer, 1);
178
179 EXPECT_EQ("quit", ReadMessage(parent));
180 WriteMessage(child, "quit");
181 });
182 }
183
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceiveAndEditBufferParent,SharedBufferTest,parent)184 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceiveAndEditBufferParent,
185 SharedBufferTest,
186 parent) {
187 RunTestClient("ReceiveAndEditBuffer", [&](MojoHandle child) {
188 // Read a pipe from the parent and forward it to our child.
189 MojoHandle pipe;
190 std::string message = ReadMessageWithHandles(parent, &pipe, 1);
191 WriteMessageWithHandles(child, message, &pipe, 1);
192
193 EXPECT_EQ("quit", ReadMessage(parent));
194 WriteMessage(child, "quit");
195 });
196 }
197
198 #if defined(OS_ANDROID) || defined(OS_MACOSX)
199 // Android multi-process tests are not executing the new process. This is flaky.
200 // Passing shared memory handles between cousins is not currently supported on
201 // OSX.
202 #define MAYBE_PassHandleBetweenCousins DISABLED_PassHandleBetweenCousins
203 #else
204 #define MAYBE_PassHandleBetweenCousins PassHandleBetweenCousins
205 #endif
TEST_F(SharedBufferTest,MAYBE_PassHandleBetweenCousins)206 TEST_F(SharedBufferTest, MAYBE_PassHandleBetweenCousins) {
207 const std::string message = "hello";
208 MojoHandle p0, p1;
209 CreateMessagePipe(&p0, &p1);
210
211 // Spawn two children who will each spawn their own child. Make sure the
212 // grandchildren (cousins to each other) can pass platform handles.
213 MojoHandle b;
214 RunTestClient("CreateAndPassBufferParent", [&](MojoHandle child1) {
215 RunTestClient("ReceiveAndEditBufferParent", [&](MojoHandle child2) {
216 MojoHandle pipe[2];
217 CreateMessagePipe(&pipe[0], &pipe[1]);
218
219 WriteMessageWithHandles(child1, message, &pipe[0], 1);
220 WriteMessageWithHandles(child2, message, &pipe[1], 1);
221
222 // Receive the buffer back from the first child.
223 ReadMessageWithHandles(child1, &b, 1);
224
225 WriteMessage(child2, "quit");
226 });
227 WriteMessage(child1, "quit");
228 });
229
230 // The second grandchild should have written this message.
231 ExpectBufferContents(b, 0, message);
232 }
233
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadAndMapWriteSharedBuffer,SharedBufferTest,h)234 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadAndMapWriteSharedBuffer,
235 SharedBufferTest,
236 h) {
237 // Receive the shared buffer.
238 MojoHandle b;
239 EXPECT_EQ("hello", ReadMessageWithHandles(h, &b, 1));
240
241 // Read from the bufer.
242 ExpectBufferContents(b, 0, "hello");
243
244 // Extract the shared memory handle and verify that it is read-only.
245 auto* dispatcher =
246 static_cast<SharedBufferDispatcher*>(Core::Get()->GetDispatcher(b).get());
247 base::subtle::PlatformSharedMemoryRegion& region =
248 dispatcher->GetRegionForTesting();
249 EXPECT_EQ(region.GetMode(),
250 base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly);
251
252 EXPECT_EQ("quit", ReadMessage(h));
253 WriteMessage(h, "ok");
254 }
255
256 #if defined(OS_ANDROID)
257 // Android multi-process tests are not executing the new process. This is flaky.
258 #define MAYBE_CreateAndPassReadOnlyBuffer DISABLED_CreateAndPassReadOnlyBuffer
259 #else
260 #define MAYBE_CreateAndPassReadOnlyBuffer CreateAndPassReadOnlyBuffer
261 #endif
TEST_F(SharedBufferTest,MAYBE_CreateAndPassReadOnlyBuffer)262 TEST_F(SharedBufferTest, MAYBE_CreateAndPassReadOnlyBuffer) {
263 RunTestClient("ReadAndMapWriteSharedBuffer", [&](MojoHandle h) {
264 // Create a new shared buffer.
265 MojoHandle b = CreateBuffer(1234);
266 WriteToBuffer(b, 0, "hello");
267
268 // Send a read-only copy of the buffer to the child.
269 MojoHandle dupe = DuplicateBuffer(b, true /* read_only */);
270 WriteMessageWithHandles(h, "hello", &dupe, 1);
271
272 WriteMessage(h, "quit");
273 EXPECT_EQ("ok", ReadMessage(h));
274 });
275 }
276
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndPassReadOnlyBuffer,SharedBufferTest,h)277 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndPassReadOnlyBuffer,
278 SharedBufferTest,
279 h) {
280 // Create a new shared buffer.
281 MojoHandle b = CreateBuffer(1234);
282 WriteToBuffer(b, 0, "hello");
283
284 // Send a read-only copy of the buffer to the parent.
285 MojoHandle dupe = DuplicateBuffer(b, true /* read_only */);
286 WriteMessageWithHandles(h, "", &dupe, 1);
287
288 EXPECT_EQ("quit", ReadMessage(h));
289 WriteMessage(h, "ok");
290 }
291
292 #if defined(OS_ANDROID)
293 // Android multi-process tests are not executing the new process. This is flaky.
294 #define MAYBE_CreateAndPassFromChildReadOnlyBuffer \
295 DISABLED_CreateAndPassFromChildReadOnlyBuffer
296 #else
297 #define MAYBE_CreateAndPassFromChildReadOnlyBuffer \
298 CreateAndPassFromChildReadOnlyBuffer
299 #endif
TEST_F(SharedBufferTest,MAYBE_CreateAndPassFromChildReadOnlyBuffer)300 TEST_F(SharedBufferTest, MAYBE_CreateAndPassFromChildReadOnlyBuffer) {
301 RunTestClient("CreateAndPassReadOnlyBuffer", [&](MojoHandle h) {
302 MojoHandle b;
303 EXPECT_EQ("", ReadMessageWithHandles(h, &b, 1));
304 ExpectBufferContents(b, 0, "hello");
305
306 // Extract the shared memory handle and verify that it is read-only.
307 auto* dispatcher = static_cast<SharedBufferDispatcher*>(
308 Core::Get()->GetDispatcher(b).get());
309 base::subtle::PlatformSharedMemoryRegion& region =
310 dispatcher->GetRegionForTesting();
311 EXPECT_EQ(region.GetMode(),
312 base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly);
313
314 WriteMessage(h, "quit");
315 EXPECT_EQ("ok", ReadMessage(h));
316 });
317 }
318
319 #endif // !defined(OS_IOS)
320
321 } // namespace
322 } // namespace core
323 } // namespace mojo
324