• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "ipc/ipc_mojo_bootstrap.h"
11 
12 #include <cstdint>
13 #include <memory>
14 #include <utility>
15 
16 #include "base/run_loop.h"
17 #include "base/task/single_thread_task_runner.h"
18 #include "base/test/task_environment.h"
19 #include "ipc/ipc.mojom.h"
20 #include "ipc/ipc_test_base.h"
21 #include "mojo/core/test/multiprocess_test_helper.h"
22 #include "mojo/public/cpp/bindings/associated_receiver.h"
23 
24 namespace {
25 
26 constexpr int32_t kTestServerPid = 42;
27 constexpr int32_t kTestClientPid = 4242;
28 
29 class Connection {
30  public:
Connection(std::unique_ptr<IPC::MojoBootstrap> bootstrap,int32_t sender_id)31   explicit Connection(std::unique_ptr<IPC::MojoBootstrap> bootstrap,
32                       int32_t sender_id)
33       : bootstrap_(std::move(bootstrap)) {
34     mojo::PendingAssociatedRemote<IPC::mojom::Channel> sender;
35     bootstrap_->Connect(&sender, &receiver_);
36     sender_.Bind(std::move(sender));
37     sender_->SetPeerPid(sender_id);
38 
39     // It's OK to start receiving right away even though `receiver_` isn't
40     // bound, because all of these tests are single-threaded and it will be
41     // bound before any incoming messages can be scheduled for processing.
42     bootstrap_->StartReceiving();
43   }
44 
TakeReceiver(mojo::PendingAssociatedReceiver<IPC::mojom::Channel> * receiver)45   void TakeReceiver(
46       mojo::PendingAssociatedReceiver<IPC::mojom::Channel>* receiver) {
47     *receiver = std::move(receiver_);
48   }
49 
GetSender()50   mojo::AssociatedRemote<IPC::mojom::Channel>& GetSender() { return sender_; }
51 
52  private:
53   mojo::AssociatedRemote<IPC::mojom::Channel> sender_;
54   mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver_;
55   std::unique_ptr<IPC::MojoBootstrap> bootstrap_;
56 };
57 
58 class PeerPidReceiver : public IPC::mojom::Channel {
59  public:
60   enum class MessageExpectation {
61     kNotExpected,
62     kExpectedValid,
63     kExpectedInvalid
64   };
65 
PeerPidReceiver(mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver,base::OnceClosure on_peer_pid_set,MessageExpectation message_expectation=MessageExpectation::kNotExpected)66   PeerPidReceiver(
67       mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver,
68       base::OnceClosure on_peer_pid_set,
69       MessageExpectation message_expectation = MessageExpectation::kNotExpected)
70       : receiver_(this, std::move(receiver)),
71         on_peer_pid_set_(std::move(on_peer_pid_set)),
72         message_expectation_(message_expectation) {
73     receiver_.set_disconnect_handler(disconnect_run_loop_.QuitClosure());
74   }
75 
76   PeerPidReceiver(const PeerPidReceiver&) = delete;
77   PeerPidReceiver& operator=(const PeerPidReceiver&) = delete;
78 
~PeerPidReceiver()79   ~PeerPidReceiver() override {
80     bool expected_message =
81         message_expectation_ != MessageExpectation::kNotExpected;
82     EXPECT_EQ(expected_message, received_message_);
83   }
84 
85   // mojom::Channel:
SetPeerPid(int32_t pid)86   void SetPeerPid(int32_t pid) override {
87     peer_pid_ = pid;
88     std::move(on_peer_pid_set_).Run();
89   }
90 
Receive(IPC::MessageView message_view)91   void Receive(IPC::MessageView message_view) override {
92     ASSERT_NE(MessageExpectation::kNotExpected, message_expectation_);
93     received_message_ = true;
94 
95     IPC::Message message(
96         reinterpret_cast<const char*>(message_view.bytes().data()),
97         message_view.bytes().size());
98     bool expected_valid =
99         message_expectation_ == MessageExpectation::kExpectedValid;
100     EXPECT_EQ(expected_valid, message.IsValid());
101   }
102 
GetAssociatedInterface(mojo::GenericPendingAssociatedReceiver receiver)103   void GetAssociatedInterface(
104       mojo::GenericPendingAssociatedReceiver receiver) override {}
105 
peer_pid() const106   int32_t peer_pid() const { return peer_pid_; }
107 
RunUntilDisconnect()108   void RunUntilDisconnect() { disconnect_run_loop_.Run(); }
109 
110  private:
111   mojo::AssociatedReceiver<IPC::mojom::Channel> receiver_;
112   base::OnceClosure on_peer_pid_set_;
113   MessageExpectation message_expectation_;
114   int32_t peer_pid_ = -1;
115   bool received_message_ = false;
116   base::RunLoop disconnect_run_loop_;
117 };
118 
119 class IPCMojoBootstrapTest : public testing::Test {
120  protected:
121   mojo::core::test::MultiprocessTestHelper helper_;
122 };
123 
TEST_F(IPCMojoBootstrapTest,Connect)124 TEST_F(IPCMojoBootstrapTest, Connect) {
125   base::test::SingleThreadTaskEnvironment task_environment;
126   Connection connection(IPC::MojoBootstrap::Create(
127                             helper_.StartChild("IPCMojoBootstrapTestClient"),
128                             IPC::Channel::MODE_SERVER,
129                             base::SingleThreadTaskRunner::GetCurrentDefault(),
130                             base::SingleThreadTaskRunner::GetCurrentDefault()),
131                         kTestServerPid);
132 
133   mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver;
134   connection.TakeReceiver(&receiver);
135 
136   base::RunLoop run_loop;
137   PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure());
138   run_loop.Run();
139 
140   EXPECT_EQ(kTestClientPid, impl.peer_pid());
141 
142   impl.RunUntilDisconnect();
143   EXPECT_TRUE(helper_.WaitForChildTestShutdown());
144 }
145 
146 // A long running process that connects to us.
MULTIPROCESS_TEST_MAIN_WITH_SETUP(IPCMojoBootstrapTestClientTestChildMain,::mojo::core::test::MultiprocessTestHelper::ChildSetup)147 MULTIPROCESS_TEST_MAIN_WITH_SETUP(
148     IPCMojoBootstrapTestClientTestChildMain,
149     ::mojo::core::test::MultiprocessTestHelper::ChildSetup) {
150   base::test::SingleThreadTaskEnvironment task_environment;
151   Connection connection(
152       IPC::MojoBootstrap::Create(
153           std::move(mojo::core::test::MultiprocessTestHelper::primordial_pipe),
154           IPC::Channel::MODE_CLIENT,
155           base::SingleThreadTaskRunner::GetCurrentDefault(),
156           base::SingleThreadTaskRunner::GetCurrentDefault()),
157       kTestClientPid);
158 
159   mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver;
160   connection.TakeReceiver(&receiver);
161 
162   base::RunLoop run_loop;
163   PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure());
164   run_loop.Run();
165 
166   EXPECT_EQ(kTestServerPid, impl.peer_pid());
167 
168   return 0;
169 }
170 
TEST_F(IPCMojoBootstrapTest,ReceiveEmptyMessage)171 TEST_F(IPCMojoBootstrapTest, ReceiveEmptyMessage) {
172   base::test::SingleThreadTaskEnvironment task_environment;
173   Connection connection(
174       IPC::MojoBootstrap::Create(
175           helper_.StartChild("IPCMojoBootstrapTestEmptyMessage"),
176           IPC::Channel::MODE_SERVER,
177           base::SingleThreadTaskRunner::GetCurrentDefault(),
178           base::SingleThreadTaskRunner::GetCurrentDefault()),
179       kTestServerPid);
180 
181   mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver;
182   connection.TakeReceiver(&receiver);
183 
184   base::RunLoop run_loop;
185   PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure(),
186                        PeerPidReceiver::MessageExpectation::kExpectedInvalid);
187   run_loop.Run();
188 
189   // Wait for the Channel to be disconnected so we can reasonably assert that
190   // the child's empty message must have been received before we pass the test.
191   impl.RunUntilDisconnect();
192 
193   EXPECT_TRUE(helper_.WaitForChildTestShutdown());
194 }
195 
196 // A long running process that connects to us.
MULTIPROCESS_TEST_MAIN_WITH_SETUP(IPCMojoBootstrapTestEmptyMessageTestChildMain,::mojo::core::test::MultiprocessTestHelper::ChildSetup)197 MULTIPROCESS_TEST_MAIN_WITH_SETUP(
198     IPCMojoBootstrapTestEmptyMessageTestChildMain,
199     ::mojo::core::test::MultiprocessTestHelper::ChildSetup) {
200   base::test::SingleThreadTaskEnvironment task_environment;
201   Connection connection(
202       IPC::MojoBootstrap::Create(
203           std::move(mojo::core::test::MultiprocessTestHelper::primordial_pipe),
204           IPC::Channel::MODE_CLIENT,
205           base::SingleThreadTaskRunner::GetCurrentDefault(),
206           base::SingleThreadTaskRunner::GetCurrentDefault()),
207       kTestClientPid);
208 
209   mojo::PendingAssociatedReceiver<IPC::mojom::Channel> receiver;
210   connection.TakeReceiver(&receiver);
211   auto& sender = connection.GetSender();
212 
213   uint8_t data = 0;
214   sender->Receive(
215       IPC::MessageView(base::span(&data, 0u), std::nullopt /* handles */));
216 
217   base::RunLoop run_loop;
218   PeerPidReceiver impl(std::move(receiver), run_loop.QuitClosure());
219   run_loop.Run();
220 
221   return 0;
222 }
223 
224 }  // namespace
225