Avi Drissman | d387f092 | 2022-09-14 20:51:31 | [diff] [blame] | 1 | // Copyright 2017 The Chromium Authors |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Ken Rockot | dba46db | 2018-07-04 18:41:04 | [diff] [blame] | 5 | #include "mojo/core/channel.h" |
Wez | 3e64a8a | 2018-03-13 05:36:06 | [diff] [blame] | 6 | |
Robert Sesek | 842a48e | 2019-04-02 00:16:18 | [diff] [blame] | 7 | #include <atomic> |
| 8 | |
Avi Drissman | d70f89a | 2023-01-11 23:52:55 | [diff] [blame] | 9 | #include "base/functional/bind.h" |
Lei Zhang | 425893e | 2021-05-14 23:28:25 | [diff] [blame] | 10 | #include "base/memory/page_size.h" |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 11 | #include "base/memory/ptr_util.h" |
Carlos Caballero | dd8bf7b0 | 2019-07-30 14:14:15 | [diff] [blame] | 12 | #include "base/message_loop/message_pump_type.h" |
Ken Rockot | cc6cad3d | 2019-01-24 23:05:35 | [diff] [blame] | 13 | #include "base/process/process_handle.h" |
Ken Rockot | fada5812 | 2018-12-11 16:49:54 | [diff] [blame] | 14 | #include "base/run_loop.h" |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 15 | #include "base/strings/stringprintf.h" |
Sean Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 16 | #include "base/task/single_thread_task_runner.h" |
Guido Urdaneta | ef4e9194 | 2020-11-09 15:06:24 | [diff] [blame] | 17 | #include "base/test/bind.h" |
Carlos Caballero | 631413d | 2019-12-03 07:39:39 | [diff] [blame] | 18 | #include "base/test/task_environment.h" |
Wez | 3e64a8a | 2018-03-13 05:36:06 | [diff] [blame] | 19 | #include "base/threading/thread.h" |
Ken Rockot | 0321c39 | 2019-06-04 20:37:36 | [diff] [blame] | 20 | #include "build/build_config.h" |
Ken Rockot | dba46db | 2018-07-04 18:41:04 | [diff] [blame] | 21 | #include "mojo/core/platform_handle_utils.h" |
Ken Rockot | 6a6dca0f | 2018-06-22 18:41:07 | [diff] [blame] | 22 | #include "mojo/public/cpp/platform/platform_channel.h" |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 23 | #include "testing/gmock/include/gmock/gmock.h" |
| 24 | #include "testing/gtest/include/gtest/gtest.h" |
Anton Bikineev | 60ef381 | 2021-05-15 18:05:03 | [diff] [blame] | 25 | #include "third_party/abseil-cpp/absl/types/optional.h" |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 26 | |
| 27 | namespace mojo { |
Ken Rockot | dba46db | 2018-07-04 18:41:04 | [diff] [blame] | 28 | namespace core { |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 29 | namespace { |
| 30 | |
| 31 | class TestChannel : public Channel { |
| 32 | public: |
Ken Rockot | fada5812 | 2018-12-11 16:49:54 | [diff] [blame] | 33 | TestChannel(Channel::Delegate* delegate) |
| 34 | : Channel(delegate, Channel::HandlePolicy::kAcceptHandles) {} |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 35 | |
| 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 Rockot | 043152da6 | 2018-06-29 03:22:16 | [diff] [blame] | 44 | MOCK_METHOD7(GetReadPlatformHandles, |
Ken Rockot | 0e45f80 | 2018-06-27 23:56:01 | [diff] [blame] | 45 | bool(const void* payload, |
| 46 | size_t payload_size, |
| 47 | size_t num_handles, |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 48 | const void* extra_header, |
| 49 | size_t extra_header_size, |
Ken Rockot | 043152da6 | 2018-06-29 03:22:16 | [diff] [blame] | 50 | std::vector<PlatformHandle>* handles, |
Ken Rockot | 0e45f80 | 2018-06-27 23:56:01 | [diff] [blame] | 51 | bool* deferred)); |
Ken Rockot | 36d44a57 | 2022-08-15 23:19:57 | [diff] [blame] | 52 | MOCK_METHOD2(GetReadPlatformHandlesForIpcz, |
| 53 | bool(size_t, std::vector<PlatformHandle>&)); |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 54 | MOCK_METHOD0(Start, void()); |
| 55 | MOCK_METHOD0(ShutDownImpl, void()); |
| 56 | MOCK_METHOD0(LeakHandle, void()); |
| 57 | |
Daniel Cheng | a2e3f7a | 2018-04-30 17:33:56 | [diff] [blame] | 58 | void Write(MessagePtr message) override {} |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 59 | |
| 60 | protected: |
Anand K Mistry | 48d93df | 2020-06-18 00:04:22 | [diff] [blame] | 61 | ~TestChannel() override = default; |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 62 | }; |
| 63 | |
| 64 | // Not using GMock as I don't think it supports movable types. |
| 65 | class MockChannelDelegate : public Channel::Delegate { |
| 66 | public: |
Anand K Mistry | 48d93df | 2020-06-18 00:04:22 | [diff] [blame] | 67 | MockChannelDelegate() = default; |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 68 | |
| 69 | size_t GetReceivedPayloadSize() const { return payload_size_; } |
| 70 | |
| 71 | const void* GetReceivedPayload() const { return payload_.get(); } |
| 72 | |
| 73 | protected: |
Ken Rockot | 043152da6 | 2018-06-29 03:22:16 | [diff] [blame] | 74 | void OnChannelMessage(const void* payload, |
| 75 | size_t payload_size, |
| 76 | std::vector<PlatformHandle> handles) override { |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 77 | 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 Rockot | 7f49ca4 | 2017-07-13 00:17:26 | [diff] [blame] | 83 | void OnChannelError(Channel::Error error) override {} |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 84 | |
| 85 | private: |
| 86 | size_t payload_size_ = 0; |
| 87 | std::unique_ptr<char[]> payload_; |
| 88 | }; |
| 89 | |
| 90 | Channel::MessagePtr CreateDefaultMessage(bool legacy_message) { |
| 91 | const size_t payload_size = 100; |
Brian Geffon | 4e9b844 | 2021-04-23 18:48:38 | [diff] [blame] | 92 | Channel::MessagePtr message = Channel::Message::CreateMessage( |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 93 | 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 | |
| 103 | void 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 | |
| 116 | void 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 | |
| 138 | TEST(ChannelTest, LegacyMessageDeserialization) { |
| 139 | Channel::MessagePtr message = CreateDefaultMessage(true /* legacy_message */); |
| 140 | Channel::MessagePtr deserialized_message = |
Ken Rockot | d62bb30 | 2021-06-16 22:09:35 | [diff] [blame] | 141 | Channel::Message::Deserialize(message->data(), message->data_num_bytes(), |
| 142 | Channel::HandlePolicy::kAcceptHandles); |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 143 | TestMessagesAreEqual(message.get(), deserialized_message.get(), |
| 144 | true /* legacy_message */); |
| 145 | } |
| 146 | |
| 147 | TEST(ChannelTest, NonLegacyMessageDeserialization) { |
| 148 | Channel::MessagePtr message = |
| 149 | CreateDefaultMessage(false /* legacy_message */); |
| 150 | Channel::MessagePtr deserialized_message = |
Ken Rockot | d62bb30 | 2021-06-16 22:09:35 | [diff] [blame] | 151 | Channel::Message::Deserialize(message->data(), message->data_num_bytes(), |
| 152 | Channel::HandlePolicy::kAcceptHandles); |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 153 | TestMessagesAreEqual(message.get(), deserialized_message.get(), |
| 154 | false /* legacy_message */); |
| 155 | } |
| 156 | |
| 157 | TEST(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 | |
| 178 | TEST(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 | |
Wez | 3e64a8a | 2018-03-13 05:36:06 | [diff] [blame] | 200 | class ChannelTestShutdownAndWriteDelegate : public Channel::Delegate { |
| 201 | public: |
| 202 | ChannelTestShutdownAndWriteDelegate( |
Ken Rockot | 29b0a32 | 2018-06-29 17:38:07 | [diff] [blame] | 203 | PlatformChannelEndpoint endpoint, |
Gabriel Charette | e926fc1 | 2019-12-16 19:00:02 | [diff] [blame] | 204 | scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
Wez | 3e64a8a | 2018-03-13 05:36:06 | [diff] [blame] | 205 | 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 Rockot | 29b0a32 | 2018-06-29 17:38:07 | [diff] [blame] | 211 | channel_ = Channel::Create(this, ConnectionParams(std::move(endpoint)), |
Ken Rockot | fada5812 | 2018-12-11 16:49:54 | [diff] [blame] | 212 | Channel::HandlePolicy::kAcceptHandles, |
Ken Rockot | 5732c6d4 | 2018-06-22 17:43:38 | [diff] [blame] | 213 | std::move(task_runner)); |
Wez | 3e64a8a | 2018-03-13 05:36:06 | [diff] [blame] | 214 | channel_->Start(); |
| 215 | } |
| 216 | ~ChannelTestShutdownAndWriteDelegate() override { channel_->ShutDown(); } |
| 217 | |
| 218 | // Channel::Delegate implementation |
Ken Rockot | 043152da6 | 2018-06-29 03:22:16 | [diff] [blame] | 219 | void OnChannelMessage(const void* payload, |
| 220 | size_t payload_size, |
| 221 | std::vector<PlatformHandle> handles) override { |
Wez | 3e64a8a | 2018-03-13 05:36:06 | [diff] [blame] | 222 | ++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. Mistry | 4780268 | 2019-11-06 00:58:24 | [diff] [blame] | 229 | FROM_HERE, |
| 230 | base::BindOnce(&Channel::Write, client_channel_, std::move(message))); |
Wez | 3e64a8a | 2018-03-13 05:36:06 | [diff] [blame] | 231 | |
| 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 | |
| 259 | TEST(ChannelTest, PeerShutdownDuringRead) { |
Carlos Caballero | 631413d | 2019-12-03 07:39:39 | [diff] [blame] | 260 | base::test::SingleThreadTaskEnvironment task_environment( |
| 261 | base::test::TaskEnvironment::MainThreadType::IO); |
Ken Rockot | 6a6dca0f | 2018-06-22 18:41:07 | [diff] [blame] | 262 | PlatformChannel channel; |
Wez | 3e64a8a | 2018-03-13 05:36:06 | [diff] [blame] | 263 | |
| 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 Caballero | dd8bf7b0 | 2019-07-30 14:14:15 | [diff] [blame] | 268 | base::Thread::Options(base::MessagePumpType::IO, 0)); |
Wez | 3e64a8a | 2018-03-13 05:36:06 | [diff] [blame] | 269 | |
Ken Rockot | fada5812 | 2018-12-11 16:49:54 | [diff] [blame] | 270 | scoped_refptr<Channel> client_channel = Channel::Create( |
| 271 | nullptr, ConnectionParams(channel.TakeRemoteEndpoint()), |
| 272 | Channel::HandlePolicy::kAcceptHandles, client_thread->task_runner()); |
Wez | 3e64a8a | 2018-03-13 05:36:06 | [diff] [blame] | 273 | 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. Mistry | 4780268 | 2019-11-06 00:58:24 | [diff] [blame] | 279 | base::BindOnce(&Channel::Write, client_channel, std::move(message))); |
Wez | 3e64a8a | 2018-03-13 05:36:06 | [diff] [blame] | 280 | |
| 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 Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 287 | channel.TakeLocalEndpoint(), |
| 288 | base::SingleThreadTaskRunner::GetCurrentDefault(), |
Ken Rockot | 29b0a32 | 2018-06-29 17:38:07 | [diff] [blame] | 289 | std::move(client_channel), std::move(client_thread), |
| 290 | run_loop.QuitClosure()); |
Wez | 3e64a8a | 2018-03-13 05:36:06 | [diff] [blame] | 291 | |
| 292 | run_loop.Run(); |
| 293 | } |
| 294 | |
Ken Rockot | fada5812 | 2018-12-11 16:49:54 | [diff] [blame] | 295 | class RejectHandlesDelegate : public Channel::Delegate { |
| 296 | public: |
| 297 | RejectHandlesDelegate() = default; |
| 298 | |
Peter Boström | feef05a | 2021-10-05 21:35:08 | [diff] [blame] | 299 | RejectHandlesDelegate(const RejectHandlesDelegate&) = delete; |
| 300 | RejectHandlesDelegate& operator=(const RejectHandlesDelegate&) = delete; |
| 301 | |
Ken Rockot | fada5812 | 2018-12-11 16:49:54 | [diff] [blame] | 302 | 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 Bikineev | 60ef381 | 2021-05-15 18:05:03 | [diff] [blame] | 323 | absl::optional<base::RunLoop> wait_for_error_loop_; |
Ken Rockot | fada5812 | 2018-12-11 16:49:54 | [diff] [blame] | 324 | }; |
| 325 | |
| 326 | TEST(ChannelTest, RejectHandles) { |
Carlos Caballero | 631413d | 2019-12-03 07:39:39 | [diff] [blame] | 327 | base::test::SingleThreadTaskEnvironment task_environment( |
| 328 | base::test::TaskEnvironment::MainThreadType::IO); |
Ken Rockot | fada5812 | 2018-12-11 16:49:54 | [diff] [blame] | 329 | PlatformChannel platform_channel; |
| 330 | |
| 331 | RejectHandlesDelegate receiver_delegate; |
Carlos Caballero | 631413d | 2019-12-03 07:39:39 | [diff] [blame] | 332 | scoped_refptr<Channel> receiver = |
| 333 | Channel::Create(&receiver_delegate, |
| 334 | ConnectionParams(platform_channel.TakeLocalEndpoint()), |
| 335 | Channel::HandlePolicy::kRejectHandles, |
Sean Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 336 | base::SingleThreadTaskRunner::GetCurrentDefault()); |
Ken Rockot | fada5812 | 2018-12-11 16:49:54 | [diff] [blame] | 337 | receiver->Start(); |
| 338 | |
| 339 | RejectHandlesDelegate sender_delegate; |
| 340 | scoped_refptr<Channel> sender = Channel::Create( |
| 341 | &sender_delegate, ConnectionParams(platform_channel.TakeRemoteEndpoint()), |
Carlos Caballero | 631413d | 2019-12-03 07:39:39 | [diff] [blame] | 342 | Channel::HandlePolicy::kRejectHandles, |
Sean Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 343 | base::SingleThreadTaskRunner::GetCurrentDefault()); |
Ken Rockot | fada5812 | 2018-12-11 16:49:54 | [diff] [blame] | 344 | 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 Geffon | 4e9b844 | 2021-04-23 18:48:38 | [diff] [blame] | 353 | auto message = Channel::Message::CreateMessage(0 /* payload_size */, |
| 354 | 1 /* max_handles */); |
Ken Rockot | fada5812 | 2018-12-11 16:49:54 | [diff] [blame] | 355 | 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 Rockot | cc6cad3d | 2019-01-24 23:05:35 | [diff] [blame] | 362 | TEST(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 Rockot | d62bb30 | 2021-06-16 22:09:35 | [diff] [blame] | 379 | EXPECT_EQ(nullptr, |
| 380 | Channel::Message::Deserialize(&message[0], kMessageSize, |
| 381 | Channel::HandlePolicy::kAcceptHandles, |
| 382 | base::kNullProcessHandle)); |
Ken Rockot | cc6cad3d | 2019-01-24 23:05:35 | [diff] [blame] | 383 | } |
| 384 | |
Fabrice de Gans | cc2c487 | 2022-02-25 15:01:57 | [diff] [blame] | 385 | // This test is only enabled for Linux-based platforms. |
Xiaohan Wang | aa41c68 | 2022-01-14 18:50:49 | [diff] [blame] | 386 | #if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_FUCHSIA) |
Ken Rockot | 0321c39 | 2019-06-04 20:37:36 | [diff] [blame] | 387 | TEST(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 Rockot | d62bb30 | 2021-06-16 22:09:35 | [diff] [blame] | 403 | EXPECT_EQ(nullptr, |
| 404 | Channel::Message::Deserialize(&message[0], kMessageSize, |
| 405 | Channel::HandlePolicy::kAcceptHandles, |
| 406 | base::kNullProcessHandle)); |
Ken Rockot | 0321c39 | 2019-06-04 20:37:36 | [diff] [blame] | 407 | } |
| 408 | #endif |
| 409 | |
Robert Sesek | 842a48e | 2019-04-02 00:16:18 | [diff] [blame] | 410 | class 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 | |
| 440 | TEST(ChannelTest, PeerStressTest) { |
| 441 | constexpr size_t kLotsOfMessages = 1024; |
| 442 | |
Carlos Caballero | 631413d | 2019-12-03 07:39:39 | [diff] [blame] | 443 | base::test::SingleThreadTaskEnvironment task_environment( |
| 444 | base::test::TaskEnvironment::MainThreadType::IO); |
Robert Sesek | 842a48e | 2019-04-02 00:16:18 | [diff] [blame] | 445 | 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 Caballero | dd8bf7b0 | 2019-07-30 14:14:15 | [diff] [blame] | 463 | thread_options.message_pump_type = base::MessagePumpType::IO; |
Robert Sesek | 842a48e | 2019-04-02 00:16:18 | [diff] [blame] | 464 | base::Thread peer_thread("peer_b_io"); |
Olivier Li | c421c6d | 2021-05-12 05:12:57 | [diff] [blame] | 465 | peer_thread.StartWithOptions(std::move(thread_options)); |
Robert Sesek | 842a48e | 2019-04-02 00:16:18 | [diff] [blame] | 466 | |
| 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 Caballero | 631413d | 2019-12-03 07:39:39 | [diff] [blame] | 474 | Channel::HandlePolicy::kRejectHandles, |
Sean Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 475 | base::SingleThreadTaskRunner::GetCurrentDefault()); |
Robert Sesek | 842a48e | 2019-04-02 00:16:18 | [diff] [blame] | 476 | |
| 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 Geffon | 4e9b844 | 2021-04-23 18:48:38 | [diff] [blame] | 486 | channel->Write(Channel::Message::CreateMessage(0, 0)); |
Robert Sesek | 842a48e | 2019-04-02 00:16:18 | [diff] [blame] | 487 | } |
| 488 | }; |
| 489 | auto send_final_message = [](scoped_refptr<Channel> channel) { |
Brian Geffon | 4e9b844 | 2021-04-23 18:48:38 | [diff] [blame] | 490 | auto message = Channel::Message::CreateMessage(1, 0); |
Robert Sesek | 842a48e | 2019-04-02 00:16:18 | [diff] [blame] | 491 | 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 Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 502 | base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( |
Robert Sesek | 842a48e | 2019-04-02 00:16:18 | [diff] [blame] | 503 | FROM_HERE, base::BindOnce(send_lots_of_messages, channel_a)); |
Sean Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 504 | base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( |
Robert Sesek | 842a48e | 2019-04-02 00:16:18 | [diff] [blame] | 505 | FROM_HERE, base::BindOnce(send_lots_of_messages, channel_a)); |
Sean Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 506 | base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( |
Robert Sesek | 842a48e | 2019-04-02 00:16:18 | [diff] [blame] | 507 | 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 Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 533 | class CallbackChannelDelegate : public Channel::Delegate { |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 534 | public: |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 535 | CallbackChannelDelegate() = default; |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 536 | |
Peter Boström | feef05a | 2021-10-05 21:35:08 | [diff] [blame] | 537 | CallbackChannelDelegate(const CallbackChannelDelegate&) = delete; |
| 538 | CallbackChannelDelegate& operator=(const CallbackChannelDelegate&) = delete; |
| 539 | |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 540 | void OnChannelMessage(const void* payload, |
| 541 | size_t payload_size, |
| 542 | std::vector<PlatformHandle> handles) override { |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 543 | if (on_message_) |
| 544 | std::move(on_message_).Run(); |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 545 | } |
| 546 | |
| 547 | void OnChannelError(Channel::Error error) override { |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 548 | if (on_error_) |
| 549 | std::move(on_error_).Run(); |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 550 | } |
| 551 | |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 552 | void set_on_message(base::OnceClosure on_message) { |
| 553 | on_message_ = std::move(on_message); |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 554 | } |
| 555 | |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 556 | void set_on_error(base::OnceClosure on_error) { |
| 557 | on_error_ = std::move(on_error); |
| 558 | } |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 559 | |
| 560 | private: |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 561 | base::OnceClosure on_message_; |
| 562 | base::OnceClosure on_error_; |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 563 | }; |
| 564 | |
| 565 | TEST(ChannelTest, MessageSizeTest) { |
Carlos Caballero | 631413d | 2019-12-03 07:39:39 | [diff] [blame] | 566 | base::test::SingleThreadTaskEnvironment task_environment( |
| 567 | base::test::TaskEnvironment::MainThreadType::IO); |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 568 | PlatformChannel platform_channel; |
| 569 | |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 570 | CallbackChannelDelegate receiver_delegate; |
Carlos Caballero | 631413d | 2019-12-03 07:39:39 | [diff] [blame] | 571 | scoped_refptr<Channel> receiver = |
| 572 | Channel::Create(&receiver_delegate, |
| 573 | ConnectionParams(platform_channel.TakeLocalEndpoint()), |
| 574 | Channel::HandlePolicy::kAcceptHandles, |
Sean Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 575 | base::SingleThreadTaskRunner::GetCurrentDefault()); |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 576 | receiver->Start(); |
| 577 | |
| 578 | MockChannelDelegate sender_delegate; |
| 579 | scoped_refptr<Channel> sender = Channel::Create( |
| 580 | &sender_delegate, ConnectionParams(platform_channel.TakeRemoteEndpoint()), |
Carlos Caballero | 631413d | 2019-12-03 07:39:39 | [diff] [blame] | 581 | Channel::HandlePolicy::kAcceptHandles, |
Sean Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 582 | base::SingleThreadTaskRunner::GetCurrentDefault()); |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 583 | 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 Geffon | 4e9b844 | 2021-04-23 18:48:38 | [diff] [blame] | 588 | auto message = Channel::Message::CreateMessage(i, 0); |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 589 | memset(message->mutable_payload(), 0xAB, i); |
| 590 | sender->Write(std::move(message)); |
| 591 | |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 592 | bool got_message = false, got_error = false; |
| 593 | |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 594 | base::RunLoop loop; |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 595 | 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 Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 605 | loop.Run(); |
| 606 | |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 607 | EXPECT_TRUE(got_message); |
| 608 | EXPECT_FALSE(got_error); |
Robert Sesek | b9f54dd | 2019-06-13 15:00:38 | [diff] [blame] | 609 | } |
| 610 | } |
| 611 | |
Xiaohan Wang | aa41c68 | 2022-01-14 18:50:49 | [diff] [blame] | 612 | #if BUILDFLAG(IS_MAC) |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 613 | TEST(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 Li | c421c6d | 2021-05-12 05:12:57 | [diff] [blame] | 622 | peer_thread.StartWithOptions(std::move(thread_options)); |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 623 | |
| 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 Drissman | dd92b53 | 2023-08-16 22:26:17 | [diff] [blame] | 652 | base::apple::ScopedMachSendRight extra_send(send_name); |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 653 | |
| 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 Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 659 | base::SingleThreadTaskRunner::GetCurrentDefault()); |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 660 | 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 Geffon | 4e9b844 | 2021-04-23 18:48:38 | [diff] [blame] | 670 | channel_b->Write(Channel::Message::CreateMessage(0, 0)); |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 671 | |
| 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 Geffon | 4e9b844 | 2021-04-23 18:48:38 | [diff] [blame] | 681 | channel_b->Write(Channel::Message::CreateMessage(0, 0)); |
| 682 | channel_b->Write(Channel::Message::CreateMessage(0, 0)); |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 683 | |
| 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 Geffon | 4e9b844 | 2021-04-23 18:48:38 | [diff] [blame] | 697 | channel_a->Write(Channel::Message::CreateMessage(0, 0)); |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 698 | |
| 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 Wang | aa41c68 | 2022-01-14 18:50:49 | [diff] [blame] | 716 | #endif // BUILDFLAG(IS_MAC) |
Robert Sesek | 4bb9235 | 2020-01-23 22:46:08 | [diff] [blame] | 717 | |
Robert Sesek | bd8a1e43 | 2022-11-15 18:02:26 | [diff] [blame] | 718 | TEST(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 | |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 781 | } // namespace |
Ken Rockot | dba46db | 2018-07-04 18:41:04 | [diff] [blame] | 782 | } // namespace core |
jcivelli | 823ec06 | 2017-03-01 03:13:49 | [diff] [blame] | 783 | } // namespace mojo |