mojo: Delete ChannelPosix's Mach port passing support.
This also removes the MachPortRelay and Mojo's base::PortProvider implementation. Neither are needed with ChannelMac, which can pass Mach ports as part of message sending. Bug: 973882 Change-Id: I767790ddb70226056138d9b840a313e2e64cebd0 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1682855 Commit-Queue: Robert Sesek <rsesek@chromium.org> Reviewed-by: Ken Rockot <rockot@google.com> Reviewed-by: Mark Mentovai <mark@chromium.org> Cr-Commit-Position: refs/heads/master@{#674495}
This commit is contained in:
base
content/app
ipc
mojo/core
BUILD.gnchannel.ccchannel.hchannel_mac.ccchannel_posix.cccore.cccore.h
embedder
mach_port_relay.ccmach_port_relay.hnode_controller.ccnode_controller.htest
services
service_manager
test
@ -376,8 +376,6 @@ jumbo_component("base") {
|
||||
"mac/mach_port_broker.mm",
|
||||
"mac/mach_port_rendezvous.cc",
|
||||
"mac/mach_port_rendezvous.h",
|
||||
"mac/mach_port_util.cc",
|
||||
"mac/mach_port_util.h",
|
||||
"mac/objc_release_properties.h",
|
||||
"mac/objc_release_properties.mm",
|
||||
"mac/os_crash_dumps.cc",
|
||||
|
@ -1,136 +0,0 @@
|
||||
// Copyright 2016 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 "base/mac/mach_port_util.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace {
|
||||
|
||||
// Struct for sending a complex Mach message.
|
||||
struct MachSendComplexMessage {
|
||||
mach_msg_header_t header;
|
||||
mach_msg_body_t body;
|
||||
mach_msg_port_descriptor_t data;
|
||||
};
|
||||
|
||||
// Struct for receiving a complex message.
|
||||
struct MachReceiveComplexMessage {
|
||||
mach_msg_header_t header;
|
||||
mach_msg_body_t body;
|
||||
mach_msg_port_descriptor_t data;
|
||||
mach_msg_trailer_t trailer;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
kern_return_t SendMachPort(mach_port_t endpoint,
|
||||
mach_port_t port_to_send,
|
||||
int disposition) {
|
||||
MachSendComplexMessage send_msg;
|
||||
send_msg.header.msgh_bits =
|
||||
MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0) | MACH_MSGH_BITS_COMPLEX;
|
||||
send_msg.header.msgh_size = sizeof(send_msg);
|
||||
send_msg.header.msgh_remote_port = endpoint;
|
||||
send_msg.header.msgh_local_port = MACH_PORT_NULL;
|
||||
send_msg.header.msgh_reserved = 0;
|
||||
send_msg.header.msgh_id = 0;
|
||||
send_msg.body.msgh_descriptor_count = 1;
|
||||
send_msg.data.name = port_to_send;
|
||||
send_msg.data.disposition = disposition;
|
||||
send_msg.data.type = MACH_MSG_PORT_DESCRIPTOR;
|
||||
|
||||
kern_return_t kr =
|
||||
mach_msg(&send_msg.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT,
|
||||
send_msg.header.msgh_size,
|
||||
0, // receive limit
|
||||
MACH_PORT_NULL, // receive name
|
||||
0, // timeout
|
||||
MACH_PORT_NULL); // notification port
|
||||
|
||||
if (kr != KERN_SUCCESS)
|
||||
mach_port_deallocate(mach_task_self(), endpoint);
|
||||
|
||||
return kr;
|
||||
}
|
||||
|
||||
base::mac::ScopedMachSendRight ReceiveMachPort(mach_port_t port_to_listen_on) {
|
||||
MachReceiveComplexMessage recv_msg;
|
||||
mach_msg_header_t* recv_hdr = &recv_msg.header;
|
||||
recv_hdr->msgh_local_port = port_to_listen_on;
|
||||
recv_hdr->msgh_size = sizeof(recv_msg);
|
||||
|
||||
kern_return_t kr =
|
||||
mach_msg(recv_hdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0,
|
||||
recv_hdr->msgh_size, port_to_listen_on, 0, MACH_PORT_NULL);
|
||||
if (kr != KERN_SUCCESS)
|
||||
return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
|
||||
if (recv_msg.header.msgh_id != 0)
|
||||
return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
|
||||
return base::mac::ScopedMachSendRight(recv_msg.data.name);
|
||||
}
|
||||
|
||||
mach_port_name_t CreateIntermediateMachPort(
|
||||
mach_port_t task_port,
|
||||
base::mac::ScopedMachSendRight port_to_insert,
|
||||
MachCreateError* error_code) {
|
||||
DCHECK_NE(mach_task_self(), task_port);
|
||||
DCHECK_NE(static_cast<mach_port_name_t>(MACH_PORT_NULL), task_port);
|
||||
|
||||
// Make a port with receive rights in the destination task.
|
||||
mach_port_name_t endpoint;
|
||||
kern_return_t kr =
|
||||
mach_port_allocate(task_port, MACH_PORT_RIGHT_RECEIVE, &endpoint);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
if (error_code)
|
||||
*error_code = MachCreateError::ERROR_MAKE_RECEIVE_PORT;
|
||||
return MACH_PORT_NULL;
|
||||
}
|
||||
|
||||
// Change its message queue limit so that it accepts one message.
|
||||
mach_port_limits limits = {};
|
||||
limits.mpl_qlimit = 1;
|
||||
kr = mach_port_set_attributes(task_port, endpoint, MACH_PORT_LIMITS_INFO,
|
||||
reinterpret_cast<mach_port_info_t>(&limits),
|
||||
MACH_PORT_LIMITS_INFO_COUNT);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
if (error_code)
|
||||
*error_code = MachCreateError::ERROR_SET_ATTRIBUTES;
|
||||
mach_port_deallocate(task_port, endpoint);
|
||||
return MACH_PORT_NULL;
|
||||
}
|
||||
|
||||
// Get a send right.
|
||||
mach_port_t send_once_right;
|
||||
mach_msg_type_name_t send_right_type;
|
||||
kr =
|
||||
mach_port_extract_right(task_port, endpoint, MACH_MSG_TYPE_MAKE_SEND_ONCE,
|
||||
&send_once_right, &send_right_type);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
if (error_code)
|
||||
*error_code = MachCreateError::ERROR_EXTRACT_DEST_RIGHT;
|
||||
mach_port_deallocate(task_port, endpoint);
|
||||
return MACH_PORT_NULL;
|
||||
}
|
||||
DCHECK_EQ(static_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND_ONCE),
|
||||
send_right_type);
|
||||
|
||||
// This call takes ownership of |send_once_right|.
|
||||
kr = base::SendMachPort(
|
||||
send_once_right, port_to_insert.get(), MACH_MSG_TYPE_COPY_SEND);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
if (error_code)
|
||||
*error_code = MachCreateError::ERROR_SEND_MACH_PORT;
|
||||
mach_port_deallocate(task_port, endpoint);
|
||||
return MACH_PORT_NULL;
|
||||
}
|
||||
|
||||
// Endpoint is intentionally leaked into the destination task. An IPC must be
|
||||
// sent to the destination task so that it can clean up this port.
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
} // namespace base
|
@ -1,48 +0,0 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
#ifndef BASE_MAC_MACH_PORT_UTIL_H_
|
||||
#define BASE_MAC_MACH_PORT_UTIL_H_
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/mac/scoped_mach_port.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
enum class MachCreateError {
|
||||
ERROR_MAKE_RECEIVE_PORT,
|
||||
ERROR_SET_ATTRIBUTES,
|
||||
ERROR_EXTRACT_DEST_RIGHT,
|
||||
ERROR_SEND_MACH_PORT,
|
||||
};
|
||||
|
||||
// Sends a Mach port to |dest_port|. Assumes that |dest_port| is a send once
|
||||
// right. Takes ownership of |dest_port|.
|
||||
BASE_EXPORT kern_return_t SendMachPort(mach_port_t dest_port,
|
||||
mach_port_t port_to_send,
|
||||
int disposition);
|
||||
|
||||
// Receives a Mach port from |port_to_listen_on|, which should have exactly one
|
||||
// queued message. Returns |MACH_PORT_NULL| on any error.
|
||||
BASE_EXPORT base::mac::ScopedMachSendRight ReceiveMachPort(
|
||||
mach_port_t port_to_listen_on);
|
||||
|
||||
// Creates an intermediate Mach port in |task_port| and sends |port_to_insert|
|
||||
// as a mach_msg to the intermediate Mach port.
|
||||
// |task_port| is the task port of another process.
|
||||
// |port_to_insert| must be a send right in the current task's name space.
|
||||
// Returns the intermediate port on success, and MACH_PORT_NULL on failure.
|
||||
// On failure, |error_code| is set if not null.
|
||||
// This method takes ownership of |port_to_insert|. On success, ownership is
|
||||
// passed to the intermediate Mach port.
|
||||
BASE_EXPORT mach_port_name_t CreateIntermediateMachPort(
|
||||
mach_port_t task_port,
|
||||
base::mac::ScopedMachSendRight port_to_insert,
|
||||
MachCreateError* error_code);
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MAC_MACH_PORT_UTIL_H_
|
@ -15,10 +15,6 @@
|
||||
#include "mojo/core/embedder/embedder.h"
|
||||
#include "mojo/core/embedder/scoped_ipc_support.h"
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#include "content/browser/mach_broker_mac.h"
|
||||
#endif
|
||||
|
||||
namespace content {
|
||||
|
||||
ServiceManagerEnvironment::ServiceManagerEnvironment(
|
||||
@ -29,10 +25,6 @@ ServiceManagerEnvironment::ServiceManagerEnvironment(
|
||||
mojo::core::ScopedIPCSupport::ShutdownPolicy::FAST)),
|
||||
service_manager_context_(
|
||||
std::make_unique<ServiceManagerContext>(ipc_thread_->task_runner())) {
|
||||
#if defined(OS_MACOSX)
|
||||
mojo::core::SetMachPortProvider(MachBroker::GetInstance());
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
auto* system_connection = ServiceManagerConnection::GetForProcess();
|
||||
RegisterCommonBrowserInterfaces(system_connection);
|
||||
system_connection->Start();
|
||||
|
@ -12,10 +12,6 @@
|
||||
#include "mojo/core/embedder/scoped_ipc_support.h"
|
||||
#include "mojo/core/test/test_support_impl.h"
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
#include "mojo/core/embedder/default_mach_broker.h"
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
base::PerfTestSuite test(argc, argv);
|
||||
|
||||
@ -25,10 +21,6 @@ int main(int argc, char** argv) {
|
||||
test_io_thread.task_runner(),
|
||||
mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN);
|
||||
mojo::test::TestSupport::Init(new mojo::core::test::TestSupportImpl());
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
mojo::core::SetMachPortProvider(
|
||||
mojo::core::DefaultMachBroker::Get()->port_provider());
|
||||
#endif
|
||||
|
||||
return test.Run();
|
||||
}
|
||||
|
@ -11,10 +11,6 @@
|
||||
#include "mojo/core/embedder/embedder.h"
|
||||
#include "mojo/core/embedder/scoped_ipc_support.h"
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
#include "mojo/core/embedder/default_mach_broker.h"
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
base::TestSuite test_suite(argc, argv);
|
||||
mojo::core::Init();
|
||||
@ -23,11 +19,6 @@ int main(int argc, char** argv) {
|
||||
test_io_thread.task_runner(),
|
||||
mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN);
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
mojo::core::SetMachPortProvider(
|
||||
mojo::core::DefaultMachBroker::Get()->port_provider());
|
||||
#endif
|
||||
|
||||
return base::LaunchUnitTests(
|
||||
argc, argv,
|
||||
base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
|
||||
|
@ -128,12 +128,8 @@ template("core_impl_source_set") {
|
||||
}
|
||||
}
|
||||
|
||||
if (is_mac && !is_ios) {
|
||||
sources += [
|
||||
"channel_mac.cc",
|
||||
"mach_port_relay.cc",
|
||||
"mach_port_relay.h",
|
||||
]
|
||||
if (is_mac) {
|
||||
sources += [ "channel_mac.cc" ]
|
||||
}
|
||||
|
||||
if (!is_nacl || is_nacl_nonsfi) {
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "build/build_config.h"
|
||||
#include "mojo/core/configuration.h"
|
||||
#include "mojo/core/core.h"
|
||||
#include "mojo/public/cpp/platform/features.h"
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
#include "base/mac/mach_logging.h"
|
||||
@ -154,12 +153,7 @@ Channel::Message::Message(size_t capacity,
|
||||
mach_ports_header_->num_ports = 0;
|
||||
// Initialize all handles to invalid values.
|
||||
for (size_t i = 0; i < max_handles_; ++i) {
|
||||
if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) {
|
||||
mach_ports_header_->entries[i].mach_entry.type = {0};
|
||||
} else {
|
||||
mach_ports_header_->entries[i].posix_entry = {
|
||||
0, static_cast<uint32_t>(MACH_PORT_NULL)};
|
||||
}
|
||||
mach_ports_header_->entries[i] = {0};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -449,56 +443,20 @@ void Channel::Message::SetHandles(
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
size_t mach_port_index = 0;
|
||||
const bool use_channel_mac =
|
||||
base::FeatureList::IsEnabled(features::kMojoChannelMac);
|
||||
if (mach_ports_header_) {
|
||||
for (size_t i = 0; i < max_handles_; ++i) {
|
||||
if (use_channel_mac) {
|
||||
mach_ports_header_->entries[i].mach_entry.type = {0};
|
||||
} else {
|
||||
mach_ports_header_->entries[i].posix_entry = {
|
||||
0, static_cast<uint32_t>(MACH_PORT_NULL)};
|
||||
}
|
||||
mach_ports_header_->entries[i] = {0};
|
||||
}
|
||||
for (size_t i = 0; i < handle_vector_.size(); i++) {
|
||||
if (use_channel_mac) {
|
||||
mach_ports_header_->entries[i].mach_entry.type =
|
||||
static_cast<uint8_t>(handle_vector_[i].handle().type());
|
||||
} else {
|
||||
if (!handle_vector_[i].is_mach_port_name() &&
|
||||
!handle_vector_[i].handle().is_mach_port()) {
|
||||
DCHECK(handle_vector_[i].handle().is_valid_fd());
|
||||
continue;
|
||||
}
|
||||
|
||||
mach_port_t port = handle_vector_[i].is_mach_port_name()
|
||||
? handle_vector_[i].mach_port_name()
|
||||
: handle_vector_[i].handle().GetMachPort().get();
|
||||
mach_ports_header_->entries[mach_port_index].posix_entry.index = i;
|
||||
mach_ports_header_->entries[mach_port_index].posix_entry.mach_port =
|
||||
port;
|
||||
mach_port_index++;
|
||||
}
|
||||
mach_ports_header_->entries[i].type =
|
||||
static_cast<uint8_t>(handle_vector_[i].handle().type());
|
||||
}
|
||||
mach_ports_header_->num_ports =
|
||||
use_channel_mac ? handle_vector_.size()
|
||||
: static_cast<uint16_t>(mach_port_index);
|
||||
mach_ports_header_->num_ports = handle_vector_.size();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<PlatformHandleInTransit> Channel::Message::TakeHandles() {
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
if (mach_ports_header_ &&
|
||||
!base::FeatureList::IsEnabled(features::kMojoChannelMac)) {
|
||||
for (size_t i = 0; i < max_handles_; ++i) {
|
||||
mach_ports_header_->entries[i].posix_entry = {
|
||||
0, static_cast<uint32_t>(MACH_PORT_NULL)};
|
||||
}
|
||||
mach_ports_header_->num_ports = 0;
|
||||
}
|
||||
#endif
|
||||
return std::move(handle_vector_);
|
||||
}
|
||||
|
||||
@ -508,23 +466,6 @@ Channel::Message::TakeHandlesForTransport() {
|
||||
// Not necessary on Windows.
|
||||
NOTREACHED();
|
||||
return std::vector<PlatformHandleInTransit>();
|
||||
#elif defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) {
|
||||
return std::move(handle_vector_);
|
||||
} else {
|
||||
std::vector<PlatformHandleInTransit> non_mach_handles;
|
||||
for (auto& handle : handle_vector_) {
|
||||
if (handle.is_mach_port_name() || handle.handle().is_mach_port()) {
|
||||
// Ownership is effectively transferred to the receiving process
|
||||
// out-of-band via MachPortRelay.
|
||||
handle.CompleteTransit();
|
||||
} else {
|
||||
non_mach_handles.emplace_back(std::move(handle));
|
||||
}
|
||||
}
|
||||
handle_vector_.clear();
|
||||
return non_mach_handles;
|
||||
}
|
||||
#else
|
||||
return std::move(handle_vector_);
|
||||
#endif
|
||||
|
@ -66,7 +66,7 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel
|
||||
// TODO(https://crbug.com/695645): remove legacy support when Arc++ has
|
||||
// updated to Mojo with normal versioned messages.
|
||||
NORMAL_LEGACY = 0,
|
||||
#if defined(OS_MACOSX)
|
||||
#if defined(OS_IOS)
|
||||
// A control message containing handles to echo back.
|
||||
HANDLES_SENT,
|
||||
// A control message containing handles that can now be closed.
|
||||
@ -111,27 +111,12 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel
|
||||
};
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
union MachPortsEntry {
|
||||
// Used with ChannelPosix.
|
||||
struct {
|
||||
// Index of Mach port in the original vector of
|
||||
// PlatformHandleInTransits.
|
||||
uint16_t index;
|
||||
|
||||
// Mach port name.
|
||||
uint32_t mach_port;
|
||||
} posix_entry;
|
||||
|
||||
// Used with ChannelMac.
|
||||
struct {
|
||||
// The PlatformHandle::Type.
|
||||
uint8_t type;
|
||||
} mach_entry;
|
||||
static_assert(sizeof(mach_port_t) <= sizeof(uint32_t),
|
||||
"mach_port_t must be no larger than uint32_t");
|
||||
struct MachPortsEntry {
|
||||
// The PlatformHandle::Type.
|
||||
uint8_t type;
|
||||
};
|
||||
static_assert(sizeof(MachPortsEntry) == 6,
|
||||
"sizeof(MachPortsEntry) must be 6 bytes");
|
||||
static_assert(sizeof(MachPortsEntry) == 1,
|
||||
"sizeof(MachPortsEntry) must be 1 byte");
|
||||
|
||||
// Structure of the extra header field when present on OSX.
|
||||
struct MachPortsExtraHeader {
|
||||
|
@ -133,8 +133,8 @@ class ChannelMac : public Channel,
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < mach_ports_header->num_ports; ++i) {
|
||||
auto type = static_cast<PlatformHandle::Type>(
|
||||
mach_ports_header->entries[i].mach_entry.type);
|
||||
auto type =
|
||||
static_cast<PlatformHandle::Type>(mach_ports_header->entries[i].type);
|
||||
if (type == PlatformHandle::Type::kNone) {
|
||||
return false;
|
||||
} else if (type == PlatformHandle::Type::kFd &&
|
||||
|
@ -28,10 +28,6 @@
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
#include "mojo/core/mach_port_relay.h"
|
||||
#endif
|
||||
|
||||
namespace mojo {
|
||||
namespace core {
|
||||
|
||||
@ -96,9 +92,6 @@ class MessageView {
|
||||
};
|
||||
|
||||
class ChannelPosix : public Channel,
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
public MachPortRelay::Observer,
|
||||
#endif
|
||||
public base::MessageLoopCurrent::DestructionObserver,
|
||||
public base::MessagePumpForIO::FdWatcher {
|
||||
public:
|
||||
@ -118,15 +111,6 @@ class ChannelPosix : public Channel,
|
||||
}
|
||||
|
||||
void Start() override {
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
auto* relay = Core::Get()->GetMachPortRelay();
|
||||
if (relay) {
|
||||
// We should only have a relay if we know the remote process handle,
|
||||
// because that means we're in the broker process.
|
||||
relay->AddObserver(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (io_task_runner_->RunsTasksInCurrentSequence()) {
|
||||
StartOnIOThread();
|
||||
} else {
|
||||
@ -142,30 +126,6 @@ class ChannelPosix : public Channel,
|
||||
}
|
||||
|
||||
void Write(MessagePtr message) override {
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
// If this message has Mach ports and we have a MachPortRelay, use the relay
|
||||
// to rewrite the ports as receive rights from which the send right can be
|
||||
// read. See |MachPortRelay::SendPortsToProcess()|.
|
||||
//
|
||||
// Note that if we don't have a relay, the receiving process must, and they
|
||||
// must also have the ability to extract a send right from the ports that
|
||||
// are already attached.
|
||||
MachPortRelay* relay = Core::Get()->GetMachPortRelay();
|
||||
if (relay && remote_process().is_valid() && message->has_mach_ports()) {
|
||||
if (relay->port_provider()->TaskForPid(remote_process().get()) ==
|
||||
MACH_PORT_NULL) {
|
||||
// We also need to have a task port for the remote process before we can
|
||||
// send it any other ports. If we don't have one yet, queue the message
|
||||
// until OnProcessReady() is invoked.
|
||||
base::AutoLock lock(task_port_wait_lock_);
|
||||
pending_outgoing_with_mach_ports_.emplace_back(std::move(message));
|
||||
return;
|
||||
}
|
||||
|
||||
relay->SendPortsToProcess(message.get(), remote_process().get());
|
||||
}
|
||||
#endif
|
||||
|
||||
bool write_error = false;
|
||||
{
|
||||
base::AutoLock lock(write_lock_);
|
||||
@ -201,82 +161,6 @@ class ChannelPosix : public Channel,
|
||||
bool* deferred) override {
|
||||
if (num_handles > std::numeric_limits<uint16_t>::max())
|
||||
return false;
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
// On OSX, we can have mach ports which are located in the extra header
|
||||
// section.
|
||||
using MachPortsEntry = Channel::Message::MachPortsEntry;
|
||||
using MachPortsExtraHeader = Channel::Message::MachPortsExtraHeader;
|
||||
if (extra_header_size <
|
||||
sizeof(MachPortsExtraHeader) + num_handles * sizeof(MachPortsEntry)) {
|
||||
return false;
|
||||
}
|
||||
const MachPortsExtraHeader* mach_ports_header =
|
||||
reinterpret_cast<const MachPortsExtraHeader*>(extra_header);
|
||||
size_t num_mach_ports = mach_ports_header->num_ports;
|
||||
if (num_mach_ports > num_handles)
|
||||
return false;
|
||||
if (incoming_fds_.size() + num_mach_ports < num_handles)
|
||||
return true;
|
||||
|
||||
std::vector<PlatformHandleInTransit> handles_in_transit(num_handles);
|
||||
const MachPortsEntry* mach_ports = mach_ports_header->entries;
|
||||
|
||||
// If we know the remote process handle, we assume all incoming Mach ports
|
||||
// are send right references owned by the remote process. Otherwise they're
|
||||
// receive ports we can use to read a send right.
|
||||
const bool extract_send_rights = remote_process().is_valid();
|
||||
for (size_t i = 0, mach_port_index = 0; i < num_handles; ++i) {
|
||||
if (mach_port_index < num_mach_ports &&
|
||||
mach_ports[mach_port_index].posix_entry.index == i) {
|
||||
mach_port_t port_name = static_cast<mach_port_t>(
|
||||
mach_ports[mach_port_index].posix_entry.mach_port);
|
||||
if (extract_send_rights) {
|
||||
handles_in_transit[i] =
|
||||
PlatformHandleInTransit::CreateForMachPortName(port_name);
|
||||
} else {
|
||||
handles_in_transit[i] = PlatformHandleInTransit(
|
||||
PlatformHandle(MachPortRelay::ReceiveSendRight(
|
||||
base::mac::ScopedMachReceiveRight(port_name))));
|
||||
}
|
||||
mach_port_index++;
|
||||
} else {
|
||||
if (incoming_fds_.empty())
|
||||
return false;
|
||||
handles_in_transit[i] = PlatformHandleInTransit(
|
||||
PlatformHandle(std::move(incoming_fds_.front())));
|
||||
incoming_fds_.pop_front();
|
||||
}
|
||||
}
|
||||
if (extract_send_rights && num_mach_ports) {
|
||||
MachPortRelay* relay = Core::Get()->GetMachPortRelay();
|
||||
DCHECK(relay);
|
||||
// Extracting send rights requires that we have a task port for the
|
||||
// remote process, which we may not yet have.
|
||||
if (relay->port_provider()->TaskForPid(remote_process().get()) !=
|
||||
MACH_PORT_NULL) {
|
||||
// We do have a task port, so extract the send rights immediately.
|
||||
for (auto& handle : handles_in_transit) {
|
||||
if (handle.is_mach_port_name()) {
|
||||
handle = PlatformHandleInTransit(PlatformHandle(relay->ExtractPort(
|
||||
handle.mach_port_name(), remote_process().get())));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No task port, we have to defer this message.
|
||||
*deferred = true;
|
||||
base::AutoLock lock(task_port_wait_lock_);
|
||||
std::vector<uint8_t> data(payload_size);
|
||||
memcpy(data.data(), payload, payload_size);
|
||||
pending_incoming_with_mach_ports_.emplace_back(
|
||||
std::move(data), std::move(handles_in_transit));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
handles->resize(handles_in_transit.size());
|
||||
for (size_t i = 0; i < handles->size(); ++i)
|
||||
handles->at(i) = handles_in_transit[i].TakeHandle();
|
||||
#else
|
||||
if (incoming_fds_.size() < num_handles)
|
||||
return true;
|
||||
|
||||
@ -285,7 +169,6 @@ class ChannelPosix : public Channel,
|
||||
handles->at(i) = PlatformHandle(std::move(incoming_fds_.front()));
|
||||
incoming_fds_.pop_front();
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -351,74 +234,14 @@ class ChannelPosix : public Channel,
|
||||
socket_.reset();
|
||||
ignore_result(server_.TakePlatformHandle());
|
||||
}
|
||||
#if defined(OS_MACOSX)
|
||||
#if defined(OS_IOS)
|
||||
fds_to_close_.clear();
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
auto* relay = Core::Get()->GetMachPortRelay();
|
||||
if (relay)
|
||||
relay->RemoveObserver(this);
|
||||
#endif
|
||||
|
||||
// May destroy the |this| if it was the last reference.
|
||||
self_ = nullptr;
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
// MachPortRelay::Observer:
|
||||
void OnProcessReady(base::ProcessHandle process) override {
|
||||
if (process != remote_process().get())
|
||||
return;
|
||||
|
||||
io_task_runner_->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(
|
||||
&ChannelPosix::FlushPendingMessagesWithMachPortsOnIOThread, this));
|
||||
}
|
||||
|
||||
void FlushPendingMessagesWithMachPortsOnIOThread() {
|
||||
// We have a task port for the remote process. Now we can send or accept
|
||||
// any pending messages with Mach ports.
|
||||
std::vector<RawIncomingMessage> incoming;
|
||||
std::vector<MessagePtr> outgoing;
|
||||
{
|
||||
base::AutoLock lock(task_port_wait_lock_);
|
||||
if (reject_incoming_messages_with_mach_ports_)
|
||||
return;
|
||||
std::swap(pending_incoming_with_mach_ports_, incoming);
|
||||
std::swap(pending_outgoing_with_mach_ports_, outgoing);
|
||||
}
|
||||
|
||||
DCHECK(remote_process().is_valid());
|
||||
base::ProcessHandle process = remote_process().get();
|
||||
MachPortRelay* relay = Core::Get()->GetMachPortRelay();
|
||||
DCHECK(relay);
|
||||
for (auto& message : incoming) {
|
||||
Channel::Delegate* d = delegate();
|
||||
if (!d)
|
||||
break;
|
||||
std::vector<PlatformHandle> handles(message.handles.size());
|
||||
for (size_t i = 0; i < message.handles.size(); ++i) {
|
||||
if (message.handles[i].is_mach_port_name()) {
|
||||
handles[i] = PlatformHandle(
|
||||
relay->ExtractPort(message.handles[i].mach_port_name(), process));
|
||||
} else {
|
||||
DCHECK(!message.handles[i].owning_process().is_valid());
|
||||
handles[i] = message.handles[i].TakeHandle();
|
||||
}
|
||||
}
|
||||
d->OnChannelMessage(message.data.data(), message.data.size(),
|
||||
std::move(handles));
|
||||
}
|
||||
|
||||
for (auto& message : outgoing) {
|
||||
relay->SendPortsToProcess(message.get(), process);
|
||||
Write(std::move(message));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// base::MessageLoopCurrent::DestructionObserver:
|
||||
void WillDestroyCurrentMessageLoop() override {
|
||||
DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
|
||||
@ -534,8 +357,8 @@ class ChannelPosix : public Channel,
|
||||
// TODO: Handle lots of handles.
|
||||
result = SendmsgWithHandles(socket_.get(), &iov, 1, fds);
|
||||
if (result >= 0) {
|
||||
#if defined(OS_MACOSX)
|
||||
// There is a bug on OSX which makes it dangerous to close
|
||||
#if defined(OS_IOS)
|
||||
// There is a bug in XNU which makes it dangerous to close
|
||||
// a file descriptor while it is in transit. So instead we
|
||||
// store the file descriptor in a set and send a message to
|
||||
// the recipient, which is queued AFTER the message that
|
||||
@ -554,7 +377,7 @@ class ChannelPosix : public Channel,
|
||||
for (auto& fd : fds)
|
||||
fds_to_close_.emplace_back(std::move(fd));
|
||||
}
|
||||
#endif // defined(OS_MACOSX)
|
||||
#endif // defined(OS_IOS)
|
||||
handles_written += num_handles_to_send;
|
||||
DCHECK_LE(handles_written, num_handles);
|
||||
message_view.set_num_handles_sent(handles_written);
|
||||
@ -574,8 +397,8 @@ class ChannelPosix : public Channel,
|
||||
if (result < 0) {
|
||||
if (errno != EAGAIN &&
|
||||
errno != EWOULDBLOCK
|
||||
#if defined(OS_MACOSX)
|
||||
// On OS X if sendmsg() is trying to send fds between processes and
|
||||
#if defined(OS_IOS)
|
||||
// On iOS if sendmsg() is trying to send fds between processes and
|
||||
// there isn't enough room in the output buffer to send the fd
|
||||
// structure over atomically then EMSGSIZE is returned.
|
||||
//
|
||||
@ -590,7 +413,7 @@ class ChannelPosix : public Channel,
|
||||
// passing the FD over atomically.
|
||||
&& errno != EMSGSIZE
|
||||
#endif
|
||||
) {
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
message_view.SetHandles(std::move(handles));
|
||||
@ -633,7 +456,7 @@ class ChannelPosix : public Channel,
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#if defined(OS_IOS)
|
||||
bool OnControlMessage(Message::MessageType message_type,
|
||||
const void* payload,
|
||||
size_t payload_size,
|
||||
@ -699,7 +522,7 @@ class ChannelPosix : public Channel,
|
||||
fds_to_close_.erase(start, it);
|
||||
return true;
|
||||
}
|
||||
#endif // defined(OS_MACOSX)
|
||||
#endif // defined(OS_IOS)
|
||||
|
||||
void OnWriteError(Error error) {
|
||||
DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
|
||||
@ -745,30 +568,10 @@ class ChannelPosix : public Channel,
|
||||
|
||||
bool leak_handle_ = false;
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#if defined(OS_IOS)
|
||||
base::Lock fds_to_close_lock_;
|
||||
std::vector<base::ScopedFD> fds_to_close_;
|
||||
#if !defined(OS_IOS)
|
||||
// Guards access to the send/receive queues below. These are messages that
|
||||
// can't be fully accepted from or dispatched to the Channel user yet because
|
||||
// we're still waiting on a task port for the remote process.
|
||||
struct RawIncomingMessage {
|
||||
RawIncomingMessage(std::vector<uint8_t> data,
|
||||
std::vector<PlatformHandleInTransit> handles)
|
||||
: data(std::move(data)), handles(std::move(handles)) {}
|
||||
RawIncomingMessage(RawIncomingMessage&&) = default;
|
||||
~RawIncomingMessage() = default;
|
||||
|
||||
std::vector<uint8_t> data;
|
||||
std::vector<PlatformHandleInTransit> handles;
|
||||
};
|
||||
|
||||
base::Lock task_port_wait_lock_;
|
||||
bool reject_incoming_messages_with_mach_ports_ = false;
|
||||
std::vector<MessagePtr> pending_outgoing_with_mach_ports_;
|
||||
std::vector<RawIncomingMessage> pending_incoming_with_mach_ports_;
|
||||
#endif // !defined(OS_IOS)
|
||||
#endif // defined(OS_MACOSX)
|
||||
#endif // defined(OS_IOS)
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ChannelPosix);
|
||||
};
|
||||
|
@ -213,18 +213,6 @@ void Core::ConnectIsolated(ConnectionParams connection_params,
|
||||
connection_name);
|
||||
}
|
||||
|
||||
void Core::SetMachPortProvider(base::PortProvider* port_provider) {
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
GetNodeController()->CreateMachPortRelay(port_provider);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
MachPortRelay* Core::GetMachPortRelay() {
|
||||
return GetNodeController()->GetMachPortRelay();
|
||||
}
|
||||
#endif
|
||||
|
||||
MojoHandle Core::AddDispatcher(scoped_refptr<Dispatcher> dispatcher) {
|
||||
base::AutoLock lock(handles_->GetLock());
|
||||
return handles_->AddDispatcher(dispatcher);
|
||||
|
@ -30,14 +30,9 @@
|
||||
#include "mojo/public/c/system/trap.h"
|
||||
#include "mojo/public/c/system/types.h"
|
||||
|
||||
namespace base {
|
||||
class PortProvider;
|
||||
}
|
||||
|
||||
namespace mojo {
|
||||
namespace core {
|
||||
|
||||
class MachPortRelay;
|
||||
class PlatformSharedMemoryMapping;
|
||||
|
||||
// |Core| is an object that implements the Mojo system calls. All public methods
|
||||
@ -112,13 +107,6 @@ class MOJO_SYSTEM_IMPL_EXPORT Core {
|
||||
const ports::PortRef& port,
|
||||
base::StringPiece connection_name);
|
||||
|
||||
// Sets the mach port provider for this process.
|
||||
void SetMachPortProvider(base::PortProvider* port_provider);
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
MachPortRelay* GetMachPortRelay();
|
||||
#endif
|
||||
|
||||
MojoHandle AddDispatcher(scoped_refptr<Dispatcher> dispatcher);
|
||||
|
||||
// Adds new dispatchers for non-message-pipe handles received in a message.
|
||||
|
@ -16,11 +16,6 @@ component("embedder") {
|
||||
"scoped_ipc_support.cc",
|
||||
]
|
||||
|
||||
if (is_mac && !is_ios) {
|
||||
public += [ "default_mach_broker.h" ]
|
||||
sources += [ "default_mach_broker.cc" ]
|
||||
}
|
||||
|
||||
defines = [ "IS_MOJO_CORE_EMBEDDER_IMPL" ]
|
||||
|
||||
public_deps = [
|
||||
|
@ -1,45 +0,0 @@
|
||||
// Copyright 2016 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 "mojo/core/embedder/default_mach_broker.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace core {
|
||||
|
||||
namespace {
|
||||
const char kBootstrapPortName[] = "mojo_default_mach_broker";
|
||||
}
|
||||
|
||||
// static
|
||||
void DefaultMachBroker::SendTaskPortToParent() {
|
||||
bool result =
|
||||
base::MachPortBroker::ChildSendTaskPortToParent(kBootstrapPortName);
|
||||
DCHECK(result);
|
||||
}
|
||||
|
||||
// static
|
||||
DefaultMachBroker* DefaultMachBroker::Get() {
|
||||
static DefaultMachBroker* broker = new DefaultMachBroker;
|
||||
return broker;
|
||||
}
|
||||
|
||||
DefaultMachBroker::DefaultMachBroker() : broker_(kBootstrapPortName) {
|
||||
bool result = broker_.Init();
|
||||
DCHECK(result);
|
||||
}
|
||||
|
||||
DefaultMachBroker::~DefaultMachBroker() {}
|
||||
|
||||
void DefaultMachBroker::ExpectPid(base::ProcessHandle pid) {
|
||||
broker_.AddPlaceholderForPid(pid);
|
||||
}
|
||||
|
||||
void DefaultMachBroker::RemovePid(base::ProcessHandle pid) {
|
||||
broker_.InvalidatePid(pid);
|
||||
}
|
||||
|
||||
} // namespace core
|
||||
} // namespace mojo
|
@ -1,53 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
#ifndef MOJO_CORE_EMBEDDER_DEFAULT_MACH_BROKER_H_
|
||||
#define MOJO_CORE_EMBEDDER_DEFAULT_MACH_BROKER_H_
|
||||
|
||||
#include "base/component_export.h"
|
||||
#include "base/mac/mach_port_broker.h"
|
||||
#include "base/macros.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace core {
|
||||
|
||||
// A singleton Mojo embedders can use to manage task port brokering among
|
||||
// connected processes.
|
||||
class COMPONENT_EXPORT(MOJO_CORE_EMBEDDER) DefaultMachBroker {
|
||||
public:
|
||||
// Sends the task port of the current process to the parent over Mach IPC.
|
||||
// For use in child processes.
|
||||
static void SendTaskPortToParent();
|
||||
|
||||
// Returns the global |DefaultMachBroker|.
|
||||
static DefaultMachBroker* Get();
|
||||
|
||||
// Registers |pid| with a MACH_PORT_NULL task port in the port provider. A
|
||||
// child's pid must be registered before the broker will accept a task port
|
||||
// from that child.
|
||||
//
|
||||
// Callers MUST have the lock acquired (see |GetLock()) while calling this.
|
||||
void ExpectPid(base::ProcessHandle pid);
|
||||
|
||||
// Removes |pid| from the port provider.
|
||||
//
|
||||
// Callers MUST have the lock acquired (see |GetLock()) while calling this.
|
||||
void RemovePid(base::ProcessHandle pid);
|
||||
|
||||
base::Lock& GetLock() { return broker_.GetLock(); }
|
||||
base::PortProvider* port_provider() { return &broker_; }
|
||||
|
||||
private:
|
||||
DefaultMachBroker();
|
||||
~DefaultMachBroker();
|
||||
|
||||
base::MachPortBroker broker_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DefaultMachBroker);
|
||||
};
|
||||
|
||||
} // namespace core
|
||||
} // namespace mojo
|
||||
|
||||
#endif // MOJO_CORE_EMBEDDER_DEFAULT_MACH_BROKER_H_
|
@ -39,12 +39,5 @@ scoped_refptr<base::TaskRunner> GetIOTaskRunner() {
|
||||
return Core::Get()->GetNodeController()->io_task_runner();
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
void SetMachPortProvider(base::PortProvider* port_provider) {
|
||||
DCHECK(port_provider);
|
||||
Core::Get()->SetMachPortProvider(port_provider);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace core
|
||||
} // namespace mojo
|
||||
|
@ -18,10 +18,6 @@
|
||||
#include "build/build_config.h"
|
||||
#include "mojo/core/embedder/configuration.h"
|
||||
|
||||
namespace base {
|
||||
class PortProvider;
|
||||
}
|
||||
|
||||
namespace mojo {
|
||||
namespace core {
|
||||
|
||||
@ -50,15 +46,6 @@ void SetDefaultProcessErrorCallback(const ProcessErrorCallback& callback);
|
||||
COMPONENT_EXPORT(MOJO_CORE_EMBEDDER)
|
||||
scoped_refptr<base::TaskRunner> GetIOTaskRunner();
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
// Set the |base::PortProvider| for this process. Can be called on any thread,
|
||||
// but must be set in the root process before any Mach ports can be transferred.
|
||||
//
|
||||
// If called at all, this must be called while a ScopedIPCSupport exists.
|
||||
COMPONENT_EXPORT(MOJO_CORE_EMBEDDER)
|
||||
void SetMachPortProvider(base::PortProvider* port_provider);
|
||||
#endif
|
||||
|
||||
} // namespace core
|
||||
} // namespace mojo
|
||||
|
||||
|
@ -1,200 +0,0 @@
|
||||
// Copyright 2016 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 "mojo/core/mach_port_relay.h"
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/mac/mach_port_util.h"
|
||||
#include "base/mac/scoped_mach_port.h"
|
||||
#include "base/metrics/histogram_macros.h"
|
||||
#include "base/process/process.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace core {
|
||||
|
||||
namespace {
|
||||
|
||||
// Errors that can occur in the broker (privileged parent) process.
|
||||
// These match tools/metrics/histograms.xml.
|
||||
// This enum is append-only.
|
||||
enum class BrokerUMAError : int {
|
||||
SUCCESS = 0,
|
||||
// Couldn't get a task port for the process with a given pid.
|
||||
ERROR_TASK_FOR_PID = 1,
|
||||
// Couldn't make a port with receive rights in the destination process.
|
||||
ERROR_MAKE_RECEIVE_PORT = 2,
|
||||
// Couldn't change the attributes of a Mach port.
|
||||
ERROR_SET_ATTRIBUTES = 3,
|
||||
// Couldn't extract a right from the destination.
|
||||
ERROR_EXTRACT_DEST_RIGHT = 4,
|
||||
// Couldn't send a Mach port in a call to mach_msg().
|
||||
ERROR_SEND_MACH_PORT = 5,
|
||||
// Couldn't extract a right from the source.
|
||||
ERROR_EXTRACT_SOURCE_RIGHT = 6,
|
||||
ERROR_MAX
|
||||
};
|
||||
|
||||
// Errors that can occur in a child process.
|
||||
// These match tools/metrics/histograms.xml.
|
||||
// This enum is append-only.
|
||||
enum class ChildUMAError : int {
|
||||
SUCCESS = 0,
|
||||
// An error occurred while trying to receive a Mach port with mach_msg().
|
||||
ERROR_RECEIVE_MACH_MESSAGE = 1,
|
||||
ERROR_MAX
|
||||
};
|
||||
|
||||
void ReportBrokerError(BrokerUMAError error) {
|
||||
UMA_HISTOGRAM_ENUMERATION("Mojo.MachPortRelay.BrokerError",
|
||||
static_cast<int>(error),
|
||||
static_cast<int>(BrokerUMAError::ERROR_MAX));
|
||||
}
|
||||
|
||||
void ReportChildError(ChildUMAError error) {
|
||||
UMA_HISTOGRAM_ENUMERATION("Mojo.MachPortRelay.ChildError",
|
||||
static_cast<int>(error),
|
||||
static_cast<int>(ChildUMAError::ERROR_MAX));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
base::mac::ScopedMachSendRight MachPortRelay::ReceiveSendRight(
|
||||
base::mac::ScopedMachReceiveRight port) {
|
||||
// MACH_PORT_NULL doesn't need translation.
|
||||
if (!port.is_valid())
|
||||
return base::mac::ScopedMachSendRight();
|
||||
|
||||
// Take ownership of the receive right. We only need it to read this single
|
||||
// send right, then it can be closed.
|
||||
base::mac::ScopedMachSendRight received_port(
|
||||
base::ReceiveMachPort(port.get()));
|
||||
if (!received_port.is_valid()) {
|
||||
ReportChildError(ChildUMAError::ERROR_RECEIVE_MACH_MESSAGE);
|
||||
DLOG(ERROR) << "Error receiving mach port";
|
||||
return base::mac::ScopedMachSendRight();
|
||||
}
|
||||
|
||||
ReportChildError(ChildUMAError::SUCCESS);
|
||||
return received_port;
|
||||
}
|
||||
|
||||
MachPortRelay::MachPortRelay(base::PortProvider* port_provider)
|
||||
: port_provider_(port_provider) {
|
||||
DCHECK(port_provider);
|
||||
port_provider_->AddObserver(this);
|
||||
}
|
||||
|
||||
MachPortRelay::~MachPortRelay() {
|
||||
port_provider_->RemoveObserver(this);
|
||||
}
|
||||
|
||||
void MachPortRelay::SendPortsToProcess(Channel::Message* message,
|
||||
base::ProcessHandle process) {
|
||||
DCHECK(message);
|
||||
mach_port_t task_port = port_provider_->TaskForPid(process);
|
||||
|
||||
std::vector<PlatformHandleInTransit> handles = message->TakeHandles();
|
||||
// Message should have handles, otherwise there's no point in calling this
|
||||
// function.
|
||||
DCHECK(!handles.empty());
|
||||
for (auto& handle : handles) {
|
||||
if (!handle.handle().is_valid_mach_port())
|
||||
continue;
|
||||
|
||||
if (task_port == MACH_PORT_NULL) {
|
||||
// Callers check the port provider for the task port before calling this
|
||||
// function, in order to queue pending messages. Therefore, if this fails,
|
||||
// it should be considered a genuine, bona fide, electrified, six-car
|
||||
// error.
|
||||
ReportBrokerError(BrokerUMAError::ERROR_TASK_FOR_PID);
|
||||
handle = PlatformHandleInTransit(
|
||||
PlatformHandle(base::mac::ScopedMachSendRight()));
|
||||
continue;
|
||||
}
|
||||
|
||||
mach_port_name_t intermediate_port;
|
||||
base::MachCreateError error_code;
|
||||
intermediate_port = base::CreateIntermediateMachPort(
|
||||
task_port, handle.TakeHandle().TakeMachPort(), &error_code);
|
||||
if (intermediate_port == MACH_PORT_NULL) {
|
||||
BrokerUMAError uma_error;
|
||||
switch (error_code) {
|
||||
case base::MachCreateError::ERROR_MAKE_RECEIVE_PORT:
|
||||
uma_error = BrokerUMAError::ERROR_MAKE_RECEIVE_PORT;
|
||||
break;
|
||||
case base::MachCreateError::ERROR_SET_ATTRIBUTES:
|
||||
uma_error = BrokerUMAError::ERROR_SET_ATTRIBUTES;
|
||||
break;
|
||||
case base::MachCreateError::ERROR_EXTRACT_DEST_RIGHT:
|
||||
uma_error = BrokerUMAError::ERROR_EXTRACT_DEST_RIGHT;
|
||||
break;
|
||||
case base::MachCreateError::ERROR_SEND_MACH_PORT:
|
||||
uma_error = BrokerUMAError::ERROR_SEND_MACH_PORT;
|
||||
break;
|
||||
}
|
||||
ReportBrokerError(uma_error);
|
||||
handle = PlatformHandleInTransit(
|
||||
PlatformHandle(base::mac::ScopedMachSendRight()));
|
||||
continue;
|
||||
}
|
||||
|
||||
handle = PlatformHandleInTransit::CreateForMachPortName(intermediate_port);
|
||||
ReportBrokerError(BrokerUMAError::SUCCESS);
|
||||
}
|
||||
message->SetHandles(std::move(handles));
|
||||
}
|
||||
|
||||
base::mac::ScopedMachSendRight MachPortRelay::ExtractPort(
|
||||
mach_port_t port_name,
|
||||
base::ProcessHandle process) {
|
||||
// No extraction necessary for MACH_PORT_NULL.
|
||||
if (port_name == MACH_PORT_NULL)
|
||||
return base::mac::ScopedMachSendRight();
|
||||
|
||||
mach_port_t task_port = port_provider_->TaskForPid(process);
|
||||
if (task_port == MACH_PORT_NULL) {
|
||||
ReportBrokerError(BrokerUMAError::ERROR_TASK_FOR_PID);
|
||||
return base::mac::ScopedMachSendRight();
|
||||
}
|
||||
|
||||
mach_port_t extracted_right = MACH_PORT_NULL;
|
||||
mach_msg_type_name_t extracted_right_type;
|
||||
kern_return_t kr =
|
||||
mach_port_extract_right(task_port, port_name, MACH_MSG_TYPE_MOVE_SEND,
|
||||
&extracted_right, &extracted_right_type);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
ReportBrokerError(BrokerUMAError::ERROR_EXTRACT_SOURCE_RIGHT);
|
||||
return base::mac::ScopedMachSendRight();
|
||||
}
|
||||
|
||||
ReportBrokerError(BrokerUMAError::SUCCESS);
|
||||
DCHECK_EQ(static_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND),
|
||||
extracted_right_type);
|
||||
return base::mac::ScopedMachSendRight(extracted_right);
|
||||
}
|
||||
|
||||
void MachPortRelay::AddObserver(Observer* observer) {
|
||||
base::AutoLock locker(observers_lock_);
|
||||
bool inserted = observers_.insert(observer).second;
|
||||
DCHECK(inserted);
|
||||
}
|
||||
|
||||
void MachPortRelay::RemoveObserver(Observer* observer) {
|
||||
base::AutoLock locker(observers_lock_);
|
||||
observers_.erase(observer);
|
||||
}
|
||||
|
||||
void MachPortRelay::OnReceivedTaskPort(base::ProcessHandle process) {
|
||||
base::AutoLock locker(observers_lock_);
|
||||
for (auto* observer : observers_)
|
||||
observer->OnProcessReady(process);
|
||||
}
|
||||
|
||||
} // namespace core
|
||||
} // namespace mojo
|
@ -1,90 +0,0 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
#ifndef MOJO_CORE_MACH_PORT_RELAY_H_
|
||||
#define MOJO_CORE_MACH_PORT_RELAY_H_
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/process/port_provider_mac.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
#include "mojo/core/channel.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace core {
|
||||
|
||||
// The MachPortRelay is used by a privileged process, usually the root process,
|
||||
// to manipulate Mach ports in a child process. Ports can be added to and
|
||||
// extracted from a child process that has registered itself with the
|
||||
// |base::PortProvider| used by this class.
|
||||
class MachPortRelay : public base::PortProvider::Observer {
|
||||
public:
|
||||
class Observer {
|
||||
public:
|
||||
// Called by the MachPortRelay to notify observers that a new process is
|
||||
// ready for Mach ports to be sent/received. There are no guarantees about
|
||||
// the thread this is called on, including the presence of a MessageLoop.
|
||||
// Implementations must not call AddObserver() or RemoveObserver() during
|
||||
// this function, as doing so will deadlock.
|
||||
virtual void OnProcessReady(base::ProcessHandle process) = 0;
|
||||
};
|
||||
|
||||
// Used by a child process to receive Mach ports from a sender (privileged)
|
||||
// process. The Mach port in |port| is interpreted as an intermediate Mach
|
||||
// port. It replaces each Mach port with the final Mach port received from the
|
||||
// intermediate port. This method takes ownership of the intermediate Mach
|
||||
// port and gives ownership of the final Mach port to the caller.
|
||||
//
|
||||
// On failure, returns a null send right.
|
||||
//
|
||||
// See SendPortsToProcess() for the definition of intermediate and final Mach
|
||||
// ports.
|
||||
static base::mac::ScopedMachSendRight ReceiveSendRight(
|
||||
base::mac::ScopedMachReceiveRight port);
|
||||
|
||||
explicit MachPortRelay(base::PortProvider* port_provider);
|
||||
~MachPortRelay() override;
|
||||
|
||||
// Sends the Mach ports attached to |message| to |process|.
|
||||
// For each Mach port attached to |message|, a new Mach port, the intermediate
|
||||
// port, is created in |process|. The message's Mach port is then sent over
|
||||
// this intermediate port and the message is modified to refer to the name of
|
||||
// the intermediate port. The Mach port received over the intermediate port in
|
||||
// the child is referred to as the final Mach port.
|
||||
//
|
||||
// All ports in |message|'s set of handles are reset by this call, and all
|
||||
// port names in the message's header are replaced with the new receive right
|
||||
// ports.
|
||||
void SendPortsToProcess(Channel::Message* message,
|
||||
base::ProcessHandle process);
|
||||
|
||||
// Given the name of a Mach send right within |process|, extracts an owned
|
||||
// send right ref and returns it. May return a null port on failure.
|
||||
base::mac::ScopedMachSendRight ExtractPort(mach_port_t port_name,
|
||||
base::ProcessHandle process);
|
||||
|
||||
// Observer interface.
|
||||
void AddObserver(Observer* observer);
|
||||
void RemoveObserver(Observer* observer);
|
||||
|
||||
base::PortProvider* port_provider() const { return port_provider_; }
|
||||
|
||||
private:
|
||||
// base::PortProvider::Observer implementation.
|
||||
void OnReceivedTaskPort(base::ProcessHandle process) override;
|
||||
|
||||
base::PortProvider* const port_provider_;
|
||||
|
||||
base::Lock observers_lock_;
|
||||
std::set<Observer*> observers_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MachPortRelay);
|
||||
};
|
||||
|
||||
} // namespace core
|
||||
} // namespace mojo
|
||||
|
||||
#endif // MOJO_CORE_MACH_PORT_RELAY_H_
|
@ -32,10 +32,6 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
#include "mojo/core/mach_port_relay.h"
|
||||
#endif
|
||||
|
||||
#if !defined(OS_NACL)
|
||||
#include "crypto/random.h"
|
||||
#endif
|
||||
@ -158,14 +154,6 @@ NodeController::NodeController(Core* core)
|
||||
DVLOG(1) << "Initializing node " << name_;
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
void NodeController::CreateMachPortRelay(base::PortProvider* port_provider) {
|
||||
base::AutoLock lock(mach_port_relay_lock_);
|
||||
DCHECK(!mach_port_relay_);
|
||||
mach_port_relay_.reset(new MachPortRelay(port_provider));
|
||||
}
|
||||
#endif
|
||||
|
||||
void NodeController::SetIOTaskRunner(
|
||||
scoped_refptr<base::TaskRunner> task_runner) {
|
||||
io_task_runner_ = task_runner;
|
||||
@ -1221,20 +1209,6 @@ void NodeController::OnChannelError(const ports::NodeName& from_node,
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
MachPortRelay* NodeController::GetMachPortRelay() {
|
||||
{
|
||||
base::AutoLock lock(inviter_lock_);
|
||||
// Return null if we're not the root.
|
||||
if (bootstrap_inviter_channel_ || inviter_name_ != ports::kInvalidNodeName)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
base::AutoLock lock(mach_port_relay_lock_);
|
||||
return mach_port_relay_.get();
|
||||
}
|
||||
#endif
|
||||
|
||||
void NodeController::CancelPendingPortMerges() {
|
||||
std::vector<ports::PortRef> ports_to_close;
|
||||
|
||||
|
@ -31,16 +31,11 @@
|
||||
#include "mojo/core/system_impl_export.h"
|
||||
#include "mojo/public/cpp/platform/platform_handle.h"
|
||||
|
||||
namespace base {
|
||||
class PortProvider;
|
||||
}
|
||||
|
||||
namespace mojo {
|
||||
namespace core {
|
||||
|
||||
class Broker;
|
||||
class Core;
|
||||
class MachPortRelay;
|
||||
|
||||
// The owner of ports::Node which facilitates core EDK implementation. All
|
||||
// public interface methods are safe to call from any thread.
|
||||
@ -66,11 +61,6 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
|
||||
return io_task_runner_;
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
// Create the relay used to transfer mach ports between processes.
|
||||
void CreateMachPortRelay(base::PortProvider* port_provider);
|
||||
#endif
|
||||
|
||||
// Called exactly once, shortly after construction, and before any other
|
||||
// methods are called on this object.
|
||||
void SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner);
|
||||
@ -233,10 +223,6 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
|
||||
void OnChannelError(const ports::NodeName& from_node,
|
||||
NodeChannel* channel) override;
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
MachPortRelay* GetMachPortRelay();
|
||||
#endif
|
||||
|
||||
// Cancels all pending port merges. These are merges which are supposed to
|
||||
// be requested from the inviter ASAP, and they may be cancelled if the
|
||||
// connection to the inviter is broken or never established.
|
||||
@ -335,12 +321,6 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
|
||||
std::unique_ptr<Broker> broker_;
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
base::Lock mach_port_relay_lock_;
|
||||
// Relay for transferring mach ports to/from broker clients.
|
||||
std::unique_ptr<MachPortRelay> mach_port_relay_;
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(NodeController);
|
||||
};
|
||||
|
||||
|
@ -35,10 +35,6 @@
|
||||
#include "mojo/public/cpp/system/platform_handle.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
#include "mojo/core/embedder/default_mach_broker.h"
|
||||
#endif
|
||||
|
||||
#if !defined(OS_FUCHSIA)
|
||||
#include "mojo/public/cpp/platform/named_platform_channel.h"
|
||||
#endif
|
||||
@ -212,26 +208,9 @@ ScopedMessagePipeHandle MultiprocessTestHelper::StartChildWithExtraSwitch(
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
// This lock needs to be held while launching the child because the Mach port
|
||||
// broker only allows task ports to be received from known child processes.
|
||||
// However, it can only know the child process's pid after the child has
|
||||
// launched. To prevent a race where the child process sends its task port
|
||||
// before the pid has been registered, the lock needs to be held over both
|
||||
// launch and child pid registration.
|
||||
auto* mach_broker = mojo::core::DefaultMachBroker::Get();
|
||||
mach_broker->GetLock().Acquire();
|
||||
#endif
|
||||
|
||||
test_child_ =
|
||||
base::SpawnMultiProcessTestChild(test_child_main, command_line, options);
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
if (test_child_.IsValid())
|
||||
mach_broker->ExpectPid(test_child_.Pid());
|
||||
mach_broker->GetLock().Release();
|
||||
#endif
|
||||
|
||||
if (launch_type == LaunchType::CHILD || launch_type == LaunchType::PEER)
|
||||
channel.RemoteProcessLaunchAttempted();
|
||||
|
||||
@ -260,13 +239,6 @@ int MultiprocessTestHelper::WaitForChildShutdown() {
|
||||
int rv = -1;
|
||||
WaitForMultiprocessTestChildExit(test_child_, TestTimeouts::action_timeout(),
|
||||
&rv);
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
auto* mach_broker = mojo::core::DefaultMachBroker::Get();
|
||||
base::AutoLock lock(mach_broker->GetLock());
|
||||
mach_broker->RemovePid(test_child_.Pid());
|
||||
#endif
|
||||
|
||||
test_child_.Close();
|
||||
return rv;
|
||||
}
|
||||
@ -282,10 +254,6 @@ void MultiprocessTestHelper::ChildSetup() {
|
||||
auto& command_line = *base::CommandLine::ForCurrentProcess();
|
||||
|
||||
bool run_as_broker_client = command_line.HasSwitch(kRunAsBrokerClient);
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
if (run_as_broker_client)
|
||||
DefaultMachBroker::SendTaskPortToParent();
|
||||
#endif
|
||||
|
||||
PlatformChannelEndpoint endpoint;
|
||||
#if !defined(OS_FUCHSIA)
|
||||
|
@ -20,10 +20,6 @@
|
||||
#include "mojo/public/tests/test_support_private.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
#include "mojo/core/embedder/default_mach_broker.h"
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
#if !defined(OS_ANDROID)
|
||||
// Silence death test thread warnings on Linux. We can afford to run our death
|
||||
@ -49,11 +45,6 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
mojo::core::Init(mojo_config);
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
mojo::core::SetMachPortProvider(
|
||||
mojo::core::DefaultMachBroker::Get()->port_provider());
|
||||
#endif
|
||||
|
||||
mojo::test::TestSupport::Init(new mojo::core::test::TestSupportImpl());
|
||||
base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
|
||||
|
||||
|
@ -25,21 +25,12 @@
|
||||
#include "services/service_manager/sandbox/linux/sandbox_linux.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#include "mojo/core/embedder/default_mach_broker.h"
|
||||
#endif
|
||||
|
||||
namespace service_manager {
|
||||
|
||||
ServiceExecutableEnvironment::ServiceExecutableEnvironment()
|
||||
: ipc_thread_("IPC Thread") {
|
||||
DCHECK(!base::MessageLoopCurrent::Get());
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
// Send our task port to the parent.
|
||||
mojo::core::DefaultMachBroker::SendTaskPortToParent();
|
||||
#endif
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
const base::CommandLine& command_line =
|
||||
*base::CommandLine::ForCurrentProcess();
|
||||
|
@ -43,10 +43,6 @@
|
||||
#include "base/win/windows_version.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#include "mojo/core/embedder/default_mach_broker.h"
|
||||
#endif
|
||||
|
||||
namespace service_manager {
|
||||
|
||||
// Thread-safe owner of state related to a service process. This facilitates
|
||||
@ -238,15 +234,7 @@ base::ProcessId ServiceProcessLauncher::ProcessState::LaunchInBackground(
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
#if defined(OS_MACOSX)
|
||||
mojo::core::DefaultMachBroker* mach_broker =
|
||||
mojo::core::DefaultMachBroker::Get();
|
||||
base::AutoLock locker(mach_broker->GetLock());
|
||||
#endif
|
||||
child_process_ = base::LaunchProcess(*child_command_line, options);
|
||||
#if defined(OS_MACOSX)
|
||||
mach_broker->ExpectPid(child_process_.Handle());
|
||||
#endif
|
||||
}
|
||||
|
||||
channel.RemoteProcessLaunchAttempted();
|
||||
|
@ -23,10 +23,6 @@
|
||||
#include "base/android/jni_android.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
#include "mojo/core/embedder/default_mach_broker.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
class ServiceTestSuite : public base::TestSuite {
|
||||
@ -82,11 +78,6 @@ int main(int argc, char** argv) {
|
||||
mojo_config.is_broker_process = true;
|
||||
mojo::core::Init(mojo_config);
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
mojo::core::SetMachPortProvider(
|
||||
mojo::core::DefaultMachBroker::Get()->port_provider());
|
||||
#endif
|
||||
|
||||
base::Thread ipc_thread("IPC thread");
|
||||
ipc_thread.StartWithOptions(
|
||||
base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
|
||||
|
Reference in New Issue
Block a user