123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767 |
- // 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 <stddef.h>
- #include <stdint.h>
- #include <memory>
- #include <utility>
- #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<IPC::Sender> 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<IPC::mojom::TestStructPasser>(
- std::move(handle)));
- }
- private:
- // IPC::mojom::TestStructPasser:
- void Pass(IPC::mojom::TestStructPtr) override { NOTREACHED(); }
- mojo::AssociatedReceiver<IPC::mojom::TestStructPasser> 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<IPC::mojom::TestStructPasser> 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<base::RunLoop> 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<uint32_t>(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<uint8_t> 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<base::Pickle::Attachment> attachment;
- EXPECT_TRUE(message.ReadAttachment(iter, &attachment));
- EXPECT_EQ(
- IPC::MessageAttachment::Type::PLATFORM_FILE,
- static_cast<IPC::MessageAttachment*>(attachment.get())->GetType());
- base::File file(
- static_cast<IPC::internal::PlatformFileAttachment*>(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<uint8_t> 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<uint32_t>(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<mojo::MessagePipeHandle>::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<IPC::Message> message(new IPC::Message());
- IPC::ParamTraits<mojo::MessagePipeHandle>::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<IPC::Message> message(new IPC::Message());
- IPC::ParamTraits<mojo::MessagePipeHandle>::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<IPC::mojom::SimpleTestDriver> 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<IPC::mojom::SimpleTestDriver> 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<IPC::Channel> channel_ = nullptr;
- mojo::AssociatedRemote<IPC::mojom::SimpleTestDriver> 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<IPC::ChannelFactory> 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<IPC::ChannelProxy> proxy_;
- };
- class IPCChannelProxyMojoTest : public IPCChannelMojoTestBase {
- public:
- void Init(const std::string& client_name) {
- IPCChannelMojoTestBase::Init(client_name);
- runner_ = std::make_unique<ChannelProxyRunner>(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<ChannelProxyRunner> 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<IPC::mojom::SimpleTestDriver>(
- 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<IPC::mojom::SimpleTestDriver> 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<IPC::mojom::SimpleTestDriver> 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<ChannelProxyRunner>(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<ChannelProxyRunner> 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<IPC::mojom::SimpleTestDriver> 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<IPC::mojom::IndirectTestDriver>(
- std::move(handle)));
- }
- void set_ping_handler(const base::RepeatingClosure& handler) {
- ping_handler_ = handler;
- }
- private:
- // IPC::mojom::IndirectTestDriver:
- void GetPingReceiver(mojo::PendingAssociatedReceiver<IPC::mojom::PingReceiver>
- 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<IPC::mojom::IndirectTestDriver> driver_receiver_{
- this};
- mojo::AssociatedReceiver<IPC::mojom::PingReceiver> 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<IPC::mojom::IndirectTestDriver> driver;
- mojo::AssociatedRemote<IPC::mojom::PingReceiver> 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<IPC::Message> 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<IPC::mojom::SimpleTestDriver>(
- std::move(handle)));
- }
- void BindReceiver(
- mojo::PendingAssociatedReceiver<IPC::mojom::SimpleTestDriver> 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<IPC::mojom::SimpleTestDriver> 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<int32_t> 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<IPC::mojom::SimpleTestClient> 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<IPC::SyncMessage> 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<base::RunLoop>();
- 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<IPC::SyncMessage> 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<IPC::Message> 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<IPC::mojom::SimpleTestClient>(
- std::move(handle)));
- }
- bool use_sync_sender_ = false;
- mojo::AssociatedReceiver<IPC::mojom::SimpleTestClient> receiver_{this};
- IPC::Sender* sync_sender_ = nullptr;
- IPC::mojom::SimpleTestDriver* driver_ = nullptr;
- std::unique_ptr<base::RunLoop> 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<IPC::mojom::SimpleTestDriver> 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<int32_t>* 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<base::queue<int32_t>> expected_values_;
- base::OnceClosure quit_closure_;
- };
- DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE(CreatePausedClient,
- ChannelProxyClient) {
- base::queue<int32_t> 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<IPC::mojom::AssociatedInterfaceVendor> vendor;
- proxy()->GetRemoteAssociatedInterface(
- vendor.BindNewEndpointAndPassReceiver());
- mojo::AssociatedRemote<IPC::mojom::SimpleTestDriver> 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 SharedMemoryRegionType>
- 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<WritableRegionTraits, UnsafeRegionTraits, ReadOnlyRegionTraits>
- AllSharedMemoryRegionTraits;
- TYPED_TEST_SUITE(IPCChannelMojoSharedMemoryRegionTypedTest,
- AllSharedMemoryRegionTraits);
- template <class SharedMemoryRegionType>
- 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<typename TypeParam::RegionType>(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<base::WritableSharedMemoryRegion>
- 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<base::UnsafeSharedMemoryRegion>
- 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<base::ReadOnlySharedMemoryRegion>
- 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
|