// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ipc/ipc_channel_mojo.h" #include #include #include #include #include "base/base_paths.h" #include "base/bind.h" #include "base/callback_helpers.h" #include "base/containers/queue.h" #include "base/files/file.h" #include "base/files/scoped_temp_dir.h" #include "base/location.h" #include "base/memory/platform_shared_memory_region.h" #include "base/memory/raw_ptr.h" #include "base/memory/read_only_shared_memory_region.h" #include "base/memory/shared_memory_mapping.h" #include "base/memory/unsafe_shared_memory_region.h" #include "base/memory/writable_shared_memory_region.h" #include "base/message_loop/message_pump_type.h" #include "base/path_service.h" #include "base/pickle.h" #include "base/run_loop.h" #include "base/synchronization/waitable_event.h" #include "base/task/single_thread_task_runner.h" #include "base/test/bind.h" #include "base/test/task_environment.h" #include "base/test/test_io_thread.h" #include "base/test/test_shared_memory_util.h" #include "base/test/test_timeouts.h" #include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "ipc/ipc_message.h" #include "ipc/ipc_message_utils.h" #include "ipc/ipc_mojo_handle_attachment.h" #include "ipc/ipc_mojo_message_helper.h" #include "ipc/ipc_mojo_param_traits.h" #include "ipc/ipc_sync_channel.h" #include "ipc/ipc_sync_message.h" #include "ipc/ipc_test.mojom.h" #include "ipc/ipc_test_base.h" #include "ipc/ipc_test_channel_listener.h" #include "mojo/public/cpp/bindings/associated_receiver.h" #include "mojo/public/cpp/bindings/associated_remote.h" #include "mojo/public/cpp/bindings/lib/validation_errors.h" #include "mojo/public/cpp/bindings/pending_associated_receiver.h" #include "mojo/public/cpp/system/functions.h" #include "mojo/public/cpp/system/wait.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) #include "base/file_descriptor_posix.h" #include "ipc/ipc_platform_file_attachment_posix.h" #endif namespace { void SendString(IPC::Sender* sender, const std::string& str) { IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); message->WriteString(str); ASSERT_TRUE(sender->Send(message)); } void SendValue(IPC::Sender* sender, int32_t value) { IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); message->WriteInt(value); ASSERT_TRUE(sender->Send(message)); } class ListenerThatExpectsOK : public IPC::Listener { public: explicit ListenerThatExpectsOK(base::OnceClosure quit_closure) : received_ok_(false), quit_closure_(std::move(quit_closure)) {} ~ListenerThatExpectsOK() override = default; bool OnMessageReceived(const IPC::Message& message) override { base::PickleIterator iter(message); std::string should_be_ok; EXPECT_TRUE(iter.ReadString(&should_be_ok)); EXPECT_EQ(should_be_ok, "OK"); received_ok_ = true; std::move(quit_closure_).Run(); return true; } void OnChannelError() override { // The connection should be healthy while the listener is waiting // message. An error can occur after that because the peer // process dies. CHECK(received_ok_); } static void SendOK(IPC::Sender* sender) { SendString(sender, "OK"); } private: bool received_ok_; base::OnceClosure quit_closure_; }; class TestListenerBase : public IPC::Listener { public: explicit TestListenerBase(base::OnceClosure quit_closure) : quit_closure_(std::move(quit_closure)) {} ~TestListenerBase() override = default; void OnChannelError() override { RunQuitClosure(); } void set_sender(IPC::Sender* sender) { sender_ = sender; } IPC::Sender* sender() const { return sender_; } void RunQuitClosure() { if (quit_closure_) std::move(quit_closure_).Run(); } private: raw_ptr sender_ = nullptr; base::OnceClosure quit_closure_; }; using IPCChannelMojoTest = IPCChannelMojoTestBase; class TestChannelListenerWithExtraExpectations : public IPC::TestChannelListener { public: TestChannelListenerWithExtraExpectations() : is_connected_called_(false) {} void OnChannelConnected(int32_t peer_pid) override { IPC::TestChannelListener::OnChannelConnected(peer_pid); EXPECT_TRUE(base::kNullProcessId != peer_pid); is_connected_called_ = true; } bool is_connected_called() const { return is_connected_called_; } private: bool is_connected_called_; }; TEST_F(IPCChannelMojoTest, ConnectedFromClient) { Init("IPCChannelMojoTestClient"); // Set up IPC channel and start client. TestChannelListenerWithExtraExpectations listener; CreateChannel(&listener); listener.Init(sender()); ASSERT_TRUE(ConnectChannel()); IPC::TestChannelListener::SendOneMessage(sender(), "hello from parent"); base::RunLoop().Run(); channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); EXPECT_TRUE(listener.is_connected_called()); EXPECT_TRUE(listener.HasSentAll()); DestroyChannel(); } // A long running process that connects to us DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestClient) { TestChannelListenerWithExtraExpectations listener; Connect(&listener); listener.Init(channel()); IPC::TestChannelListener::SendOneMessage(channel(), "hello from child"); base::RunLoop().Run(); EXPECT_TRUE(listener.is_connected_called()); EXPECT_TRUE(listener.HasSentAll()); Close(); } class ListenerExpectingErrors : public TestListenerBase { public: ListenerExpectingErrors(base::OnceClosure quit_closure) : TestListenerBase(std::move(quit_closure)), has_error_(false) {} bool OnMessageReceived(const IPC::Message& message) override { return true; } void OnChannelError() override { has_error_ = true; TestListenerBase::OnChannelError(); } bool has_error() const { return has_error_; } private: bool has_error_; }; class ListenerThatQuits : public IPC::Listener { public: explicit ListenerThatQuits(base::OnceClosure quit_closure) : quit_closure_(std::move(quit_closure)) {} bool OnMessageReceived(const IPC::Message& message) override { return true; } void OnChannelConnected(int32_t peer_pid) override { std::move(quit_closure_).Run(); } private: base::OnceClosure quit_closure_; }; // A long running process that connects to us. DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoErraticTestClient) { base::RunLoop run_loop; ListenerThatQuits listener(run_loop.QuitClosure()); Connect(&listener); run_loop.Run(); Close(); } TEST_F(IPCChannelMojoTest, SendFailWithPendingMessages) { Init("IPCChannelMojoErraticTestClient"); // Set up IPC channel and start client. base::RunLoop run_loop; ListenerExpectingErrors listener(run_loop.QuitClosure()); CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); // This matches a value in mojo/edk/system/constants.h const int kMaxMessageNumBytes = 4 * 1024 * 1024; std::string overly_large_data(kMaxMessageNumBytes, '*'); // This messages are queued as pending. for (size_t i = 0; i < 10; ++i) { IPC::TestChannelListener::SendOneMessage(sender(), overly_large_data.c_str()); } run_loop.Run(); channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); EXPECT_TRUE(listener.has_error()); DestroyChannel(); } class ListenerThatBindsATestStructPasser : public IPC::Listener, public IPC::mojom::TestStructPasser { public: ListenerThatBindsATestStructPasser() = default; ~ListenerThatBindsATestStructPasser() override = default; bool OnMessageReceived(const IPC::Message& message) override { return true; } void OnChannelConnected(int32_t peer_pid) override {} void OnChannelError() override { NOTREACHED(); } void OnAssociatedInterfaceRequest( const std::string& interface_name, mojo::ScopedInterfaceEndpointHandle handle) override { CHECK_EQ(interface_name, IPC::mojom::TestStructPasser::Name_); receiver_.Bind( mojo::PendingAssociatedReceiver( std::move(handle))); } private: // IPC::mojom::TestStructPasser: void Pass(IPC::mojom::TestStructPtr) override { NOTREACHED(); } mojo::AssociatedReceiver receiver_{this}; }; class ListenerThatExpectsNoError : public IPC::Listener { public: ListenerThatExpectsNoError(base::OnceClosure connect_closure, base::OnceClosure quit_closure) : connect_closure_(std::move(connect_closure)), quit_closure_(std::move(quit_closure)) {} bool OnMessageReceived(const IPC::Message& message) override { base::PickleIterator iter(message); std::string should_be_ok; EXPECT_TRUE(iter.ReadString(&should_be_ok)); EXPECT_EQ(should_be_ok, "OK"); std::move(quit_closure_).Run(); return true; } void OnChannelConnected(int32_t peer_pid) override { std::move(connect_closure_).Run(); } void OnChannelError() override { NOTREACHED(); } private: base::OnceClosure connect_closure_; base::OnceClosure quit_closure_; }; DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT( IPCChannelMojoNoImplicitChanelClosureClient) { base::RunLoop wait_to_connect_loop; base::RunLoop wait_to_quit_loop; ListenerThatExpectsNoError listener(wait_to_connect_loop.QuitClosure(), wait_to_quit_loop.QuitClosure()); Connect(&listener); wait_to_connect_loop.Run(); mojo::AssociatedRemote passer; channel()->GetAssociatedInterfaceSupport()->GetRemoteAssociatedInterface( passer.BindNewEndpointAndPassReceiver()); // This avoids hitting DCHECKs in the serialization code meant to stop us from // making such "mistakes" as the one we're about to make below. mojo::internal::SerializationWarningObserverForTesting suppress_those_dchecks; // Send an invalid message. The TestStruct argument is not allowed to be null. // This will elicit a validation error in the parent process, but should not // actually disconnect the channel. passer->Pass(nullptr); // Wait until the parent says it's OK to quit, so it has time to verify its // expected behavior. wait_to_quit_loop.Run(); Close(); } TEST_F(IPCChannelMojoTest, NoImplicitChannelClosure) { // Verifies that OnChannelError is not invoked due to conditions other than // peer closure (e.g. a malformed inbound message). Instead we should always // be able to handle validation errors via Mojo bad message reporting. // NOTE: We can't create a RunLoop before Init() is called, but we have to set // the default ProcessErrorCallback (which we want to reference the RunLoop) // before Init() launches a child process. Hence the absl::optional here. absl::optional wait_for_error_loop; bool process_error_received = false; mojo::SetDefaultProcessErrorHandler( base::BindLambdaForTesting([&](const std::string&) { process_error_received = true; wait_for_error_loop->Quit(); })); Init("IPCChannelMojoNoImplicitChanelClosureClient"); wait_for_error_loop.emplace(); ListenerThatBindsATestStructPasser listener; CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); wait_for_error_loop->Run(); EXPECT_TRUE(process_error_received); mojo::SetDefaultProcessErrorHandler(base::NullCallback()); // Tell the child it can quit and wait for it to shut down. ListenerThatExpectsOK::SendOK(channel()); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); } struct TestingMessagePipe { TestingMessagePipe() { EXPECT_EQ(MOJO_RESULT_OK, mojo::CreateMessagePipe(nullptr, &self, &peer)); } mojo::ScopedMessagePipeHandle self; mojo::ScopedMessagePipeHandle peer; }; class HandleSendingHelper { public: static std::string GetSendingFileContent() { return "Hello"; } static void WritePipe(IPC::Message* message, TestingMessagePipe* pipe) { std::string content = HandleSendingHelper::GetSendingFileContent(); EXPECT_EQ(MOJO_RESULT_OK, mojo::WriteMessageRaw(pipe->self.get(), &content[0], static_cast(content.size()), nullptr, 0, 0)); EXPECT_TRUE(IPC::MojoMessageHelper::WriteMessagePipeTo( message, std::move(pipe->peer))); } static void WritePipeThenSend(IPC::Sender* sender, TestingMessagePipe* pipe) { IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); WritePipe(message, pipe); ASSERT_TRUE(sender->Send(message)); } static void ReadReceivedPipe(const IPC::Message& message, base::PickleIterator* iter) { mojo::ScopedMessagePipeHandle pipe; EXPECT_TRUE( IPC::MojoMessageHelper::ReadMessagePipeFrom(&message, iter, &pipe)); std::vector content; ASSERT_EQ(MOJO_RESULT_OK, mojo::Wait(pipe.get(), MOJO_HANDLE_SIGNAL_READABLE)); EXPECT_EQ(MOJO_RESULT_OK, mojo::ReadMessageRaw(pipe.get(), &content, nullptr, 0)); EXPECT_EQ(std::string(content.begin(), content.end()), GetSendingFileContent()); } #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) static base::FilePath GetSendingFilePath(const base::FilePath& dir_path) { return dir_path.Append("ListenerThatExpectsFile.txt"); } static void WriteFile(IPC::Message* message, base::File& file) { std::string content = GetSendingFileContent(); file.WriteAtCurrentPos(content.data(), content.size()); file.Flush(); message->WriteAttachment(new IPC::internal::PlatformFileAttachment( base::ScopedFD(file.TakePlatformFile()))); } static void WriteFileThenSend(IPC::Sender* sender, base::File& file) { IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); WriteFile(message, file); ASSERT_TRUE(sender->Send(message)); } static void WriteFileAndPipeThenSend(IPC::Sender* sender, base::File& file, TestingMessagePipe* pipe) { IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); WriteFile(message, file); WritePipe(message, pipe); ASSERT_TRUE(sender->Send(message)); } static void ReadReceivedFile(const IPC::Message& message, base::PickleIterator* iter) { scoped_refptr attachment; EXPECT_TRUE(message.ReadAttachment(iter, &attachment)); EXPECT_EQ( IPC::MessageAttachment::Type::PLATFORM_FILE, static_cast(attachment.get())->GetType()); base::File file( static_cast(attachment.get()) ->TakePlatformFile()); std::string content(GetSendingFileContent().size(), ' '); file.Read(0, &content[0], content.size()); EXPECT_EQ(content, GetSendingFileContent()); } #endif }; class ListenerThatExpectsMessagePipe : public TestListenerBase { public: ListenerThatExpectsMessagePipe(base::OnceClosure quit_closure) : TestListenerBase(std::move(quit_closure)) {} ~ListenerThatExpectsMessagePipe() override = default; bool OnMessageReceived(const IPC::Message& message) override { base::PickleIterator iter(message); HandleSendingHelper::ReadReceivedPipe(message, &iter); ListenerThatExpectsOK::SendOK(sender()); return true; } }; TEST_F(IPCChannelMojoTest, SendMessagePipe) { Init("IPCChannelMojoTestSendMessagePipeClient"); base::RunLoop run_loop; ListenerThatExpectsOK listener(run_loop.QuitClosure()); CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); TestingMessagePipe pipe; HandleSendingHelper::WritePipeThenSend(channel(), &pipe); run_loop.Run(); channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); } DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestSendMessagePipeClient) { base::RunLoop run_loop; ListenerThatExpectsMessagePipe listener(run_loop.QuitClosure()); Connect(&listener); listener.set_sender(channel()); run_loop.Run(); Close(); } void ReadOK(mojo::MessagePipeHandle pipe) { std::vector should_be_ok; CHECK_EQ(MOJO_RESULT_OK, mojo::Wait(pipe, MOJO_HANDLE_SIGNAL_READABLE)); CHECK_EQ(MOJO_RESULT_OK, mojo::ReadMessageRaw(pipe, &should_be_ok, nullptr, 0)); EXPECT_EQ("OK", std::string(should_be_ok.begin(), should_be_ok.end())); } void WriteOK(mojo::MessagePipeHandle pipe) { std::string ok("OK"); CHECK_EQ(MOJO_RESULT_OK, mojo::WriteMessageRaw(pipe, &ok[0], static_cast(ok.size()), nullptr, 0, 0)); } class ListenerThatExpectsMessagePipeUsingParamTrait : public TestListenerBase { public: explicit ListenerThatExpectsMessagePipeUsingParamTrait( base::OnceClosure quit_closure, bool receiving_valid) : TestListenerBase(std::move(quit_closure)), receiving_valid_(receiving_valid) {} ~ListenerThatExpectsMessagePipeUsingParamTrait() override = default; bool OnMessageReceived(const IPC::Message& message) override { base::PickleIterator iter(message); mojo::MessagePipeHandle handle; EXPECT_TRUE(IPC::ParamTraits::Read(&message, &iter, &handle)); EXPECT_EQ(handle.is_valid(), receiving_valid_); if (receiving_valid_) { ReadOK(handle); MojoClose(handle.value()); } ListenerThatExpectsOK::SendOK(sender()); return true; } private: bool receiving_valid_; }; class ParamTraitMessagePipeClient : public IpcChannelMojoTestClient { public: void RunTest(bool receiving_valid_handle) { base::RunLoop run_loop; ListenerThatExpectsMessagePipeUsingParamTrait listener( run_loop.QuitClosure(), receiving_valid_handle); Connect(&listener); listener.set_sender(channel()); run_loop.Run(); Close(); } }; TEST_F(IPCChannelMojoTest, ParamTraitValidMessagePipe) { Init("ParamTraitValidMessagePipeClient"); base::RunLoop run_loop; ListenerThatExpectsOK listener(run_loop.QuitClosure()); CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); TestingMessagePipe pipe; std::unique_ptr message(new IPC::Message()); IPC::ParamTraits::Write(message.get(), pipe.peer.release()); WriteOK(pipe.self.get()); channel()->Send(message.release()); run_loop.Run(); channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); } DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE( ParamTraitValidMessagePipeClient, ParamTraitMessagePipeClient) { RunTest(true); } TEST_F(IPCChannelMojoTest, ParamTraitInvalidMessagePipe) { Init("ParamTraitInvalidMessagePipeClient"); base::RunLoop run_loop; ListenerThatExpectsOK listener(run_loop.QuitClosure()); CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); mojo::MessagePipeHandle invalid_handle; std::unique_ptr message(new IPC::Message()); IPC::ParamTraits::Write(message.get(), invalid_handle); channel()->Send(message.release()); run_loop.Run(); channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); } DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE( ParamTraitInvalidMessagePipeClient, ParamTraitMessagePipeClient) { RunTest(false); } TEST_F(IPCChannelMojoTest, SendFailAfterClose) { Init("IPCChannelMojoTestSendOkClient"); base::RunLoop run_loop; ListenerThatExpectsOK listener(run_loop.QuitClosure()); CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); run_loop.Run(); channel()->Close(); ASSERT_FALSE(channel()->Send(new IPC::Message())); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); } class ListenerSendingOneOk : public TestListenerBase { public: ListenerSendingOneOk(base::OnceClosure quit_closure) : TestListenerBase(std::move(quit_closure)) {} bool OnMessageReceived(const IPC::Message& message) override { return true; } void OnChannelConnected(int32_t peer_pid) override { ListenerThatExpectsOK::SendOK(sender()); RunQuitClosure(); } }; DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestSendOkClient) { base::RunLoop run_loop; ListenerSendingOneOk listener(run_loop.QuitClosure()); Connect(&listener); listener.set_sender(channel()); run_loop.Run(); Close(); } class ListenerWithSimpleAssociatedInterface : public IPC::Listener, public IPC::mojom::SimpleTestDriver { public: static const int kNumMessages; explicit ListenerWithSimpleAssociatedInterface(base::OnceClosure quit_closure) : quit_closure_(std::move(quit_closure)) {} ~ListenerWithSimpleAssociatedInterface() override = default; bool OnMessageReceived(const IPC::Message& message) override { base::PickleIterator iter(message); int32_t should_be_expected; EXPECT_TRUE(iter.ReadInt(&should_be_expected)); EXPECT_EQ(should_be_expected, next_expected_value_); num_messages_received_++; return true; } void OnChannelError() override { CHECK(!quit_closure_); } void RegisterInterfaceFactory(IPC::Channel* channel) { channel->GetAssociatedInterfaceSupport()->AddAssociatedInterface( base::BindRepeating( &ListenerWithSimpleAssociatedInterface::BindReceiver, base::Unretained(this))); } private: // IPC::mojom::SimpleTestDriver: void ExpectValue(int32_t value) override { next_expected_value_ = value; } void GetExpectedValue(GetExpectedValueCallback callback) override { NOTREACHED(); } void RequestValue(RequestValueCallback callback) override { NOTREACHED(); } void RequestQuit(RequestQuitCallback callback) override { EXPECT_EQ(kNumMessages, num_messages_received_); std::move(callback).Run(); std::move(quit_closure_).Run(); } void BindReceiver( mojo::PendingAssociatedReceiver receiver) { DCHECK(!receiver_.is_bound()); receiver_.Bind(std::move(receiver)); } int32_t next_expected_value_ = 0; int num_messages_received_ = 0; base::OnceClosure quit_closure_; mojo::AssociatedReceiver receiver_{this}; }; const int ListenerWithSimpleAssociatedInterface::kNumMessages = 1000; class ListenerSendingAssociatedMessages : public IPC::Listener { public: explicit ListenerSendingAssociatedMessages(base::OnceClosure quit_closure) : quit_closure_(std::move(quit_closure)) {} bool OnMessageReceived(const IPC::Message& message) override { return true; } void OnChannelConnected(int32_t peer_pid) override { DCHECK(channel_); channel_->GetAssociatedInterfaceSupport()->GetRemoteAssociatedInterface( driver_.BindNewEndpointAndPassReceiver()); // Send a bunch of interleaved messages, alternating between the associated // interface and a legacy IPC::Message. for (int i = 0; i < ListenerWithSimpleAssociatedInterface::kNumMessages; ++i) { driver_->ExpectValue(i); SendValue(channel_, i); } driver_->RequestQuit(base::BindOnce( &ListenerSendingAssociatedMessages::OnQuitAck, base::Unretained(this))); } void set_channel(IPC::Channel* channel) { channel_ = channel; } private: void OnQuitAck() { std::move(quit_closure_).Run(); } raw_ptr channel_ = nullptr; mojo::AssociatedRemote driver_; base::OnceClosure quit_closure_; }; TEST_F(IPCChannelMojoTest, SimpleAssociatedInterface) { Init("SimpleAssociatedInterfaceClient"); base::RunLoop run_loop; ListenerWithSimpleAssociatedInterface listener(run_loop.QuitClosure()); CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); listener.RegisterInterfaceFactory(channel()); run_loop.Run(); channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); } DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(SimpleAssociatedInterfaceClient) { base::RunLoop run_loop; ListenerSendingAssociatedMessages listener(run_loop.QuitClosure()); Connect(&listener); listener.set_channel(channel()); run_loop.Run(); Close(); } class ChannelProxyRunner { public: ChannelProxyRunner(mojo::ScopedMessagePipeHandle handle, bool for_server) : for_server_(for_server), handle_(std::move(handle)), io_thread_("ChannelProxyRunner IO thread"), never_signaled_(base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED) { } ChannelProxyRunner(const ChannelProxyRunner&) = delete; ChannelProxyRunner& operator=(const ChannelProxyRunner&) = delete; void CreateProxy(IPC::Listener* listener) { io_thread_.StartWithOptions( base::Thread::Options(base::MessagePumpType::IO, 0)); proxy_ = IPC::SyncChannel::Create(listener, io_thread_.task_runner(), base::ThreadTaskRunnerHandle::Get(), &never_signaled_); } void RunProxy() { std::unique_ptr factory; if (for_server_) { factory = IPC::ChannelMojo::CreateServerFactory( std::move(handle_), io_thread_.task_runner(), base::ThreadTaskRunnerHandle::Get()); } else { factory = IPC::ChannelMojo::CreateClientFactory( std::move(handle_), io_thread_.task_runner(), base::ThreadTaskRunnerHandle::Get()); } proxy_->Init(std::move(factory), true); } IPC::ChannelProxy* proxy() { return proxy_.get(); } private: const bool for_server_; mojo::ScopedMessagePipeHandle handle_; base::Thread io_thread_; base::WaitableEvent never_signaled_; std::unique_ptr proxy_; }; class IPCChannelProxyMojoTest : public IPCChannelMojoTestBase { public: void Init(const std::string& client_name) { IPCChannelMojoTestBase::Init(client_name); runner_ = std::make_unique(TakeHandle(), true); } void CreateProxy(IPC::Listener* listener) { runner_->CreateProxy(listener); } void RunProxy() { runner_->RunProxy(); } void DestroyProxy() { runner_.reset(); base::RunLoop().RunUntilIdle(); } IPC::ChannelProxy* proxy() { return runner_->proxy(); } private: std::unique_ptr runner_; }; class ListenerWithSimpleProxyAssociatedInterface : public IPC::Listener, public IPC::mojom::SimpleTestDriver { public: static const int kNumMessages; explicit ListenerWithSimpleProxyAssociatedInterface( base::OnceClosure quit_closure) : quit_closure_(std::move(quit_closure)) {} ~ListenerWithSimpleProxyAssociatedInterface() override = default; bool OnMessageReceived(const IPC::Message& message) override { base::PickleIterator iter(message); int32_t should_be_expected; EXPECT_TRUE(iter.ReadInt(&should_be_expected)); EXPECT_EQ(should_be_expected, next_expected_value_); num_messages_received_++; return true; } void OnChannelError() override { CHECK(!quit_closure_); } void OnAssociatedInterfaceRequest( const std::string& interface_name, mojo::ScopedInterfaceEndpointHandle handle) override { DCHECK_EQ(interface_name, IPC::mojom::SimpleTestDriver::Name_); receiver_.Bind( mojo::PendingAssociatedReceiver( std::move(handle))); } bool received_all_messages() const { return num_messages_received_ == kNumMessages && !quit_closure_; } private: // IPC::mojom::SimpleTestDriver: void ExpectValue(int32_t value) override { next_expected_value_ = value; } void GetExpectedValue(GetExpectedValueCallback callback) override { std::move(callback).Run(next_expected_value_); } void RequestValue(RequestValueCallback callback) override { NOTREACHED(); } void RequestQuit(RequestQuitCallback callback) override { std::move(callback).Run(); receiver_.reset(); std::move(quit_closure_).Run(); } void BindReceiver( mojo::PendingAssociatedReceiver receiver) { DCHECK(!receiver_.is_bound()); receiver_.Bind(std::move(receiver)); } int32_t next_expected_value_ = 0; int num_messages_received_ = 0; base::OnceClosure quit_closure_; mojo::AssociatedReceiver receiver_{this}; }; const int ListenerWithSimpleProxyAssociatedInterface::kNumMessages = 1000; TEST_F(IPCChannelProxyMojoTest, ProxyThreadAssociatedInterface) { Init("ProxyThreadAssociatedInterfaceClient"); base::RunLoop run_loop; ListenerWithSimpleProxyAssociatedInterface listener(run_loop.QuitClosure()); CreateProxy(&listener); RunProxy(); run_loop.Run(); EXPECT_TRUE(WaitForClientShutdown()); EXPECT_TRUE(listener.received_all_messages()); DestroyProxy(); } class ChannelProxyClient { public: void Init(mojo::ScopedMessagePipeHandle handle) { runner_ = std::make_unique(std::move(handle), false); } void CreateProxy(IPC::Listener* listener) { runner_->CreateProxy(listener); } void RunProxy() { runner_->RunProxy(); } void DestroyProxy() { runner_.reset(); base::RunLoop().RunUntilIdle(); } void RequestQuitAndWaitForAck(IPC::mojom::SimpleTestDriver* driver) { base::RunLoop loop; driver->RequestQuit(loop.QuitClosure()); loop.Run(); } IPC::ChannelProxy* proxy() { return runner_->proxy(); } private: base::test::SingleThreadTaskEnvironment task_environment_; std::unique_ptr runner_; }; class DummyListener : public IPC::Listener { public: // IPC::Listener bool OnMessageReceived(const IPC::Message& message) override { return true; } }; DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE( ProxyThreadAssociatedInterfaceClient, ChannelProxyClient) { DummyListener listener; CreateProxy(&listener); RunProxy(); // Send a bunch of interleaved messages, alternating between the associated // interface and a legacy IPC::Message. mojo::AssociatedRemote driver; proxy()->GetRemoteAssociatedInterface( driver.BindNewEndpointAndPassReceiver()); for (int i = 0; i < ListenerWithSimpleProxyAssociatedInterface::kNumMessages; ++i) { driver->ExpectValue(i); SendValue(proxy(), i); } base::RunLoop run_loop; driver->RequestQuit(run_loop.QuitClosure()); run_loop.Run(); DestroyProxy(); } class ListenerWithIndirectProxyAssociatedInterface : public IPC::Listener, public IPC::mojom::IndirectTestDriver, public IPC::mojom::PingReceiver { public: ListenerWithIndirectProxyAssociatedInterface() = default; ~ListenerWithIndirectProxyAssociatedInterface() override = default; // IPC::Listener: bool OnMessageReceived(const IPC::Message& message) override { return true; } void OnAssociatedInterfaceRequest( const std::string& interface_name, mojo::ScopedInterfaceEndpointHandle handle) override { DCHECK(!driver_receiver_.is_bound()); DCHECK_EQ(interface_name, IPC::mojom::IndirectTestDriver::Name_); driver_receiver_.Bind( mojo::PendingAssociatedReceiver( std::move(handle))); } void set_ping_handler(const base::RepeatingClosure& handler) { ping_handler_ = handler; } private: // IPC::mojom::IndirectTestDriver: void GetPingReceiver(mojo::PendingAssociatedReceiver receiver) override { ping_receiver_receiver_.Bind(std::move(receiver)); } // IPC::mojom::PingReceiver: void Ping(PingCallback callback) override { std::move(callback).Run(); ping_handler_.Run(); } mojo::AssociatedReceiver driver_receiver_{ this}; mojo::AssociatedReceiver ping_receiver_receiver_{ this}; base::RepeatingClosure ping_handler_; }; TEST_F(IPCChannelProxyMojoTest, ProxyThreadAssociatedInterfaceIndirect) { // Tests that we can pipeline interface requests and subsequent messages // targeting proxy thread bindings, and the channel will still dispatch // messages appropriately. Init("ProxyThreadAssociatedInterfaceIndirectClient"); ListenerWithIndirectProxyAssociatedInterface listener; CreateProxy(&listener); RunProxy(); base::RunLoop loop; listener.set_ping_handler(loop.QuitClosure()); loop.Run(); EXPECT_TRUE(WaitForClientShutdown()); DestroyProxy(); } DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE( ProxyThreadAssociatedInterfaceIndirectClient, ChannelProxyClient) { DummyListener listener; CreateProxy(&listener); RunProxy(); // Use an interface requested via another interface. On the remote end both // interfaces are bound on the proxy thread. This ensures that the Ping // message we send will still be dispatched properly even though the remote // endpoint may not have been bound yet by the time the message is initially // processed on the IO thread. mojo::AssociatedRemote driver; mojo::AssociatedRemote ping_receiver; proxy()->GetRemoteAssociatedInterface( driver.BindNewEndpointAndPassReceiver()); driver->GetPingReceiver(ping_receiver.BindNewEndpointAndPassReceiver()); base::RunLoop loop; ping_receiver->Ping(loop.QuitClosure()); loop.Run(); DestroyProxy(); } class ListenerWithSyncAssociatedInterface : public IPC::Listener, public IPC::mojom::SimpleTestDriver { public: ListenerWithSyncAssociatedInterface() = default; ~ListenerWithSyncAssociatedInterface() override = default; void set_sync_sender(IPC::Sender* sync_sender) { sync_sender_ = sync_sender; } void RunUntilQuitRequested() { base::RunLoop loop; quit_closure_ = loop.QuitClosure(); loop.Run(); } void CloseBinding() { receiver_.reset(); } void set_response_value(int32_t response) { response_value_ = response; } private: // IPC::mojom::SimpleTestDriver: void ExpectValue(int32_t value) override { next_expected_value_ = value; } void GetExpectedValue(GetExpectedValueCallback callback) override { std::move(callback).Run(next_expected_value_); } void RequestValue(RequestValueCallback callback) override { std::move(callback).Run(response_value_); } void RequestQuit(RequestQuitCallback callback) override { std::move(quit_closure_).Run(); std::move(callback).Run(); } // IPC::Listener: bool OnMessageReceived(const IPC::Message& message) override { EXPECT_EQ(0u, message.type()); EXPECT_TRUE(message.is_sync()); EXPECT_TRUE(message.should_unblock()); std::unique_ptr reply( IPC::SyncMessage::GenerateReply(&message)); reply->WriteInt(response_value_); DCHECK(sync_sender_); EXPECT_TRUE(sync_sender_->Send(reply.release())); return true; } void OnAssociatedInterfaceRequest( const std::string& interface_name, mojo::ScopedInterfaceEndpointHandle handle) override { DCHECK(!receiver_.is_bound()); DCHECK_EQ(interface_name, IPC::mojom::SimpleTestDriver::Name_); receiver_.Bind( mojo::PendingAssociatedReceiver( std::move(handle))); } void BindReceiver( mojo::PendingAssociatedReceiver receiver) { DCHECK(!receiver_.is_bound()); receiver_.Bind(std::move(receiver)); } IPC::Sender* sync_sender_ = nullptr; int32_t next_expected_value_ = 0; int32_t response_value_ = 0; base::OnceClosure quit_closure_; mojo::AssociatedReceiver receiver_{this}; }; class SyncReplyReader : public IPC::MessageReplyDeserializer { public: explicit SyncReplyReader(int32_t* storage) : storage_(storage) {} SyncReplyReader(const SyncReplyReader&) = delete; SyncReplyReader& operator=(const SyncReplyReader&) = delete; ~SyncReplyReader() override = default; private: // IPC::MessageReplyDeserializer: bool SerializeOutputParameters(const IPC::Message& message, base::PickleIterator iter) override { if (!iter.ReadInt(storage_)) return false; return true; } raw_ptr storage_; }; TEST_F(IPCChannelProxyMojoTest, SyncAssociatedInterface) { Init("SyncAssociatedInterface"); ListenerWithSyncAssociatedInterface listener; CreateProxy(&listener); listener.set_sync_sender(proxy()); RunProxy(); // Run the client's simple sanity check to completion. listener.RunUntilQuitRequested(); // Verify that we can send a sync IPC and service an incoming sync request // while waiting on it listener.set_response_value(42); mojo::AssociatedRemote client; proxy()->GetRemoteAssociatedInterface( client.BindNewEndpointAndPassReceiver()); int32_t received_value; EXPECT_TRUE(client->RequestValue(&received_value)); EXPECT_EQ(42, received_value); // Do it again. This time the client will send a classical sync IPC to us // while we wait. received_value = 0; EXPECT_TRUE(client->RequestValue(&received_value)); EXPECT_EQ(42, received_value); // Now make a classical sync IPC request to the client. It will send a // sync associated interface message to us while we wait. received_value = 0; std::unique_ptr request( new IPC::SyncMessage(0, 0, IPC::Message::PRIORITY_NORMAL, new SyncReplyReader(&received_value))); EXPECT_TRUE(proxy()->Send(request.release())); EXPECT_EQ(42, received_value); listener.CloseBinding(); EXPECT_TRUE(WaitForClientShutdown()); DestroyProxy(); } class SimpleTestClientImpl : public IPC::mojom::SimpleTestClient, public IPC::Listener { public: SimpleTestClientImpl() = default; SimpleTestClientImpl(const SimpleTestClientImpl&) = delete; SimpleTestClientImpl& operator=(const SimpleTestClientImpl&) = delete; ~SimpleTestClientImpl() override = default; void set_driver(IPC::mojom::SimpleTestDriver* driver) { driver_ = driver; } void set_sync_sender(IPC::Sender* sync_sender) { sync_sender_ = sync_sender; } void WaitForValueRequest() { run_loop_ = std::make_unique(); run_loop_->Run(); } void UseSyncSenderForRequest(bool use_sync_sender) { use_sync_sender_ = use_sync_sender; } private: // IPC::mojom::SimpleTestClient: void RequestValue(RequestValueCallback callback) override { int32_t response = 0; if (use_sync_sender_) { std::unique_ptr reply(new IPC::SyncMessage( 0, 0, IPC::Message::PRIORITY_NORMAL, new SyncReplyReader(&response))); EXPECT_TRUE(sync_sender_->Send(reply.release())); } else { DCHECK(driver_); EXPECT_TRUE(driver_->RequestValue(&response)); } std::move(callback).Run(response); DCHECK(run_loop_); run_loop_->Quit(); } // IPC::Listener: bool OnMessageReceived(const IPC::Message& message) override { int32_t response; DCHECK(driver_); EXPECT_TRUE(driver_->RequestValue(&response)); std::unique_ptr reply( IPC::SyncMessage::GenerateReply(&message)); reply->WriteInt(response); EXPECT_TRUE(sync_sender_->Send(reply.release())); DCHECK(run_loop_); run_loop_->Quit(); return true; } void OnAssociatedInterfaceRequest( const std::string& interface_name, mojo::ScopedInterfaceEndpointHandle handle) override { DCHECK(!receiver_.is_bound()); DCHECK_EQ(interface_name, IPC::mojom::SimpleTestClient::Name_); receiver_.Bind( mojo::PendingAssociatedReceiver( std::move(handle))); } bool use_sync_sender_ = false; mojo::AssociatedReceiver receiver_{this}; IPC::Sender* sync_sender_ = nullptr; IPC::mojom::SimpleTestDriver* driver_ = nullptr; std::unique_ptr run_loop_; }; DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE(SyncAssociatedInterface, ChannelProxyClient) { SimpleTestClientImpl client_impl; CreateProxy(&client_impl); client_impl.set_sync_sender(proxy()); RunProxy(); mojo::AssociatedRemote driver; proxy()->GetRemoteAssociatedInterface( driver.BindNewEndpointAndPassReceiver()); client_impl.set_driver(driver.get()); // Simple sync message sanity check. driver->ExpectValue(42); int32_t expected_value = 0; EXPECT_TRUE(driver->GetExpectedValue(&expected_value)); EXPECT_EQ(42, expected_value); RequestQuitAndWaitForAck(driver.get()); // Wait for the test driver to perform a sync call test with our own sync // associated interface message nested inside. client_impl.UseSyncSenderForRequest(false); client_impl.WaitForValueRequest(); // Wait for the test driver to perform a sync call test with our own classical // sync IPC nested inside. client_impl.UseSyncSenderForRequest(true); client_impl.WaitForValueRequest(); // Wait for the test driver to perform a classical sync IPC request, with our // own sync associated interface message nested inside. client_impl.UseSyncSenderForRequest(false); client_impl.WaitForValueRequest(); DestroyProxy(); } TEST_F(IPCChannelProxyMojoTest, Pause) { // Ensures that pausing a channel elicits the expected behavior when sending // messages, unpausing, sending more messages, and then manually flushing. // Specifically a sequence like: // // Connect() // Send(A) // Pause() // Send(B) // Send(C) // Unpause(false) // Send(D) // Send(E) // Flush() // // must result in the other end receiving messages A, D, E, B, D; in that // order. // // This behavior is required by some consumers of IPC::Channel, and it is not // sufficient to leave this up to the consumer to implement since associated // interface requests and messages also need to be queued according to the // same policy. Init("CreatePausedClient"); DummyListener listener; CreateProxy(&listener); RunProxy(); // This message must be sent immediately since the channel is unpaused. SendValue(proxy(), 1); proxy()->Pause(); // These messages must be queued internally since the channel is paused. SendValue(proxy(), 2); SendValue(proxy(), 3); proxy()->Unpause(false /* flush */); // These messages must be sent immediately since the channel is unpaused. SendValue(proxy(), 4); SendValue(proxy(), 5); // Now we flush the previously queued messages. proxy()->Flush(); EXPECT_TRUE(WaitForClientShutdown()); DestroyProxy(); } class ExpectValueSequenceListener : public IPC::Listener { public: ExpectValueSequenceListener(base::queue* expected_values, base::OnceClosure quit_closure) : expected_values_(expected_values), quit_closure_(std::move(quit_closure)) {} ExpectValueSequenceListener(const ExpectValueSequenceListener&) = delete; ExpectValueSequenceListener& operator=(const ExpectValueSequenceListener&) = delete; ~ExpectValueSequenceListener() override = default; // IPC::Listener: bool OnMessageReceived(const IPC::Message& message) override { DCHECK(!expected_values_->empty()); base::PickleIterator iter(message); int32_t should_be_expected; EXPECT_TRUE(iter.ReadInt(&should_be_expected)); EXPECT_EQ(expected_values_->front(), should_be_expected); expected_values_->pop(); if (expected_values_->empty()) std::move(quit_closure_).Run(); return true; } private: raw_ptr> expected_values_; base::OnceClosure quit_closure_; }; DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE(CreatePausedClient, ChannelProxyClient) { base::queue expected_values; base::RunLoop run_loop; ExpectValueSequenceListener listener(&expected_values, run_loop.QuitClosure()); CreateProxy(&listener); expected_values.push(1); expected_values.push(4); expected_values.push(5); expected_values.push(2); expected_values.push(3); RunProxy(); run_loop.Run(); EXPECT_TRUE(expected_values.empty()); DestroyProxy(); } TEST_F(IPCChannelProxyMojoTest, AssociatedRequestClose) { Init("DropAssociatedRequest"); DummyListener listener; CreateProxy(&listener); RunProxy(); mojo::AssociatedRemote vendor; proxy()->GetRemoteAssociatedInterface( vendor.BindNewEndpointAndPassReceiver()); mojo::AssociatedRemote tester; vendor->GetTestInterface(tester.BindNewEndpointAndPassReceiver()); base::RunLoop run_loop; tester.set_disconnect_handler(run_loop.QuitClosure()); run_loop.Run(); tester.reset(); proxy()->GetRemoteAssociatedInterface( tester.BindNewEndpointAndPassReceiver()); EXPECT_TRUE(WaitForClientShutdown()); DestroyProxy(); } class AssociatedInterfaceDroppingListener : public IPC::Listener { public: AssociatedInterfaceDroppingListener(base::OnceClosure callback) : callback_(std::move(callback)) {} bool OnMessageReceived(const IPC::Message& message) override { return false; } void OnAssociatedInterfaceRequest( const std::string& interface_name, mojo::ScopedInterfaceEndpointHandle handle) override { if (interface_name == IPC::mojom::SimpleTestDriver::Name_) std::move(callback_).Run(); } private: base::OnceClosure callback_; }; DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE(DropAssociatedRequest, ChannelProxyClient) { base::RunLoop run_loop; AssociatedInterfaceDroppingListener listener(run_loop.QuitClosure()); CreateProxy(&listener); RunProxy(); run_loop.Run(); DestroyProxy(); } #if !BUILDFLAG(IS_APPLE) // TODO(wez): On Mac we need to set up a MachPortBroker before we can transfer // Mach ports (which underpin Sharedmemory on Mac) across IPC. template class IPCChannelMojoSharedMemoryRegionTypedTest : public IPCChannelMojoTest {}; struct WritableRegionTraits { using RegionType = base::WritableSharedMemoryRegion; static const char kClientName[]; }; const char WritableRegionTraits::kClientName[] = "IPCChannelMojoTestSendWritableSharedMemoryRegionClient"; struct UnsafeRegionTraits { using RegionType = base::UnsafeSharedMemoryRegion; static const char kClientName[]; }; const char UnsafeRegionTraits::kClientName[] = "IPCChannelMojoTestSendUnsafeSharedMemoryRegionClient"; struct ReadOnlyRegionTraits { using RegionType = base::ReadOnlySharedMemoryRegion; static const char kClientName[]; }; const char ReadOnlyRegionTraits::kClientName[] = "IPCChannelMojoTestSendReadOnlySharedMemoryRegionClient"; typedef ::testing:: Types AllSharedMemoryRegionTraits; TYPED_TEST_SUITE(IPCChannelMojoSharedMemoryRegionTypedTest, AllSharedMemoryRegionTraits); template class ListenerThatExpectsSharedMemoryRegion : public TestListenerBase { public: explicit ListenerThatExpectsSharedMemoryRegion(base::OnceClosure quit_closure) : TestListenerBase(std::move(quit_closure)) {} bool OnMessageReceived(const IPC::Message& message) override { base::PickleIterator iter(message); SharedMemoryRegionType region; EXPECT_TRUE(IPC::ReadParam(&message, &iter, ®ion)); EXPECT_TRUE(region.IsValid()); // Verify the shared memory region has expected content. typename SharedMemoryRegionType::MappingType mapping = region.Map(); std::string content = HandleSendingHelper::GetSendingFileContent(); EXPECT_EQ(0, memcmp(mapping.memory(), content.data(), content.size())); ListenerThatExpectsOK::SendOK(sender()); return true; } }; TYPED_TEST(IPCChannelMojoSharedMemoryRegionTypedTest, Send) { this->Init(TypeParam::kClientName); const size_t size = 1004; typename TypeParam::RegionType region; base::WritableSharedMemoryMapping mapping; std::tie(region, mapping) = base::CreateMappedRegion(size); std::string content = HandleSendingHelper::GetSendingFileContent(); memcpy(mapping.memory(), content.data(), content.size()); // Create a success listener, and launch the child process. base::RunLoop run_loop; ListenerThatExpectsOK listener(run_loop.QuitClosure()); this->CreateChannel(&listener); ASSERT_TRUE(this->ConnectChannel()); // Send the child process an IPC with |shmem| attached, to verify // that is is correctly wrapped, transferred and unwrapped. IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); IPC::WriteParam(message, region); ASSERT_TRUE(this->channel()->Send(message)); run_loop.Run(); this->channel()->Close(); EXPECT_TRUE(this->WaitForClientShutdown()); EXPECT_FALSE(region.IsValid()); this->DestroyChannel(); } DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT( IPCChannelMojoTestSendWritableSharedMemoryRegionClient) { base::RunLoop run_loop; ListenerThatExpectsSharedMemoryRegion listener(run_loop.QuitClosure()); Connect(&listener); listener.set_sender(channel()); run_loop.Run(); Close(); } DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT( IPCChannelMojoTestSendUnsafeSharedMemoryRegionClient) { base::RunLoop run_loop; ListenerThatExpectsSharedMemoryRegion listener(run_loop.QuitClosure()); Connect(&listener); listener.set_sender(channel()); run_loop.Run(); Close(); } DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT( IPCChannelMojoTestSendReadOnlySharedMemoryRegionClient) { base::RunLoop run_loop; ListenerThatExpectsSharedMemoryRegion listener(run_loop.QuitClosure()); Connect(&listener); listener.set_sender(channel()); run_loop.Run(); Close(); } #endif // !BUILDFLAG(IS_APPLE) #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) class ListenerThatExpectsFile : public TestListenerBase { public: explicit ListenerThatExpectsFile(base::OnceClosure quit_closure) : TestListenerBase(std::move(quit_closure)) {} bool OnMessageReceived(const IPC::Message& message) override { base::PickleIterator iter(message); HandleSendingHelper::ReadReceivedFile(message, &iter); ListenerThatExpectsOK::SendOK(sender()); return true; } }; TEST_F(IPCChannelMojoTest, SendPlatformFile) { Init("IPCChannelMojoTestSendPlatformFileClient"); base::RunLoop run_loop; ListenerThatExpectsOK listener(run_loop.QuitClosure()); CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); base::File file(HandleSendingHelper::GetSendingFilePath(temp_dir.GetPath()), base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE | base::File::FLAG_READ); HandleSendingHelper::WriteFileThenSend(channel(), file); run_loop.Run(); channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); } DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestSendPlatformFileClient) { base::RunLoop run_loop; ListenerThatExpectsFile listener(run_loop.QuitClosure()); Connect(&listener); listener.set_sender(channel()); run_loop.Run(); Close(); } class ListenerThatExpectsFileAndMessagePipe : public TestListenerBase { public: explicit ListenerThatExpectsFileAndMessagePipe(base::OnceClosure quit_closure) : TestListenerBase(std::move(quit_closure)) {} ~ListenerThatExpectsFileAndMessagePipe() override = default; bool OnMessageReceived(const IPC::Message& message) override { base::PickleIterator iter(message); HandleSendingHelper::ReadReceivedFile(message, &iter); HandleSendingHelper::ReadReceivedPipe(message, &iter); ListenerThatExpectsOK::SendOK(sender()); return true; } }; TEST_F(IPCChannelMojoTest, SendPlatformFileAndMessagePipe) { Init("IPCChannelMojoTestSendPlatformFileAndMessagePipeClient"); base::RunLoop run_loop; ListenerThatExpectsOK listener(run_loop.QuitClosure()); CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); base::File file(HandleSendingHelper::GetSendingFilePath(temp_dir.GetPath()), base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE | base::File::FLAG_READ); TestingMessagePipe pipe; HandleSendingHelper::WriteFileAndPipeThenSend(channel(), file, &pipe); run_loop.Run(); channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); } DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT( IPCChannelMojoTestSendPlatformFileAndMessagePipeClient) { base::RunLoop run_loop; ListenerThatExpectsFileAndMessagePipe listener(run_loop.QuitClosure()); Connect(&listener); listener.set_sender(channel()); run_loop.Run(); Close(); } #endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) const base::ProcessId kMagicChildId = 54321; class ListenerThatVerifiesPeerPid : public TestListenerBase { public: explicit ListenerThatVerifiesPeerPid(base::OnceClosure quit_closure) : TestListenerBase(std::move(quit_closure)) {} void OnChannelConnected(int32_t peer_pid) override { EXPECT_EQ(peer_pid, kMagicChildId); RunQuitClosure(); } bool OnMessageReceived(const IPC::Message& message) override { NOTREACHED(); return true; } }; // The global PID is only used on systems that use the zygote. Hence, this // test is disabled on other platforms. TEST_F(IPCChannelMojoTest, VerifyGlobalPid) { Init("IPCChannelMojoTestVerifyGlobalPidClient"); base::RunLoop run_loop; ListenerThatVerifiesPeerPid listener(run_loop.QuitClosure()); CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); run_loop.Run(); channel()->Close(); EXPECT_TRUE(WaitForClientShutdown()); DestroyChannel(); } DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(IPCChannelMojoTestVerifyGlobalPidClient) { IPC::Channel::SetGlobalPid(kMagicChildId); base::RunLoop run_loop; ListenerThatQuits listener(run_loop.QuitClosure()); Connect(&listener); run_loop.Run(); Close(); } #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) } // namespace