| 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
 | 
| 
 |