Index: ipc/attachment_broker_mac_unittest.cc |
diff --git a/ipc/attachment_broker_mac_unittest.cc b/ipc/attachment_broker_mac_unittest.cc |
deleted file mode 100644 |
index 76c424a8e92492d3ff2a703230a74e4fee4addc2..0000000000000000000000000000000000000000 |
--- a/ipc/attachment_broker_mac_unittest.cc |
+++ /dev/null |
@@ -1,1300 +0,0 @@ |
-// Copyright 2015 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 "build/build_config.h" |
- |
-#include <fcntl.h> |
-#include <mach/mach_vm.h> |
-#include <stddef.h> |
-#include <sys/mman.h> |
- |
-#include <memory> |
-#include <tuple> |
- |
-#include "base/command_line.h" |
-#include "base/files/file_util.h" |
-#include "base/files/scoped_file.h" |
-#include "base/files/scoped_temp_dir.h" |
-#include "base/mac/mac_util.h" |
-#include "base/mac/mach_logging.h" |
-#include "base/memory/free_deleter.h" |
-#include "base/memory/shared_memory.h" |
-#include "base/run_loop.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/synchronization/spin_wait.h" |
-#include "base/threading/thread.h" |
-#include "base/time/time.h" |
-#include "ipc/attachment_broker_messages.h" |
-#include "ipc/attachment_broker_privileged_mac.h" |
-#include "ipc/attachment_broker_unprivileged_mac.h" |
-#include "ipc/ipc_listener.h" |
-#include "ipc/ipc_message.h" |
-#include "ipc/ipc_test_base.h" |
-#include "ipc/ipc_test_messages.h" |
-#include "ipc/test_util_mac.h" |
- |
-namespace { |
- |
-const char kDataBuffer1[] = "This is some test data to write to the file."; |
-const char kDataBuffer2[] = "The lazy dog and a fox."; |
-const char kDataBuffer3[] = "Two green bears but not a potato."; |
-const char kDataBuffer4[] = "Red potato is best potato."; |
-const std::string g_service_switch_name = "service_name"; |
-const size_t g_large_message_size = 8 * 1024 * 1024; |
-const int g_large_message_count = 1000; |
-const size_t g_medium_message_size = 512 * 1024; |
- |
-// Running the message loop is expected to increase the number of resident |
-// pages. The exact amount is non-deterministic, but for a simple test suite |
-// like this one, the increase is expected to be less than 1 MB. |
-const size_t g_expected_memory_increase = 1024 * 1024; |
- |
-enum TestResult { |
- RESULT_UNKNOWN, |
- RESULT_SUCCESS, |
- RESULT_FAILURE, |
-}; |
- |
-mach_vm_size_t GetResidentSize() { |
- task_basic_info_64 info; |
- mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT; |
- kern_return_t kr = task_info(mach_task_self(), TASK_BASIC_INFO_64, |
- reinterpret_cast<task_info_t>(&info), &count); |
- MACH_CHECK(kr == KERN_SUCCESS, kr) << "Couldn't get resident size."; |
- |
- return info.resident_size; |
-} |
- |
-base::mac::ScopedMachSendRight GetMachPortFromBrokeredAttachment( |
- const scoped_refptr<IPC::BrokerableAttachment>& attachment) { |
- if (attachment->GetType() != |
- IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) { |
- LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT."; |
- return base::mac::ScopedMachSendRight(MACH_PORT_NULL); |
- } |
- |
- if (attachment->GetBrokerableType() != IPC::BrokerableAttachment::MACH_PORT) { |
- LOG(INFO) << "Brokerable type not MACH_PORT."; |
- return base::mac::ScopedMachSendRight(MACH_PORT_NULL); |
- } |
- |
- IPC::internal::MachPortAttachmentMac* received_mach_port_attachment = |
- static_cast<IPC::internal::MachPortAttachmentMac*>(attachment.get()); |
- base::mac::ScopedMachSendRight send_right( |
- received_mach_port_attachment->get_mach_port()); |
- received_mach_port_attachment->reset_mach_port_ownership(); |
- return send_right; |
-} |
- |
-// Makes a Mach port backed SharedMemory region and fills it with |contents|. |
-std::unique_ptr<base::SharedMemory> MakeSharedMemory( |
- const std::string& contents) { |
- base::SharedMemoryHandle shm(contents.size()); |
- if (!shm.IsValid()) { |
- LOG(ERROR) << "Failed to make SharedMemoryHandle."; |
- return nullptr; |
- } |
- std::unique_ptr<base::SharedMemory> shared_memory( |
- new base::SharedMemory(shm, false)); |
- shared_memory->Map(contents.size()); |
- memcpy(shared_memory->memory(), contents.c_str(), contents.size()); |
- return shared_memory; |
-} |
- |
-// |message| must be deserializable as a TestSharedMemoryHandleMsg1. |
-base::SharedMemoryHandle GetSharedMemoryHandleFromMsg1( |
- const IPC::Message& message) { |
- // Expect a message with a brokered attachment. |
- if (!message.HasBrokerableAttachments()) { |
- LOG(ERROR) << "Message missing brokerable attachment."; |
- return base::SharedMemoryHandle(); |
- } |
- |
- TestSharedMemoryHandleMsg1::Schema::Param p; |
- if (!TestSharedMemoryHandleMsg1::Read(&message, &p)) { |
- LOG(ERROR) << "Failed to deserialize message."; |
- return base::SharedMemoryHandle(); |
- } |
- |
- return std::get<1>(p); |
-} |
- |
-// |message| must be deserializable as a TestSharedMemoryHandleMsg2. Returns |
-// whether deserialization was successful. |handle1| and |handle2| are output |
-// variables populated on success. |
-bool GetSharedMemoryHandlesFromMsg2(const IPC::Message& message, |
- base::SharedMemoryHandle* handle1, |
- base::SharedMemoryHandle* handle2) { |
- // Expect a message with a brokered attachment. |
- if (!message.HasBrokerableAttachments()) { |
- LOG(ERROR) << "Message missing brokerable attachment."; |
- return false; |
- } |
- |
- TestSharedMemoryHandleMsg2::Schema::Param p; |
- if (!TestSharedMemoryHandleMsg2::Read(&message, &p)) { |
- LOG(ERROR) << "Failed to deserialize message."; |
- return false; |
- } |
- |
- *handle1 = std::get<0>(p); |
- *handle2 = std::get<1>(p); |
- return true; |
-} |
- |
-// Returns |nullptr| on error. |
-std::unique_ptr<base::SharedMemory> MapSharedMemoryHandle( |
- const base::SharedMemoryHandle& shm, |
- bool read_only) { |
- if (!shm.IsValid()) { |
- LOG(ERROR) << "Invalid SharedMemoryHandle"; |
- return nullptr; |
- } |
- |
- size_t size; |
- if (!shm.GetSize(&size)) { |
- LOG(ERROR) << "Couldn't get size of SharedMemoryHandle"; |
- return nullptr; |
- } |
- |
- std::unique_ptr<base::SharedMemory> shared_memory( |
- new base::SharedMemory(shm, read_only)); |
- shared_memory->Map(size); |
- return shared_memory; |
-} |
- |
-// This method maps the SharedMemoryHandle, checks the contents, and then |
-// consumes a reference to the underlying Mach port. |
-bool CheckContentsOfSharedMemoryHandle(const base::SharedMemoryHandle& shm, |
- const std::string& contents) { |
- std::unique_ptr<base::SharedMemory> shared_memory( |
- MapSharedMemoryHandle(shm, false)); |
- |
- if (memcmp(shared_memory->memory(), contents.c_str(), contents.size()) != 0) { |
- LOG(ERROR) << "Shared Memory contents not equivalent"; |
- return false; |
- } |
- return true; |
-} |
- |
-// This method mmaps the FileDescriptor, checks the contents, and then munmaps |
-// the FileDescriptor and closes the underlying fd. |
-bool CheckContentsOfFileDescriptor(const base::FileDescriptor& file_descriptor, |
- const std::string& contents) { |
- base::ScopedFD fd_closer(file_descriptor.fd); |
- lseek(file_descriptor.fd, 0, SEEK_SET); |
- std::unique_ptr<char, base::FreeDeleter> buffer( |
- static_cast<char*>(malloc(contents.size()))); |
- if (!base::ReadFromFD(file_descriptor.fd, buffer.get(), contents.size())) |
- return false; |
- |
- int result = memcmp(buffer.get(), contents.c_str(), contents.size()); |
- return result == 0; |
-} |
- |
-// Open |fp| and populate it with |contents|. |
-base::FileDescriptor MakeFileDescriptor(const base::FilePath& fp, |
- const std::string& contents) { |
- int fd = open(fp.value().c_str(), O_RDWR, S_IWUSR | S_IRUSR); |
- base::ScopedFD fd_closer(fd); |
- if (fd <= 0) { |
- LOG(ERROR) << "Error opening file at: " << fp.value(); |
- return base::FileDescriptor(); |
- } |
- |
- if (lseek(fd, 0, SEEK_SET) != 0) { |
- LOG(ERROR) << "Error changing offset"; |
- return base::FileDescriptor(); |
- } |
- |
- if (write(fd, contents.c_str(), contents.size()) != |
- static_cast<ssize_t>(contents.size())) { |
- LOG(ERROR) << "Error writing to file"; |
- return base::FileDescriptor(); |
- } |
- |
- return base::FileDescriptor(fd_closer.release(), true); |
-} |
- |
-// Maps both handles, then checks that their contents matches |contents|. Then |
-// checks that changes to one are reflected in the other. Then consumes |
-// references to both underlying Mach ports. |
-bool CheckContentsOfTwoEquivalentSharedMemoryHandles( |
- const base::SharedMemoryHandle& handle1, |
- const base::SharedMemoryHandle& handle2, |
- const std::string& contents) { |
- std::unique_ptr<base::SharedMemory> shared_memory1( |
- MapSharedMemoryHandle(handle1, false)); |
- std::unique_ptr<base::SharedMemory> shared_memory2( |
- MapSharedMemoryHandle(handle2, false)); |
- |
- if (memcmp(shared_memory1->memory(), contents.c_str(), contents.size()) != |
- 0) { |
- LOG(ERROR) << "Incorrect contents in shared_memory1"; |
- return false; |
- } |
- |
- if (memcmp(shared_memory1->memory(), shared_memory2->memory(), |
- contents.size()) != 0) { |
- LOG(ERROR) << "Incorrect contents in shared_memory2"; |
- return false; |
- } |
- |
- // Updating shared_memory1 should update shared_memory2. |
- const char known_string[] = "string bean"; |
- if (shared_memory1->mapped_size() < strlen(known_string) || |
- shared_memory2->mapped_size() < strlen(known_string)) { |
- LOG(ERROR) << "Shared memory size is too small"; |
- return false; |
- } |
- memcpy(shared_memory1->memory(), known_string, strlen(known_string)); |
- |
- if (memcmp(shared_memory1->memory(), shared_memory2->memory(), |
- strlen(known_string)) != 0) { |
- LOG(ERROR) << "Incorrect contents in shared_memory2"; |
- return false; |
- } |
- |
- return true; |
-} |
- |
-// |message| must be deserializable as a TestSharedMemoryHandleMsg1. Returns |
-// whether the contents of the attached shared memory region matches |contents|. |
-// Consumes a reference to the underlying Mach port. |
-bool CheckContentsOfMessage1(const IPC::Message& message, |
- const std::string& contents) { |
- base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message)); |
- return CheckContentsOfSharedMemoryHandle(shm, contents); |
-} |
- |
-// Once the test is finished, send a control message to the parent process with |
-// the result. The message may require the runloop to be run before its |
-// dispatched. |
-void SendControlMessage(IPC::Sender* sender, bool success) { |
- IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); |
- TestResult result = success ? RESULT_SUCCESS : RESULT_FAILURE; |
- message->WriteInt(result); |
- sender->Send(message); |
-} |
- |
-// Records the most recently received brokerable attachment's id. |
-class AttachmentBrokerObserver : public IPC::AttachmentBroker::Observer { |
- public: |
- void ReceivedBrokerableAttachmentWithId( |
- const IPC::BrokerableAttachment::AttachmentId& id) override { |
- id_ = id; |
- } |
- IPC::BrokerableAttachment::AttachmentId* get_id() { return &id_; } |
- |
- private: |
- IPC::BrokerableAttachment::AttachmentId id_; |
-}; |
- |
-// A broker which always sets the current process as the destination process |
-// for attachments. |
-class MockBroker : public IPC::AttachmentBrokerUnprivilegedMac { |
- public: |
- MockBroker() {} |
- ~MockBroker() override {} |
- bool SendAttachmentToProcess( |
- const scoped_refptr<IPC::BrokerableAttachment>& attachment, |
- base::ProcessId destination_process) override { |
- return IPC::AttachmentBrokerUnprivilegedMac::SendAttachmentToProcess( |
- attachment, base::Process::Current().Pid()); |
- } |
-}; |
- |
-// Forwards all messages to |listener_|. Quits the message loop after a |
-// message is received, or the channel has an error. |
-class ProxyListener : public IPC::Listener { |
- public: |
- ProxyListener() : listener_(nullptr), reason_(MESSAGE_RECEIVED) {} |
- ~ProxyListener() override {} |
- |
- // The reason for exiting the message loop. |
- enum Reason { MESSAGE_RECEIVED, CHANNEL_ERROR }; |
- |
- bool OnMessageReceived(const IPC::Message& message) override { |
- bool result = false; |
- if (listener_) |
- result = listener_->OnMessageReceived(message); |
- reason_ = MESSAGE_RECEIVED; |
- messages_.push_back(message); |
- base::MessageLoop::current()->QuitNow(); |
- return result; |
- } |
- |
- void OnChannelError() override { |
- reason_ = CHANNEL_ERROR; |
- base::MessageLoop::current()->QuitNow(); |
- } |
- |
- void set_listener(IPC::Listener* listener) { listener_ = listener; } |
- Reason get_reason() { return reason_; } |
- IPC::Message get_first_message() { |
- DCHECK(!messages_.empty()); |
- return messages_[0]; |
- } |
- void pop_first_message() { |
- DCHECK(!messages_.empty()); |
- messages_.erase(messages_.begin()); |
- } |
- bool has_message() { return !messages_.empty(); } |
- |
- private: |
- IPC::Listener* listener_; |
- Reason reason_; |
- std::vector<IPC::Message> messages_; |
-}; |
- |
-// Waits for a result to be sent over the channel. Quits the message loop |
-// after a message is received, or the channel has an error. |
-class ResultListener : public IPC::Listener { |
- public: |
- ResultListener() : result_(RESULT_UNKNOWN) {} |
- ~ResultListener() override {} |
- |
- bool OnMessageReceived(const IPC::Message& message) override { |
- base::PickleIterator iter(message); |
- |
- int result; |
- EXPECT_TRUE(iter.ReadInt(&result)); |
- result_ = static_cast<TestResult>(result); |
- return true; |
- } |
- |
- TestResult get_result() { return result_; } |
- |
- private: |
- TestResult result_; |
-}; |
- |
-class MockPortProvider : public base::PortProvider { |
- public: |
- mach_port_t TaskForPid(base::ProcessHandle process) const override { |
- auto it = port_map_.find(process); |
- if (it != port_map_.end()) |
- return it->second; |
- return MACH_PORT_NULL; |
- } |
- |
- void InsertEntry(base::ProcessHandle process, mach_port_t task_port) { |
- port_map_[process] = task_port; |
- NotifyObservers(process); |
- } |
- |
- void ClearPortMap() { port_map_.clear(); } |
- |
- private: |
- std::map<base::ProcessHandle, mach_port_t> port_map_; |
-}; |
- |
-// End-to-end tests for the attachment brokering process on Mac. |
-// The parent process acts as an unprivileged process. The child process acts |
-// as the privileged process. |
-class IPCAttachmentBrokerMacTest : public IPCTestBase { |
- public: |
- IPCAttachmentBrokerMacTest() {} |
- ~IPCAttachmentBrokerMacTest() override {} |
- |
- base::CommandLine MakeCmdLine(const std::string& procname) override { |
- base::CommandLine command_line = IPCTestBase::MakeCmdLine(procname); |
- // Pass the service name to the child process. |
- command_line.AppendSwitchASCII(g_service_switch_name, service_name_); |
- return command_line; |
- } |
- |
- // Takes ownership of |broker|. Has no effect if called after CommonSetUp(). |
- void SetBroker(IPC::AttachmentBrokerUnprivilegedMac* broker) { |
- broker_.reset(broker); |
- } |
- |
- // Mach Setup that needs to occur before child processes are forked. |
- void MachPreForkSetUp() { |
- service_name_ = IPC::CreateRandomServiceName(); |
- server_port_.reset(IPC::BecomeMachServer(service_name_.c_str()).release()); |
- } |
- |
- // Mach Setup that needs to occur after child processes are forked. |
- void MachPostForkSetUp() { |
- client_port_.reset(IPC::ReceiveMachPort(server_port_.get()).release()); |
- IPC::SendMachPort( |
- client_port_.get(), mach_task_self(), MACH_MSG_TYPE_COPY_SEND); |
- } |
- |
- // Setup shared between tests. |
- void CommonSetUp(const char* name) { |
- PreConnectSetUp(name); |
- PostConnectSetUp(); |
- } |
- |
- // All of setup before the channel is connected. |
- void PreConnectSetUp(const char* name) { |
- Init(name); |
- MachPreForkSetUp(); |
- |
- if (!broker_.get()) |
- SetBroker(new IPC::AttachmentBrokerUnprivilegedMac); |
- |
- broker_->AddObserver(&observer_, task_runner()); |
- CreateChannel(&proxy_listener_); |
- broker_->RegisterBrokerCommunicationChannel(channel()); |
- } |
- |
- // All of setup including the connection and everything after. |
- void PostConnectSetUp() { |
- ASSERT_TRUE(ConnectChannel()); |
- ASSERT_TRUE(StartClient()); |
- |
- MachPostForkSetUp(); |
- active_names_at_start_ = IPC::GetActiveNameCount(); |
- get_proxy_listener()->set_listener(&result_listener_); |
- } |
- |
- void CheckChildResult() { |
- ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED, |
- get_proxy_listener()->get_reason()); |
- ASSERT_EQ(get_result_listener()->get_result(), RESULT_SUCCESS); |
- } |
- |
- void FinalCleanUp() { |
- // There should be no leaked names. |
- SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE( |
- base::TimeDelta::FromSeconds(10), |
- active_names_at_start_ == IPC::GetActiveNameCount()); |
- EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount()); |
- |
- // Close the channel so the client's OnChannelError() gets fired. |
- channel()->Close(); |
- |
- EXPECT_TRUE(WaitForClientShutdown()); |
- DestroyChannel(); |
- broker_.reset(); |
- } |
- |
- // Teardown shared between most tests. |
- void CommonTearDown() { |
- CheckChildResult(); |
- FinalCleanUp(); |
- } |
- |
- // Makes a SharedMemory region, fills it with |contents|, sends the handle |
- // over Chrome IPC, and unmaps the region. |
- void SendMessage1(const std::string& contents) { |
- std::unique_ptr<base::SharedMemory> shared_memory( |
- MakeSharedMemory(contents)); |
- IPC::Message* message = |
- new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200); |
- sender()->Send(message); |
- } |
- |
- ProxyListener* get_proxy_listener() { return &proxy_listener_; } |
- IPC::AttachmentBrokerUnprivilegedMac* get_broker() { return broker_.get(); } |
- AttachmentBrokerObserver* get_observer() { return &observer_; } |
- ResultListener* get_result_listener() { return &result_listener_; } |
- |
- protected: |
- // The number of active names immediately after set up. |
- mach_msg_type_number_t active_names_at_start_; |
- |
- private: |
- ProxyListener proxy_listener_; |
- std::unique_ptr<IPC::AttachmentBrokerUnprivilegedMac> broker_; |
- AttachmentBrokerObserver observer_; |
- |
- // A port on which the main process listens for mach messages from the child |
- // process. |
- base::mac::ScopedMachReceiveRight server_port_; |
- |
- // A port on which the child process listens for mach messages from the main |
- // process. |
- base::mac::ScopedMachSendRight client_port_; |
- |
- std::string service_name_; |
- |
- ResultListener result_listener_; |
-}; |
- |
-// These objects are globally accessible, and are expected to outlive all IPC |
-// Channels. |
-struct ChildProcessGlobals { |
- MockPortProvider port_provider; |
- |
- // The broker must be destroyed before the port_provider, so that the broker |
- // gets a chance to unregister itself as an observer. This doesn't matter |
- // outside of tests, since neither port_provider nor broker will ever be |
- // destroyed. |
- std::unique_ptr<IPC::AttachmentBrokerPrivilegedMac> broker; |
- base::mac::ScopedMachSendRight server_task_port; |
- |
- // Total resident memory before running the message loop. |
- mach_vm_size_t initial_resident_size; |
- |
- // Whether to emit log statements while processing messages. |
- bool message_logging; |
-}; |
- |
-using OnMessageReceivedCallback = void (*)(IPC::Sender* sender, |
- const IPC::Message& message, |
- ChildProcessGlobals* globals); |
- |
-// Sets up the Mach communication ports with the server. Returns a set of |
-// globals that must live at least as long as the test. |
-std::unique_ptr<ChildProcessGlobals> CommonChildProcessSetUp() { |
- base::CommandLine cmd_line = *base::CommandLine::ForCurrentProcess(); |
- std::string service_name = |
- cmd_line.GetSwitchValueASCII(g_service_switch_name); |
- base::mac::ScopedMachSendRight server_port( |
- IPC::LookupServer(service_name.c_str())); |
- base::mac::ScopedMachReceiveRight client_port(IPC::MakeReceivingPort()); |
- |
- // Send the port that this process is listening on to the server. |
- IPC::SendMachPort( |
- server_port.get(), client_port.get(), MACH_MSG_TYPE_MAKE_SEND); |
- |
- // Receive the task port of the server process. |
- base::mac::ScopedMachSendRight server_task_port( |
- IPC::ReceiveMachPort(client_port.get())); |
- |
- std::unique_ptr<ChildProcessGlobals> globals(new ChildProcessGlobals); |
- globals->broker.reset( |
- new IPC::AttachmentBrokerPrivilegedMac(&globals->port_provider)); |
- globals->port_provider.InsertEntry(getppid(), server_task_port.get()); |
- globals->server_task_port.reset(server_task_port.release()); |
- globals->message_logging = true; |
- return globals; |
-} |
- |
-int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback, |
- const char* channel_name) { |
- LOG(INFO) << "Privileged process start."; |
- std::unique_ptr<ChildProcessGlobals> globals(CommonChildProcessSetUp()); |
- |
- mach_msg_type_number_t active_names_at_start = IPC::GetActiveNameCount(); |
- |
- base::MessageLoopForIO main_message_loop; |
- ProxyListener listener; |
- |
- std::unique_ptr<IPC::Channel> channel(IPC::Channel::CreateClient( |
- IPCTestBase::GetChannelName(channel_name), &listener)); |
- globals->broker->RegisterCommunicationChannel(channel.get(), nullptr); |
- CHECK(channel->Connect()); |
- |
- globals->initial_resident_size = GetResidentSize(); |
- |
- while (true) { |
- if (globals->message_logging) |
- LOG(INFO) << "Privileged process spinning run loop."; |
- base::RunLoop().Run(); |
- ProxyListener::Reason reason = listener.get_reason(); |
- if (reason == ProxyListener::CHANNEL_ERROR) |
- break; |
- |
- while (listener.has_message()) { |
- if (globals->message_logging) |
- LOG(INFO) << "Privileged process running callback."; |
- callback(channel.get(), listener.get_first_message(), globals.get()); |
- if (globals->message_logging) |
- LOG(INFO) << "Privileged process finishing callback."; |
- listener.pop_first_message(); |
- } |
- } |
- |
- if (active_names_at_start != IPC::GetActiveNameCount()) { |
- LOG(INFO) << "Memory leak!."; |
- } |
- LOG(INFO) << "Privileged process end."; |
- return 0; |
-} |
- |
-// An unprivileged process makes a shared memory region, and writes a string to |
-// it. The SharedMemoryHandle is sent to the privileged process using Chrome |
-// IPC. The privileged process checks that it received the same memory region. |
-TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandle) { |
- CommonSetUp("SendSharedMemoryHandle"); |
- |
- SendMessage1(kDataBuffer1); |
- base::RunLoop().Run(); |
- CommonTearDown(); |
-} |
- |
-void SendSharedMemoryHandleCallback(IPC::Sender* sender, |
- const IPC::Message& message, |
- ChildProcessGlobals* globals) { |
- bool success = CheckContentsOfMessage1(message, kDataBuffer1); |
- SendControlMessage(sender, success); |
-} |
- |
-MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandle) { |
- return CommonPrivilegedProcessMain(&SendSharedMemoryHandleCallback, |
- "SendSharedMemoryHandle"); |
-} |
- |
-// Similar to SendSharedMemoryHandle, but sends a very long shared memory |
-// region. |
-TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleLong) { |
- CommonSetUp("SendSharedMemoryHandleLong"); |
- |
- std::string buffer(1 << 23, 'a'); |
- SendMessage1(buffer); |
- base::RunLoop().Run(); |
- CommonTearDown(); |
-} |
- |
-void SendSharedMemoryHandleLongCallback(IPC::Sender* sender, |
- const IPC::Message& message, |
- ChildProcessGlobals* globals) { |
- std::string buffer(1 << 23, 'a'); |
- bool success = CheckContentsOfMessage1(message, buffer); |
- SendControlMessage(sender, success); |
-} |
- |
-MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleLong) { |
- return CommonPrivilegedProcessMain(&SendSharedMemoryHandleLongCallback, |
- "SendSharedMemoryHandleLong"); |
-} |
- |
-// Similar to SendSharedMemoryHandle, but sends two different shared memory |
-// regions in two messages. |
-TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesDifferentSharedMemoryHandle) { |
- CommonSetUp("SendTwoMessagesDifferentSharedMemoryHandle"); |
- |
- SendMessage1(kDataBuffer1); |
- SendMessage1(kDataBuffer2); |
- base::RunLoop().Run(); |
- CommonTearDown(); |
-} |
- |
-void SendTwoMessagesDifferentSharedMemoryHandleCallback( |
- IPC::Sender* sender, |
- const IPC::Message& message, |
- ChildProcessGlobals* globals) { |
- static int count = 0; |
- static bool success = true; |
- ++count; |
- if (count == 1) { |
- success &= CheckContentsOfMessage1(message, kDataBuffer1); |
- } else if (count == 2) { |
- success &= CheckContentsOfMessage1(message, kDataBuffer2); |
- SendControlMessage(sender, success); |
- } |
-} |
- |
-MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesDifferentSharedMemoryHandle) { |
- return CommonPrivilegedProcessMain( |
- &SendTwoMessagesDifferentSharedMemoryHandleCallback, |
- "SendTwoMessagesDifferentSharedMemoryHandle"); |
-} |
- |
-// Similar to SendSharedMemoryHandle, but sends the same shared memory region in |
-// two messages. |
-TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesSameSharedMemoryHandle) { |
- CommonSetUp("SendTwoMessagesSameSharedMemoryHandle"); |
- |
- { |
- std::unique_ptr<base::SharedMemory> shared_memory( |
- MakeSharedMemory(kDataBuffer1)); |
- |
- for (int i = 0; i < 2; ++i) { |
- IPC::Message* message = |
- new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200); |
- sender()->Send(message); |
- } |
- } |
- |
- base::RunLoop().Run(); |
- CommonTearDown(); |
-} |
- |
-void SendTwoMessagesSameSharedMemoryHandleCallback( |
- IPC::Sender* sender, |
- const IPC::Message& message, |
- ChildProcessGlobals* globals) { |
- static int count = 0; |
- static base::SharedMemoryHandle handle1; |
- ++count; |
- |
- if (count == 1) { |
- handle1 = GetSharedMemoryHandleFromMsg1(message); |
- } else if (count == 2) { |
- base::SharedMemoryHandle handle2(GetSharedMemoryHandleFromMsg1(message)); |
- |
- bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles( |
- handle1, handle2, kDataBuffer1); |
- SendControlMessage(sender, success); |
- } |
-} |
- |
-MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesSameSharedMemoryHandle) { |
- return CommonPrivilegedProcessMain( |
- &SendTwoMessagesSameSharedMemoryHandleCallback, |
- "SendTwoMessagesSameSharedMemoryHandle"); |
-} |
- |
-// Similar to SendSharedMemoryHandle, but sends one message with two different |
-// memory regions. |
-TEST_F(IPCAttachmentBrokerMacTest, |
- SendOneMessageWithTwoDifferentSharedMemoryHandles) { |
- CommonSetUp("SendOneMessageWithTwoDifferentSharedMemoryHandles"); |
- |
- { |
- std::unique_ptr<base::SharedMemory> shared_memory1( |
- MakeSharedMemory(kDataBuffer1)); |
- std::unique_ptr<base::SharedMemory> shared_memory2( |
- MakeSharedMemory(kDataBuffer2)); |
- IPC::Message* message = new TestSharedMemoryHandleMsg2( |
- shared_memory1->handle(), shared_memory2->handle()); |
- sender()->Send(message); |
- } |
- base::RunLoop().Run(); |
- CommonTearDown(); |
-} |
- |
-void SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback( |
- IPC::Sender* sender, |
- const IPC::Message& message, |
- ChildProcessGlobals* globals) { |
- base::SharedMemoryHandle handle1; |
- base::SharedMemoryHandle handle2; |
- if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) { |
- LOG(ERROR) << "Failed to deserialize message."; |
- SendControlMessage(sender, false); |
- return; |
- } |
- |
- bool success = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) && |
- CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2); |
- SendControlMessage(sender, success); |
-} |
- |
-MULTIPROCESS_IPC_TEST_CLIENT_MAIN( |
- SendOneMessageWithTwoDifferentSharedMemoryHandles) { |
- return CommonPrivilegedProcessMain( |
- &SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback, |
- "SendOneMessageWithTwoDifferentSharedMemoryHandles"); |
-} |
- |
-// Similar to SendSharedMemoryHandle, but sends one message that contains the |
-// same memory region twice. |
-TEST_F(IPCAttachmentBrokerMacTest, |
- SendOneMessageWithTwoSameSharedMemoryHandles) { |
- CommonSetUp("SendOneMessageWithTwoSameSharedMemoryHandles"); |
- |
- { |
- std::unique_ptr<base::SharedMemory> shared_memory( |
- MakeSharedMemory(kDataBuffer1)); |
- IPC::Message* message = new TestSharedMemoryHandleMsg2( |
- shared_memory->handle(), shared_memory->handle()); |
- sender()->Send(message); |
- } |
- base::RunLoop().Run(); |
- CommonTearDown(); |
-} |
- |
-void SendOneMessageWithTwoSameSharedMemoryHandlesCallback( |
- IPC::Sender* sender, |
- const IPC::Message& message, |
- ChildProcessGlobals* globals) { |
- base::SharedMemoryHandle handle1; |
- base::SharedMemoryHandle handle2; |
- if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) { |
- LOG(ERROR) << "Failed to deserialize message."; |
- SendControlMessage(sender, false); |
- return; |
- } |
- |
- bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles( |
- handle1, handle2, kDataBuffer1); |
- SendControlMessage(sender, success); |
-} |
- |
-MULTIPROCESS_IPC_TEST_CLIENT_MAIN( |
- SendOneMessageWithTwoSameSharedMemoryHandles) { |
- return CommonPrivilegedProcessMain( |
- &SendOneMessageWithTwoSameSharedMemoryHandlesCallback, |
- "SendOneMessageWithTwoSameSharedMemoryHandles"); |
-} |
- |
-// Sends one message with two Posix FDs and two Mach ports. |
-TEST_F(IPCAttachmentBrokerMacTest, SendPosixFDAndMachPort) { |
- base::ScopedTempDir temp_dir; |
- ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
- base::FilePath fp1, fp2; |
- ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.GetPath(), &fp1)); |
- ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.GetPath(), &fp2)); |
- |
- CommonSetUp("SendPosixFDAndMachPort"); |
- |
- { |
- std::unique_ptr<base::SharedMemory> shared_memory1( |
- MakeSharedMemory(kDataBuffer1)); |
- std::unique_ptr<base::SharedMemory> shared_memory2( |
- MakeSharedMemory(kDataBuffer2)); |
- |
- base::FileDescriptor file_descriptor1( |
- MakeFileDescriptor(fp1, kDataBuffer3)); |
- base::FileDescriptor file_descriptor2( |
- MakeFileDescriptor(fp2, kDataBuffer4)); |
- |
- IPC::Message* message = new TestSharedMemoryHandleMsg3( |
- file_descriptor1, shared_memory1->handle(), file_descriptor2, |
- shared_memory2->handle()); |
- sender()->Send(message); |
- } |
- |
- base::RunLoop().Run(); |
- CommonTearDown(); |
-} |
- |
-void SendPosixFDAndMachPortCallback(IPC::Sender* sender, |
- const IPC::Message& message, |
- ChildProcessGlobals* globals) { |
- TestSharedMemoryHandleMsg3::Schema::Param p; |
- if (!TestSharedMemoryHandleMsg3::Read(&message, &p)) { |
- LOG(ERROR) << "Failed to deserialize message."; |
- SendControlMessage(sender, false); |
- return; |
- } |
- |
- base::SharedMemoryHandle handle1 = std::get<1>(p); |
- base::SharedMemoryHandle handle2 = std::get<3>(p); |
- bool success1 = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) && |
- CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2); |
- if (!success1) |
- LOG(ERROR) << "SharedMemoryHandles have wrong contents."; |
- |
- bool success2 = |
- CheckContentsOfFileDescriptor(std::get<0>(p), kDataBuffer3) && |
- CheckContentsOfFileDescriptor(std::get<2>(p), kDataBuffer4); |
- if (!success2) |
- LOG(ERROR) << "FileDescriptors have wrong contents."; |
- |
- SendControlMessage(sender, success1 && success2); |
-} |
- |
-MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendPosixFDAndMachPort) { |
- return CommonPrivilegedProcessMain(&SendPosixFDAndMachPortCallback, |
- "SendPosixFDAndMachPort"); |
-} |
- |
-// Similar to SendHandle, except the attachment's destination process is this |
-// process. This is an unrealistic scenario, but simulates an unprivileged |
-// process sending an attachment to another unprivileged process. |
-TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelf) { |
- SetBroker(new MockBroker); |
- PreConnectSetUp("SendSharedMemoryHandleToSelf"); |
- // Technically, the channel is an endpoint, but we need the proxy listener to |
- // receive the messages so that it can quit the message loop. |
- channel()->SetAttachmentBrokerEndpoint(false); |
- PostConnectSetUp(); |
- get_proxy_listener()->set_listener(get_broker()); |
- |
- { |
- std::unique_ptr<base::SharedMemory> shared_memory( |
- MakeSharedMemory(kDataBuffer1)); |
- mach_port_urefs_t ref_count = IPC::GetMachRefCount( |
- shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND); |
- |
- IPC::Message* message = |
- new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200); |
- sender()->Send(message); |
- |
- // Wait until the child process has sent this process a message. |
- base::RunLoop().Run(); |
- |
- // Wait for any asynchronous activity to complete. |
- base::RunLoop().RunUntilIdle(); |
- |
- // Get the received attachment. |
- IPC::BrokerableAttachment::AttachmentId* id = get_observer()->get_id(); |
- ASSERT_TRUE(id); |
- scoped_refptr<IPC::BrokerableAttachment> received_attachment; |
- get_broker()->GetAttachmentWithId(*id, &received_attachment); |
- ASSERT_NE(received_attachment.get(), nullptr); |
- |
- // Check that it's has the same name, but that the ref count has increased. |
- base::mac::ScopedMachSendRight memory_object( |
- GetMachPortFromBrokeredAttachment(received_attachment)); |
- ASSERT_EQ(memory_object, shared_memory->handle().GetMemoryObject()); |
- EXPECT_EQ(ref_count + 1, |
- IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(), |
- MACH_PORT_RIGHT_SEND)); |
- } |
- |
- FinalCleanUp(); |
-} |
- |
-void SendSharedMemoryHandleToSelfCallback(IPC::Sender* sender, |
- const IPC::Message&, |
- ChildProcessGlobals* globals) { |
- // Do nothing special. The default behavior already runs the |
- // AttachmentBrokerPrivilegedMac. |
-} |
- |
-MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelf) { |
- return CommonPrivilegedProcessMain(&SendSharedMemoryHandleToSelfCallback, |
- "SendSharedMemoryHandleToSelf"); |
-} |
- |
-// Similar to SendSharedMemoryHandle, but uses a ChannelProxy instead of a |
-// Channel. |
-TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleChannelProxy) { |
- Init("SendSharedMemoryHandleChannelProxy"); |
- MachPreForkSetUp(); |
- |
- SetBroker(new IPC::AttachmentBrokerUnprivilegedMac); |
- get_broker()->AddObserver(get_observer(), task_runner()); |
- |
- std::unique_ptr<base::Thread> thread( |
- new base::Thread("ChannelProxyTestServerThread")); |
- base::Thread::Options options; |
- options.message_loop_type = base::MessageLoop::TYPE_IO; |
- thread->StartWithOptions(options); |
- |
- set_channel_proxy(std::unique_ptr<IPC::ChannelProxy>(new IPC::ChannelProxy( |
- get_proxy_listener(), thread->task_runner().get()))); |
- get_broker()->RegisterBrokerCommunicationChannel(channel_proxy()); |
- channel_proxy()->Init( |
- CreateChannelFactory(GetTestChannelHandle(), thread->task_runner().get()), |
- true); |
- |
- ASSERT_TRUE(StartClient()); |
- |
- MachPostForkSetUp(); |
- active_names_at_start_ = IPC::GetActiveNameCount(); |
- get_proxy_listener()->set_listener(get_result_listener()); |
- |
- SendMessage1(kDataBuffer1); |
- base::RunLoop().Run(); |
- |
- CheckChildResult(); |
- |
- // There should be no leaked names. |
- EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount()); |
- |
- // Close the channel so the client's OnChannelError() gets fired. |
- channel_proxy()->Close(); |
- |
- EXPECT_TRUE(WaitForClientShutdown()); |
- DestroyChannelProxy(); |
-} |
- |
-void SendSharedMemoryHandleChannelProxyCallback(IPC::Sender* sender, |
- const IPC::Message& message, |
- ChildProcessGlobals* globals) { |
- bool success = CheckContentsOfMessage1(message, kDataBuffer1); |
- SendControlMessage(sender, success); |
-} |
- |
-MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleChannelProxy) { |
- return CommonPrivilegedProcessMain( |
- &SendSharedMemoryHandleChannelProxyCallback, |
- "SendSharedMemoryHandleChannelProxy"); |
-} |
- |
-// Similar to SendSharedMemoryHandle, but first makes a copy of the handle using |
-// ShareToProcess(). |
-TEST_F(IPCAttachmentBrokerMacTest, ShareToProcess) { |
- CommonSetUp("ShareToProcess"); |
- |
- { |
- std::unique_ptr<base::SharedMemory> shared_memory( |
- MakeSharedMemory(kDataBuffer1)); |
- base::SharedMemoryHandle new_handle; |
- ASSERT_TRUE(shared_memory->ShareToProcess(0, &new_handle)); |
- IPC::Message* message = |
- new TestSharedMemoryHandleMsg1(100, new_handle, 200); |
- sender()->Send(message); |
- } |
- |
- base::RunLoop().Run(); |
- CommonTearDown(); |
-} |
- |
-void ShareToProcessCallback(IPC::Sender* sender, |
- const IPC::Message& message, |
- ChildProcessGlobals* globals) { |
- bool success = CheckContentsOfMessage1(message, kDataBuffer1); |
- SendControlMessage(sender, success); |
-} |
- |
-MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareToProcess) { |
- return CommonPrivilegedProcessMain(&ShareToProcessCallback, "ShareToProcess"); |
-} |
- |
-// Similar to ShareToProcess, but instead shares the memory object only with |
-// read permissions. |
-TEST_F(IPCAttachmentBrokerMacTest, ShareReadOnlyToProcess) { |
- CommonSetUp("ShareReadOnlyToProcess"); |
- |
- { |
- std::unique_ptr<base::SharedMemory> shared_memory( |
- MakeSharedMemory(kDataBuffer1)); |
- base::SharedMemoryHandle new_handle; |
- ASSERT_TRUE(shared_memory->ShareReadOnlyToProcess(0, &new_handle)); |
- IPC::Message* message = |
- new TestSharedMemoryHandleMsg1(100, new_handle, 200); |
- sender()->Send(message); |
- } |
- |
- base::RunLoop().Run(); |
- CommonTearDown(); |
-} |
- |
-void ShareReadOnlyToProcessCallback(IPC::Sender* sender, |
- const IPC::Message& message, |
- ChildProcessGlobals* globals) { |
- base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message)); |
- |
- // Try to map the memory as writable. |
- std::unique_ptr<base::SharedMemory> shared_memory( |
- MapSharedMemoryHandle(shm, false)); |
- ASSERT_EQ(nullptr, shared_memory->memory()); |
- |
- // Now try as read-only. |
- std::unique_ptr<base::SharedMemory> shared_memory2( |
- MapSharedMemoryHandle(shm.Duplicate(), true)); |
- int current_prot, max_prot; |
- ASSERT_TRUE(IPC::GetMachProtections(shared_memory2->memory(), |
- shared_memory2->mapped_size(), |
- ¤t_prot, &max_prot)); |
- ASSERT_EQ(VM_PROT_READ, current_prot); |
- ASSERT_EQ(VM_PROT_READ, max_prot); |
- |
- bool success = |
- memcmp(shared_memory2->memory(), kDataBuffer1, strlen(kDataBuffer1)) == 0; |
- SendControlMessage(sender, success); |
-} |
- |
-MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareReadOnlyToProcess) { |
- return CommonPrivilegedProcessMain(&ShareReadOnlyToProcessCallback, |
- "ShareReadOnlyToProcess"); |
-} |
- |
-// Similar to SendSharedMemoryHandleToSelf, but the child process pretends to |
-// not have the task port for the parent process. |
-TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelfDelayedPort) { |
- SetBroker(new MockBroker); |
- PreConnectSetUp("SendSharedMemoryHandleToSelfDelayedPort"); |
- // Technically, the channel is an endpoint, but we need the proxy listener to |
- // receive the messages so that it can quit the message loop. |
- channel()->SetAttachmentBrokerEndpoint(false); |
- PostConnectSetUp(); |
- get_proxy_listener()->set_listener(get_broker()); |
- |
- { |
- std::unique_ptr<base::SharedMemory> shared_memory( |
- MakeSharedMemory(kDataBuffer1)); |
- mach_port_urefs_t ref_count = IPC::GetMachRefCount( |
- shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND); |
- |
- std::vector<IPC::BrokerableAttachment::AttachmentId> ids; |
- const int kMessagesToTest = 3; |
- for (int i = 0; i < kMessagesToTest; ++i) { |
- base::SharedMemoryHandle h = shared_memory->handle().Duplicate(); |
- ids.push_back( |
- IPC::BrokerableAttachment::AttachmentId::CreateIdWithRandomNonce()); |
- IPC::internal::MachPortAttachmentMac::WireFormat wire_format( |
- h.GetMemoryObject(), getpid(), ids[i]); |
- sender()->Send(new AttachmentBrokerMsg_DuplicateMachPort(wire_format)); |
- |
- // Send a dummy message, which will trigger the callback handler in the |
- // child process. |
- sender()->Send(new TestSharedMemoryHandleMsg4(1)); |
- } |
- |
- int received_message_count = 0; |
- while (received_message_count < kMessagesToTest) { |
- // Wait until the child process has sent this process a message. |
- base::RunLoop().Run(); |
- |
- // Wait for any asynchronous activity to complete. |
- base::RunLoop().RunUntilIdle(); |
- |
- while (get_proxy_listener()->has_message()) { |
- get_proxy_listener()->pop_first_message(); |
- received_message_count++; |
- } |
- } |
- |
- for (int i = 0; i < kMessagesToTest; ++i) { |
- IPC::BrokerableAttachment::AttachmentId* id = &ids[i]; |
- ASSERT_TRUE(id); |
- scoped_refptr<IPC::BrokerableAttachment> received_attachment; |
- get_broker()->GetAttachmentWithId(*id, &received_attachment); |
- ASSERT_NE(received_attachment.get(), nullptr); |
- |
- base::mac::ScopedMachSendRight memory_object( |
- GetMachPortFromBrokeredAttachment(received_attachment)); |
- ASSERT_EQ(shared_memory->handle().GetMemoryObject(), memory_object); |
- } |
- |
- // Check that the ref count hasn't changed. |
- EXPECT_EQ(ref_count, |
- IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(), |
- MACH_PORT_RIGHT_SEND)); |
- } |
- |
- FinalCleanUp(); |
-} |
- |
-void SendSharedMemoryHandleToSelfDelayedPortCallback( |
- IPC::Sender* sender, |
- const IPC::Message& message, |
- ChildProcessGlobals* globals) { |
- static int i = 0; |
- static base::ProcessId pid = message.get_sender_pid(); |
- static mach_port_t task_port = globals->port_provider.TaskForPid(pid); |
- ++i; |
- |
- if (i == 1) { |
- // Pretend to not have the task port for the parent. |
- globals->port_provider.ClearPortMap(); |
- } else if (i == 2) { |
- // Intentionally do nothing. |
- } else if (i == 3) { |
- // Setting the task port should trigger callbacks, eventually resulting in |
- // multiple attachment broker messages. |
- globals->port_provider.InsertEntry(pid, task_port); |
- } |
-} |
- |
-MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelfDelayedPort) { |
- return CommonPrivilegedProcessMain( |
- &SendSharedMemoryHandleToSelfDelayedPortCallback, |
- "SendSharedMemoryHandleToSelfDelayedPort"); |
-} |
- |
-// Tests the memory usage characteristics of attachment brokering a single large |
-// message. This test has the *potential* to be flaky, since it compares |
-// resident memory at different points in time, and that measurement is |
-// non-deterministic. |
-TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageLargeMessage) { |
- CommonSetUp("MemoryUsageLargeMessage"); |
- |
- std::string test_string(g_large_message_size, 'a'); |
- SendMessage1(test_string); |
- base::RunLoop().Run(); |
- CommonTearDown(); |
-} |
- |
-void MemoryUsageLargeMessageCallback(IPC::Sender* sender, |
- const IPC::Message& message, |
- ChildProcessGlobals* globals) { |
- EXPECT_LE(GetResidentSize(), |
- globals->initial_resident_size + g_expected_memory_increase); |
- |
- base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message)); |
- std::unique_ptr<base::SharedMemory> shared_memory( |
- MapSharedMemoryHandle(shm, false)); |
- EXPECT_LE(GetResidentSize(), |
- globals->initial_resident_size + g_expected_memory_increase); |
- |
- char* addr = static_cast<char*>(shared_memory->memory()); |
- for (size_t i = 0; i < g_large_message_size; i += 1024) { |
- addr[i] = 'a'; |
- } |
- EXPECT_GE(GetResidentSize(), |
- globals->initial_resident_size + g_large_message_size); |
- |
- shared_memory.reset(); |
-#if !defined(ADDRESS_SANITIZER) && !defined(LEAK_SANITIZER) && \ |
- !defined(MEMORY_SANITIZER) && !defined(THREAD_SANITIZER) && \ |
- !defined(UNDEFINED_SANITIZER) |
- // Under a sanitizer build, releasing memory does not necessarily reduce the |
- // amount of resident memory. |
- EXPECT_LE(GetResidentSize(), |
- globals->initial_resident_size + g_expected_memory_increase); |
-#endif |
- |
- SendControlMessage(sender, true); |
-} |
- |
-MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageLargeMessage) { |
- return CommonPrivilegedProcessMain(&MemoryUsageLargeMessageCallback, |
- "MemoryUsageLargeMessage"); |
-} |
- |
-// Tests the memory usage characteristics of attachment brokering many small |
-// messages. This test has the *potential* to be flaky, since it compares |
-// resident memory at different points in time, and that measurement is |
-// non-deterministic. |
-TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageManyMessages) { |
- CommonSetUp("MemoryUsageManyMessages"); |
- |
- for (int i = 0; i < g_large_message_count; ++i) { |
- std::string message = base::IntToString(i); |
- message += '\0'; |
- size_t end = message.size(); |
- message.resize(g_medium_message_size); |
- std::fill(message.begin() + end, message.end(), 'a'); |
- SendMessage1(message); |
- |
- base::RunLoop().RunUntilIdle(); |
- } |
- |
- if (get_result_listener()->get_result() == RESULT_UNKNOWN) |
- base::RunLoop().Run(); |
- |
- CommonTearDown(); |
-} |
- |
-void MemoryUsageManyMessagesCallback(IPC::Sender* sender, |
- const IPC::Message& message, |
- ChildProcessGlobals* globals) { |
- static int message_index = 0; |
- |
- { |
- // Map the shared memory, and make sure that its pages are counting towards |
- // resident size. |
- base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message)); |
- std::unique_ptr<base::SharedMemory> shared_memory( |
- MapSharedMemoryHandle(shm, false)); |
- |
- char* addr = static_cast<char*>(shared_memory->memory()); |
- std::string message_string(addr); |
- int message_int; |
- ASSERT_TRUE(base::StringToInt(message_string, &message_int)); |
- ASSERT_EQ(message_index, message_int); |
- for (size_t i = 0; i < g_medium_message_size; i += 1024) { |
- addr[i] = 'a'; |
- } |
- } |
- |
- ++message_index; |
- |
- if (message_index == 1) { |
- // Disable message logging, since it significantly contributes towards total |
- // memory usage. |
- LOG(INFO) << "Disable privileged process message logging."; |
- globals->message_logging = false; |
- } |
- |
- if (message_index == g_large_message_count) { |
- size_t memory_increase_kb = |
- (GetResidentSize() - globals->initial_resident_size) / 1024; |
- LOG(INFO) << "Increase in memory usage in KB: " << memory_increase_kb; |
- |
-#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \ |
- defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \ |
- defined(UNDEFINED_SANITIZER) |
- // Under a sanitizer build, releasing memory does not necessarily reduce the |
- // amount of resident memory. |
- bool success = true; |
-#else |
- // The total increase in resident size should be less than 1MB. The exact |
- // amount is not deterministic. |
- bool success = memory_increase_kb < 1024; |
-#endif |
- |
- SendControlMessage(sender, success); |
- } |
-} |
- |
-MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageManyMessages) { |
- return CommonPrivilegedProcessMain(&MemoryUsageManyMessagesCallback, |
- "MemoryUsageManyMessages"); |
-} |
- |
-} // namespace |