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