• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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 <cstdint>
6 #include <string>
7 
8 #include "base/base_paths.h"
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/command_line.h"
12 #include "base/files/file_path.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/optional.h"
16 #include "base/path_service.h"
17 #include "base/run_loop.h"
18 #include "base/synchronization/lock.h"
19 #include "base/test/multiprocess_test.h"
20 #include "base/test/scoped_task_environment.h"
21 #include "base/threading/sequenced_task_runner_handle.h"
22 #include "build/build_config.h"
23 #include "mojo/core/test/mojo_test_base.h"
24 #include "mojo/public/c/system/invitation.h"
25 #include "mojo/public/cpp/platform/named_platform_channel.h"
26 #include "mojo/public/cpp/platform/platform_channel.h"
27 #include "mojo/public/cpp/system/platform_handle.h"
28 
29 namespace mojo {
30 namespace core {
31 namespace {
32 
33 enum class TransportType {
34   kChannel,
35   kChannelServer,
36 };
37 
38 const char kSecondaryChannelHandleSwitch[] = "test-secondary-channel-handle";
39 
40 class InvitationTest : public test::MojoTestBase {
41  public:
42   InvitationTest() = default;
43   ~InvitationTest() override = default;
44 
45  protected:
46   static base::Process LaunchChildTestClient(
47       const std::string& test_client_name,
48       MojoHandle* primordial_pipes,
49       size_t num_primordial_pipes,
50       TransportType transport_type,
51       MojoSendInvitationFlags send_flags,
52       MojoProcessErrorHandler error_handler = nullptr,
53       uintptr_t error_handler_context = 0,
54       base::CommandLine* custom_command_line = nullptr,
55       base::LaunchOptions* custom_launch_options = nullptr);
56 
57   static void SendInvitationToClient(
58       PlatformHandle endpoint_handle,
59       base::ProcessHandle process,
60       MojoHandle* primordial_pipes,
61       size_t num_primordial_pipes,
62       TransportType transport_type,
63       MojoSendInvitationFlags flags,
64       MojoProcessErrorHandler error_handler,
65       uintptr_t error_handler_context,
66       base::StringPiece isolated_invitation_name);
67 
68  private:
69   base::test::ScopedTaskEnvironment task_environment_;
70 
71   DISALLOW_COPY_AND_ASSIGN(InvitationTest);
72 };
73 
PrepareToPassRemoteEndpoint(PlatformChannel * channel,base::LaunchOptions * options,base::CommandLine * command_line,base::StringPiece switch_name={})74 void PrepareToPassRemoteEndpoint(PlatformChannel* channel,
75                                  base::LaunchOptions* options,
76                                  base::CommandLine* command_line,
77                                  base::StringPiece switch_name = {}) {
78   std::string value;
79 #if defined(OS_FUCHSIA)
80   channel->PrepareToPassRemoteEndpoint(&options->handles_to_transfer, &value);
81 #elif defined(OS_POSIX)
82   channel->PrepareToPassRemoteEndpoint(&options->fds_to_remap, &value);
83 #elif defined(OS_WIN)
84   channel->PrepareToPassRemoteEndpoint(&options->handles_to_inherit, &value);
85 #else
86 #error "Platform not yet supported."
87 #endif
88 
89   if (switch_name.empty())
90     switch_name = PlatformChannel::kHandleSwitch;
91   command_line->AppendSwitchASCII(switch_name.as_string(), value);
92 }
93 
TEST_F(InvitationTest,Create)94 TEST_F(InvitationTest, Create) {
95   MojoHandle invitation;
96   EXPECT_EQ(MOJO_RESULT_OK, MojoCreateInvitation(nullptr, &invitation));
97   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(invitation));
98 
99   MojoCreateInvitationOptions options;
100   options.struct_size = sizeof(options);
101   options.flags = MOJO_CREATE_INVITATION_FLAG_NONE;
102   EXPECT_EQ(MOJO_RESULT_OK, MojoCreateInvitation(&options, &invitation));
103   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(invitation));
104 }
105 
TEST_F(InvitationTest,InvalidArguments)106 TEST_F(InvitationTest, InvalidArguments) {
107   MojoHandle invitation;
108   MojoCreateInvitationOptions invalid_create_options;
109   invalid_create_options.struct_size = 0;
110   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
111             MojoCreateInvitation(&invalid_create_options, &invitation));
112   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
113             MojoCreateInvitation(nullptr, nullptr));
114 
115   // We need a valid invitation handle to exercise some of the other invalid
116   // argument cases below.
117   EXPECT_EQ(MOJO_RESULT_OK, MojoCreateInvitation(nullptr, &invitation));
118 
119   MojoHandle pipe;
120   MojoAttachMessagePipeToInvitationOptions invalid_attach_options;
121   invalid_attach_options.struct_size = 0;
122   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
123             MojoAttachMessagePipeToInvitation(MOJO_HANDLE_INVALID, "x", 1,
124                                               nullptr, &pipe));
125   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
126             MojoAttachMessagePipeToInvitation(invitation, "x", 1,
127                                               &invalid_attach_options, &pipe));
128   EXPECT_EQ(
129       MOJO_RESULT_INVALID_ARGUMENT,
130       MojoAttachMessagePipeToInvitation(invitation, "x", 1, nullptr, nullptr));
131 
132   MojoExtractMessagePipeFromInvitationOptions invalid_extract_options;
133   invalid_extract_options.struct_size = 0;
134   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
135             MojoExtractMessagePipeFromInvitation(MOJO_HANDLE_INVALID, "x", 1,
136                                                  nullptr, &pipe));
137   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
138             MojoExtractMessagePipeFromInvitation(
139                 invitation, "x", 1, &invalid_extract_options, &pipe));
140   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
141             MojoExtractMessagePipeFromInvitation(invitation, "x", 1, nullptr,
142                                                  nullptr));
143 
144   PlatformChannel channel;
145   MojoPlatformHandle endpoint_handle;
146   endpoint_handle.struct_size = sizeof(endpoint_handle);
147   PlatformHandle::ToMojoPlatformHandle(
148       channel.TakeLocalEndpoint().TakePlatformHandle(), &endpoint_handle);
149   ASSERT_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
150 
151   MojoInvitationTransportEndpoint valid_endpoint;
152   valid_endpoint.struct_size = sizeof(valid_endpoint);
153   valid_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL;
154   valid_endpoint.num_platform_handles = 1;
155   valid_endpoint.platform_handles = &endpoint_handle;
156 
157   MojoSendInvitationOptions invalid_send_options;
158   invalid_send_options.struct_size = 0;
159   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
160             MojoSendInvitation(MOJO_HANDLE_INVALID, nullptr, &valid_endpoint,
161                                nullptr, 0, nullptr));
162   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
163             MojoSendInvitation(invitation, nullptr, &valid_endpoint, nullptr, 0,
164                                &invalid_send_options));
165 
166   MojoInvitationTransportEndpoint invalid_endpoint;
167   invalid_endpoint.struct_size = 0;
168   invalid_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL;
169   invalid_endpoint.num_platform_handles = 1;
170   invalid_endpoint.platform_handles = &endpoint_handle;
171   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
172             MojoSendInvitation(invitation, nullptr, &invalid_endpoint, nullptr,
173                                0, nullptr));
174 
175   invalid_endpoint.struct_size = sizeof(invalid_endpoint);
176   invalid_endpoint.num_platform_handles = 0;
177   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
178             MojoSendInvitation(invitation, nullptr, &invalid_endpoint, nullptr,
179                                0, nullptr));
180 
181   MojoPlatformHandle invalid_platform_handle;
182   invalid_platform_handle.struct_size = 0;
183   invalid_endpoint.num_platform_handles = 1;
184   invalid_endpoint.platform_handles = &invalid_platform_handle;
185   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
186             MojoSendInvitation(invitation, nullptr, &invalid_endpoint, nullptr,
187                                0, nullptr));
188   invalid_platform_handle.struct_size = sizeof(invalid_platform_handle);
189   invalid_platform_handle.type = MOJO_PLATFORM_HANDLE_TYPE_INVALID;
190   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
191             MojoSendInvitation(invitation, nullptr, &invalid_endpoint, nullptr,
192                                0, nullptr));
193 
194   invalid_endpoint.num_platform_handles = 1;
195   invalid_endpoint.platform_handles = nullptr;
196   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
197             MojoSendInvitation(invitation, nullptr, &invalid_endpoint, nullptr,
198                                0, nullptr));
199 
200   MojoHandle accepted_invitation;
201   MojoAcceptInvitationOptions invalid_accept_options;
202   invalid_accept_options.struct_size = 0;
203   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
204             MojoAcceptInvitation(nullptr, nullptr, &accepted_invitation));
205   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
206             MojoAcceptInvitation(&valid_endpoint, &invalid_accept_options,
207                                  &accepted_invitation));
208   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
209             MojoAcceptInvitation(&valid_endpoint, nullptr, nullptr));
210 
211   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(invitation));
212 }
213 
TEST_F(InvitationTest,AttachAndExtractLocally)214 TEST_F(InvitationTest, AttachAndExtractLocally) {
215   MojoHandle invitation;
216   EXPECT_EQ(MOJO_RESULT_OK, MojoCreateInvitation(nullptr, &invitation));
217 
218   MojoHandle pipe0 = MOJO_HANDLE_INVALID;
219   EXPECT_EQ(MOJO_RESULT_OK, MojoAttachMessagePipeToInvitation(
220                                 invitation, "x", 1, nullptr, &pipe0));
221   EXPECT_NE(MOJO_HANDLE_INVALID, pipe0);
222 
223   MojoHandle pipe1 = MOJO_HANDLE_INVALID;
224   EXPECT_EQ(MOJO_RESULT_OK, MojoExtractMessagePipeFromInvitation(
225                                 invitation, "x", 1, nullptr, &pipe1));
226   EXPECT_NE(MOJO_HANDLE_INVALID, pipe1);
227 
228   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(invitation));
229 
230   // Should be able to communicate over the pipe.
231   const std::string kMessage = "RSVP LOL";
232   WriteMessage(pipe0, kMessage);
233   EXPECT_EQ(kMessage, ReadMessage(pipe1));
234 
235   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe0));
236   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe1));
237 }
238 
TEST_F(InvitationTest,ClosedInvitationClosesAttachments)239 TEST_F(InvitationTest, ClosedInvitationClosesAttachments) {
240   MojoHandle invitation;
241   EXPECT_EQ(MOJO_RESULT_OK, MojoCreateInvitation(nullptr, &invitation));
242 
243   MojoHandle pipe = MOJO_HANDLE_INVALID;
244   EXPECT_EQ(MOJO_RESULT_OK, MojoAttachMessagePipeToInvitation(
245                                 invitation, "x", 1, nullptr, &pipe));
246   EXPECT_NE(MOJO_HANDLE_INVALID, pipe);
247 
248   // Closing the invitation should close |pipe|'s peer.
249   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(invitation));
250 
251   EXPECT_EQ(MOJO_RESULT_OK,
252             WaitForSignals(pipe, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
253   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe));
254 }
255 
TEST_F(InvitationTest,AttachNameInUse)256 TEST_F(InvitationTest, AttachNameInUse) {
257   MojoHandle invitation;
258   EXPECT_EQ(MOJO_RESULT_OK, MojoCreateInvitation(nullptr, &invitation));
259 
260   MojoHandle pipe0 = MOJO_HANDLE_INVALID;
261   EXPECT_EQ(MOJO_RESULT_OK, MojoAttachMessagePipeToInvitation(
262                                 invitation, "x", 1, nullptr, &pipe0));
263   EXPECT_NE(MOJO_HANDLE_INVALID, pipe0);
264 
265   MojoHandle pipe1 = MOJO_HANDLE_INVALID;
266   EXPECT_EQ(
267       MOJO_RESULT_ALREADY_EXISTS,
268       MojoAttachMessagePipeToInvitation(invitation, "x", 1, nullptr, &pipe1));
269   EXPECT_EQ(MOJO_HANDLE_INVALID, pipe1);
270   EXPECT_EQ(MOJO_RESULT_OK, MojoAttachMessagePipeToInvitation(
271                                 invitation, "y", 1, nullptr, &pipe1));
272   EXPECT_NE(MOJO_HANDLE_INVALID, pipe1);
273 
274   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(invitation));
275   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe0));
276   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe1));
277 }
278 
279 // static
LaunchChildTestClient(const std::string & test_client_name,MojoHandle * primordial_pipes,size_t num_primordial_pipes,TransportType transport_type,MojoSendInvitationFlags send_flags,MojoProcessErrorHandler error_handler,uintptr_t error_handler_context,base::CommandLine * custom_command_line,base::LaunchOptions * custom_launch_options)280 base::Process InvitationTest::LaunchChildTestClient(
281     const std::string& test_client_name,
282     MojoHandle* primordial_pipes,
283     size_t num_primordial_pipes,
284     TransportType transport_type,
285     MojoSendInvitationFlags send_flags,
286     MojoProcessErrorHandler error_handler,
287     uintptr_t error_handler_context,
288     base::CommandLine* custom_command_line,
289     base::LaunchOptions* custom_launch_options) {
290   base::CommandLine default_command_line =
291       base::GetMultiProcessTestChildBaseCommandLine();
292   base::CommandLine& command_line =
293       custom_command_line ? *custom_command_line : default_command_line;
294 
295   base::LaunchOptions default_launch_options;
296   base::LaunchOptions& launch_options =
297       custom_launch_options ? *custom_launch_options : default_launch_options;
298 #if defined(OS_WIN)
299   launch_options.start_hidden = true;
300 #endif
301 
302   base::Optional<PlatformChannel> channel;
303   base::Optional<NamedPlatformChannel> named_channel;
304   PlatformHandle local_endpoint_handle;
305   if (transport_type == TransportType::kChannel) {
306     channel.emplace();
307     PrepareToPassRemoteEndpoint(&channel.value(), &launch_options,
308                                 &command_line);
309     local_endpoint_handle = channel->TakeLocalEndpoint().TakePlatformHandle();
310   } else {
311 #if defined(OS_FUCHSIA)
312     NOTREACHED() << "Named pipe support does not exist for Mojo on Fuchsia.";
313 #else
314     NamedPlatformChannel::Options named_channel_options;
315 #if !defined(OS_WIN)
316     CHECK(base::PathService::Get(base::DIR_TEMP,
317                                  &named_channel_options.socket_dir));
318 #endif
319     named_channel.emplace(named_channel_options);
320     named_channel->PassServerNameOnCommandLine(&command_line);
321     local_endpoint_handle =
322         named_channel->TakeServerEndpoint().TakePlatformHandle();
323 #endif
324   }
325 
326   base::Process child_process = base::SpawnMultiProcessTestChild(
327       test_client_name, command_line, launch_options);
328   if (channel)
329     channel->RemoteProcessLaunchAttempted();
330 
331   SendInvitationToClient(std::move(local_endpoint_handle),
332                          child_process.Handle(), primordial_pipes,
333                          num_primordial_pipes, transport_type, send_flags,
334                          error_handler, error_handler_context, "");
335 
336   return child_process;
337 }
338 
339 // static
SendInvitationToClient(PlatformHandle endpoint_handle,base::ProcessHandle process,MojoHandle * primordial_pipes,size_t num_primordial_pipes,TransportType transport_type,MojoSendInvitationFlags flags,MojoProcessErrorHandler error_handler,uintptr_t error_handler_context,base::StringPiece isolated_invitation_name)340 void InvitationTest::SendInvitationToClient(
341     PlatformHandle endpoint_handle,
342     base::ProcessHandle process,
343     MojoHandle* primordial_pipes,
344     size_t num_primordial_pipes,
345     TransportType transport_type,
346     MojoSendInvitationFlags flags,
347     MojoProcessErrorHandler error_handler,
348     uintptr_t error_handler_context,
349     base::StringPiece isolated_invitation_name) {
350   MojoPlatformHandle handle;
351   PlatformHandle::ToMojoPlatformHandle(std::move(endpoint_handle), &handle);
352   CHECK_NE(handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
353 
354   MojoHandle invitation;
355   CHECK_EQ(MOJO_RESULT_OK, MojoCreateInvitation(nullptr, &invitation));
356   for (uint32_t name = 0; name < num_primordial_pipes; ++name) {
357     CHECK_EQ(MOJO_RESULT_OK,
358              MojoAttachMessagePipeToInvitation(invitation, &name, 4, nullptr,
359                                                &primordial_pipes[name]));
360   }
361 
362   MojoPlatformProcessHandle process_handle;
363   process_handle.struct_size = sizeof(process_handle);
364 #if defined(OS_WIN)
365   process_handle.value =
366       static_cast<uint64_t>(reinterpret_cast<uintptr_t>(process));
367 #else
368   process_handle.value = static_cast<uint64_t>(process);
369 #endif
370 
371   MojoInvitationTransportEndpoint transport_endpoint;
372   transport_endpoint.struct_size = sizeof(transport_endpoint);
373   if (transport_type == TransportType::kChannel)
374     transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL;
375   else
376     transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER;
377   transport_endpoint.num_platform_handles = 1;
378   transport_endpoint.platform_handles = &handle;
379 
380   MojoSendInvitationOptions options;
381   options.struct_size = sizeof(options);
382   options.flags = flags;
383   if (flags & MOJO_SEND_INVITATION_FLAG_ISOLATED) {
384     options.isolated_connection_name = isolated_invitation_name.data();
385     options.isolated_connection_name_length =
386         static_cast<uint32_t>(isolated_invitation_name.size());
387   }
388   CHECK_EQ(MOJO_RESULT_OK,
389            MojoSendInvitation(invitation, &process_handle, &transport_endpoint,
390                               error_handler, error_handler_context, &options));
391 }
392 
393 class TestClientBase : public InvitationTest {
394  public:
AcceptInvitation(MojoAcceptInvitationFlags flags,base::StringPiece switch_name={})395   static MojoHandle AcceptInvitation(MojoAcceptInvitationFlags flags,
396                                      base::StringPiece switch_name = {}) {
397     const auto& command_line = *base::CommandLine::ForCurrentProcess();
398     PlatformChannelEndpoint channel_endpoint =
399         NamedPlatformChannel::ConnectToServer(command_line);
400     if (!channel_endpoint.is_valid()) {
401       if (switch_name.empty()) {
402         channel_endpoint =
403             PlatformChannel::RecoverPassedEndpointFromCommandLine(command_line);
404       } else {
405         channel_endpoint = PlatformChannel::RecoverPassedEndpointFromString(
406             command_line.GetSwitchValueASCII(switch_name));
407       }
408     }
409     MojoPlatformHandle endpoint_handle;
410     PlatformHandle::ToMojoPlatformHandle(channel_endpoint.TakePlatformHandle(),
411                                          &endpoint_handle);
412     CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
413 
414     MojoInvitationTransportEndpoint transport_endpoint;
415     transport_endpoint.struct_size = sizeof(transport_endpoint);
416     transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL;
417     transport_endpoint.num_platform_handles = 1;
418     transport_endpoint.platform_handles = &endpoint_handle;
419 
420     MojoAcceptInvitationOptions options;
421     options.struct_size = sizeof(options);
422     options.flags = flags;
423     MojoHandle invitation;
424     CHECK_EQ(MOJO_RESULT_OK,
425              MojoAcceptInvitation(&transport_endpoint, &options, &invitation));
426     return invitation;
427   }
428 
429  private:
430   DISALLOW_COPY_AND_ASSIGN(TestClientBase);
431 };
432 
433 #define DEFINE_TEST_CLIENT(name)             \
434   class name##Impl : public TestClientBase { \
435    public:                                   \
436     static void Run();                       \
437   };                                         \
438   MULTIPROCESS_TEST_MAIN(name) {             \
439     name##Impl::Run();                       \
440     return 0;                                \
441   }                                          \
442   void name##Impl::Run()
443 
444 const std::string kTestMessage1 = "i am the pusher robot";
445 const std::string kTestMessage2 = "i push the messages down the pipe";
446 const std::string kTestMessage3 = "i am the shover robot";
447 const std::string kTestMessage4 = "i shove the messages down the pipe";
448 
TEST_F(InvitationTest,SendInvitation)449 TEST_F(InvitationTest, SendInvitation) {
450   MojoHandle primordial_pipe;
451   base::Process child_process = LaunchChildTestClient(
452       "SendInvitationClient", &primordial_pipe, 1, TransportType::kChannel,
453       MOJO_SEND_INVITATION_FLAG_NONE);
454 
455   WriteMessage(primordial_pipe, kTestMessage1);
456   EXPECT_EQ(MOJO_RESULT_OK,
457             WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_READABLE));
458   EXPECT_EQ(kTestMessage3, ReadMessage(primordial_pipe));
459   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(primordial_pipe));
460 
461   int wait_result = -1;
462   base::WaitForMultiprocessTestChildExit(
463       child_process, TestTimeouts::action_timeout(), &wait_result);
464   child_process.Close();
465   EXPECT_EQ(0, wait_result);
466 }
467 
DEFINE_TEST_CLIENT(SendInvitationClient)468 DEFINE_TEST_CLIENT(SendInvitationClient) {
469   MojoHandle primordial_pipe;
470   MojoHandle invitation = AcceptInvitation(MOJO_ACCEPT_INVITATION_FLAG_NONE);
471   const uint32_t pipe_name = 0;
472   ASSERT_EQ(MOJO_RESULT_OK,
473             MojoExtractMessagePipeFromInvitation(invitation, &pipe_name, 4,
474                                                  nullptr, &primordial_pipe));
475   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(invitation));
476 
477   WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_READABLE);
478   ASSERT_EQ(kTestMessage1, ReadMessage(primordial_pipe));
479   WriteMessage(primordial_pipe, kTestMessage3);
480   WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_PEER_CLOSED);
481 
482   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(primordial_pipe));
483 }
484 
TEST_F(InvitationTest,SendInvitationMultiplePipes)485 TEST_F(InvitationTest, SendInvitationMultiplePipes) {
486   MojoHandle pipes[2];
487   base::Process child_process = LaunchChildTestClient(
488       "SendInvitationMultiplePipesClient", pipes, 2, TransportType::kChannel,
489       MOJO_SEND_INVITATION_FLAG_NONE);
490 
491   WriteMessage(pipes[0], kTestMessage1);
492   WriteMessage(pipes[1], kTestMessage2);
493   EXPECT_EQ(MOJO_RESULT_OK,
494             WaitForSignals(pipes[0], MOJO_HANDLE_SIGNAL_READABLE));
495   EXPECT_EQ(MOJO_RESULT_OK,
496             WaitForSignals(pipes[1], MOJO_HANDLE_SIGNAL_READABLE));
497   EXPECT_EQ(kTestMessage3, ReadMessage(pipes[0]));
498   EXPECT_EQ(kTestMessage4, ReadMessage(pipes[1]));
499 
500   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(pipes[0]));
501   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(pipes[1]));
502 
503   int wait_result = -1;
504   base::WaitForMultiprocessTestChildExit(
505       child_process, TestTimeouts::action_timeout(), &wait_result);
506   child_process.Close();
507   EXPECT_EQ(0, wait_result);
508 }
509 
DEFINE_TEST_CLIENT(SendInvitationMultiplePipesClient)510 DEFINE_TEST_CLIENT(SendInvitationMultiplePipesClient) {
511   MojoHandle pipes[2];
512   MojoHandle invitation = AcceptInvitation(MOJO_ACCEPT_INVITATION_FLAG_NONE);
513   const uint32_t pipe_names[] = {0, 1};
514   ASSERT_EQ(MOJO_RESULT_OK,
515             MojoExtractMessagePipeFromInvitation(invitation, &pipe_names[0], 4,
516                                                  nullptr, &pipes[0]));
517   ASSERT_EQ(MOJO_RESULT_OK,
518             MojoExtractMessagePipeFromInvitation(invitation, &pipe_names[1], 4,
519                                                  nullptr, &pipes[1]));
520 
521   WaitForSignals(pipes[0], MOJO_HANDLE_SIGNAL_READABLE);
522   WaitForSignals(pipes[1], MOJO_HANDLE_SIGNAL_READABLE);
523   ASSERT_EQ(kTestMessage1, ReadMessage(pipes[0]));
524   ASSERT_EQ(kTestMessage2, ReadMessage(pipes[1]));
525   WriteMessage(pipes[0], kTestMessage3);
526   WriteMessage(pipes[1], kTestMessage4);
527   WaitForSignals(pipes[0], MOJO_HANDLE_SIGNAL_PEER_CLOSED);
528   WaitForSignals(pipes[1], MOJO_HANDLE_SIGNAL_PEER_CLOSED);
529 }
530 
531 #if !defined(OS_FUCHSIA)
TEST_F(InvitationTest,SendInvitationWithServer)532 TEST_F(InvitationTest, SendInvitationWithServer) {
533   MojoHandle primordial_pipe;
534   base::Process child_process = LaunchChildTestClient(
535       "SendInvitationWithServerClient", &primordial_pipe, 1,
536       TransportType::kChannelServer, MOJO_SEND_INVITATION_FLAG_NONE);
537 
538   WriteMessage(primordial_pipe, kTestMessage1);
539   EXPECT_EQ(MOJO_RESULT_OK,
540             WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_READABLE));
541   EXPECT_EQ(kTestMessage3, ReadMessage(primordial_pipe));
542   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(primordial_pipe));
543 
544   int wait_result = -1;
545   base::WaitForMultiprocessTestChildExit(
546       child_process, TestTimeouts::action_timeout(), &wait_result);
547   child_process.Close();
548   EXPECT_EQ(0, wait_result);
549 }
550 
DEFINE_TEST_CLIENT(SendInvitationWithServerClient)551 DEFINE_TEST_CLIENT(SendInvitationWithServerClient) {
552   MojoHandle primordial_pipe;
553   MojoHandle invitation = AcceptInvitation(MOJO_ACCEPT_INVITATION_FLAG_NONE);
554   const uint32_t pipe_name = 0;
555   ASSERT_EQ(MOJO_RESULT_OK,
556             MojoExtractMessagePipeFromInvitation(invitation, &pipe_name, 4,
557                                                  nullptr, &primordial_pipe));
558   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(invitation));
559 
560   WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_READABLE);
561   ASSERT_EQ(kTestMessage1, ReadMessage(primordial_pipe));
562   WriteMessage(primordial_pipe, kTestMessage3);
563   WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_PEER_CLOSED);
564 
565   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(primordial_pipe));
566 }
567 #endif  // !defined(OS_FUCHSIA)
568 
569 const char kErrorMessage[] = "ur bad :(";
570 const char kDisconnectMessage[] = "go away plz";
571 
572 class RemoteProcessState {
573  public:
RemoteProcessState()574   RemoteProcessState()
575       : callback_task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
576   ~RemoteProcessState() = default;
577 
disconnected()578   bool disconnected() {
579     base::AutoLock lock(lock_);
580     return disconnected_;
581   }
582 
set_error_callback(base::RepeatingClosure callback)583   void set_error_callback(base::RepeatingClosure callback) {
584     error_callback_ = std::move(callback);
585   }
586 
set_expected_error_message(const std::string & expected)587   void set_expected_error_message(const std::string& expected) {
588     expected_error_message_ = expected;
589   }
590 
NotifyError(const std::string & error_message,bool disconnected)591   void NotifyError(const std::string& error_message, bool disconnected) {
592     base::AutoLock lock(lock_);
593     CHECK(!disconnected_);
594     EXPECT_NE(error_message.find(expected_error_message_), std::string::npos);
595     disconnected_ = disconnected;
596     ++call_count_;
597     if (error_callback_)
598       callback_task_runner_->PostTask(FROM_HERE, error_callback_);
599   }
600 
601  private:
602   const scoped_refptr<base::SequencedTaskRunner> callback_task_runner_;
603 
604   base::Lock lock_;
605   int call_count_ = 0;
606   bool disconnected_ = false;
607   std::string expected_error_message_;
608   base::RepeatingClosure error_callback_;
609 
610   DISALLOW_COPY_AND_ASSIGN(RemoteProcessState);
611 };
612 
TestProcessErrorHandler(uintptr_t context,const MojoProcessErrorDetails * details)613 void TestProcessErrorHandler(uintptr_t context,
614                              const MojoProcessErrorDetails* details) {
615   auto* state = reinterpret_cast<RemoteProcessState*>(context);
616   std::string error_message;
617   if (details->error_message) {
618     error_message =
619         std::string(details->error_message, details->error_message_length - 1);
620   }
621   state->NotifyError(error_message,
622                      details->flags & MOJO_PROCESS_ERROR_FLAG_DISCONNECTED);
623 }
624 
TEST_F(InvitationTest,ProcessErrors)625 TEST_F(InvitationTest, ProcessErrors) {
626   RemoteProcessState process_state;
627   MojoHandle pipe;
628   base::Process child_process = LaunchChildTestClient(
629       "ProcessErrorsClient", &pipe, 1, TransportType::kChannel,
630       MOJO_SEND_INVITATION_FLAG_NONE, &TestProcessErrorHandler,
631       reinterpret_cast<uintptr_t>(&process_state));
632 
633   MojoMessageHandle message;
634   WaitForSignals(pipe, MOJO_HANDLE_SIGNAL_READABLE);
635   EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(pipe, nullptr, &message));
636 
637   base::RunLoop error_loop;
638   process_state.set_error_callback(error_loop.QuitClosure());
639 
640   // Report this message as "bad". This should cause the error handler to be
641   // invoked and the RunLoop to be quit.
642   process_state.set_expected_error_message(kErrorMessage);
643   EXPECT_EQ(MOJO_RESULT_OK,
644             MojoNotifyBadMessage(message, kErrorMessage, sizeof(kErrorMessage),
645                                  nullptr));
646   error_loop.Run();
647   EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message));
648 
649   // Now tell the child it can exit, and wait for it to disconnect.
650   base::RunLoop disconnect_loop;
651   process_state.set_error_callback(disconnect_loop.QuitClosure());
652   process_state.set_expected_error_message(std::string());
653   WriteMessage(pipe, kDisconnectMessage);
654   disconnect_loop.Run();
655 
656   EXPECT_TRUE(process_state.disconnected());
657 
658   int wait_result = -1;
659   base::WaitForMultiprocessTestChildExit(
660       child_process, TestTimeouts::action_timeout(), &wait_result);
661   child_process.Close();
662   EXPECT_EQ(0, wait_result);
663 }
664 
DEFINE_TEST_CLIENT(ProcessErrorsClient)665 DEFINE_TEST_CLIENT(ProcessErrorsClient) {
666   MojoHandle pipe;
667   MojoHandle invitation = AcceptInvitation(MOJO_ACCEPT_INVITATION_FLAG_NONE);
668   const uint32_t pipe_name = 0;
669   ASSERT_EQ(MOJO_RESULT_OK, MojoExtractMessagePipeFromInvitation(
670                                 invitation, &pipe_name, 4, nullptr, &pipe));
671   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(invitation));
672 
673   // Send a message. Contents are irrelevant, the test process is just going to
674   // flag it as a bad.
675   WriteMessage(pipe, "doesn't matter");
676 
677   // Wait for our goodbye before exiting.
678   WaitForSignals(pipe, MOJO_HANDLE_SIGNAL_READABLE);
679   EXPECT_EQ(kDisconnectMessage, ReadMessage(pipe));
680 }
681 
TEST_F(InvitationTest,SendIsolatedInvitation)682 TEST_F(InvitationTest, SendIsolatedInvitation) {
683   MojoHandle primordial_pipe;
684   base::Process child_process = LaunchChildTestClient(
685       "SendIsolatedInvitationClient", &primordial_pipe, 1,
686       TransportType::kChannel, MOJO_SEND_INVITATION_FLAG_ISOLATED);
687 
688   WriteMessage(primordial_pipe, kTestMessage1);
689   EXPECT_EQ(MOJO_RESULT_OK,
690             WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_READABLE));
691   EXPECT_EQ(kTestMessage3, ReadMessage(primordial_pipe));
692   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(primordial_pipe));
693 
694   int wait_result = -1;
695   base::WaitForMultiprocessTestChildExit(
696       child_process, TestTimeouts::action_timeout(), &wait_result);
697   child_process.Close();
698   EXPECT_EQ(0, wait_result);
699 }
700 
DEFINE_TEST_CLIENT(SendIsolatedInvitationClient)701 DEFINE_TEST_CLIENT(SendIsolatedInvitationClient) {
702   MojoHandle primordial_pipe;
703   MojoHandle invitation =
704       AcceptInvitation(MOJO_ACCEPT_INVITATION_FLAG_ISOLATED);
705   const uint32_t pipe_name = 0;
706   ASSERT_EQ(MOJO_RESULT_OK,
707             MojoExtractMessagePipeFromInvitation(invitation, &pipe_name, 4,
708                                                  nullptr, &primordial_pipe));
709   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(invitation));
710 
711   WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_READABLE);
712   ASSERT_EQ(kTestMessage1, ReadMessage(primordial_pipe));
713   WriteMessage(primordial_pipe, kTestMessage3);
714   WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_PEER_CLOSED);
715 
716   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(primordial_pipe));
717 }
718 
TEST_F(InvitationTest,SendMultipleIsolatedInvitations)719 TEST_F(InvitationTest, SendMultipleIsolatedInvitations) {
720   // We send a secondary transport to the client process so we can send a second
721   // isolated invitation.
722   base::CommandLine command_line =
723       base::GetMultiProcessTestChildBaseCommandLine();
724   PlatformChannel secondary_transport;
725   base::LaunchOptions options;
726   PrepareToPassRemoteEndpoint(&secondary_transport, &options, &command_line,
727                               kSecondaryChannelHandleSwitch);
728 
729   MojoHandle primordial_pipe;
730   base::Process child_process = LaunchChildTestClient(
731       "SendMultipleIsolatedInvitationsClient", &primordial_pipe, 1,
732       TransportType::kChannel, MOJO_SEND_INVITATION_FLAG_ISOLATED, nullptr, 0,
733       &command_line, &options);
734   secondary_transport.RemoteProcessLaunchAttempted();
735 
736   WriteMessage(primordial_pipe, kTestMessage1);
737   EXPECT_EQ(MOJO_RESULT_OK,
738             WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_READABLE));
739   EXPECT_EQ(kTestMessage3, ReadMessage(primordial_pipe));
740 
741   // Send another invitation over our seconary pipe. This should trample the
742   // original connection, breaking the first pipe.
743   MojoHandle new_pipe;
744   SendInvitationToClient(
745       secondary_transport.TakeLocalEndpoint().TakePlatformHandle(),
746       child_process.Handle(), &new_pipe, 1, TransportType::kChannel,
747       MOJO_SEND_INVITATION_FLAG_ISOLATED, nullptr, 0, "");
748   WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_PEER_CLOSED);
749   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(primordial_pipe));
750 
751   // And the new pipe should be working.
752   WriteMessage(new_pipe, kTestMessage1);
753   EXPECT_EQ(MOJO_RESULT_OK,
754             WaitForSignals(new_pipe, MOJO_HANDLE_SIGNAL_READABLE));
755   EXPECT_EQ(kTestMessage3, ReadMessage(new_pipe));
756   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(new_pipe));
757 
758   int wait_result = -1;
759   base::WaitForMultiprocessTestChildExit(
760       child_process, TestTimeouts::action_timeout(), &wait_result);
761   child_process.Close();
762   EXPECT_EQ(0, wait_result);
763 }
764 
DEFINE_TEST_CLIENT(SendMultipleIsolatedInvitationsClient)765 DEFINE_TEST_CLIENT(SendMultipleIsolatedInvitationsClient) {
766   MojoHandle primordial_pipe;
767   MojoHandle invitation =
768       AcceptInvitation(MOJO_ACCEPT_INVITATION_FLAG_ISOLATED);
769   const uint32_t pipe_name = 0;
770   ASSERT_EQ(MOJO_RESULT_OK,
771             MojoExtractMessagePipeFromInvitation(invitation, &pipe_name, 4,
772                                                  nullptr, &primordial_pipe));
773   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(invitation));
774 
775   WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_READABLE);
776   ASSERT_EQ(kTestMessage1, ReadMessage(primordial_pipe));
777   WriteMessage(primordial_pipe, kTestMessage3);
778 
779   // The above pipe should get closed once we accept a new invitation.
780   invitation = AcceptInvitation(MOJO_ACCEPT_INVITATION_FLAG_ISOLATED,
781                                 kSecondaryChannelHandleSwitch);
782   WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_PEER_CLOSED);
783   primordial_pipe = MOJO_HANDLE_INVALID;
784   ASSERT_EQ(MOJO_RESULT_OK,
785             MojoExtractMessagePipeFromInvitation(invitation, &pipe_name, 4,
786                                                  nullptr, &primordial_pipe));
787   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(invitation));
788   WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_READABLE);
789   ASSERT_EQ(kTestMessage1, ReadMessage(primordial_pipe));
790   WriteMessage(primordial_pipe, kTestMessage3);
791   WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_PEER_CLOSED);
792 
793   ASSERT_EQ(MOJO_RESULT_OK, MojoClose(primordial_pipe));
794 }
795 
TEST_F(InvitationTest,SendIsolatedInvitationWithDuplicateName)796 TEST_F(InvitationTest, SendIsolatedInvitationWithDuplicateName) {
797   PlatformChannel channel1;
798   PlatformChannel channel2;
799   MojoHandle pipe0, pipe1;
800   const char kConnectionName[] = "there can be only one!";
801   SendInvitationToClient(
802       channel1.TakeLocalEndpoint().TakePlatformHandle(),
803       base::kNullProcessHandle, &pipe0, 1, TransportType::kChannel,
804       MOJO_SEND_INVITATION_FLAG_ISOLATED, nullptr, 0, kConnectionName);
805 
806   // Send another invitation with the same connection name. |pipe0| should be
807   // disconnected as the first invitation's connection is torn down.
808   SendInvitationToClient(
809       channel2.TakeLocalEndpoint().TakePlatformHandle(),
810       base::kNullProcessHandle, &pipe1, 1, TransportType::kChannel,
811       MOJO_SEND_INVITATION_FLAG_ISOLATED, nullptr, 0, kConnectionName);
812 
813   WaitForSignals(pipe0, MOJO_HANDLE_SIGNAL_PEER_CLOSED);
814 }
815 
TEST_F(InvitationTest,SendIsolatedInvitationToSelf)816 TEST_F(InvitationTest, SendIsolatedInvitationToSelf) {
817   PlatformChannel channel;
818   MojoHandle pipe0, pipe1;
819   SendInvitationToClient(channel.TakeLocalEndpoint().TakePlatformHandle(),
820                          base::kNullProcessHandle, &pipe0, 1,
821                          TransportType::kChannel,
822                          MOJO_SEND_INVITATION_FLAG_ISOLATED, nullptr, 0, "");
823   SendInvitationToClient(channel.TakeRemoteEndpoint().TakePlatformHandle(),
824                          base::kNullProcessHandle, &pipe1, 1,
825                          TransportType::kChannel,
826                          MOJO_SEND_INVITATION_FLAG_ISOLATED, nullptr, 0, "");
827 
828   WriteMessage(pipe0, kTestMessage1);
829   EXPECT_EQ(kTestMessage1, ReadMessage(pipe1));
830   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe0));
831   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe1));
832 }
833 
TEST_F(InvitationTest,BrokenInvitationTransportBreaksAttachedPipe)834 TEST_F(InvitationTest, BrokenInvitationTransportBreaksAttachedPipe) {
835   MojoHandle primordial_pipe;
836   base::Process child_process = LaunchChildTestClient(
837       "BrokenTransportClient", &primordial_pipe, 1, TransportType::kChannel,
838       MOJO_SEND_INVITATION_FLAG_NONE);
839 
840   EXPECT_EQ(MOJO_RESULT_OK,
841             WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
842   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(primordial_pipe));
843 
844   int wait_result = -1;
845   base::WaitForMultiprocessTestChildExit(
846       child_process, TestTimeouts::action_timeout(), &wait_result);
847   child_process.Close();
848   EXPECT_EQ(0, wait_result);
849 }
850 
TEST_F(InvitationTest,BrokenIsolatedInvitationTransportBreaksAttachedPipe)851 TEST_F(InvitationTest, BrokenIsolatedInvitationTransportBreaksAttachedPipe) {
852   MojoHandle primordial_pipe;
853   base::Process child_process = LaunchChildTestClient(
854       "BrokenTransportClient", &primordial_pipe, 1, TransportType::kChannel,
855       MOJO_SEND_INVITATION_FLAG_ISOLATED);
856 
857   EXPECT_EQ(MOJO_RESULT_OK,
858             WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
859   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(primordial_pipe));
860 
861   int wait_result = -1;
862   base::WaitForMultiprocessTestChildExit(
863       child_process, TestTimeouts::action_timeout(), &wait_result);
864   child_process.Close();
865   EXPECT_EQ(0, wait_result);
866 }
867 
DEFINE_TEST_CLIENT(BrokenTransportClient)868 DEFINE_TEST_CLIENT(BrokenTransportClient) {
869   // No-op. Exit immediately without accepting any invitation.
870 }
871 
872 }  // namespace
873 }  // namespace core
874 }  // namespace mojo
875