[go: nahoru, domu]

blob: 6bb1cd3438ddda569551c7d243c21a0afa18b0ae [file] [log] [blame]
Avi Drissmand387f0922022-09-14 20:51:311// Copyright 2017 The Chromium Authors
jcivelli823ec062017-03-01 03:13:492// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Ken Rockotdba46db2018-07-04 18:41:045#include "mojo/core/channel.h"
Wez3e64a8a2018-03-13 05:36:066
Robert Sesek842a48e2019-04-02 00:16:187#include <atomic>
8
Avi Drissmand70f89a2023-01-11 23:52:559#include "base/functional/bind.h"
Lei Zhang425893e2021-05-14 23:28:2510#include "base/memory/page_size.h"
jcivelli823ec062017-03-01 03:13:4911#include "base/memory/ptr_util.h"
Carlos Caballerodd8bf7b02019-07-30 14:14:1512#include "base/message_loop/message_pump_type.h"
Ken Rockotcc6cad3d2019-01-24 23:05:3513#include "base/process/process_handle.h"
Ken Rockotfada58122018-12-11 16:49:5414#include "base/run_loop.h"
Robert Sesekb9f54dd2019-06-13 15:00:3815#include "base/strings/stringprintf.h"
Sean Maher5b9af51f2022-11-21 15:32:4716#include "base/task/single_thread_task_runner.h"
Guido Urdanetaef4e91942020-11-09 15:06:2417#include "base/test/bind.h"
Carlos Caballero631413d2019-12-03 07:39:3918#include "base/test/task_environment.h"
Wez3e64a8a2018-03-13 05:36:0619#include "base/threading/thread.h"
Ken Rockot0321c392019-06-04 20:37:3620#include "build/build_config.h"
Ken Rockotdba46db2018-07-04 18:41:0421#include "mojo/core/platform_handle_utils.h"
Ken Rockot6a6dca0f2018-06-22 18:41:0722#include "mojo/public/cpp/platform/platform_channel.h"
jcivelli823ec062017-03-01 03:13:4923#include "testing/gmock/include/gmock/gmock.h"
24#include "testing/gtest/include/gtest/gtest.h"
Anton Bikineev60ef3812021-05-15 18:05:0325#include "third_party/abseil-cpp/absl/types/optional.h"
jcivelli823ec062017-03-01 03:13:4926
27namespace mojo {
Ken Rockotdba46db2018-07-04 18:41:0428namespace core {
jcivelli823ec062017-03-01 03:13:4929namespace {
30
31class TestChannel : public Channel {
32 public:
Ken Rockotfada58122018-12-11 16:49:5433 TestChannel(Channel::Delegate* delegate)
34 : Channel(delegate, Channel::HandlePolicy::kAcceptHandles) {}
jcivelli823ec062017-03-01 03:13:4935
36 char* GetReadBufferTest(size_t* buffer_capacity) {
37 return GetReadBuffer(buffer_capacity);
38 }
39
40 bool OnReadCompleteTest(size_t bytes_read, size_t* next_read_size_hint) {
41 return OnReadComplete(bytes_read, next_read_size_hint);
42 }
43
Ken Rockot043152da62018-06-29 03:22:1644 MOCK_METHOD7(GetReadPlatformHandles,
Ken Rockot0e45f802018-06-27 23:56:0145 bool(const void* payload,
46 size_t payload_size,
47 size_t num_handles,
jcivelli823ec062017-03-01 03:13:4948 const void* extra_header,
49 size_t extra_header_size,
Ken Rockot043152da62018-06-29 03:22:1650 std::vector<PlatformHandle>* handles,
Ken Rockot0e45f802018-06-27 23:56:0151 bool* deferred));
Ken Rockot36d44a572022-08-15 23:19:5752 MOCK_METHOD2(GetReadPlatformHandlesForIpcz,
53 bool(size_t, std::vector<PlatformHandle>&));
jcivelli823ec062017-03-01 03:13:4954 MOCK_METHOD0(Start, void());
55 MOCK_METHOD0(ShutDownImpl, void());
56 MOCK_METHOD0(LeakHandle, void());
57
Daniel Chenga2e3f7a2018-04-30 17:33:5658 void Write(MessagePtr message) override {}
jcivelli823ec062017-03-01 03:13:4959
60 protected:
Anand K Mistry48d93df2020-06-18 00:04:2261 ~TestChannel() override = default;
jcivelli823ec062017-03-01 03:13:4962};
63
64// Not using GMock as I don't think it supports movable types.
65class MockChannelDelegate : public Channel::Delegate {
66 public:
Anand K Mistry48d93df2020-06-18 00:04:2267 MockChannelDelegate() = default;
jcivelli823ec062017-03-01 03:13:4968
69 size_t GetReceivedPayloadSize() const { return payload_size_; }
70
71 const void* GetReceivedPayload() const { return payload_.get(); }
72
73 protected:
Ken Rockot043152da62018-06-29 03:22:1674 void OnChannelMessage(const void* payload,
75 size_t payload_size,
76 std::vector<PlatformHandle> handles) override {
jcivelli823ec062017-03-01 03:13:4977 payload_.reset(new char[payload_size]);
78 memcpy(payload_.get(), payload, payload_size);
79 payload_size_ = payload_size;
80 }
81
82 // Notify that an error has occured and the Channel will cease operation.
Ken Rockot7f49ca42017-07-13 00:17:2683 void OnChannelError(Channel::Error error) override {}
jcivelli823ec062017-03-01 03:13:4984
85 private:
86 size_t payload_size_ = 0;
87 std::unique_ptr<char[]> payload_;
88};
89
90Channel::MessagePtr CreateDefaultMessage(bool legacy_message) {
91 const size_t payload_size = 100;
Brian Geffon4e9b8442021-04-23 18:48:3892 Channel::MessagePtr message = Channel::Message::CreateMessage(
jcivelli823ec062017-03-01 03:13:4993 payload_size, 0,
94 legacy_message ? Channel::Message::MessageType::NORMAL_LEGACY
95 : Channel::Message::MessageType::NORMAL);
96 char* payload = static_cast<char*>(message->mutable_payload());
97 for (size_t i = 0; i < payload_size; i++) {
98 payload[i] = static_cast<char>(i);
99 }
100 return message;
101}
102
103void TestMemoryEqual(const void* data1,
104 size_t data1_size,
105 const void* data2,
106 size_t data2_size) {
107 ASSERT_EQ(data1_size, data2_size);
108 const unsigned char* data1_char = static_cast<const unsigned char*>(data1);
109 const unsigned char* data2_char = static_cast<const unsigned char*>(data2);
110 for (size_t i = 0; i < data1_size; i++) {
111 // ASSERT so we don't log tons of errors if the data is different.
112 ASSERT_EQ(data1_char[i], data2_char[i]);
113 }
114}
115
116void TestMessagesAreEqual(Channel::Message* message1,
117 Channel::Message* message2,
118 bool legacy_messages) {
119 // If any of the message is null, this is probably not what you wanted to
120 // test.
121 ASSERT_NE(nullptr, message1);
122 ASSERT_NE(nullptr, message2);
123
124 ASSERT_EQ(message1->payload_size(), message2->payload_size());
125 EXPECT_EQ(message1->has_handles(), message2->has_handles());
126
127 TestMemoryEqual(message1->payload(), message1->payload_size(),
128 message2->payload(), message2->payload_size());
129
130 if (legacy_messages)
131 return;
132
133 ASSERT_EQ(message1->extra_header_size(), message2->extra_header_size());
134 TestMemoryEqual(message1->extra_header(), message1->extra_header_size(),
135 message2->extra_header(), message2->extra_header_size());
136}
137
138TEST(ChannelTest, LegacyMessageDeserialization) {
139 Channel::MessagePtr message = CreateDefaultMessage(true /* legacy_message */);
140 Channel::MessagePtr deserialized_message =
Ken Rockotd62bb302021-06-16 22:09:35141 Channel::Message::Deserialize(message->data(), message->data_num_bytes(),
142 Channel::HandlePolicy::kAcceptHandles);
jcivelli823ec062017-03-01 03:13:49143 TestMessagesAreEqual(message.get(), deserialized_message.get(),
144 true /* legacy_message */);
145}
146
147TEST(ChannelTest, NonLegacyMessageDeserialization) {
148 Channel::MessagePtr message =
149 CreateDefaultMessage(false /* legacy_message */);
150 Channel::MessagePtr deserialized_message =
Ken Rockotd62bb302021-06-16 22:09:35151 Channel::Message::Deserialize(message->data(), message->data_num_bytes(),
152 Channel::HandlePolicy::kAcceptHandles);
jcivelli823ec062017-03-01 03:13:49153 TestMessagesAreEqual(message.get(), deserialized_message.get(),
154 false /* legacy_message */);
155}
156
157TEST(ChannelTest, OnReadLegacyMessage) {
158 size_t buffer_size = 100 * 1024;
159 Channel::MessagePtr message = CreateDefaultMessage(true /* legacy_message */);
160
161 MockChannelDelegate channel_delegate;
162 scoped_refptr<TestChannel> channel = new TestChannel(&channel_delegate);
163 char* read_buffer = channel->GetReadBufferTest(&buffer_size);
164 ASSERT_LT(message->data_num_bytes(),
165 buffer_size); // Bad test. Increase buffer
166 // size.
167 memcpy(read_buffer, message->data(), message->data_num_bytes());
168
169 size_t next_read_size_hint = 0;
170 EXPECT_TRUE(channel->OnReadCompleteTest(message->data_num_bytes(),
171 &next_read_size_hint));
172
173 TestMemoryEqual(message->payload(), message->payload_size(),
174 channel_delegate.GetReceivedPayload(),
175 channel_delegate.GetReceivedPayloadSize());
176}
177
178TEST(ChannelTest, OnReadNonLegacyMessage) {
179 size_t buffer_size = 100 * 1024;
180 Channel::MessagePtr message =
181 CreateDefaultMessage(false /* legacy_message */);
182
183 MockChannelDelegate channel_delegate;
184 scoped_refptr<TestChannel> channel = new TestChannel(&channel_delegate);
185 char* read_buffer = channel->GetReadBufferTest(&buffer_size);
186 ASSERT_LT(message->data_num_bytes(),
187 buffer_size); // Bad test. Increase buffer
188 // size.
189 memcpy(read_buffer, message->data(), message->data_num_bytes());
190
191 size_t next_read_size_hint = 0;
192 EXPECT_TRUE(channel->OnReadCompleteTest(message->data_num_bytes(),
193 &next_read_size_hint));
194
195 TestMemoryEqual(message->payload(), message->payload_size(),
196 channel_delegate.GetReceivedPayload(),
197 channel_delegate.GetReceivedPayloadSize());
198}
199
Wez3e64a8a2018-03-13 05:36:06200class ChannelTestShutdownAndWriteDelegate : public Channel::Delegate {
201 public:
202 ChannelTestShutdownAndWriteDelegate(
Ken Rockot29b0a322018-06-29 17:38:07203 PlatformChannelEndpoint endpoint,
Gabriel Charettee926fc12019-12-16 19:00:02204 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
Wez3e64a8a2018-03-13 05:36:06205 scoped_refptr<Channel> client_channel,
206 std::unique_ptr<base::Thread> client_thread,
207 base::RepeatingClosure quit_closure)
208 : quit_closure_(std::move(quit_closure)),
209 client_channel_(std::move(client_channel)),
210 client_thread_(std::move(client_thread)) {
Ken Rockot29b0a322018-06-29 17:38:07211 channel_ = Channel::Create(this, ConnectionParams(std::move(endpoint)),
Ken Rockotfada58122018-12-11 16:49:54212 Channel::HandlePolicy::kAcceptHandles,
Ken Rockot5732c6d42018-06-22 17:43:38213 std::move(task_runner));
Wez3e64a8a2018-03-13 05:36:06214 channel_->Start();
215 }
216 ~ChannelTestShutdownAndWriteDelegate() override { channel_->ShutDown(); }
217
218 // Channel::Delegate implementation
Ken Rockot043152da62018-06-29 03:22:16219 void OnChannelMessage(const void* payload,
220 size_t payload_size,
221 std::vector<PlatformHandle> handles) override {
Wez3e64a8a2018-03-13 05:36:06222 ++message_count_;
223
224 // If |client_channel_| exists then close it and its thread.
225 if (client_channel_) {
226 // Write a fresh message, making our channel readable again.
227 Channel::MessagePtr message = CreateDefaultMessage(false);
228 client_thread_->task_runner()->PostTask(
Anand K. Mistry47802682019-11-06 00:58:24229 FROM_HERE,
230 base::BindOnce(&Channel::Write, client_channel_, std::move(message)));
Wez3e64a8a2018-03-13 05:36:06231
232 // Close the channel and wait for it to shutdown.
233 client_channel_->ShutDown();
234 client_channel_ = nullptr;
235
236 client_thread_->Stop();
237 client_thread_ = nullptr;
238 }
239
240 // Write a message to the channel, to verify whether this triggers an
241 // OnChannelError callback before all messages were read.
242 Channel::MessagePtr message = CreateDefaultMessage(false);
243 channel_->Write(std::move(message));
244 }
245
246 void OnChannelError(Channel::Error error) override {
247 EXPECT_EQ(2, message_count_);
248 quit_closure_.Run();
249 }
250
251 base::RepeatingClosure quit_closure_;
252 int message_count_ = 0;
253 scoped_refptr<Channel> channel_;
254
255 scoped_refptr<Channel> client_channel_;
256 std::unique_ptr<base::Thread> client_thread_;
257};
258
259TEST(ChannelTest, PeerShutdownDuringRead) {
Carlos Caballero631413d2019-12-03 07:39:39260 base::test::SingleThreadTaskEnvironment task_environment(
261 base::test::TaskEnvironment::MainThreadType::IO);
Ken Rockot6a6dca0f2018-06-22 18:41:07262 PlatformChannel channel;
Wez3e64a8a2018-03-13 05:36:06263
264 // Create a "client" Channel with one end of the pipe, and Start() it.
265 std::unique_ptr<base::Thread> client_thread =
266 std::make_unique<base::Thread>("clientio_thread");
267 client_thread->StartWithOptions(
Carlos Caballerodd8bf7b02019-07-30 14:14:15268 base::Thread::Options(base::MessagePumpType::IO, 0));
Wez3e64a8a2018-03-13 05:36:06269
Ken Rockotfada58122018-12-11 16:49:54270 scoped_refptr<Channel> client_channel = Channel::Create(
271 nullptr, ConnectionParams(channel.TakeRemoteEndpoint()),
272 Channel::HandlePolicy::kAcceptHandles, client_thread->task_runner());
Wez3e64a8a2018-03-13 05:36:06273 client_channel->Start();
274
275 // On the "client" IO thread, create and write a message.
276 Channel::MessagePtr message = CreateDefaultMessage(false);
277 client_thread->task_runner()->PostTask(
278 FROM_HERE,
Anand K. Mistry47802682019-11-06 00:58:24279 base::BindOnce(&Channel::Write, client_channel, std::move(message)));
Wez3e64a8a2018-03-13 05:36:06280
281 // Create a "server" Channel with the other end of the pipe, and process the
282 // messages from it. The |server_delegate| will ShutDown the client end of
283 // the pipe after the first message, and quit the RunLoop when OnChannelError
284 // is received.
285 base::RunLoop run_loop;
286 ChannelTestShutdownAndWriteDelegate server_delegate(
Sean Maher5b9af51f2022-11-21 15:32:47287 channel.TakeLocalEndpoint(),
288 base::SingleThreadTaskRunner::GetCurrentDefault(),
Ken Rockot29b0a322018-06-29 17:38:07289 std::move(client_channel), std::move(client_thread),
290 run_loop.QuitClosure());
Wez3e64a8a2018-03-13 05:36:06291
292 run_loop.Run();
293}
294
Ken Rockotfada58122018-12-11 16:49:54295class RejectHandlesDelegate : public Channel::Delegate {
296 public:
297 RejectHandlesDelegate() = default;
298
Peter Boströmfeef05a2021-10-05 21:35:08299 RejectHandlesDelegate(const RejectHandlesDelegate&) = delete;
300 RejectHandlesDelegate& operator=(const RejectHandlesDelegate&) = delete;
301
Ken Rockotfada58122018-12-11 16:49:54302 size_t num_messages() const { return num_messages_; }
303
304 // Channel::Delegate:
305 void OnChannelMessage(const void* payload,
306 size_t payload_size,
307 std::vector<PlatformHandle> handles) override {
308 ++num_messages_;
309 }
310
311 void OnChannelError(Channel::Error error) override {
312 if (wait_for_error_loop_)
313 wait_for_error_loop_->Quit();
314 }
315
316 void WaitForError() {
317 wait_for_error_loop_.emplace();
318 wait_for_error_loop_->Run();
319 }
320
321 private:
322 size_t num_messages_ = 0;
Anton Bikineev60ef3812021-05-15 18:05:03323 absl::optional<base::RunLoop> wait_for_error_loop_;
Ken Rockotfada58122018-12-11 16:49:54324};
325
326TEST(ChannelTest, RejectHandles) {
Carlos Caballero631413d2019-12-03 07:39:39327 base::test::SingleThreadTaskEnvironment task_environment(
328 base::test::TaskEnvironment::MainThreadType::IO);
Ken Rockotfada58122018-12-11 16:49:54329 PlatformChannel platform_channel;
330
331 RejectHandlesDelegate receiver_delegate;
Carlos Caballero631413d2019-12-03 07:39:39332 scoped_refptr<Channel> receiver =
333 Channel::Create(&receiver_delegate,
334 ConnectionParams(platform_channel.TakeLocalEndpoint()),
335 Channel::HandlePolicy::kRejectHandles,
Sean Maher5b9af51f2022-11-21 15:32:47336 base::SingleThreadTaskRunner::GetCurrentDefault());
Ken Rockotfada58122018-12-11 16:49:54337 receiver->Start();
338
339 RejectHandlesDelegate sender_delegate;
340 scoped_refptr<Channel> sender = Channel::Create(
341 &sender_delegate, ConnectionParams(platform_channel.TakeRemoteEndpoint()),
Carlos Caballero631413d2019-12-03 07:39:39342 Channel::HandlePolicy::kRejectHandles,
Sean Maher5b9af51f2022-11-21 15:32:47343 base::SingleThreadTaskRunner::GetCurrentDefault());
Ken Rockotfada58122018-12-11 16:49:54344 sender->Start();
345
346 // Create another platform channel just to stuff one of its endpoint handles
347 // into a message. Sending this message to the receiver should cause the
348 // receiver to reject it and close the Channel without ever dispatching the
349 // message.
350 PlatformChannel dummy_channel;
351 std::vector<mojo::PlatformHandle> handles;
352 handles.push_back(dummy_channel.TakeLocalEndpoint().TakePlatformHandle());
Brian Geffon4e9b8442021-04-23 18:48:38353 auto message = Channel::Message::CreateMessage(0 /* payload_size */,
354 1 /* max_handles */);
Ken Rockotfada58122018-12-11 16:49:54355 message->SetHandles(std::move(handles));
356 sender->Write(std::move(message));
357
358 receiver_delegate.WaitForError();
359 EXPECT_EQ(0u, receiver_delegate.num_messages());
360}
361
Ken Rockotcc6cad3d2019-01-24 23:05:35362TEST(ChannelTest, DeserializeMessage_BadExtraHeaderSize) {
363 // Verifies that a message payload is rejected when the extra header chunk
364 // size not properly aligned.
365 constexpr uint16_t kBadAlignment = kChannelMessageAlignment + 1;
366 constexpr uint16_t kTotalHeaderSize =
367 sizeof(Channel::Message::Header) + kBadAlignment;
368 constexpr uint32_t kEmptyPayloadSize = 8;
369 constexpr uint32_t kMessageSize = kTotalHeaderSize + kEmptyPayloadSize;
370 char message[kMessageSize];
371 memset(message, 0, kMessageSize);
372
373 Channel::Message::Header* header =
374 reinterpret_cast<Channel::Message::Header*>(&message[0]);
375 header->num_bytes = kMessageSize;
376 header->num_header_bytes = kTotalHeaderSize;
377 header->message_type = Channel::Message::MessageType::NORMAL;
378 header->num_handles = 0;
Ken Rockotd62bb302021-06-16 22:09:35379 EXPECT_EQ(nullptr,
380 Channel::Message::Deserialize(&message[0], kMessageSize,
381 Channel::HandlePolicy::kAcceptHandles,
382 base::kNullProcessHandle));
Ken Rockotcc6cad3d2019-01-24 23:05:35383}
384
Fabrice de Ganscc2c4872022-02-25 15:01:57385// This test is only enabled for Linux-based platforms.
Xiaohan Wangaa41c682022-01-14 18:50:49386#if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_FUCHSIA)
Ken Rockot0321c392019-06-04 20:37:36387TEST(ChannelTest, DeserializeMessage_NonZeroExtraHeaderSize) {
388 // Verifies that a message payload is rejected when the extra header chunk
389 // size anything but zero on Linux, even if it's aligned.
390 constexpr uint16_t kTotalHeaderSize =
391 sizeof(Channel::Message::Header) + kChannelMessageAlignment;
392 constexpr uint32_t kEmptyPayloadSize = 8;
393 constexpr uint32_t kMessageSize = kTotalHeaderSize + kEmptyPayloadSize;
394 char message[kMessageSize];
395 memset(message, 0, kMessageSize);
396
397 Channel::Message::Header* header =
398 reinterpret_cast<Channel::Message::Header*>(&message[0]);
399 header->num_bytes = kMessageSize;
400 header->num_header_bytes = kTotalHeaderSize;
401 header->message_type = Channel::Message::MessageType::NORMAL;
402 header->num_handles = 0;
Ken Rockotd62bb302021-06-16 22:09:35403 EXPECT_EQ(nullptr,
404 Channel::Message::Deserialize(&message[0], kMessageSize,
405 Channel::HandlePolicy::kAcceptHandles,
406 base::kNullProcessHandle));
Ken Rockot0321c392019-06-04 20:37:36407}
408#endif
409
Robert Sesek842a48e2019-04-02 00:16:18410class CountingChannelDelegate : public Channel::Delegate {
411 public:
412 explicit CountingChannelDelegate(base::OnceClosure on_final_message)
413 : on_final_message_(std::move(on_final_message)) {}
414 ~CountingChannelDelegate() override = default;
415
416 void OnChannelMessage(const void* payload,
417 size_t payload_size,
418 std::vector<PlatformHandle> handles) override {
419 // If this is the special "final message", run the closure.
420 if (payload_size == 1) {
421 auto* payload_str = reinterpret_cast<const char*>(payload);
422 if (payload_str[0] == '!') {
423 std::move(on_final_message_).Run();
424 return;
425 }
426 }
427
428 ++message_count_;
429 }
430
431 void OnChannelError(Channel::Error error) override { ++error_count_; }
432
433 size_t message_count_ = 0;
434 size_t error_count_ = 0;
435
436 private:
437 base::OnceClosure on_final_message_;
438};
439
440TEST(ChannelTest, PeerStressTest) {
441 constexpr size_t kLotsOfMessages = 1024;
442
Carlos Caballero631413d2019-12-03 07:39:39443 base::test::SingleThreadTaskEnvironment task_environment(
444 base::test::TaskEnvironment::MainThreadType::IO);
Robert Sesek842a48e2019-04-02 00:16:18445 base::RunLoop run_loop;
446
447 // Both channels should receive all the messages that each is sent. When
448 // the count becomes 2 (indicating both channels have received the final
449 // message), quit the main test thread's run loop.
450 std::atomic_int count_channels_received_final_message(0);
451 auto quit_when_both_channels_received_final_message = base::BindRepeating(
452 [](std::atomic_int* count_channels_received_final_message,
453 base::OnceClosure quit_closure) {
454 if (++(*count_channels_received_final_message) == 2) {
455 std::move(quit_closure).Run();
456 }
457 },
458 base::Unretained(&count_channels_received_final_message),
459 run_loop.QuitClosure());
460
461 // Create a second IO thread for the peer channel.
462 base::Thread::Options thread_options;
Carlos Caballerodd8bf7b02019-07-30 14:14:15463 thread_options.message_pump_type = base::MessagePumpType::IO;
Robert Sesek842a48e2019-04-02 00:16:18464 base::Thread peer_thread("peer_b_io");
Olivier Lic421c6d2021-05-12 05:12:57465 peer_thread.StartWithOptions(std::move(thread_options));
Robert Sesek842a48e2019-04-02 00:16:18466
467 // Create two channels that run on separate threads.
468 PlatformChannel platform_channel;
469
470 CountingChannelDelegate delegate_a(
471 quit_when_both_channels_received_final_message);
472 scoped_refptr<Channel> channel_a = Channel::Create(
473 &delegate_a, ConnectionParams(platform_channel.TakeLocalEndpoint()),
Carlos Caballero631413d2019-12-03 07:39:39474 Channel::HandlePolicy::kRejectHandles,
Sean Maher5b9af51f2022-11-21 15:32:47475 base::SingleThreadTaskRunner::GetCurrentDefault());
Robert Sesek842a48e2019-04-02 00:16:18476
477 CountingChannelDelegate delegate_b(
478 quit_when_both_channels_received_final_message);
479 scoped_refptr<Channel> channel_b = Channel::Create(
480 &delegate_b, ConnectionParams(platform_channel.TakeRemoteEndpoint()),
481 Channel::HandlePolicy::kRejectHandles, peer_thread.task_runner());
482
483 // Send a lot of messages, followed by a final terminating message.
484 auto send_lots_of_messages = [](scoped_refptr<Channel> channel) {
485 for (size_t i = 0; i < kLotsOfMessages; ++i) {
Brian Geffon4e9b8442021-04-23 18:48:38486 channel->Write(Channel::Message::CreateMessage(0, 0));
Robert Sesek842a48e2019-04-02 00:16:18487 }
488 };
489 auto send_final_message = [](scoped_refptr<Channel> channel) {
Brian Geffon4e9b8442021-04-23 18:48:38490 auto message = Channel::Message::CreateMessage(1, 0);
Robert Sesek842a48e2019-04-02 00:16:18491 auto* payload = static_cast<char*>(message->mutable_payload());
492 payload[0] = '!';
493 channel->Write(std::move(message));
494 };
495
496 channel_a->Start();
497 channel_b->Start();
498
499 send_lots_of_messages(channel_a);
500 send_lots_of_messages(channel_b);
501
Sean Maher5b9af51f2022-11-21 15:32:47502 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
Robert Sesek842a48e2019-04-02 00:16:18503 FROM_HERE, base::BindOnce(send_lots_of_messages, channel_a));
Sean Maher5b9af51f2022-11-21 15:32:47504 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
Robert Sesek842a48e2019-04-02 00:16:18505 FROM_HERE, base::BindOnce(send_lots_of_messages, channel_a));
Sean Maher5b9af51f2022-11-21 15:32:47506 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
Robert Sesek842a48e2019-04-02 00:16:18507 FROM_HERE, base::BindOnce(send_final_message, channel_a));
508
509 peer_thread.task_runner()->PostTask(
510 FROM_HERE, base::BindOnce(send_lots_of_messages, channel_b));
511 peer_thread.task_runner()->PostTask(
512 FROM_HERE, base::BindOnce(send_lots_of_messages, channel_b));
513 peer_thread.task_runner()->PostTask(
514 FROM_HERE, base::BindOnce(send_final_message, channel_b));
515
516 // Run until quit_when_both_channels_received_final_message quits the loop.
517 run_loop.Run();
518
519 channel_a->ShutDown();
520 channel_b->ShutDown();
521
522 peer_thread.StopSoon();
523
524 base::RunLoop().RunUntilIdle();
525
526 EXPECT_EQ(kLotsOfMessages * 3, delegate_a.message_count_);
527 EXPECT_EQ(kLotsOfMessages * 3, delegate_b.message_count_);
528
529 EXPECT_EQ(0u, delegate_a.error_count_);
530 EXPECT_EQ(0u, delegate_b.error_count_);
531}
532
Robert Sesek4bb92352020-01-23 22:46:08533class CallbackChannelDelegate : public Channel::Delegate {
Robert Sesekb9f54dd2019-06-13 15:00:38534 public:
Robert Sesek4bb92352020-01-23 22:46:08535 CallbackChannelDelegate() = default;
Robert Sesekb9f54dd2019-06-13 15:00:38536
Peter Boströmfeef05a2021-10-05 21:35:08537 CallbackChannelDelegate(const CallbackChannelDelegate&) = delete;
538 CallbackChannelDelegate& operator=(const CallbackChannelDelegate&) = delete;
539
Robert Sesekb9f54dd2019-06-13 15:00:38540 void OnChannelMessage(const void* payload,
541 size_t payload_size,
542 std::vector<PlatformHandle> handles) override {
Robert Sesek4bb92352020-01-23 22:46:08543 if (on_message_)
544 std::move(on_message_).Run();
Robert Sesekb9f54dd2019-06-13 15:00:38545 }
546
547 void OnChannelError(Channel::Error error) override {
Robert Sesek4bb92352020-01-23 22:46:08548 if (on_error_)
549 std::move(on_error_).Run();
Robert Sesekb9f54dd2019-06-13 15:00:38550 }
551
Robert Sesek4bb92352020-01-23 22:46:08552 void set_on_message(base::OnceClosure on_message) {
553 on_message_ = std::move(on_message);
Robert Sesekb9f54dd2019-06-13 15:00:38554 }
555
Robert Sesek4bb92352020-01-23 22:46:08556 void set_on_error(base::OnceClosure on_error) {
557 on_error_ = std::move(on_error);
558 }
Robert Sesekb9f54dd2019-06-13 15:00:38559
560 private:
Robert Sesek4bb92352020-01-23 22:46:08561 base::OnceClosure on_message_;
562 base::OnceClosure on_error_;
Robert Sesekb9f54dd2019-06-13 15:00:38563};
564
565TEST(ChannelTest, MessageSizeTest) {
Carlos Caballero631413d2019-12-03 07:39:39566 base::test::SingleThreadTaskEnvironment task_environment(
567 base::test::TaskEnvironment::MainThreadType::IO);
Robert Sesekb9f54dd2019-06-13 15:00:38568 PlatformChannel platform_channel;
569
Robert Sesek4bb92352020-01-23 22:46:08570 CallbackChannelDelegate receiver_delegate;
Carlos Caballero631413d2019-12-03 07:39:39571 scoped_refptr<Channel> receiver =
572 Channel::Create(&receiver_delegate,
573 ConnectionParams(platform_channel.TakeLocalEndpoint()),
574 Channel::HandlePolicy::kAcceptHandles,
Sean Maher5b9af51f2022-11-21 15:32:47575 base::SingleThreadTaskRunner::GetCurrentDefault());
Robert Sesekb9f54dd2019-06-13 15:00:38576 receiver->Start();
577
578 MockChannelDelegate sender_delegate;
579 scoped_refptr<Channel> sender = Channel::Create(
580 &sender_delegate, ConnectionParams(platform_channel.TakeRemoteEndpoint()),
Carlos Caballero631413d2019-12-03 07:39:39581 Channel::HandlePolicy::kAcceptHandles,
Sean Maher5b9af51f2022-11-21 15:32:47582 base::SingleThreadTaskRunner::GetCurrentDefault());
Robert Sesekb9f54dd2019-06-13 15:00:38583 sender->Start();
584
585 for (uint32_t i = 0; i < base::GetPageSize() * 4; ++i) {
586 SCOPED_TRACE(base::StringPrintf("message size %d", i));
587
Brian Geffon4e9b8442021-04-23 18:48:38588 auto message = Channel::Message::CreateMessage(i, 0);
Robert Sesekb9f54dd2019-06-13 15:00:38589 memset(message->mutable_payload(), 0xAB, i);
590 sender->Write(std::move(message));
591
Robert Sesek4bb92352020-01-23 22:46:08592 bool got_message = false, got_error = false;
593
Robert Sesekb9f54dd2019-06-13 15:00:38594 base::RunLoop loop;
Robert Sesek4bb92352020-01-23 22:46:08595 receiver_delegate.set_on_message(
596 base::BindLambdaForTesting([&got_message, &loop]() {
597 got_message = true;
598 loop.Quit();
599 }));
600 receiver_delegate.set_on_error(
601 base::BindLambdaForTesting([&got_error, &loop]() {
602 got_error = true;
603 loop.Quit();
604 }));
Robert Sesekb9f54dd2019-06-13 15:00:38605 loop.Run();
606
Robert Sesek4bb92352020-01-23 22:46:08607 EXPECT_TRUE(got_message);
608 EXPECT_FALSE(got_error);
Robert Sesekb9f54dd2019-06-13 15:00:38609 }
610}
611
Xiaohan Wangaa41c682022-01-14 18:50:49612#if BUILDFLAG(IS_MAC)
Robert Sesek4bb92352020-01-23 22:46:08613TEST(ChannelTest, SendToDeadMachPortName) {
614 base::test::SingleThreadTaskEnvironment task_environment(
615 base::test::TaskEnvironment::MainThreadType::IO);
616
617 // Create a second IO thread for the B channel. It needs to process tasks
618 // separately from channel A.
619 base::Thread::Options thread_options;
620 thread_options.message_pump_type = base::MessagePumpType::IO;
621 base::Thread peer_thread("channel_b_io");
Olivier Lic421c6d2021-05-12 05:12:57622 peer_thread.StartWithOptions(std::move(thread_options));
Robert Sesek4bb92352020-01-23 22:46:08623
624 // Create a PlatformChannel send/receive right pair.
625 PlatformChannel platform_channel;
626
627 mach_port_urefs_t send = 0, dead = 0;
628 mach_port_t send_name = platform_channel.local_endpoint()
629 .platform_handle()
630 .GetMachSendRight()
631 .get();
632
633 auto get_send_name_refs = [&send, &dead, send_name]() {
634 kern_return_t kr = mach_port_get_refs(mach_task_self(), send_name,
635 MACH_PORT_RIGHT_SEND, &send);
636 ASSERT_EQ(kr, KERN_SUCCESS);
637 kr = mach_port_get_refs(mach_task_self(), send_name,
638 MACH_PORT_RIGHT_DEAD_NAME, &dead);
639 ASSERT_EQ(kr, KERN_SUCCESS);
640 };
641
642 get_send_name_refs();
643 EXPECT_EQ(1u, send);
644 EXPECT_EQ(0u, dead);
645
646 // Add an extra send right.
647 ASSERT_EQ(KERN_SUCCESS, mach_port_mod_refs(mach_task_self(), send_name,
648 MACH_PORT_RIGHT_SEND, 1));
649 get_send_name_refs();
650 EXPECT_EQ(2u, send);
651 EXPECT_EQ(0u, dead);
Avi Drissmandd92b532023-08-16 22:26:17652 base::apple::ScopedMachSendRight extra_send(send_name);
Robert Sesek4bb92352020-01-23 22:46:08653
654 // Channel A gets created with the Mach send right from |platform_channel|.
655 CallbackChannelDelegate delegate_a;
656 scoped_refptr<Channel> channel_a = Channel::Create(
657 &delegate_a, ConnectionParams(platform_channel.TakeLocalEndpoint()),
658 Channel::HandlePolicy::kAcceptHandles,
Sean Maher5b9af51f2022-11-21 15:32:47659 base::SingleThreadTaskRunner::GetCurrentDefault());
Robert Sesek4bb92352020-01-23 22:46:08660 channel_a->Start();
661
662 // Channel B gets the receive right.
663 MockChannelDelegate delegate_b;
664 scoped_refptr<Channel> channel_b = Channel::Create(
665 &delegate_b, ConnectionParams(platform_channel.TakeRemoteEndpoint()),
666 Channel::HandlePolicy::kAcceptHandles, peer_thread.task_runner());
667 channel_b->Start();
668
669 // Ensure the channels have started and are talking.
Brian Geffon4e9b8442021-04-23 18:48:38670 channel_b->Write(Channel::Message::CreateMessage(0, 0));
Robert Sesek4bb92352020-01-23 22:46:08671
672 {
673 base::RunLoop loop;
674 delegate_a.set_on_message(loop.QuitClosure());
675 loop.Run();
676 }
677
678 // Queue two messages from B to A. Two are required so that channel A does
679 // not immediately process the dead-name notification when channel B shuts
680 // down.
Brian Geffon4e9b8442021-04-23 18:48:38681 channel_b->Write(Channel::Message::CreateMessage(0, 0));
682 channel_b->Write(Channel::Message::CreateMessage(0, 0));
Robert Sesek4bb92352020-01-23 22:46:08683
684 // Turn Channel A's send right into a dead name.
685 channel_b->ShutDown();
686 channel_b = nullptr;
687
688 // ShutDown() posts a task on the channel's TaskRunner, so wait for that
689 // to run.
690 base::WaitableEvent event;
691 peer_thread.task_runner()->PostTask(
692 FROM_HERE,
693 base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(&event)));
694 event.Wait();
695
696 // Force a send-to-dead-name on Channel A.
Brian Geffon4e9b8442021-04-23 18:48:38697 channel_a->Write(Channel::Message::CreateMessage(0, 0));
Robert Sesek4bb92352020-01-23 22:46:08698
699 {
700 base::RunLoop loop;
701 delegate_a.set_on_error(base::BindOnce(
702 [](scoped_refptr<Channel> channel, base::RunLoop* loop) {
703 channel->ShutDown();
704 channel = nullptr;
705 loop->QuitWhenIdle();
706 },
707 channel_a, base::Unretained(&loop)));
708 loop.Run();
709 }
710
711 // The only remaining ref should be the extra one that was added in the test.
712 get_send_name_refs();
713 EXPECT_EQ(0u, send);
714 EXPECT_EQ(1u, dead);
715}
Xiaohan Wangaa41c682022-01-14 18:50:49716#endif // BUILDFLAG(IS_MAC)
Robert Sesek4bb92352020-01-23 22:46:08717
Robert Sesekbd8a1e432022-11-15 18:02:26718TEST(ChannelTest, ShutDownStress) {
719 base::test::SingleThreadTaskEnvironment task_environment(
720 base::test::TaskEnvironment::MainThreadType::IO);
721
722 // Create a second IO thread for Channel B.
723 base::Thread peer_thread("channel_b_io");
724 peer_thread.StartWithOptions(
725 base::Thread::Options(base::MessagePumpType::IO, 0));
726
727 // Create two channels, A and B, which run on different threads.
728 PlatformChannel platform_channel;
729
730 CallbackChannelDelegate delegate_a;
731 scoped_refptr<Channel> channel_a = Channel::Create(
732 &delegate_a, ConnectionParams(platform_channel.TakeLocalEndpoint()),
733 Channel::HandlePolicy::kRejectHandles,
734 task_environment.GetMainThreadTaskRunner());
735 channel_a->Start();
736
737 scoped_refptr<Channel> channel_b = Channel::Create(
738 nullptr, ConnectionParams(platform_channel.TakeRemoteEndpoint()),
739 Channel::HandlePolicy::kRejectHandles, peer_thread.task_runner());
740 channel_b->Start();
741
742 base::WaitableEvent go_event;
743
744 // Warm up the channel to ensure that A and B are connected, then quit.
745 channel_b->Write(Channel::Message::CreateMessage(0, 0));
746 {
747 base::RunLoop run_loop;
748 delegate_a.set_on_message(run_loop.QuitClosure());
749 run_loop.Run();
750 }
751
752 // Block the peer thread while some tasks are queued up from the test main
753 // thread.
754 peer_thread.task_runner()->PostTask(
755 FROM_HERE,
756 base::BindOnce(&base::WaitableEvent::Wait, base::Unretained(&go_event)));
757
758 // First, write some messages for Channel B.
759 for (int i = 0; i < 500; ++i) {
760 channel_b->Write(Channel::Message::CreateMessage(0, 0));
761 }
762
763 // Then shut down channel B.
764 channel_b->ShutDown();
765
766 // Un-block the peer thread.
767 go_event.Signal();
768
769 // And then flood the channel with messages. This will suss out data races
770 // during Channel B's shutdown, since Writes can happen across threads
771 // without a PostTask.
772 for (int i = 0; i < 1000; ++i) {
773 channel_b->Write(Channel::Message::CreateMessage(0, 0));
774 }
775
776 // Explicitly join the thread to wait for pending tasks, which may reference
777 // stack variables, to complete.
778 peer_thread.Stop();
779}
780
jcivelli823ec062017-03-01 03:13:49781} // namespace
Ken Rockotdba46db2018-07-04 18:41:04782} // namespace core
jcivelli823ec062017-03-01 03:13:49783} // namespace mojo