diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-24 12:15:48 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-28 13:30:04 +0000 |
commit | b014812705fc80bff0a5c120dfcef88f349816dc (patch) | |
tree | 25a2e2d9fa285f1add86aa333389a839f81a39ae /chromium/mojo/edk/system | |
parent | 9f4560b1027ae06fdb497023cdcaf91b8511fa74 (diff) | |
download | qtwebengine-chromium-b014812705fc80bff0a5c120dfcef88f349816dc.tar.gz |
BASELINE: Update Chromium to 68.0.3440.125
Change-Id: I23f19369e01f688e496f5bf179abb521ad73874f
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/mojo/edk/system')
55 files changed, 2986 insertions, 1604 deletions
diff --git a/chromium/mojo/edk/system/BUILD.gn b/chromium/mojo/edk/system/BUILD.gn index 6387dcda11b..235f32e31e1 100644 --- a/chromium/mojo/edk/system/BUILD.gn +++ b/chromium/mojo/edk/system/BUILD.gn @@ -52,6 +52,7 @@ source_set("test_sources") { if (!is_ios) { sources += [ "data_pipe_unittest.cc", + "invitation_unittest.cc", "multiprocess_message_pipe_unittest.cc", "platform_wrapper_unittest.cc", ] diff --git a/chromium/mojo/edk/system/broker.h b/chromium/mojo/edk/system/broker.h index 8fb61aa9b83..6961f641e0c 100644 --- a/chromium/mojo/edk/system/broker.h +++ b/chromium/mojo/edk/system/broker.h @@ -7,38 +7,38 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/writable_shared_memory_region.h" #include "base/synchronization/lock.h" #include "mojo/edk/embedder/scoped_platform_handle.h" namespace mojo { namespace edk { -class PlatformSharedBuffer; - // The Broker is a channel to the broker process, which allows synchronous IPCs // to fulfill shared memory allocation requests on some platforms. class Broker { public: // Note: This is blocking, and will wait for the first message over // |platform_handle|. - explicit Broker(ScopedPlatformHandle platform_handle); + explicit Broker(ScopedInternalPlatformHandle platform_handle); ~Broker(); // Returns the platform handle that should be used to establish a NodeChannel // to the process which is inviting us to join its network. This is the first // handle read off the Broker channel upon construction. - ScopedPlatformHandle GetInviterPlatformHandle(); + ScopedInternalPlatformHandle GetInviterInternalPlatformHandle(); // Request a shared buffer from the broker process. Blocks the current thread. - scoped_refptr<PlatformSharedBuffer> GetSharedBuffer(size_t num_bytes); + base::WritableSharedMemoryRegion GetWritableSharedMemoryRegion( + size_t num_bytes); private: // Handle to the broker process, used for synchronous IPCs. - ScopedPlatformHandle sync_channel_; + ScopedInternalPlatformHandle sync_channel_; // Handle to the inviter process which is recieved in the first first message // over |sync_channel_|. - ScopedPlatformHandle inviter_channel_; + ScopedInternalPlatformHandle inviter_channel_; // Lock to only allow one sync message at a time. This avoids having to deal // with message ordering since we can only have one request at a time diff --git a/chromium/mojo/edk/system/broker_host.cc b/chromium/mojo/edk/system/broker_host.cc index 8076383d1b6..8966e239654 100644 --- a/chromium/mojo/edk/system/broker_host.cc +++ b/chromium/mojo/edk/system/broker_host.cc @@ -7,12 +7,13 @@ #include <utility> #include "base/logging.h" +#include "base/memory/platform_shared_memory_region.h" #include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" #include "base/threading/thread_task_runner_handle.h" +#include "build/build_config.h" #include "mojo/edk/embedder/named_platform_channel_pair.h" #include "mojo/edk/embedder/named_platform_handle.h" -#include "mojo/edk/embedder/platform_shared_buffer.h" +#include "mojo/edk/embedder/platform_handle_utils.h" #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/broker_messages.h" @@ -20,17 +21,17 @@ namespace mojo { namespace edk { BrokerHost::BrokerHost(base::ProcessHandle client_process, - ScopedPlatformHandle platform_handle, + ScopedInternalPlatformHandle platform_handle, const ProcessErrorCallback& process_error_callback) : process_error_callback_(process_error_callback) #if defined(OS_WIN) , - client_process_(client_process) + client_process_(ScopedProcessHandle::CloneFrom(client_process)) #endif { CHECK(platform_handle.is_valid()); - base::MessageLoop::current()->AddDestructionObserver(this); + base::MessageLoopCurrent::Get()->AddDestructionObserver(this); channel_ = Channel::Create( this, @@ -41,17 +42,17 @@ BrokerHost::BrokerHost(base::ProcessHandle client_process, BrokerHost::~BrokerHost() { // We're always destroyed on the creation thread, which is the IO thread. - base::MessageLoop::current()->RemoveDestructionObserver(this); + base::MessageLoopCurrent::Get()->RemoveDestructionObserver(this); if (channel_) channel_->ShutDown(); } bool BrokerHost::PrepareHandlesForClient( - std::vector<ScopedPlatformHandle>* handles) { + std::vector<ScopedInternalPlatformHandle>* handles) { #if defined(OS_WIN) if (!Channel::Message::RewriteHandles(base::GetCurrentProcessHandle(), - client_process_, handles)) { + client_process_.get(), handles)) { // NOTE: We only log an error here. We do not signal a logical error or // prevent any message from being sent. The client should handle unexpected // invalid handles appropriately. @@ -62,7 +63,7 @@ bool BrokerHost::PrepareHandlesForClient( return true; } -bool BrokerHost::SendChannel(ScopedPlatformHandle handle) { +bool BrokerHost::SendChannel(ScopedInternalPlatformHandle handle) { CHECK(handle.is_valid()); CHECK(channel_); @@ -75,7 +76,7 @@ bool BrokerHost::SendChannel(ScopedPlatformHandle handle) { Channel::MessagePtr message = CreateBrokerMessage(BrokerMessageType::INIT, 1, nullptr); #endif - std::vector<ScopedPlatformHandle> handles(1); + std::vector<ScopedInternalPlatformHandle> handles(1); handles[0] = std::move(handle); // This may legitimately fail on Windows if the client process is in another @@ -104,24 +105,31 @@ void BrokerHost::SendNamedChannel(const base::StringPiece16& pipe_name) { #endif // defined(OS_WIN) void BrokerHost::OnBufferRequest(uint32_t num_bytes) { - scoped_refptr<PlatformSharedBuffer> read_only_buffer; - scoped_refptr<PlatformSharedBuffer> buffer = - PlatformSharedBuffer::Create(num_bytes); - if (buffer) - read_only_buffer = buffer->CreateReadOnlyDuplicate(); - if (!read_only_buffer) - buffer = nullptr; + base::subtle::PlatformSharedMemoryRegion region = + base::subtle::PlatformSharedMemoryRegion::CreateWritable(num_bytes); + + std::vector<ScopedInternalPlatformHandle> handles(2); + if (region.IsValid()) { + ExtractInternalPlatformHandlesFromSharedMemoryRegionHandle( + region.PassPlatformHandle(), &handles[0], &handles[1]); +#if !defined(OS_POSIX) || defined(OS_ANDROID) || defined(OS_FUCHSIA) || \ + (defined(OS_MACOSX) && !defined(OS_IOS)) + // Non-POSIX systems, as well as Android, Fuchsia, and non-iOS Mac, only use + // a single handle to represent a writable region. + DCHECK(!handles[1].is_valid()); + handles.resize(1); +#else + DCHECK(handles[1].is_valid()); +#endif + } BufferResponseData* response; Channel::MessagePtr message = CreateBrokerMessage( - BrokerMessageType::BUFFER_RESPONSE, buffer ? 2 : 0, 0, &response); - if (buffer) { - base::UnguessableToken guid = buffer->GetGUID(); + BrokerMessageType::BUFFER_RESPONSE, handles.size(), 0, &response); + if (!handles.empty()) { + base::UnguessableToken guid = region.GetGUID(); response->guid_high = guid.GetHighForSerialization(); response->guid_low = guid.GetLowForSerialization(); - std::vector<ScopedPlatformHandle> handles(2); - handles[0] = buffer->PassPlatformHandle(); - handles[1] = read_only_buffer->PassPlatformHandle(); PrepareHandlesForClient(&handles); message->SetHandles(std::move(handles)); } @@ -129,9 +137,10 @@ void BrokerHost::OnBufferRequest(uint32_t num_bytes) { channel_->Write(std::move(message)); } -void BrokerHost::OnChannelMessage(const void* payload, - size_t payload_size, - std::vector<ScopedPlatformHandle> handles) { +void BrokerHost::OnChannelMessage( + const void* payload, + size_t payload_size, + std::vector<ScopedInternalPlatformHandle> handles) { if (payload_size < sizeof(BrokerMessageHeader)) return; diff --git a/chromium/mojo/edk/system/broker_host.h b/chromium/mojo/edk/system/broker_host.h index 3f1b7ce1bef..1681bdca6c2 100644 --- a/chromium/mojo/edk/system/broker_host.h +++ b/chromium/mojo/edk/system/broker_host.h @@ -9,12 +9,13 @@ #include <vector> #include "base/macros.h" -#include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_current.h" #include "base/process/process_handle.h" #include "base/strings/string_piece.h" #include "mojo/edk/embedder/process_error_callback.h" #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/channel.h" +#include "mojo/edk/system/scoped_process_handle.h" namespace mojo { namespace edk { @@ -22,14 +23,14 @@ namespace edk { // The BrokerHost is a channel to a broker client process, servicing synchronous // IPCs issued by the client. class BrokerHost : public Channel::Delegate, - public base::MessageLoop::DestructionObserver { + public base::MessageLoopCurrent::DestructionObserver { public: BrokerHost(base::ProcessHandle client_process, - ScopedPlatformHandle handle, + ScopedInternalPlatformHandle handle, const ProcessErrorCallback& process_error_callback); // Send |handle| to the client, to be used to establish a NodeChannel to us. - bool SendChannel(ScopedPlatformHandle handle); + bool SendChannel(ScopedInternalPlatformHandle handle); #if defined(OS_WIN) // Sends a named channel to the client. Like above, but for named pipes. @@ -39,15 +40,17 @@ class BrokerHost : public Channel::Delegate, private: ~BrokerHost() override; - bool PrepareHandlesForClient(std::vector<ScopedPlatformHandle>* handles); + bool PrepareHandlesForClient( + std::vector<ScopedInternalPlatformHandle>* handles); // Channel::Delegate: - void OnChannelMessage(const void* payload, - size_t payload_size, - std::vector<ScopedPlatformHandle> handles) override; + void OnChannelMessage( + const void* payload, + size_t payload_size, + std::vector<ScopedInternalPlatformHandle> handles) override; void OnChannelError(Channel::Error error) override; - // base::MessageLoop::DestructionObserver: + // base::MessageLoopCurrent::DestructionObserver: void WillDestroyCurrentMessageLoop() override; void OnBufferRequest(uint32_t num_bytes); @@ -55,7 +58,7 @@ class BrokerHost : public Channel::Delegate, const ProcessErrorCallback process_error_callback_; #if defined(OS_WIN) - base::ProcessHandle client_process_; + ScopedProcessHandle client_process_; #endif scoped_refptr<Channel> channel_; diff --git a/chromium/mojo/edk/system/broker_posix.cc b/chromium/mojo/edk/system/broker_posix.cc index 88695e9b646..4b5c15c0fbc 100644 --- a/chromium/mojo/edk/system/broker_posix.cc +++ b/chromium/mojo/edk/system/broker_posix.cc @@ -10,9 +10,10 @@ #include <utility> #include "base/logging.h" +#include "base/memory/platform_shared_memory_region.h" +#include "build/build_config.h" #include "mojo/edk/embedder/platform_channel_utils_posix.h" #include "mojo/edk/embedder/platform_handle_utils.h" -#include "mojo/edk/embedder/platform_shared_buffer.h" #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/broker_messages.h" #include "mojo/edk/system/channel.h" @@ -23,14 +24,14 @@ namespace edk { namespace { Channel::MessagePtr WaitForBrokerMessage( - const ScopedPlatformHandle& platform_handle, + const ScopedInternalPlatformHandle& platform_handle, BrokerMessageType expected_type, size_t expected_num_handles, size_t expected_data_size, - std::vector<ScopedPlatformHandle>* incoming_handles) { + std::vector<ScopedInternalPlatformHandle>* incoming_handles) { Channel::MessagePtr message(new Channel::Message( sizeof(BrokerMessageHeader) + expected_data_size, expected_num_handles)); - base::circular_deque<ScopedPlatformHandle> incoming_platform_handles; + base::circular_deque<ScopedInternalPlatformHandle> incoming_platform_handles; ssize_t read_result = PlatformChannelRecvmsg( platform_handle, const_cast<void*>(message->data()), message->data_num_bytes(), &incoming_platform_handles, true /* block */); @@ -65,7 +66,7 @@ Channel::MessagePtr WaitForBrokerMessage( } // namespace -Broker::Broker(ScopedPlatformHandle platform_handle) +Broker::Broker(ScopedInternalPlatformHandle platform_handle) : sync_channel_(std::move(platform_handle)) { CHECK(sync_channel_.is_valid()); @@ -76,7 +77,7 @@ Broker::Broker(ScopedPlatformHandle platform_handle) PCHECK(flags != -1); // Wait for the first message, which should contain a handle. - std::vector<ScopedPlatformHandle> incoming_platform_handles; + std::vector<ScopedInternalPlatformHandle> incoming_platform_handles; if (WaitForBrokerMessage(sync_channel_, BrokerMessageType::INIT, 1, 0, &incoming_platform_handles)) { inviter_channel_ = std::move(incoming_platform_handles[0]); @@ -85,11 +86,12 @@ Broker::Broker(ScopedPlatformHandle platform_handle) Broker::~Broker() = default; -ScopedPlatformHandle Broker::GetInviterPlatformHandle() { +ScopedInternalPlatformHandle Broker::GetInviterInternalPlatformHandle() { return std::move(inviter_channel_); } -scoped_refptr<PlatformSharedBuffer> Broker::GetSharedBuffer(size_t num_bytes) { +base::WritableSharedMemoryRegion Broker::GetWritableSharedMemoryRegion( + size_t num_bytes) { base::AutoLock lock(lock_); BufferRequestData* buffer_request; @@ -100,29 +102,45 @@ scoped_refptr<PlatformSharedBuffer> Broker::GetSharedBuffer(size_t num_bytes) { sync_channel_, out_message->data(), out_message->data_num_bytes()); if (write_result < 0) { PLOG(ERROR) << "Error sending sync broker message"; - return nullptr; + return base::WritableSharedMemoryRegion(); } else if (static_cast<size_t>(write_result) != out_message->data_num_bytes()) { LOG(ERROR) << "Error sending complete broker message"; - return nullptr; + return base::WritableSharedMemoryRegion(); } - std::vector<ScopedPlatformHandle> incoming_platform_handles; +#if !defined(OS_POSIX) || defined(OS_ANDROID) || defined(OS_FUCHSIA) || \ + (defined(OS_MACOSX) && !defined(OS_IOS)) + // Non-POSIX systems, as well as Android, Fuchsia, and non-iOS Mac, only use + // a single handle to represent a writable region. + constexpr size_t kNumExpectedHandles = 1; +#else + constexpr size_t kNumExpectedHandles = 2; +#endif + + std::vector<ScopedInternalPlatformHandle> incoming_platform_handles; Channel::MessagePtr message = WaitForBrokerMessage( - sync_channel_, BrokerMessageType::BUFFER_RESPONSE, 2, + sync_channel_, BrokerMessageType::BUFFER_RESPONSE, kNumExpectedHandles, sizeof(BufferResponseData), &incoming_platform_handles); if (message) { const BufferResponseData* data; if (!GetBrokerMessageData(message.get(), &data)) - return nullptr; - base::UnguessableToken guid = - base::UnguessableToken::Deserialize(data->guid_high, data->guid_low); - return PlatformSharedBuffer::CreateFromPlatformHandlePair( - num_bytes, guid, std::move(incoming_platform_handles[0]), - std::move(incoming_platform_handles[1])); + return base::WritableSharedMemoryRegion(); + + if (incoming_platform_handles.size() == 1) + incoming_platform_handles.emplace_back(); + return base::WritableSharedMemoryRegion::Deserialize( + base::subtle::PlatformSharedMemoryRegion::Take( + CreateSharedMemoryRegionHandleFromInternalPlatformHandles( + std::move(incoming_platform_handles[0]), + std::move(incoming_platform_handles[1])), + base::subtle::PlatformSharedMemoryRegion::Mode::kWritable, + num_bytes, + base::UnguessableToken::Deserialize(data->guid_high, + data->guid_low))); } - return nullptr; + return base::WritableSharedMemoryRegion(); } } // namespace edk diff --git a/chromium/mojo/edk/system/broker_win.cc b/chromium/mojo/edk/system/broker_win.cc index 0d489649797..a2dea366c0c 100644 --- a/chromium/mojo/edk/system/broker_win.cc +++ b/chromium/mojo/edk/system/broker_win.cc @@ -8,12 +8,13 @@ #include <utility> #include "base/debug/alias.h" +#include "base/memory/platform_shared_memory_region.h" #include "base/numerics/safe_conversions.h" #include "base/strings/string_piece.h" #include "mojo/edk/embedder/named_platform_handle.h" #include "mojo/edk/embedder/named_platform_handle_utils.h" #include "mojo/edk/embedder/platform_handle.h" -#include "mojo/edk/embedder/platform_shared_buffer.h" +#include "mojo/edk/embedder/platform_handle_utils.h" #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/broker.h" #include "mojo/edk/system/broker_messages.h" @@ -29,13 +30,13 @@ const size_t kMaxBrokerMessageSize = 256; bool TakeHandlesFromBrokerMessage(Channel::Message* message, size_t num_handles, - ScopedPlatformHandle* out_handles) { + ScopedInternalPlatformHandle* out_handles) { if (message->num_handles() != num_handles) { DLOG(ERROR) << "Received unexpected number of handles in broker message"; return false; } - std::vector<ScopedPlatformHandle> handles = message->TakeHandles(); + std::vector<ScopedInternalPlatformHandle> handles = message->TakeHandles(); DCHECK_EQ(handles.size(), num_handles); DCHECK(out_handles); @@ -44,7 +45,7 @@ bool TakeHandlesFromBrokerMessage(Channel::Message* message, return true; } -Channel::MessagePtr WaitForBrokerMessage(PlatformHandle platform_handle, +Channel::MessagePtr WaitForBrokerMessage(InternalPlatformHandle platform_handle, BrokerMessageType expected_type) { char buffer[kMaxBrokerMessageSize]; DWORD bytes_read = 0; @@ -85,7 +86,8 @@ Channel::MessagePtr WaitForBrokerMessage(PlatformHandle platform_handle, } // namespace -Broker::Broker(ScopedPlatformHandle handle) : sync_channel_(std::move(handle)) { +Broker::Broker(ScopedInternalPlatformHandle handle) + : sync_channel_(std::move(handle)) { CHECK(sync_channel_.is_valid()); Channel::MessagePtr message = WaitForBrokerMessage(sync_channel_.get(), BrokerMessageType::INIT); @@ -115,11 +117,12 @@ Broker::Broker(ScopedPlatformHandle handle) : sync_channel_(std::move(handle)) { Broker::~Broker() {} -ScopedPlatformHandle Broker::GetInviterPlatformHandle() { +ScopedInternalPlatformHandle Broker::GetInviterInternalPlatformHandle() { return std::move(inviter_channel_); } -scoped_refptr<PlatformSharedBuffer> Broker::GetSharedBuffer(size_t num_bytes) { +base::WritableSharedMemoryRegion Broker::GetWritableSharedMemoryRegion( + size_t num_bytes) { base::AutoLock lock(lock_); BufferRequestData* buffer_request; Channel::MessagePtr out_message = CreateBrokerMessage( @@ -132,24 +135,27 @@ scoped_refptr<PlatformSharedBuffer> Broker::GetSharedBuffer(size_t num_bytes) { if (!result || static_cast<size_t>(bytes_written) != out_message->data_num_bytes()) { PLOG(ERROR) << "Error sending sync broker message"; - return nullptr; + return base::WritableSharedMemoryRegion(); } - ScopedPlatformHandle handles[2]; + ScopedInternalPlatformHandle handle; Channel::MessagePtr response = WaitForBrokerMessage( sync_channel_.get(), BrokerMessageType::BUFFER_RESPONSE); - if (response && - TakeHandlesFromBrokerMessage(response.get(), 2, &handles[0])) { + if (response && TakeHandlesFromBrokerMessage(response.get(), 1, &handle)) { BufferResponseData* data; if (!GetBrokerMessageData(response.get(), &data)) - return nullptr; - base::UnguessableToken guid = - base::UnguessableToken::Deserialize(data->guid_high, data->guid_low); - return PlatformSharedBuffer::CreateFromPlatformHandlePair( - num_bytes, guid, std::move(handles[0]), std::move(handles[1])); + return base::WritableSharedMemoryRegion(); + return base::WritableSharedMemoryRegion::Deserialize( + base::subtle::PlatformSharedMemoryRegion::Take( + CreateSharedMemoryRegionHandleFromInternalPlatformHandles( + std::move(handle), ScopedInternalPlatformHandle()), + base::subtle::PlatformSharedMemoryRegion::Mode::kWritable, + num_bytes, + base::UnguessableToken::Deserialize(data->guid_high, + data->guid_low))); } - return nullptr; + return base::WritableSharedMemoryRegion(); } } // namespace edk diff --git a/chromium/mojo/edk/system/channel.cc b/chromium/mojo/edk/system/channel.cc index 41ff3ee3509..0005193ca3d 100644 --- a/chromium/mojo/edk/system/channel.cc +++ b/chromium/mojo/edk/system/channel.cc @@ -250,10 +250,10 @@ Channel::MessagePtr Channel::Message::Deserialize(const void* data, } #if defined(OS_WIN) - std::vector<ScopedPlatformHandle> handles(num_handles); + std::vector<ScopedInternalPlatformHandle> handles(num_handles); for (size_t i = 0; i < num_handles; i++) { - handles[i] = ScopedPlatformHandle( - PlatformHandle(base::win::Uint32ToHandle(message->handles_[i].handle))); + handles[i] = ScopedInternalPlatformHandle(InternalPlatformHandle( + base::win::Uint32ToHandle(message->handles_[i].handle))); } message->SetHandles(std::move(handles)); #endif @@ -343,8 +343,8 @@ bool Channel::Message::has_mach_ports() const { return false; for (const auto& handle : handle_vector_) { - if (handle.get().type == PlatformHandle::Type::MACH || - handle.get().type == PlatformHandle::Type::MACH_NAME) { + if (handle.get().type == InternalPlatformHandle::Type::MACH || + handle.get().type == InternalPlatformHandle::Type::MACH_NAME) { return true; } } @@ -366,7 +366,7 @@ Channel::Message::Header* Channel::Message::header() const { } void Channel::Message::SetHandles( - std::vector<ScopedPlatformHandle> new_handles) { + std::vector<ScopedInternalPlatformHandle> new_handles) { if (is_legacy_message()) { // Old semantics for ChromeOS and Android if (legacy_header()->num_handles == 0) { @@ -401,8 +401,9 @@ void Channel::Message::SetHandles( {0, static_cast<uint32_t>(MACH_PORT_NULL)}; } for (size_t i = 0; i < handle_vector_.size(); i++) { - if (handle_vector_[i].get().type == PlatformHandle::Type::MACH || - handle_vector_[i].get().type == PlatformHandle::Type::MACH_NAME) { + if (handle_vector_[i].get().type == InternalPlatformHandle::Type::MACH || + handle_vector_[i].get().type == + InternalPlatformHandle::Type::MACH_NAME) { mach_port_t port = handle_vector_[i].get().port; mach_ports_header_->entries[mach_port_index].index = i; mach_ports_header_->entries[mach_port_index].mach_port = port; @@ -414,7 +415,7 @@ void Channel::Message::SetHandles( #endif } -std::vector<ScopedPlatformHandle> Channel::Message::TakeHandles() { +std::vector<ScopedInternalPlatformHandle> Channel::Message::TakeHandles() { #if defined(OS_MACOSX) && !defined(OS_IOS) if (mach_ports_header_) { for (size_t i = 0; i < max_handles_; ++i) { @@ -431,15 +432,16 @@ std::vector<ScopedPlatformHandle> Channel::Message::TakeHandles() { return std::move(handle_vector_); } -std::vector<ScopedPlatformHandle> Channel::Message::TakeHandlesForTransport() { +std::vector<ScopedInternalPlatformHandle> +Channel::Message::TakeHandlesForTransport() { #if defined(OS_WIN) // Not necessary on Windows. NOTREACHED(); - return std::vector<ScopedPlatformHandle>(); + return std::vector<ScopedInternalPlatformHandle>(); #elif defined(OS_MACOSX) && !defined(OS_IOS) for (auto it = handle_vector_.begin(); it != handle_vector_.end();) { - if (it->get().type == PlatformHandle::Type::MACH || - it->get().type == PlatformHandle::Type::MACH_NAME) { + if (it->get().type == InternalPlatformHandle::Type::MACH || + it->get().type == InternalPlatformHandle::Type::MACH_NAME) { // For Mach port names, we can can just leak them. They're not real // ports anyways. For real ports, they're leaked because this is a child // process and the remote process will take ownership. @@ -463,7 +465,7 @@ std::vector<ScopedPlatformHandle> Channel::Message::TakeHandlesForTransport() { bool Channel::Message::RewriteHandles( base::ProcessHandle from_process, base::ProcessHandle to_process, - std::vector<ScopedPlatformHandle>* handles) { + std::vector<ScopedInternalPlatformHandle>* handles) { bool success = true; for (size_t i = 0; i < handles->size(); ++i) { if (!(*handles)[i].is_valid()) { @@ -476,7 +478,14 @@ bool Channel::Message::RewriteHandles( &(*handles)[i].get().handle, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); if (result) { - (*handles)[i].get().owning_process = to_process; + if (to_process == base::GetCurrentProcessHandle()) { + (*handles)[i].get().owning_process = to_process; + } else { + // If this handle is bound for an external process, make sure it owns + // its own copy of the target process handle. + (*handles)[i].get().owning_process = + ScopedProcessHandle::CloneFrom(to_process).release(); + } } else { success = false; @@ -699,10 +708,10 @@ bool Channel::OnReadComplete(size_t bytes_read, size_t *next_read_size_hint) { const uint16_t num_handles = header ? header->num_handles : legacy_header->num_handles; - std::vector<ScopedPlatformHandle> handles; + std::vector<ScopedInternalPlatformHandle> handles; if (num_handles > 0) { - if (!GetReadPlatformHandles(num_handles, extra_header, extra_header_size, - &handles)) { + if (!GetReadInternalPlatformHandles(num_handles, extra_header, + extra_header_size, &handles)) { return false; } @@ -737,10 +746,11 @@ void Channel::OnError(Error error) { delegate_->OnChannelError(error); } -bool Channel::OnControlMessage(Message::MessageType message_type, - const void* payload, - size_t payload_size, - std::vector<ScopedPlatformHandle> handles) { +bool Channel::OnControlMessage( + Message::MessageType message_type, + const void* payload, + size_t payload_size, + std::vector<ScopedInternalPlatformHandle> handles) { return false; } diff --git a/chromium/mojo/edk/system/channel.h b/chromium/mojo/edk/system/channel.h index 57c8ed81ec6..ef9669cc39a 100644 --- a/chromium/mojo/edk/system/channel.h +++ b/chromium/mojo/edk/system/channel.h @@ -88,7 +88,7 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel #if defined(OS_MACOSX) && !defined(OS_IOS) struct MachPortsEntry { - // Index of Mach port in the original vector of PlatformHandles. + // Index of Mach port in the original vector of InternalPlatformHandles. uint16_t index; // Mach port name. @@ -179,13 +179,13 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel // Note: SetHandles() and TakeHandles() invalidate any previous value of // handles(). - void SetHandles(std::vector<ScopedPlatformHandle> new_handles); - std::vector<ScopedPlatformHandle> TakeHandles(); + void SetHandles(std::vector<ScopedInternalPlatformHandle> new_handles); + std::vector<ScopedInternalPlatformHandle> TakeHandles(); // Version of TakeHandles that returns a vector of platform handles suitable // for transfer over an underlying OS mechanism. i.e. file descriptors over // a unix domain socket. Any handle that cannot be transferred this way, // such as Mach ports, will be removed. - std::vector<ScopedPlatformHandle> TakeHandlesForTransport(); + std::vector<ScopedInternalPlatformHandle> TakeHandlesForTransport(); #if defined(OS_WIN) // Prepares the handles in this message for use in a different process. @@ -193,9 +193,10 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel // call they'll belong to |to_process|. The source handles are always // closed by this call. Returns false iff one or more handles failed // duplication. - static bool RewriteHandles(base::ProcessHandle from_process, - base::ProcessHandle to_process, - std::vector<ScopedPlatformHandle>* handles); + static bool RewriteHandles( + base::ProcessHandle from_process, + base::ProcessHandle to_process, + std::vector<ScopedInternalPlatformHandle>* handles); #endif void SetVersionForTest(uint16_t version_number); @@ -215,7 +216,7 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel // Maximum number of handles which may be attached to this message. size_t max_handles_ = 0; - std::vector<ScopedPlatformHandle> handle_vector_; + std::vector<ScopedInternalPlatformHandle> handle_vector_; #if defined(OS_WIN) // On Windows, handles are serialised into the extra header section. @@ -255,7 +256,7 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel virtual void OnChannelMessage( const void* payload, size_t payload_size, - std::vector<ScopedPlatformHandle> handles) = 0; + std::vector<ScopedInternalPlatformHandle> handles) = 0; // Notify that an error has occured and the Channel will cease operation. virtual void OnChannelError(Error error) = 0; @@ -326,18 +327,19 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel // insufficient number of handles to be available when this call is made, but // this is not necessarily an error condition. In such cases this returns // |true| but |*handles| will also be reset to null. - virtual bool GetReadPlatformHandles( + virtual bool GetReadInternalPlatformHandles( size_t num_handles, const void* extra_header, size_t extra_header_size, - std::vector<ScopedPlatformHandle>* handles) = 0; + std::vector<ScopedInternalPlatformHandle>* handles) = 0; // Handles a received control message. Returns |true| if the message is // accepted, or |false| otherwise. - virtual bool OnControlMessage(Message::MessageType message_type, - const void* payload, - size_t payload_size, - std::vector<ScopedPlatformHandle> handles); + virtual bool OnControlMessage( + Message::MessageType message_type, + const void* payload, + size_t payload_size, + std::vector<ScopedInternalPlatformHandle> handles); private: friend class base::RefCountedThreadSafe<Channel>; diff --git a/chromium/mojo/edk/system/channel_fuchsia.cc b/chromium/mojo/edk/system/channel_fuchsia.cc index 31ddb9486c1..364792cc32b 100644 --- a/chromium/mojo/edk/system/channel_fuchsia.cc +++ b/chromium/mojo/edk/system/channel_fuchsia.cc @@ -19,7 +19,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_current.h" #include "base/message_loop/message_pump_for_io.h" #include "base/synchronization/lock.h" #include "base/task_runner.h" @@ -31,9 +31,10 @@ namespace { const size_t kMaxBatchReadCapacity = 256 * 1024; -bool UnwrapPlatformHandle(ScopedPlatformHandle handle, - Channel::Message::HandleInfoEntry* info_out, - std::vector<ScopedPlatformHandle>* handles_out) { +bool UnwrapInternalPlatformHandle( + ScopedInternalPlatformHandle handle, + Channel::Message::HandleInfoEntry* info_out, + std::vector<ScopedInternalPlatformHandle>* handles_out) { DCHECK(handle.get().is_valid()); if (!handle.get().is_valid_fd()) { @@ -53,8 +54,8 @@ bool UnwrapPlatformHandle(ScopedPlatformHandle handle, zx_status_t result = fdio_transfer_fd(handle.get().as_fd(), 0, handles, info); if (result > 0) { // On success, the fd in |handle| has been transferred and is no longer - // valid. Release from the ScopedPlatformHandle to avoid close()ing an - // invalid handle. + // valid. Release from the ScopedInternalPlatformHandle to avoid close()ing + // an invalid handle. ignore_result(handle.release()); } else if (result == ZX_ERR_UNAVAILABLE) { // No luck, try cloning instead. @@ -74,22 +75,23 @@ bool UnwrapPlatformHandle(ScopedPlatformHandle handle, for (int i = 0; i < result; ++i) { DCHECK_EQ(PA_HND_TYPE(info[0]), PA_HND_TYPE(info[i])); DCHECK_EQ(0u, PA_HND_SUBTYPE(info[i])); - handles_out->emplace_back(PlatformHandle::ForHandle(handles[i])); + handles_out->emplace_back(InternalPlatformHandle::ForHandle(handles[i])); } return true; } -ScopedPlatformHandle WrapPlatformHandles( +ScopedInternalPlatformHandle WrapInternalPlatformHandles( Channel::Message::HandleInfoEntry info, base::circular_deque<base::ScopedZxHandle>* handles) { - ScopedPlatformHandle out_handle; + ScopedInternalPlatformHandle out_handle; if (!info.type) { - out_handle.reset(PlatformHandle::ForHandle(handles->front().release())); + out_handle.reset( + InternalPlatformHandle::ForHandle(handles->front().release())); handles->pop_front(); } else { if (info.count > FDIO_MAX_HANDLES) - return ScopedPlatformHandle(); + return ScopedInternalPlatformHandle(); // Fetch the required number of handles from |handles| and set up type info. zx_handle_t fd_handles[FDIO_MAX_HANDLES] = {}; @@ -105,7 +107,7 @@ ScopedPlatformHandle WrapPlatformHandles( fdio_create_fd(fd_handles, fd_infos, info.count, out_fd.receive()); if (result != ZX_OK) { DLOG(ERROR) << "fdio_create_fd: " << zx_status_get_string(result); - return ScopedPlatformHandle(); + return ScopedInternalPlatformHandle(); } // The handles are owned by FDIO now, so |release()| them before removing @@ -115,7 +117,7 @@ ScopedPlatformHandle WrapPlatformHandles( handles->pop_front(); } - out_handle.reset(PlatformHandle::ForFd(out_fd.release())); + out_handle.reset(InternalPlatformHandle::ForFd(out_fd.release())); } return out_handle; } @@ -155,9 +157,9 @@ class MessageView { offset_ += num_bytes; } - std::vector<ScopedPlatformHandle> TakeHandles() { + std::vector<ScopedInternalPlatformHandle> TakeHandles() { if (handles_.empty()) - return std::vector<ScopedPlatformHandle>(); + return std::vector<ScopedInternalPlatformHandle>(); // We can only pass Fuchsia handles via IPC, so unwrap any FDIO file- // descriptors in |handles_| into the underlying handles, and serialize the @@ -166,12 +168,12 @@ class MessageView { message_->mutable_extra_header()); memset(handles_info, 0, message_->extra_header_size()); - std::vector<ScopedPlatformHandle> in_handles = std::move(handles_); + std::vector<ScopedInternalPlatformHandle> in_handles = std::move(handles_); handles_.reserve(in_handles.size()); for (size_t i = 0; i < in_handles.size(); i++) { - if (!UnwrapPlatformHandle(std::move(in_handles[i]), &handles_info[i], - &handles_)) - return std::vector<ScopedPlatformHandle>(); + if (!UnwrapInternalPlatformHandle(std::move(in_handles[i]), + &handles_info[i], &handles_)) + return std::vector<ScopedInternalPlatformHandle>(); } return std::move(handles_); } @@ -179,13 +181,13 @@ class MessageView { private: Channel::MessagePtr message_; size_t offset_; - std::vector<ScopedPlatformHandle> handles_; + std::vector<ScopedInternalPlatformHandle> handles_; DISALLOW_COPY_AND_ASSIGN(MessageView); }; class ChannelFuchsia : public Channel, - public base::MessageLoop::DestructionObserver, + public base::MessageLoopCurrent::DestructionObserver, public base::MessagePumpForIO::ZxHandleWatcher { public: ChannelFuchsia(Delegate* delegate, @@ -236,11 +238,11 @@ class ChannelFuchsia : public Channel, leak_handle_ = true; } - bool GetReadPlatformHandles( + bool GetReadInternalPlatformHandles( size_t num_handles, const void* extra_header, size_t extra_header_size, - std::vector<ScopedPlatformHandle>* handles) override { + std::vector<ScopedInternalPlatformHandle>* handles) override { DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); if (num_handles > std::numeric_limits<uint16_t>::max()) return false; @@ -271,7 +273,8 @@ class ChannelFuchsia : public Channel, handles->reserve(num_handles); for (size_t i = 0; i < num_handles; ++i) { handles->emplace_back( - WrapPlatformHandles(handles_info[i], &incoming_handles_).release()); + WrapInternalPlatformHandles(handles_info[i], &incoming_handles_) + .release()); } return true; } @@ -284,17 +287,17 @@ class ChannelFuchsia : public Channel, void StartOnIOThread() { DCHECK(!read_watch_); - base::MessageLoop::current()->AddDestructionObserver(this); + base::MessageLoopCurrent::Get()->AddDestructionObserver(this); read_watch_.reset( new base::MessagePumpForIO::ZxHandleWatchController(FROM_HERE)); - base::MessageLoopForIO::current()->WatchZxHandle( + base::MessageLoopCurrentForIO::Get()->WatchZxHandle( handle_.get().as_handle(), true /* persistent */, ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, read_watch_.get(), this); } void ShutDownOnIOThread() { - base::MessageLoop::current()->RemoveDestructionObserver(this); + base::MessageLoopCurrent::Get()->RemoveDestructionObserver(this); read_watch_.reset(); if (leak_handle_) @@ -305,7 +308,7 @@ class ChannelFuchsia : public Channel, self_ = nullptr; } - // base::MessageLoop::DestructionObserver: + // base::MessageLoopCurrent::DestructionObserver: void WillDestroyCurrentMessageLoop() override { DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); if (self_) @@ -378,7 +381,7 @@ class ChannelFuchsia : public Channel, do { message_view.advance_data_offset(write_bytes); - std::vector<ScopedPlatformHandle> outgoing_handles = + std::vector<ScopedInternalPlatformHandle> outgoing_handles = message_view.TakeHandles(); zx_handle_t handles[ZX_CHANNEL_MAX_MSG_HANDLES] = {}; size_t handles_count = outgoing_handles.size(); @@ -433,7 +436,7 @@ class ChannelFuchsia : public Channel, // Keeps the Channel alive at least until explicit shutdown on the IO thread. scoped_refptr<Channel> self_; - ScopedPlatformHandle handle_; + ScopedInternalPlatformHandle handle_; scoped_refptr<base::TaskRunner> io_task_runner_; // These members are only used on the IO thread. diff --git a/chromium/mojo/edk/system/channel_posix.cc b/chromium/mojo/edk/system/channel_posix.cc index 998fe5d6716..42d78d533f1 100644 --- a/chromium/mojo/edk/system/channel_posix.cc +++ b/chromium/mojo/edk/system/channel_posix.cc @@ -16,7 +16,7 @@ #include "base/location.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_current.h" #include "base/message_loop/message_pump_for_io.h" #include "base/synchronization/lock.h" #include "base/task_runner.h" @@ -69,25 +69,25 @@ class MessageView { offset_ += num_bytes; } - std::vector<ScopedPlatformHandle> TakeHandles() { + std::vector<ScopedInternalPlatformHandle> TakeHandles() { return std::move(handles_); } Channel::MessagePtr TakeMessage() { return std::move(message_); } - void SetHandles(std::vector<ScopedPlatformHandle> handles) { + void SetHandles(std::vector<ScopedInternalPlatformHandle> handles) { handles_ = std::move(handles); } private: Channel::MessagePtr message_; size_t offset_; - std::vector<ScopedPlatformHandle> handles_; + std::vector<ScopedInternalPlatformHandle> handles_; DISALLOW_COPY_AND_ASSIGN(MessageView); }; class ChannelPosix : public Channel, - public base::MessageLoop::DestructionObserver, + public base::MessageLoopCurrent::DestructionObserver, public base::MessagePumpForIO::FdWatcher { public: ChannelPosix(Delegate* delegate, @@ -143,11 +143,11 @@ class ChannelPosix : public Channel, leak_handle_ = true; } - bool GetReadPlatformHandles( + bool GetReadInternalPlatformHandles( size_t num_handles, const void* extra_header, size_t extra_header_size, - std::vector<ScopedPlatformHandle>* handles) override { + std::vector<ScopedInternalPlatformHandle>* handles) override { if (num_handles > std::numeric_limits<uint16_t>::max()) return false; #if defined(OS_MACOSX) && !defined(OS_IOS) @@ -172,12 +172,13 @@ class ChannelPosix : public Channel, 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].index == i) { - handles->at(i).reset(PlatformHandle( + handles->at(i).reset(InternalPlatformHandle( static_cast<mach_port_t>(mach_ports[mach_port_index].mach_port))); - DCHECK_EQ(handles->at(i).get().type, PlatformHandle::Type::MACH); + DCHECK_EQ(handles->at(i).get().type, + InternalPlatformHandle::Type::MACH); // These are actually just Mach port names until they're resolved from // the remote process. - handles->at(i).get().type = PlatformHandle::Type::MACH_NAME; + handles->at(i).get().type = InternalPlatformHandle::Type::MACH_NAME; mach_port_index++; } else { if (incoming_platform_handles_.empty()) @@ -211,15 +212,15 @@ class ChannelPosix : public Channel, DCHECK(!write_watcher_); read_watcher_.reset( new base::MessagePumpForIO::FdWatchController(FROM_HERE)); - base::MessageLoop::current()->AddDestructionObserver(this); + base::MessageLoopCurrent::Get()->AddDestructionObserver(this); if (handle_.get().needs_connection) { - base::MessageLoopForIO::current()->WatchFileDescriptor( + base::MessageLoopCurrentForIO::Get()->WatchFileDescriptor( handle_.get().handle, false /* persistent */, base::MessagePumpForIO::WATCH_READ, read_watcher_.get(), this); } else { write_watcher_.reset( new base::MessagePumpForIO::FdWatchController(FROM_HERE)); - base::MessageLoopForIO::current()->WatchFileDescriptor( + base::MessageLoopCurrentForIO::Get()->WatchFileDescriptor( handle_.get().handle, true /* persistent */, base::MessagePumpForIO::WATCH_READ, read_watcher_.get(), this); base::AutoLock lock(write_lock_); @@ -239,7 +240,7 @@ class ChannelPosix : public Channel, return; if (io_task_runner_->RunsTasksInCurrentSequence()) { pending_write_ = true; - base::MessageLoopForIO::current()->WatchFileDescriptor( + base::MessageLoopCurrentForIO::Get()->WatchFileDescriptor( handle_.get().handle, false /* persistent */, base::MessagePumpForIO::WATCH_WRITE, write_watcher_.get(), this); } else { @@ -250,7 +251,7 @@ class ChannelPosix : public Channel, } void ShutDownOnIOThread() { - base::MessageLoop::current()->RemoveDestructionObserver(this); + base::MessageLoopCurrent::Get()->RemoveDestructionObserver(this); read_watcher_.reset(); write_watcher_.reset(); @@ -265,7 +266,7 @@ class ChannelPosix : public Channel, self_ = nullptr; } - // base::MessageLoop::DestructionObserver: + // base::MessageLoopCurrent::DestructionObserver: void WillDestroyCurrentMessageLoop() override { DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); if (self_) @@ -278,9 +279,9 @@ class ChannelPosix : public Channel, if (handle_.get().needs_connection) { #if !defined(OS_NACL) read_watcher_.reset(); - base::MessageLoop::current()->RemoveDestructionObserver(this); + base::MessageLoopCurrent::Get()->RemoveDestructionObserver(this); - ScopedPlatformHandle accept_fd; + ScopedInternalPlatformHandle accept_fd; ServerAcceptConnection(handle_, &accept_fd); if (!accept_fd.is_valid()) { OnError(Error::kConnectionFailed); @@ -358,7 +359,8 @@ class ChannelPosix : public Channel, message_view.advance_data_offset(bytes_written); ssize_t result; - std::vector<ScopedPlatformHandle> handles = message_view.TakeHandles(); + std::vector<ScopedInternalPlatformHandle> handles = + message_view.TakeHandles(); if (!handles.empty()) { iovec iov = {const_cast<void*>(message_view.data()), message_view.data_num_bytes()}; @@ -457,10 +459,11 @@ class ChannelPosix : public Channel, } #if defined(OS_MACOSX) - bool OnControlMessage(Message::MessageType message_type, - const void* payload, - size_t payload_size, - std::vector<ScopedPlatformHandle> handles) override { + bool OnControlMessage( + Message::MessageType message_type, + const void* payload, + size_t payload_size, + std::vector<ScopedInternalPlatformHandle> handles) override { switch (message_type) { case Message::MessageType::HANDLES_SENT: { if (payload_size == 0) @@ -499,7 +502,7 @@ class ChannelPosix : public Channel, auto start = std::find_if(handles_to_close_.begin(), handles_to_close_.end(), - [&fds](const ScopedPlatformHandle& handle) { + [&fds](const ScopedInternalPlatformHandle& handle) { return handle.get().handle == fds[0]; }); if (start == handles_to_close_.end()) @@ -520,7 +523,7 @@ class ChannelPosix : public Channel, if (i != num_fds) return false; - // Close the FDs by erase()ing their ScopedPlatformHandles. + // Close the FDs by erase()ing their ScopedInternalPlatformHandles. handles_to_close_.erase(start, it); return true; } @@ -546,14 +549,14 @@ class ChannelPosix : public Channel, // Keeps the Channel alive at least until explicit shutdown on the IO thread. scoped_refptr<Channel> self_; - ScopedPlatformHandle handle_; + ScopedInternalPlatformHandle handle_; scoped_refptr<base::TaskRunner> io_task_runner_; // These watchers must only be accessed on the IO thread. std::unique_ptr<base::MessagePumpForIO::FdWatchController> read_watcher_; std::unique_ptr<base::MessagePumpForIO::FdWatchController> write_watcher_; - base::circular_deque<ScopedPlatformHandle> incoming_platform_handles_; + base::circular_deque<ScopedInternalPlatformHandle> incoming_platform_handles_; // Protects |pending_write_| and |outgoing_messages_|. base::Lock write_lock_; @@ -565,7 +568,7 @@ class ChannelPosix : public Channel, #if defined(OS_MACOSX) base::Lock handles_to_close_lock_; - std::vector<ScopedPlatformHandle> handles_to_close_; + std::vector<ScopedInternalPlatformHandle> handles_to_close_; #endif DISALLOW_COPY_AND_ASSIGN(ChannelPosix); diff --git a/chromium/mojo/edk/system/channel_unittest.cc b/chromium/mojo/edk/system/channel_unittest.cc index de6aa850640..90ff9b3728f 100644 --- a/chromium/mojo/edk/system/channel_unittest.cc +++ b/chromium/mojo/edk/system/channel_unittest.cc @@ -28,16 +28,16 @@ class TestChannel : public Channel { return OnReadComplete(bytes_read, next_read_size_hint); } - MOCK_METHOD4(GetReadPlatformHandles, + MOCK_METHOD4(GetReadInternalPlatformHandles, bool(size_t num_handles, const void* extra_header, size_t extra_header_size, - std::vector<ScopedPlatformHandle>* handles)); + std::vector<ScopedInternalPlatformHandle>* handles)); MOCK_METHOD0(Start, void()); MOCK_METHOD0(ShutDownImpl, void()); MOCK_METHOD0(LeakHandle, void()); - void Write(MessagePtr message) {} + void Write(MessagePtr message) override {} protected: ~TestChannel() override {} @@ -53,9 +53,10 @@ class MockChannelDelegate : public Channel::Delegate { const void* GetReceivedPayload() const { return payload_.get(); } protected: - void OnChannelMessage(const void* payload, - size_t payload_size, - std::vector<ScopedPlatformHandle> handles) override { + void OnChannelMessage( + const void* payload, + size_t payload_size, + std::vector<ScopedInternalPlatformHandle> handles) override { payload_.reset(new char[payload_size]); memcpy(payload_.get(), payload, payload_size); payload_size_ = payload_size; @@ -180,7 +181,7 @@ TEST(ChannelTest, OnReadNonLegacyMessage) { class ChannelTestShutdownAndWriteDelegate : public Channel::Delegate { public: ChannelTestShutdownAndWriteDelegate( - ScopedPlatformHandle handle, + ScopedInternalPlatformHandle handle, scoped_refptr<base::TaskRunner> task_runner, scoped_refptr<Channel> client_channel, std::unique_ptr<base::Thread> client_thread, @@ -196,9 +197,10 @@ class ChannelTestShutdownAndWriteDelegate : public Channel::Delegate { ~ChannelTestShutdownAndWriteDelegate() override { channel_->ShutDown(); } // Channel::Delegate implementation - void OnChannelMessage(const void* payload, - size_t payload_size, - std::vector<ScopedPlatformHandle> handles) override { + void OnChannelMessage( + const void* payload, + size_t payload_size, + std::vector<ScopedInternalPlatformHandle> handles) override { ++message_count_; // If |client_channel_| exists then close it and its thread. diff --git a/chromium/mojo/edk/system/channel_win.cc b/chromium/mojo/edk/system/channel_win.cc index ff4c8135fc3..123e295f9db 100644 --- a/chromium/mojo/edk/system/channel_win.cc +++ b/chromium/mojo/edk/system/channel_win.cc @@ -16,7 +16,7 @@ #include "base/location.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_current.h" #include "base/message_loop/message_pump_for_io.h" #include "base/synchronization/lock.h" #include "base/task_runner.h" @@ -29,11 +29,11 @@ namespace edk { namespace { class ChannelWin : public Channel, - public base::MessageLoop::DestructionObserver, + public base::MessageLoopCurrent::DestructionObserver, public base::MessagePumpForIO::IOHandler { public: ChannelWin(Delegate* delegate, - ScopedPlatformHandle handle, + ScopedInternalPlatformHandle handle, scoped_refptr<base::TaskRunner> io_task_runner) : Channel(delegate), self_(this), @@ -79,11 +79,11 @@ class ChannelWin : public Channel, leak_handle_ = true; } - bool GetReadPlatformHandles( + bool GetReadInternalPlatformHandles( size_t num_handles, const void* extra_header, size_t extra_header_size, - std::vector<ScopedPlatformHandle>* handles) override { + std::vector<ScopedInternalPlatformHandle>* handles) override { DCHECK(extra_header); if (num_handles > std::numeric_limits<uint16_t>::max()) return false; @@ -95,7 +95,7 @@ class ChannelWin : public Channel, const HandleEntry* extra_header_handles = reinterpret_cast<const HandleEntry*>(extra_header); for (size_t i = 0; i < num_handles; i++) { - handles->emplace_back(ScopedPlatformHandle(PlatformHandle( + handles->emplace_back(ScopedInternalPlatformHandle(InternalPlatformHandle( base::win::Uint32ToHandle(extra_header_handles[i].handle)))); } return true; @@ -106,8 +106,8 @@ class ChannelWin : public Channel, ~ChannelWin() override {} void StartOnIOThread() { - base::MessageLoop::current()->AddDestructionObserver(this); - base::MessageLoopForIO::current()->RegisterIOHandler( + base::MessageLoopCurrent::Get()->AddDestructionObserver(this); + base::MessageLoopCurrentForIO::Get()->RegisterIOHandler( handle_.get().handle, this); if (handle_.get().needs_connection) { @@ -150,7 +150,7 @@ class ChannelWin : public Channel, } void ShutDownOnIOThread() { - base::MessageLoop::current()->RemoveDestructionObserver(this); + base::MessageLoopCurrent::Get()->RemoveDestructionObserver(this); // BUG(crbug.com/583525): This function is expected to be called once, and // |handle_| should be valid at this point. @@ -164,7 +164,7 @@ class ChannelWin : public Channel, self_ = nullptr; } - // base::MessageLoop::DestructionObserver: + // base::MessageLoopCurrent::DestructionObserver: void WillDestroyCurrentMessageLoop() override { DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); if (self_) @@ -235,10 +235,14 @@ class ChannelWin : public Channel, Channel::MessagePtr message = std::move(outgoing_messages_.front()); outgoing_messages_.pop_front(); - // Clear any handles so they don't get closed on destruction. - std::vector<ScopedPlatformHandle> handles = message->TakeHandles(); + // Invalidate all the scoped handles so we don't attempt to close them. + // Note that we don't simply release these objects because they also own + // an internal process handle (in |owning_process|) which *does* need to + // be closed. + std::vector<ScopedInternalPlatformHandle> handles = + message->TakeHandles(); for (auto& handle : handles) - ignore_result(handle.release()); + handle.get().handle = INVALID_HANDLE_VALUE; // Overlapped WriteFile() to a pipe should always fully complete. if (message->data_num_bytes() != bytes_written) @@ -311,7 +315,7 @@ class ChannelWin : public Channel, // Keeps the Channel alive at least until explicit shutdown on the IO thread. scoped_refptr<Channel> self_; - ScopedPlatformHandle handle_; + ScopedInternalPlatformHandle handle_; const scoped_refptr<base::TaskRunner> io_task_runner_; base::MessagePumpForIO::IOContext connect_context_; diff --git a/chromium/mojo/edk/system/core.cc b/chromium/mojo/edk/system/core.cc index bf2f95c06b4..58bc403cd50 100644 --- a/chromium/mojo/edk/system/core.cc +++ b/chromium/mojo/edk/system/core.cc @@ -6,6 +6,7 @@ #include <string.h> +#include <algorithm> #include <utility> #include "base/bind.h" @@ -14,21 +15,25 @@ #include "base/logging.h" #include "base/macros.h" #include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" +#include "base/memory/writable_shared_memory_region.h" #include "base/rand_util.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_piece.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "base/trace_event/memory_dump_manager.h" #include "build/build_config.h" -#include "mojo/edk/embedder/platform_shared_buffer.h" +#include "mojo/edk/embedder/platform_handle_utils.h" #include "mojo/edk/embedder/process_error_callback.h" #include "mojo/edk/system/channel.h" #include "mojo/edk/system/configuration.h" #include "mojo/edk/system/data_pipe_consumer_dispatcher.h" #include "mojo/edk/system/data_pipe_producer_dispatcher.h" #include "mojo/edk/system/handle_signals_state.h" +#include "mojo/edk/system/invitation_dispatcher.h" #include "mojo/edk/system/message_pipe_dispatcher.h" #include "mojo/edk/system/platform_handle_dispatcher.h" +#include "mojo/edk/system/platform_shared_memory_mapping.h" #include "mojo/edk/system/ports/event.h" #include "mojo/edk/system/ports/name.h" #include "mojo/edk/system/ports/node.h" @@ -49,96 +54,69 @@ const uint32_t kMaxHandlesPerMessage = 1024 * 1024; // pipes too; for now we just use a constant. This only affects bootstrap pipes. const uint64_t kUnknownPipeIdForDebug = 0x7f7f7f7f7f7f7f7fUL; -MojoResult MojoPlatformHandleToScopedPlatformHandle( - const MojoPlatformHandle* platform_handle, - ScopedPlatformHandle* out_handle) { - if (platform_handle->struct_size != sizeof(MojoPlatformHandle)) - return MOJO_RESULT_INVALID_ARGUMENT; - - if (platform_handle->type == MOJO_PLATFORM_HANDLE_TYPE_INVALID) { - out_handle->reset(); - return MOJO_RESULT_OK; - } - - PlatformHandle handle; - switch (platform_handle->type) { -#if defined(OS_FUCHSIA) - case MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE: - handle = PlatformHandle::ForHandle(platform_handle->value); - break; - case MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR: - handle = PlatformHandle::ForFd(platform_handle->value); - break; - -#elif defined(OS_POSIX) - case MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR: - handle.handle = static_cast<int>(platform_handle->value); - break; -#endif - -#if defined(OS_MACOSX) && !defined(OS_IOS) - case MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT: - handle.type = PlatformHandle::Type::MACH; - handle.port = static_cast<mach_port_t>(platform_handle->value); - break; -#endif - -#if defined(OS_WIN) - case MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE: - handle.handle = reinterpret_cast<HANDLE>(platform_handle->value); - break; -#endif - - default: - return MOJO_RESULT_INVALID_ARGUMENT; - } - - out_handle->reset(handle); - return MOJO_RESULT_OK; -} - -MojoResult ScopedPlatformHandleToMojoPlatformHandle( - ScopedPlatformHandle handle, - MojoPlatformHandle* platform_handle) { - if (platform_handle->struct_size != sizeof(MojoPlatformHandle)) - return MOJO_RESULT_INVALID_ARGUMENT; - - if (!handle.is_valid()) { - platform_handle->type = MOJO_PLATFORM_HANDLE_TYPE_INVALID; - return MOJO_RESULT_OK; - } - -#if defined(OS_FUCHSIA) - if (handle.get().is_valid_fd()) { - platform_handle->type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR; - platform_handle->value = handle.release().as_fd(); - } else { - platform_handle->type = MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE; - platform_handle->value = handle.release().as_handle(); +void InvokeProcessErrorCallbackOnTaskRunner( + scoped_refptr<base::TaskRunner> task_runner, + MojoProcessErrorHandler handler, + uintptr_t context, + const std::string& error, + MojoProcessErrorFlags flags) { + // We always run the handler asynchronously to ensure no Mojo core reentrancy. + task_runner->PostTask( + FROM_HERE, + base::BindOnce( + [](MojoProcessErrorHandler handler, uintptr_t context, + const std::string& error, MojoProcessErrorFlags flags) { + MojoProcessErrorDetails details; + details.struct_size = sizeof(details); + DCHECK(base::IsValueInRangeForNumericType<uint32_t>(error.size())); + details.error_message_length = static_cast<uint32_t>(error.size()); + if (!error.empty()) + details.error_message = error.data(); + else + details.error_message = nullptr; + details.flags = flags; + handler(context, &details); + }, + handler, context, error, flags)); +} + +// Helper class which is bound to the lifetime of a ProcessErrorCallback +// generated by the |MojoSendInvitation()| API. When the last reference to the +// error callback is lost within the EDK, which will happen shortly after a +// connection to the process is lost, that obviously guarantees that no more +// invocations of the callback will occur. At that point, the corresponding +// instance of this object (owned by the callback -- see Core::SendInvitation) +// will be destroyed. +class ProcessDisconnectHandler { + public: + ProcessDisconnectHandler(scoped_refptr<base::TaskRunner> task_runner, + MojoProcessErrorHandler handler, + uintptr_t context) + : task_runner_(std::move(task_runner)), + handler_(handler), + context_(context) {} + + ~ProcessDisconnectHandler() { + InvokeProcessErrorCallbackOnTaskRunner( + task_runner_, handler_, context_, std::string(), + MOJO_PROCESS_ERROR_FLAG_DISCONNECTED); } -#elif defined(OS_POSIX) - switch (handle.get().type) { - case PlatformHandle::Type::POSIX: - platform_handle->type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR; - platform_handle->value = static_cast<uint64_t>(handle.release().handle); - break; -#if defined(OS_MACOSX) && !defined(OS_IOS) - case PlatformHandle::Type::MACH: - platform_handle->type = MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT; - platform_handle->value = static_cast<uint64_t>(handle.release().port); - break; -#endif // defined(OS_MACOSX) && !defined(OS_IOS) + private: + const scoped_refptr<base::TaskRunner> task_runner_; + const MojoProcessErrorHandler handler_; + const uintptr_t context_; - default: - return MOJO_RESULT_INVALID_ARGUMENT; - } -#elif defined(OS_WIN) - platform_handle->type = MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE; - platform_handle->value = reinterpret_cast<uint64_t>(handle.release().handle); -#endif // defined(OS_WIN) + DISALLOW_COPY_AND_ASSIGN(ProcessDisconnectHandler); +}; - return MOJO_RESULT_OK; +void RunMojoProcessErrorHandler(ProcessDisconnectHandler* disconnect_handler, + scoped_refptr<base::TaskRunner> task_runner, + MojoProcessErrorHandler handler, + uintptr_t context, + const std::string& error) { + InvokeProcessErrorCallbackOnTaskRunner(task_runner, handler, context, error, + MOJO_PROCESS_ERROR_FLAG_NONE); } } // namespace @@ -180,6 +158,13 @@ scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) { return handles_->GetDispatcher(handle); } +scoped_refptr<Dispatcher> Core::GetAndRemoveDispatcher(MojoHandle handle) { + scoped_refptr<Dispatcher> dispatcher; + base::AutoLock lock(handles_->GetLock()); + handles_->GetAndRemoveDispatcher(handle, &dispatcher); + return dispatcher; +} + void Core::SetDefaultProcessErrorCallback( const ProcessErrorCallback& callback) { default_process_error_callback_ = callback; @@ -278,8 +263,8 @@ void Core::ReleaseDispatchersForTransit( handles_->CancelTransit(dispatchers); } -MojoResult Core::CreatePlatformHandleWrapper( - ScopedPlatformHandle platform_handle, +MojoResult Core::CreateInternalPlatformHandleWrapper( + ScopedInternalPlatformHandle platform_handle, MojoHandle* wrapper_handle) { MojoHandle h = AddDispatcher( PlatformHandleDispatcher::Create(std::move(platform_handle))); @@ -289,9 +274,9 @@ MojoResult Core::CreatePlatformHandleWrapper( return MOJO_RESULT_OK; } -MojoResult Core::PassWrappedPlatformHandle( +MojoResult Core::PassWrappedInternalPlatformHandle( MojoHandle wrapper_handle, - ScopedPlatformHandle* platform_handle) { + ScopedInternalPlatformHandle* platform_handle) { base::AutoLock lock(handles_->GetLock()); scoped_refptr<Dispatcher> d; MojoResult result = handles_->GetAndRemoveDispatcher(wrapper_handle, &d); @@ -300,7 +285,7 @@ MojoResult Core::PassWrappedPlatformHandle( if (d->GetType() == Dispatcher::Type::PLATFORM_HANDLE) { PlatformHandleDispatcher* phd = static_cast<PlatformHandleDispatcher*>(d.get()); - *platform_handle = phd->PassPlatformHandle(); + *platform_handle = phd->PassInternalPlatformHandle(); } else { result = MOJO_RESULT_INVALID_ARGUMENT; } @@ -308,72 +293,6 @@ MojoResult Core::PassWrappedPlatformHandle( return result; } -MojoResult Core::CreateSharedBufferWrapper( - base::SharedMemoryHandle shared_memory_handle, - size_t num_bytes, - bool read_only, - MojoHandle* mojo_wrapper_handle) { - DCHECK(num_bytes); - scoped_refptr<PlatformSharedBuffer> platform_buffer = - PlatformSharedBuffer::CreateFromSharedMemoryHandle(num_bytes, read_only, - shared_memory_handle); - if (!platform_buffer) - return MOJO_RESULT_UNKNOWN; - - scoped_refptr<SharedBufferDispatcher> dispatcher; - MojoResult result = SharedBufferDispatcher::CreateFromPlatformSharedBuffer( - platform_buffer, &dispatcher); - if (result != MOJO_RESULT_OK) - return result; - MojoHandle h = AddDispatcher(dispatcher); - if (h == MOJO_HANDLE_INVALID) - return MOJO_RESULT_RESOURCE_EXHAUSTED; - *mojo_wrapper_handle = h; - return MOJO_RESULT_OK; -} - -MojoResult Core::PassSharedMemoryHandle( - MojoHandle mojo_handle, - base::SharedMemoryHandle* shared_memory_handle, - size_t* num_bytes, - bool* read_only) { - if (!shared_memory_handle) - return MOJO_RESULT_INVALID_ARGUMENT; - - scoped_refptr<Dispatcher> dispatcher; - MojoResult result = MOJO_RESULT_OK; - { - base::AutoLock lock(handles_->GetLock()); - // Get the dispatcher and check it before removing it from the handle table - // to ensure that the dispatcher is of the correct type. This ensures we - // don't close and remove the wrong type of dispatcher. - dispatcher = handles_->GetDispatcher(mojo_handle); - if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::SHARED_BUFFER) - return MOJO_RESULT_INVALID_ARGUMENT; - - result = handles_->GetAndRemoveDispatcher(mojo_handle, &dispatcher); - if (result != MOJO_RESULT_OK) - return result; - } - - SharedBufferDispatcher* shm_dispatcher = - static_cast<SharedBufferDispatcher*>(dispatcher.get()); - scoped_refptr<PlatformSharedBuffer> platform_shared_buffer = - shm_dispatcher->PassPlatformSharedBuffer(); - - if (!platform_shared_buffer) - return MOJO_RESULT_INVALID_ARGUMENT; - - if (num_bytes) - *num_bytes = platform_shared_buffer->GetNumBytes(); - if (read_only) - *read_only = platform_shared_buffer->IsReadOnly(); - *shared_memory_handle = platform_shared_buffer->DuplicateSharedMemoryHandle(); - - shm_dispatcher->Close(); - return result; -} - void Core::RequestShutdown(const base::Closure& callback) { GetNodeController()->RequestShutdown(callback); } @@ -388,17 +307,6 @@ MojoHandle Core::ExtractMessagePipeFromInvitation(const std::string& name) { return handle; } -MojoResult Core::SetProperty(MojoPropertyType type, const void* value) { - base::AutoLock locker(property_lock_); - switch (type) { - case MOJO_PROPERTY_TYPE_SYNC_CALL_ALLOWED: - property_sync_call_allowed_ = *static_cast<const bool*>(value); - return MOJO_RESULT_OK; - default: - return MOJO_RESULT_INVALID_ARGUMENT; - } -} - MojoTimeTicks Core::GetTimeTicksNow() { return base::TimeTicks::Now().ToInternalValue(); } @@ -641,17 +549,6 @@ MojoResult Core::GetMessageContext(MojoMessageHandle message_handle, return MOJO_RESULT_OK; } -MojoResult Core::GetProperty(MojoPropertyType type, void* value) { - base::AutoLock locker(property_lock_); - switch (type) { - case MOJO_PROPERTY_TYPE_SYNC_CALL_ALLOWED: - *static_cast<bool*>(value) = property_sync_call_allowed_; - return MOJO_RESULT_OK; - default: - return MOJO_RESULT_INVALID_ARGUMENT; - } -} - MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options, MojoHandle* message_pipe_handle0, MojoHandle* message_pipe_handle1) { @@ -686,7 +583,7 @@ MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options, MojoResult Core::WriteMessage(MojoHandle message_pipe_handle, MojoMessageHandle message_handle, - MojoWriteMessageFlags flags) { + const MojoWriteMessageOptions* options) { RequestContext request_context; if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; @@ -698,12 +595,12 @@ MojoResult Core::WriteMessage(MojoHandle message_pipe_handle, auto dispatcher = GetDispatcher(message_pipe_handle); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - return dispatcher->WriteMessage(std::move(message_event), flags); + return dispatcher->WriteMessage(std::move(message_event)); } MojoResult Core::ReadMessage(MojoHandle message_pipe_handle, - MojoMessageHandle* message_handle, - MojoReadMessageFlags flags) { + const MojoReadMessageOptions* options, + MojoMessageHandle* message_handle) { RequestContext request_context; auto dispatcher = GetDispatcher(message_pipe_handle); if (!dispatcher || !message_handle) @@ -719,7 +616,9 @@ MojoResult Core::ReadMessage(MojoHandle message_pipe_handle, return MOJO_RESULT_OK; } -MojoResult Core::FuseMessagePipes(MojoHandle handle0, MojoHandle handle1) { +MojoResult Core::FuseMessagePipes(MojoHandle handle0, + MojoHandle handle1, + const MojoFuseMessagePipesOptions* options) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher0; scoped_refptr<Dispatcher> dispatcher1; @@ -758,7 +657,8 @@ MojoResult Core::FuseMessagePipes(MojoHandle handle0, MojoHandle handle1) { MojoResult Core::NotifyBadMessage(MojoMessageHandle message_handle, const char* error, - size_t error_num_bytes) { + size_t error_num_bytes, + const MojoNotifyBadMessageOptions* options) { if (!message_handle) return MOJO_RESULT_INVALID_ARGUMENT; @@ -797,10 +697,30 @@ MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options, return MOJO_RESULT_INVALID_ARGUMENT; } - scoped_refptr<PlatformSharedBuffer> ring_buffer = - GetNodeController()->CreateSharedBuffer( - create_options.capacity_num_bytes); - if (!ring_buffer) + base::subtle::PlatformSharedMemoryRegion ring_buffer_region = + base::WritableSharedMemoryRegion::TakeHandleForSerialization( + GetNodeController()->CreateSharedBuffer( + create_options.capacity_num_bytes)); + + // NOTE: We demote the writable region to an unsafe region so that the + // producer handle can be transferred freely. There is no compelling reason + // to restrict access rights of consumers since they are the exclusive + // consumer of this pipe, and it would be impossible to support such access + // control on Android anyway. + auto writable_region_handle = ring_buffer_region.PassPlatformHandle(); +#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA) && \ + (!defined(OS_MACOSX) || defined(OS_IOS)) + // This isn't strictly necessary, but it does make the handle configuration + // consistent with regular UnsafeSharedMemoryRegions. + writable_region_handle.readonly_fd.reset(); +#endif + base::UnsafeSharedMemoryRegion producer_region = + base::UnsafeSharedMemoryRegion::Deserialize( + base::subtle::PlatformSharedMemoryRegion::Take( + std::move(writable_region_handle), + base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe, + create_options.capacity_num_bytes, ring_buffer_region.GetGUID())); + if (!producer_region.IsValid()) return MOJO_RESULT_RESOURCE_EXHAUSTED; ports::PortRef port0, port1; @@ -809,14 +729,17 @@ MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options, DCHECK(data_pipe_producer_handle); DCHECK(data_pipe_consumer_handle); + base::UnsafeSharedMemoryRegion consumer_region = producer_region.Duplicate(); uint64_t pipe_id = base::RandUint64(); scoped_refptr<Dispatcher> producer = DataPipeProducerDispatcher::Create( - GetNodeController(), port0, ring_buffer, create_options, pipe_id); + GetNodeController(), port0, std::move(producer_region), create_options, + pipe_id); if (!producer) return MOJO_RESULT_RESOURCE_EXHAUSTED; scoped_refptr<Dispatcher> consumer = DataPipeConsumerDispatcher::Create( - GetNodeController(), port1, ring_buffer, create_options, pipe_id); + GetNodeController(), port1, std::move(consumer_region), create_options, + pipe_id); if (!consumer) { producer->Close(); return MOJO_RESULT_RESOURCE_EXHAUSTED; @@ -842,80 +765,131 @@ MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options, MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle, const void* elements, uint32_t* num_bytes, - MojoWriteDataFlags flags) { + const MojoWriteDataOptions* options) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_producer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - return dispatcher->WriteData(elements, num_bytes, flags); + MojoWriteDataOptions validated_options; + if (options) { + if (options->struct_size < sizeof(*options)) + return MOJO_RESULT_INVALID_ARGUMENT; + + constexpr MojoWriteDataFlags kSupportedFlags = + MOJO_WRITE_DATA_FLAG_NONE | MOJO_WRITE_DATA_FLAG_ALL_OR_NONE; + if (options->flags & ~kSupportedFlags) + return MOJO_RESULT_UNIMPLEMENTED; + validated_options.flags = options->flags; + } else { + validated_options.flags = MOJO_WRITE_DATA_FLAG_NONE; + } + return dispatcher->WriteData(elements, num_bytes, validated_options); } MojoResult Core::BeginWriteData(MojoHandle data_pipe_producer_handle, + const MojoBeginWriteDataOptions* options, void** buffer, - uint32_t* buffer_num_bytes, - MojoWriteDataFlags flags) { + uint32_t* buffer_num_bytes) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_producer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - - return dispatcher->BeginWriteData(buffer, buffer_num_bytes, flags); + if (options) { + if (options->struct_size < sizeof(*options)) + return MOJO_RESULT_INVALID_ARGUMENT; + if (options->flags != MOJO_BEGIN_WRITE_DATA_FLAG_NONE) + return MOJO_RESULT_UNIMPLEMENTED; + } + return dispatcher->BeginWriteData(buffer, buffer_num_bytes); } MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle, - uint32_t num_bytes_written) { + uint32_t num_bytes_written, + const MojoEndWriteDataOptions* options) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_producer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - + if (options) { + if (options->struct_size < sizeof(*options)) + return MOJO_RESULT_INVALID_ARGUMENT; + if (options->flags != MOJO_END_WRITE_DATA_FLAG_NONE) + return MOJO_RESULT_UNIMPLEMENTED; + } return dispatcher->EndWriteData(num_bytes_written); } MojoResult Core::ReadData(MojoHandle data_pipe_consumer_handle, + const MojoReadDataOptions* options, void* elements, - uint32_t* num_bytes, - MojoReadDataFlags flags) { + uint32_t* num_bytes) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_consumer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - return dispatcher->ReadData(elements, num_bytes, flags); + MojoReadDataOptions validated_options; + if (options) { + if (options->struct_size < sizeof(*options)) + return MOJO_RESULT_INVALID_ARGUMENT; + + constexpr MojoReadDataFlags kSupportedFlags = + MOJO_READ_DATA_FLAG_NONE | MOJO_READ_DATA_FLAG_ALL_OR_NONE | + MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_QUERY | + MOJO_READ_DATA_FLAG_PEEK; + if (options->flags & ~kSupportedFlags) + return MOJO_RESULT_UNIMPLEMENTED; + validated_options.flags = options->flags; + } else { + validated_options.flags = MOJO_WRITE_DATA_FLAG_NONE; + } + return dispatcher->ReadData(validated_options, elements, num_bytes); } MojoResult Core::BeginReadData(MojoHandle data_pipe_consumer_handle, + const MojoBeginReadDataOptions* options, const void** buffer, - uint32_t* buffer_num_bytes, - MojoReadDataFlags flags) { + uint32_t* buffer_num_bytes) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_consumer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - return dispatcher->BeginReadData(buffer, buffer_num_bytes, flags); + if (options) { + if (options->struct_size < sizeof(*options)) + return MOJO_RESULT_INVALID_ARGUMENT; + if (options->flags != MOJO_BEGIN_READ_DATA_FLAG_NONE) + return MOJO_RESULT_UNIMPLEMENTED; + } + return dispatcher->BeginReadData(buffer, buffer_num_bytes); } MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle, - uint32_t num_bytes_read) { + uint32_t num_bytes_read, + const MojoEndReadDataOptions* options) { RequestContext request_context; scoped_refptr<Dispatcher> dispatcher( GetDispatcher(data_pipe_consumer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; - + if (options) { + if (options->struct_size < sizeof(*options)) + return MOJO_RESULT_INVALID_ARGUMENT; + if (options->flags != MOJO_END_READ_DATA_FLAG_NONE) + return MOJO_RESULT_UNIMPLEMENTED; + } return dispatcher->EndReadData(num_bytes_read); } MojoResult Core::CreateSharedBuffer( - const MojoCreateSharedBufferOptions* options, uint64_t num_bytes, + const MojoCreateSharedBufferOptions* options, MojoHandle* shared_buffer_handle) { RequestContext request_context; MojoCreateSharedBufferOptions validated_options = {}; @@ -971,15 +945,20 @@ MojoResult Core::DuplicateBufferHandle( MojoResult Core::MapBuffer(MojoHandle buffer_handle, uint64_t offset, uint64_t num_bytes, - void** buffer, - MojoMapBufferFlags flags) { - RequestContext request_context; + const MojoMapBufferOptions* options, + void** buffer) { scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle)); if (!dispatcher) return MOJO_RESULT_INVALID_ARGUMENT; + if (options) { + if (options->struct_size < sizeof(*options)) + return MOJO_RESULT_INVALID_ARGUMENT; + if (options->flags != MOJO_MAP_BUFFER_FLAG_NONE) + return MOJO_RESULT_UNIMPLEMENTED; + } - std::unique_ptr<PlatformSharedBufferMapping> mapping; - MojoResult result = dispatcher->MapBuffer(offset, num_bytes, flags, &mapping); + std::unique_ptr<PlatformSharedMemoryMapping> mapping; + MojoResult result = dispatcher->MapBuffer(offset, num_bytes, &mapping); if (result != MOJO_RESULT_OK) return result; @@ -987,33 +966,42 @@ MojoResult Core::MapBuffer(MojoHandle buffer_handle, void* address = mapping->GetBase(); { base::AutoLock locker(mapping_table_lock_); - result = mapping_table_.AddMapping(std::move(mapping)); + if (mapping_table_.size() >= GetConfiguration().max_mapping_table_size) + return MOJO_RESULT_RESOURCE_EXHAUSTED; + auto emplace_result = mapping_table_.emplace(address, std::move(mapping)); + DCHECK(emplace_result.second); } - if (result != MOJO_RESULT_OK) - return result; *buffer = address; return MOJO_RESULT_OK; } MojoResult Core::UnmapBuffer(void* buffer) { - RequestContext request_context; - std::unique_ptr<PlatformSharedBufferMapping> mapping; - MojoResult result; + std::unique_ptr<PlatformSharedMemoryMapping> mapping; // Destroy |mapping| while not holding the lock. { base::AutoLock lock(mapping_table_lock_); - result = mapping_table_.RemoveMapping(buffer, &mapping); + auto iter = mapping_table_.find(buffer); + if (iter == mapping_table_.end()) + return MOJO_RESULT_INVALID_ARGUMENT; + + // Grab a reference so that it gets unmapped outside of this lock. + mapping = std::move(iter->second); + mapping_table_.erase(iter); } - return result; + return MOJO_RESULT_OK; } MojoResult Core::GetBufferInfo(MojoHandle buffer_handle, - const MojoSharedBufferOptions* options, + const MojoGetBufferInfoOptions* options, MojoSharedBufferInfo* info) { - if (options && options->struct_size != sizeof(MojoSharedBufferOptions)) - return MOJO_RESULT_INVALID_ARGUMENT; - if (!info || info->struct_size != sizeof(MojoSharedBufferInfo)) + if (options) { + if (options->struct_size < sizeof(*options)) + return MOJO_RESULT_INVALID_ARGUMENT; + if (options->flags != MOJO_GET_BUFFER_INFO_FLAG_NONE) + return MOJO_RESULT_UNIMPLEMENTED; + } + if (!info || info->struct_size < sizeof(MojoSharedBufferInfo)) return MOJO_RESULT_INVALID_ARGUMENT; scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle)); @@ -1023,54 +1011,94 @@ MojoResult Core::GetBufferInfo(MojoHandle buffer_handle, return dispatcher->GetBufferInfo(info); } -MojoResult Core::WrapPlatformHandle(const MojoPlatformHandle* platform_handle, - MojoHandle* mojo_handle) { - ScopedPlatformHandle handle; - MojoResult result = - MojoPlatformHandleToScopedPlatformHandle(platform_handle, &handle); +MojoResult Core::WrapInternalPlatformHandle( + const MojoPlatformHandle* platform_handle, + const MojoWrapPlatformHandleOptions* options, + MojoHandle* mojo_handle) { + ScopedInternalPlatformHandle handle; + MojoResult result = MojoPlatformHandleToScopedInternalPlatformHandle( + platform_handle, &handle); if (result != MOJO_RESULT_OK) return result; - return CreatePlatformHandleWrapper(std::move(handle), mojo_handle); + return CreateInternalPlatformHandleWrapper(std::move(handle), mojo_handle); } -MojoResult Core::UnwrapPlatformHandle(MojoHandle mojo_handle, - MojoPlatformHandle* platform_handle) { - ScopedPlatformHandle handle; - MojoResult result = PassWrappedPlatformHandle(mojo_handle, &handle); +MojoResult Core::UnwrapInternalPlatformHandle( + MojoHandle mojo_handle, + const MojoUnwrapPlatformHandleOptions* options, + MojoPlatformHandle* platform_handle) { + ScopedInternalPlatformHandle handle; + MojoResult result = PassWrappedInternalPlatformHandle(mojo_handle, &handle); if (result != MOJO_RESULT_OK) return result; - return ScopedPlatformHandleToMojoPlatformHandle(std::move(handle), - platform_handle); + return ScopedInternalPlatformHandleToMojoPlatformHandle(std::move(handle), + platform_handle); } -MojoResult Core::WrapPlatformSharedBufferHandle( - const MojoPlatformHandle* platform_handle, - size_t size, +MojoResult Core::WrapPlatformSharedMemoryRegion( + const MojoPlatformHandle* platform_handles, + uint32_t num_platform_handles, + uint64_t size, const MojoSharedBufferGuid* guid, - MojoPlatformSharedBufferHandleFlags flags, + MojoPlatformSharedMemoryRegionAccessMode access_mode, + const MojoWrapPlatformSharedMemoryRegionOptions* options, MojoHandle* mojo_handle) { DCHECK(size); - ScopedPlatformHandle handle; - MojoResult result = - MojoPlatformHandleToScopedPlatformHandle(platform_handle, &handle); - if (result != MOJO_RESULT_OK) - return result; + +#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA) && \ + (!defined(OS_MACOSX) || defined(OS_IOS)) + if (access_mode == MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE) { + if (num_platform_handles != 2) + return MOJO_RESULT_INVALID_ARGUMENT; + } +#else + if (num_platform_handles != 1) + return MOJO_RESULT_INVALID_ARGUMENT; +#endif + + ScopedInternalPlatformHandle handles[2]; + bool handles_ok = true; + for (size_t i = 0; i < num_platform_handles; ++i) { + MojoResult result = MojoPlatformHandleToScopedInternalPlatformHandle( + &platform_handles[i], &handles[i]); + if (result != MOJO_RESULT_OK) + handles_ok = false; + } + if (!handles_ok) + return MOJO_RESULT_INVALID_ARGUMENT; base::UnguessableToken token = base::UnguessableToken::Deserialize(guid->high, guid->low); - const bool read_only = - flags & MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_HANDLE_IS_READ_ONLY; - scoped_refptr<PlatformSharedBuffer> platform_buffer = - PlatformSharedBuffer::CreateFromPlatformHandle(size, read_only, token, - std::move(handle)); - if (!platform_buffer) + + base::subtle::PlatformSharedMemoryRegion::Mode mode; + switch (access_mode) { + case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY: + mode = base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly; + break; + case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE: + mode = base::subtle::PlatformSharedMemoryRegion::Mode::kWritable; + break; + case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE: + mode = base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe; + break; + default: + return MOJO_RESULT_INVALID_ARGUMENT; + } + + base::subtle::PlatformSharedMemoryRegion region = + base::subtle::PlatformSharedMemoryRegion::Take( + CreateSharedMemoryRegionHandleFromInternalPlatformHandles( + std::move(handles[0]), std::move(handles[1])), + mode, size, token); + if (!region.IsValid()) return MOJO_RESULT_UNKNOWN; scoped_refptr<SharedBufferDispatcher> dispatcher; - result = SharedBufferDispatcher::CreateFromPlatformSharedBuffer( - platform_buffer, &dispatcher); + MojoResult result = + SharedBufferDispatcher::CreateFromPlatformSharedMemoryRegion( + std::move(region), &dispatcher); if (result != MOJO_RESULT_OK) return result; @@ -1084,12 +1112,14 @@ MojoResult Core::WrapPlatformSharedBufferHandle( return MOJO_RESULT_OK; } -MojoResult Core::UnwrapPlatformSharedBufferHandle( +MojoResult Core::UnwrapPlatformSharedMemoryRegion( MojoHandle mojo_handle, - MojoPlatformHandle* platform_handle, - size_t* size, + const MojoUnwrapPlatformSharedMemoryRegionOptions* options, + MojoPlatformHandle* platform_handles, + uint32_t* num_platform_handles, + uint64_t* size, MojoSharedBufferGuid* guid, - MojoPlatformSharedBufferHandleFlags* flags) { + MojoPlatformSharedMemoryRegionAccessMode* access_mode) { scoped_refptr<Dispatcher> dispatcher; MojoResult result = MOJO_RESULT_OK; { @@ -1106,25 +1136,298 @@ MojoResult Core::UnwrapPlatformSharedBufferHandle( SharedBufferDispatcher* shm_dispatcher = static_cast<SharedBufferDispatcher*>(dispatcher.get()); - scoped_refptr<PlatformSharedBuffer> platform_shared_buffer = - shm_dispatcher->PassPlatformSharedBuffer(); - DCHECK(platform_shared_buffer); - + base::subtle::PlatformSharedMemoryRegion region = + shm_dispatcher->PassPlatformSharedMemoryRegion(); + DCHECK(region.IsValid()); DCHECK(size); - *size = platform_shared_buffer->GetNumBytes(); + *size = region.GetSize(); - base::UnguessableToken token = platform_shared_buffer->GetGUID(); + base::UnguessableToken token = region.GetGUID(); guid->high = token.GetHighForSerialization(); guid->low = token.GetLowForSerialization(); - DCHECK(flags); - *flags = MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_NONE; - if (platform_shared_buffer->IsReadOnly()) - *flags |= MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_HANDLE_IS_READ_ONLY; + DCHECK(access_mode); + switch (region.GetMode()) { + case base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly: + *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY; + break; + case base::subtle::PlatformSharedMemoryRegion::Mode::kWritable: + *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE; + break; + case base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe: + *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE; + break; + default: + return MOJO_RESULT_INVALID_ARGUMENT; + } + + ScopedInternalPlatformHandle handle; + ScopedInternalPlatformHandle read_only_handle; + ExtractInternalPlatformHandlesFromSharedMemoryRegionHandle( + region.PassPlatformHandle(), &handle, &read_only_handle); + + const uint32_t available_handle_storage_slots = *num_platform_handles; + if (available_handle_storage_slots < 1) + return MOJO_RESULT_RESOURCE_EXHAUSTED; + *num_platform_handles = 1; +#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA) && \ + (!defined(OS_MACOSX) || defined(OS_IOS)) + if (region.GetMode() == + base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) { + if (available_handle_storage_slots < 2) + return MOJO_RESULT_INVALID_ARGUMENT; + if (ScopedInternalPlatformHandleToMojoPlatformHandle( + std::move(read_only_handle), &platform_handles[1]) != + MOJO_RESULT_OK) { + return MOJO_RESULT_INVALID_ARGUMENT; + } + *num_platform_handles = 2; + } +#endif + + if (ScopedInternalPlatformHandleToMojoPlatformHandle( + std::move(handle), &platform_handles[0]) != MOJO_RESULT_OK) { + return MOJO_RESULT_INVALID_ARGUMENT; + } + + return MOJO_RESULT_OK; +} + +MojoResult Core::CreateInvitation(const MojoCreateInvitationOptions* options, + MojoHandle* invitation_handle) { + if (options && options->struct_size < sizeof(*options)) + return MOJO_RESULT_INVALID_ARGUMENT; + if (!invitation_handle) + return MOJO_RESULT_INVALID_ARGUMENT; + + *invitation_handle = AddDispatcher(new InvitationDispatcher); + if (*invitation_handle == MOJO_HANDLE_INVALID) + return MOJO_RESULT_RESOURCE_EXHAUSTED; + + return MOJO_RESULT_OK; +} + +MojoResult Core::AttachMessagePipeToInvitation( + MojoHandle invitation_handle, + const void* name, + uint32_t name_num_bytes, + const MojoAttachMessagePipeToInvitationOptions* options, + MojoHandle* message_pipe_handle) { + if (options && options->struct_size < sizeof(*options)) + return MOJO_RESULT_INVALID_ARGUMENT; + if (!message_pipe_handle) + return MOJO_RESULT_INVALID_ARGUMENT; + if (name_num_bytes == 0) + return MOJO_RESULT_INVALID_ARGUMENT; + + scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle); + if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION) + return MOJO_RESULT_INVALID_ARGUMENT; + auto* invitation_dispatcher = + static_cast<InvitationDispatcher*>(dispatcher.get()); + + RequestContext request_context; + + ports::PortRef remote_peer_port; + MojoHandle local_handle = CreatePartialMessagePipe(&remote_peer_port); + if (local_handle == MOJO_HANDLE_INVALID) + return MOJO_RESULT_RESOURCE_EXHAUSTED; + + MojoResult result = invitation_dispatcher->AttachMessagePipe( + base::StringPiece(static_cast<const char*>(name), name_num_bytes), + std::move(remote_peer_port)); + if (result != MOJO_RESULT_OK) { + Close(local_handle); + return result; + } + + *message_pipe_handle = local_handle; + return MOJO_RESULT_OK; +} + +MojoResult Core::ExtractMessagePipeFromInvitation( + MojoHandle invitation_handle, + const void* name, + uint32_t name_num_bytes, + const MojoExtractMessagePipeFromInvitationOptions* options, + MojoHandle* message_pipe_handle) { + if (options && options->struct_size < sizeof(*options)) + return MOJO_RESULT_INVALID_ARGUMENT; + if (!message_pipe_handle) + return MOJO_RESULT_INVALID_ARGUMENT; + if (name_num_bytes == 0) + return MOJO_RESULT_INVALID_ARGUMENT; - ScopedPlatformHandle handle = platform_shared_buffer->PassPlatformHandle(); - return ScopedPlatformHandleToMojoPlatformHandle(std::move(handle), - platform_handle); + RequestContext request_context; + + base::StringPiece name_string(static_cast<const char*>(name), name_num_bytes); + scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle); + if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION) + return MOJO_RESULT_INVALID_ARGUMENT; + auto* invitation_dispatcher = + static_cast<InvitationDispatcher*>(dispatcher.get()); + // First attempt to extract from the invitation object itself. This is for + // cases where this creation was created in-process. + MojoResult extract_result = invitation_dispatcher->ExtractMessagePipe( + name_string, message_pipe_handle); + if (extract_result == MOJO_RESULT_OK || + extract_result == MOJO_RESULT_RESOURCE_EXHAUSTED) { + return extract_result; + } + + *message_pipe_handle = + ExtractMessagePipeFromInvitation(name_string.as_string()); + if (*message_pipe_handle == MOJO_HANDLE_INVALID) + return MOJO_RESULT_RESOURCE_EXHAUSTED; + return MOJO_RESULT_OK; +} + +MojoResult Core::SendInvitation( + MojoHandle invitation_handle, + const MojoPlatformProcessHandle* process_handle, + const MojoInvitationTransportEndpoint* transport_endpoint, + MojoProcessErrorHandler error_handler, + uintptr_t error_handler_context, + const MojoSendInvitationOptions* options) { + if (options && options->struct_size < sizeof(*options)) + return MOJO_RESULT_INVALID_ARGUMENT; + + base::ProcessHandle target_process = base::kNullProcessHandle; + if (process_handle) { + if (process_handle->struct_size < sizeof(*process_handle)) + return MOJO_RESULT_INVALID_ARGUMENT; +#if defined(OS_WIN) + target_process = reinterpret_cast<base::ProcessHandle>( + static_cast<uintptr_t>(process_handle->value)); +#else + target_process = static_cast<base::ProcessHandle>(process_handle->value); +#endif + } + + ProcessErrorCallback process_error_callback; + if (error_handler) { + auto error_handler_task_runner = GetNodeController()->io_task_runner(); + process_error_callback = base::BindRepeating( + &RunMojoProcessErrorHandler, + base::Owned(new ProcessDisconnectHandler( + error_handler_task_runner, error_handler, error_handler_context)), + error_handler_task_runner, error_handler, error_handler_context); + } else if (default_process_error_callback_) { + process_error_callback = default_process_error_callback_; + } + + if (!transport_endpoint) + return MOJO_RESULT_INVALID_ARGUMENT; + if (transport_endpoint->struct_size < sizeof(*transport_endpoint)) + return MOJO_RESULT_INVALID_ARGUMENT; + if (transport_endpoint->num_platform_handles == 0) + return MOJO_RESULT_INVALID_ARGUMENT; + if (!transport_endpoint->platform_handles) + return MOJO_RESULT_INVALID_ARGUMENT; + if (transport_endpoint->type != MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL && + transport_endpoint->type != + MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) { + return MOJO_RESULT_UNIMPLEMENTED; + } + + scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle); + if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION) + return MOJO_RESULT_INVALID_ARGUMENT; + auto* invitation_dispatcher = + static_cast<InvitationDispatcher*>(dispatcher.get()); + + ScopedInternalPlatformHandle endpoint_handle; + MojoResult result = MojoPlatformHandleToScopedInternalPlatformHandle( + &transport_endpoint->platform_handles[0], &endpoint_handle); + if (result != MOJO_RESULT_OK || !endpoint_handle.is_valid()) + return MOJO_RESULT_INVALID_ARGUMENT; + +#if defined(OS_WIN) || (defined(OS_POSIX) && !defined(OS_FUCHSIA)) + if (transport_endpoint->type == MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) + endpoint_handle.get().needs_connection = true; +#endif + + // At this point everything else has been validated, so we can take ownership + // of the dispatcher. + { + base::AutoLock lock(handles_->GetLock()); + scoped_refptr<Dispatcher> removed_dispatcher; + MojoResult result = handles_->GetAndRemoveDispatcher(invitation_handle, + &removed_dispatcher); + if (result != MOJO_RESULT_OK) { + // Release ownership of the endpoint platform handle, per the API + // contract. The caller retains ownership on failure. + ignore_result(endpoint_handle.release()); + return result; + } + DCHECK_EQ(removed_dispatcher.get(), invitation_dispatcher); + } + + ConnectionParams connection_params(TransportProtocol::kLegacy, + std::move(endpoint_handle)); + + std::vector<std::pair<std::string, ports::PortRef>> attached_ports; + InvitationDispatcher::PortMapping attached_port_map = + invitation_dispatcher->TakeAttachedPorts(); + invitation_dispatcher->Close(); + for (auto& entry : attached_port_map) + attached_ports.emplace_back(entry.first, std::move(entry.second)); + + RequestContext request_context; + GetNodeController()->SendBrokerClientInvitation( + target_process, std::move(connection_params), attached_ports, + process_error_callback); + + return MOJO_RESULT_OK; +} + +MojoResult Core::AcceptInvitation( + const MojoInvitationTransportEndpoint* transport_endpoint, + const MojoAcceptInvitationOptions* options, + MojoHandle* invitation_handle) { + if (options && options->struct_size < sizeof(*options)) + return MOJO_RESULT_INVALID_ARGUMENT; + + if (!transport_endpoint) + return MOJO_RESULT_INVALID_ARGUMENT; + if (transport_endpoint->struct_size < sizeof(*transport_endpoint)) + return MOJO_RESULT_INVALID_ARGUMENT; + if (transport_endpoint->num_platform_handles == 0) + return MOJO_RESULT_INVALID_ARGUMENT; + if (!transport_endpoint->platform_handles) + return MOJO_RESULT_INVALID_ARGUMENT; + if (transport_endpoint->type != MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL && + transport_endpoint->type != + MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) { + return MOJO_RESULT_UNIMPLEMENTED; + } + + if (!invitation_handle) + return MOJO_RESULT_INVALID_ARGUMENT; + *invitation_handle = AddDispatcher(new InvitationDispatcher); + if (*invitation_handle == MOJO_HANDLE_INVALID) + return MOJO_RESULT_RESOURCE_EXHAUSTED; + + ScopedInternalPlatformHandle endpoint_handle; + MojoResult result = MojoPlatformHandleToScopedInternalPlatformHandle( + &transport_endpoint->platform_handles[0], &endpoint_handle); + if (result != MOJO_RESULT_OK) { + Close(*invitation_handle); + *invitation_handle = MOJO_HANDLE_INVALID; + return MOJO_RESULT_INVALID_ARGUMENT; + } + +#if defined(OS_WIN) || (defined(OS_POSIX) && !defined(OS_FUCHSIA)) + if (transport_endpoint->type == MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) + endpoint_handle.get().needs_connection = true; +#endif + + RequestContext request_context; + ConnectionParams connection_params(TransportProtocol::kLegacy, + std::move(endpoint_handle)); + GetNodeController()->AcceptBrokerClientInvitation( + std::move(connection_params)); + return MOJO_RESULT_OK; } void Core::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) { diff --git a/chromium/mojo/edk/system/core.h b/chromium/mojo/edk/system/core.h index 478971e2dc6..9401189c809 100644 --- a/chromium/mojo/edk/system/core.h +++ b/chromium/mojo/edk/system/core.h @@ -19,11 +19,11 @@ #include "mojo/edk/system/dispatcher.h" #include "mojo/edk/system/handle_signals_state.h" #include "mojo/edk/system/handle_table.h" -#include "mojo/edk/system/mapping_table.h" #include "mojo/edk/system/node_controller.h" #include "mojo/edk/system/system_impl_export.h" #include "mojo/public/c/system/buffer.h" #include "mojo/public/c/system/data_pipe.h" +#include "mojo/public/c/system/invitation.h" #include "mojo/public/c/system/message_pipe.h" #include "mojo/public/c/system/platform_handle.h" #include "mojo/public/c/system/trap.h" @@ -36,6 +36,8 @@ class PortProvider; namespace mojo { namespace edk { +class PlatformSharedMemoryMapping; + // |Core| is an object that implements the Mojo system calls. All public methods // are thread-safe. class MOJO_SYSTEM_IMPL_EXPORT Core { @@ -53,6 +55,7 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { NodeController* GetNodeController(); scoped_refptr<Dispatcher> GetDispatcher(MojoHandle handle); + scoped_refptr<Dispatcher> GetAndRemoveDispatcher(MojoHandle handle); void SetDefaultProcessErrorCallback(const ProcessErrorCallback& callback); @@ -137,23 +140,13 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { bool in_transit); // See "mojo/edk/embedder/embedder.h" for more information on these functions. - MojoResult CreatePlatformHandleWrapper(ScopedPlatformHandle platform_handle, - MojoHandle* wrapper_handle); - - MojoResult PassWrappedPlatformHandle(MojoHandle wrapper_handle, - ScopedPlatformHandle* platform_handle); + MojoResult CreateInternalPlatformHandleWrapper( + ScopedInternalPlatformHandle platform_handle, + MojoHandle* wrapper_handle); - MojoResult CreateSharedBufferWrapper( - base::SharedMemoryHandle shared_memory_handle, - size_t num_bytes, - bool read_only, - MojoHandle* mojo_wrapper_handle); - - MojoResult PassSharedMemoryHandle( - MojoHandle mojo_handle, - base::SharedMemoryHandle* shared_memory_handle, - size_t* num_bytes, - bool* read_only); + MojoResult PassWrappedInternalPlatformHandle( + MojoHandle wrapper_handle, + ScopedInternalPlatformHandle* platform_handle); // Requests that the EDK tear itself down. |callback| will be called once // the shutdown process is complete. Note that |callback| is always called @@ -163,8 +156,6 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { // may be called from any thread. Beware! void RequestShutdown(const base::Closure& callback); - MojoResult SetProperty(MojoPropertyType type, const void* value); - // --------------------------------------------------------------------------- // The following methods are essentially implementations of the Mojo Core @@ -223,7 +214,6 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { MojoResult GetMessageContext(MojoMessageHandle message_handle, const MojoGetMessageContextOptions* options, uintptr_t* context); - MojoResult GetProperty(MojoPropertyType type, void* value); // These methods correspond to the API functions defined in // "mojo/public/c/system/message_pipe.h": @@ -232,14 +222,17 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { MojoHandle* message_pipe_handle1); MojoResult WriteMessage(MojoHandle message_pipe_handle, MojoMessageHandle message_handle, - MojoWriteMessageFlags flags); + const MojoWriteMessageOptions* options); MojoResult ReadMessage(MojoHandle message_pipe_handle, - MojoMessageHandle* message_handle, - MojoReadMessageFlags flags); - MojoResult FuseMessagePipes(MojoHandle handle0, MojoHandle handle1); + const MojoReadMessageOptions* options, + MojoMessageHandle* message_handle); + MojoResult FuseMessagePipes(MojoHandle handle0, + MojoHandle handle1, + const MojoFuseMessagePipesOptions* options); MojoResult NotifyBadMessage(MojoMessageHandle message_handle, const char* error, - size_t error_num_bytes); + size_t error_num_bytes, + const MojoNotifyBadMessageOptions* options); // These methods correspond to the API functions defined in // "mojo/public/c/system/data_pipe.h": @@ -249,28 +242,30 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { MojoResult WriteData(MojoHandle data_pipe_producer_handle, const void* elements, uint32_t* num_bytes, - MojoWriteDataFlags flags); + const MojoWriteDataOptions* options); MojoResult BeginWriteData(MojoHandle data_pipe_producer_handle, + const MojoBeginWriteDataOptions* options, void** buffer, - uint32_t* buffer_num_bytes, - MojoWriteDataFlags flags); + uint32_t* buffer_num_bytes); MojoResult EndWriteData(MojoHandle data_pipe_producer_handle, - uint32_t num_bytes_written); + uint32_t num_bytes_written, + const MojoEndWriteDataOptions* options); MojoResult ReadData(MojoHandle data_pipe_consumer_handle, + const MojoReadDataOptions* options, void* elements, - uint32_t* num_bytes, - MojoReadDataFlags flags); + uint32_t* num_bytes); MojoResult BeginReadData(MojoHandle data_pipe_consumer_handle, + const MojoBeginReadDataOptions* options, const void** buffer, - uint32_t* buffer_num_bytes, - MojoReadDataFlags flags); + uint32_t* buffer_num_bytes); MojoResult EndReadData(MojoHandle data_pipe_consumer_handle, - uint32_t num_bytes_read); + uint32_t num_bytes_read, + const MojoEndReadDataOptions* options); // These methods correspond to the API functions defined in // "mojo/public/c/system/buffer.h": - MojoResult CreateSharedBuffer(const MojoCreateSharedBufferOptions* options, - uint64_t num_bytes, + MojoResult CreateSharedBuffer(uint64_t num_bytes, + const MojoCreateSharedBufferOptions* options, MojoHandle* shared_buffer_handle); MojoResult DuplicateBufferHandle( MojoHandle buffer_handle, @@ -279,31 +274,66 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { MojoResult MapBuffer(MojoHandle buffer_handle, uint64_t offset, uint64_t num_bytes, - void** buffer, - MojoMapBufferFlags flags); + const MojoMapBufferOptions* options, + void** buffer); MojoResult UnmapBuffer(void* buffer); MojoResult GetBufferInfo(MojoHandle buffer_handle, - const MojoSharedBufferOptions* options, + const MojoGetBufferInfoOptions* options, MojoSharedBufferInfo* info); // These methods correspond to the API functions defined in // "mojo/public/c/system/platform_handle.h". - MojoResult WrapPlatformHandle(const MojoPlatformHandle* platform_handle, - MojoHandle* mojo_handle); - MojoResult UnwrapPlatformHandle(MojoHandle mojo_handle, - MojoPlatformHandle* platform_handle); - MojoResult WrapPlatformSharedBufferHandle( + MojoResult WrapInternalPlatformHandle( const MojoPlatformHandle* platform_handle, - size_t size, + const MojoWrapPlatformHandleOptions* options, + MojoHandle* mojo_handle); + MojoResult UnwrapInternalPlatformHandle( + MojoHandle mojo_handle, + const MojoUnwrapPlatformHandleOptions* options, + MojoPlatformHandle* platform_handle); + MojoResult WrapPlatformSharedMemoryRegion( + const MojoPlatformHandle* platform_handles, + uint32_t num_platform_handles, + uint64_t size, const MojoSharedBufferGuid* guid, - MojoPlatformSharedBufferHandleFlags flags, + MojoPlatformSharedMemoryRegionAccessMode access_mode, + const MojoWrapPlatformSharedMemoryRegionOptions* options, MojoHandle* mojo_handle); - MojoResult UnwrapPlatformSharedBufferHandle( + MojoResult UnwrapPlatformSharedMemoryRegion( MojoHandle mojo_handle, - MojoPlatformHandle* platform_handle, - size_t* size, + const MojoUnwrapPlatformSharedMemoryRegionOptions* options, + MojoPlatformHandle* platform_handles, + uint32_t* num_platform_handles, + uint64_t* size, MojoSharedBufferGuid* guid, - MojoPlatformSharedBufferHandleFlags* flags); + MojoPlatformSharedMemoryRegionAccessMode* access_mode); + + // Invitation API. + MojoResult CreateInvitation(const MojoCreateInvitationOptions* options, + MojoHandle* invitation_handle); + MojoResult AttachMessagePipeToInvitation( + MojoHandle invitation_handle, + const void* name, + uint32_t name_num_bytes, + const MojoAttachMessagePipeToInvitationOptions* options, + MojoHandle* message_pipe_handle); + MojoResult ExtractMessagePipeFromInvitation( + MojoHandle invitation_handle, + const void* name, + uint32_t name_num_bytes, + const MojoExtractMessagePipeFromInvitationOptions* options, + MojoHandle* message_pipe_handle); + MojoResult SendInvitation( + MojoHandle invitation_handle, + const MojoPlatformProcessHandle* process_handle, + const MojoInvitationTransportEndpoint* transport_endpoint, + MojoProcessErrorHandler error_handler, + uintptr_t error_handler_context, + const MojoSendInvitationOptions* options); + MojoResult AcceptInvitation( + const MojoInvitationTransportEndpoint* transport_endpoint, + const MojoAcceptInvitationOptions* options, + MojoHandle* invitation_handle); void GetActiveHandlesForTest(std::vector<MojoHandle>* handles); @@ -334,11 +364,10 @@ class MOJO_SYSTEM_IMPL_EXPORT Core { std::unique_ptr<HandleTable> handles_; base::Lock mapping_table_lock_; // Protects |mapping_table_|. - MappingTable mapping_table_; - base::Lock property_lock_; - // Properties that can be read using the MojoGetProperty() API. - bool property_sync_call_allowed_ = true; + using MappingTable = + std::unordered_map<void*, std::unique_ptr<PlatformSharedMemoryMapping>>; + MappingTable mapping_table_; DISALLOW_COPY_AND_ASSIGN(Core); }; diff --git a/chromium/mojo/edk/system/core_test_base.cc b/chromium/mojo/edk/system/core_test_base.cc index ff7b7c3ae52..a025a9bbf3b 100644 --- a/chromium/mojo/edk/system/core_test_base.cc +++ b/chromium/mojo/edk/system/core_test_base.cc @@ -41,8 +41,7 @@ class MockDispatcher : public Dispatcher { } MojoResult WriteMessage( - std::unique_ptr<ports::UserMessageEvent> message_event, - MojoWriteMessageFlags /*flags*/) override { + std::unique_ptr<ports::UserMessageEvent> message_event) override { info_->IncrementWriteMessageCallCount(); return MOJO_RESULT_OK; } @@ -55,14 +54,13 @@ class MockDispatcher : public Dispatcher { MojoResult WriteData(const void* elements, uint32_t* num_bytes, - MojoWriteDataFlags flags) override { + const MojoWriteDataOptions& options) override { info_->IncrementWriteDataCallCount(); return MOJO_RESULT_UNIMPLEMENTED; } MojoResult BeginWriteData(void** buffer, - uint32_t* buffer_num_bytes, - MojoWriteDataFlags flags) override { + uint32_t* buffer_num_bytes) override { info_->IncrementBeginWriteDataCallCount(); return MOJO_RESULT_UNIMPLEMENTED; } @@ -72,16 +70,15 @@ class MockDispatcher : public Dispatcher { return MOJO_RESULT_UNIMPLEMENTED; } - MojoResult ReadData(void* elements, - uint32_t* num_bytes, - MojoReadDataFlags flags) override { + MojoResult ReadData(const MojoReadDataOptions& options, + void* elements, + uint32_t* num_bytes) override { info_->IncrementReadDataCallCount(); return MOJO_RESULT_UNIMPLEMENTED; } MojoResult BeginReadData(const void** buffer, - uint32_t* buffer_num_bytes, - MojoReadDataFlags flags) override { + uint32_t* buffer_num_bytes) override { info_->IncrementBeginReadDataCallCount(); return MOJO_RESULT_UNIMPLEMENTED; } diff --git a/chromium/mojo/edk/system/core_unittest.cc b/chromium/mojo/edk/system/core_unittest.cc index 7fe7ba0e95b..a35208b7a46 100644 --- a/chromium/mojo/edk/system/core_unittest.cc +++ b/chromium/mojo/edk/system/core_unittest.cc @@ -51,46 +51,41 @@ TEST_F(CoreTest, Basic) { ASSERT_EQ(0u, info.GetWriteMessageCallCount()); MojoMessageHandle message; ASSERT_EQ(MOJO_RESULT_OK, core()->CreateMessage(nullptr, &message)); - ASSERT_EQ(MOJO_RESULT_OK, - core()->WriteMessage(h, message, MOJO_WRITE_MESSAGE_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h, message, nullptr)); ASSERT_EQ(1u, info.GetWriteMessageCallCount()); ASSERT_EQ(0u, info.GetReadMessageCallCount()); - ASSERT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h, &message, MOJO_READ_MESSAGE_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_OK, core()->ReadMessage(h, nullptr, &message)); ASSERT_EQ(1u, info.GetReadMessageCallCount()); - ASSERT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h, &message, MOJO_READ_MESSAGE_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_OK, core()->ReadMessage(h, nullptr, &message)); ASSERT_EQ(2u, info.GetReadMessageCallCount()); ASSERT_EQ(0u, info.GetWriteDataCallCount()); ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED, - core()->WriteData(h, nullptr, nullptr, MOJO_WRITE_DATA_FLAG_NONE)); + core()->WriteData(h, nullptr, nullptr, nullptr)); ASSERT_EQ(1u, info.GetWriteDataCallCount()); ASSERT_EQ(0u, info.GetBeginWriteDataCallCount()); - ASSERT_EQ( - MOJO_RESULT_UNIMPLEMENTED, - core()->BeginWriteData(h, nullptr, nullptr, MOJO_WRITE_DATA_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED, + core()->BeginWriteData(h, nullptr, nullptr, nullptr)); ASSERT_EQ(1u, info.GetBeginWriteDataCallCount()); ASSERT_EQ(0u, info.GetEndWriteDataCallCount()); - ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->EndWriteData(h, 0)); + ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->EndWriteData(h, 0, nullptr)); ASSERT_EQ(1u, info.GetEndWriteDataCallCount()); ASSERT_EQ(0u, info.GetReadDataCallCount()); ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED, - core()->ReadData(h, nullptr, nullptr, MOJO_READ_DATA_FLAG_NONE)); + core()->ReadData(h, nullptr, nullptr, nullptr)); ASSERT_EQ(1u, info.GetReadDataCallCount()); ASSERT_EQ(0u, info.GetBeginReadDataCallCount()); - ASSERT_EQ( - MOJO_RESULT_UNIMPLEMENTED, - core()->BeginReadData(h, nullptr, nullptr, MOJO_READ_DATA_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED, + core()->BeginReadData(h, nullptr, nullptr, nullptr)); ASSERT_EQ(1u, info.GetBeginReadDataCallCount()); ASSERT_EQ(0u, info.GetEndReadDataCallCount()); - ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->EndReadData(h, 0)); + ASSERT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->EndReadData(h, 0, nullptr)); ASSERT_EQ(1u, info.GetEndReadDataCallCount()); ASSERT_EQ(0u, info.GetDtorCallCount()); @@ -122,23 +117,20 @@ TEST_F(CoreTest, InvalidArguments) { // |WriteMessageNew()|: // Only check arguments checked by |Core|, namely |handle|, |handles|, and // |num_handles|. - { - ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->WriteMessage(MOJO_HANDLE_INVALID, 0, - MOJO_WRITE_MESSAGE_FLAG_NONE)); - } + ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + core()->WriteMessage(MOJO_HANDLE_INVALID, 0, nullptr)); // |ReadMessageNew()|: // Only check arguments checked by |Core|, namely |handle|, |handles|, and // |num_handles|. { ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->ReadMessage(MOJO_HANDLE_INVALID, nullptr, - MOJO_READ_MESSAGE_FLAG_NONE)); + core()->ReadMessage(MOJO_HANDLE_INVALID, nullptr, nullptr)); + MockHandleInfo info; MojoHandle h = CreateMockHandle(&info); ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->ReadMessage(h, nullptr, MOJO_READ_MESSAGE_FLAG_NONE)); + core()->ReadMessage(h, nullptr, nullptr)); // Checked by |Core|, shouldn't go through to the dispatcher. ASSERT_EQ(0u, info.GetReadMessageCallCount()); ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h)); @@ -168,7 +160,7 @@ TEST_F(CoreTest, MessagePipe) { // Try to read anyway. MojoMessageHandle message; ASSERT_EQ(MOJO_RESULT_SHOULD_WAIT, - core()->ReadMessage(h[0], &message, MOJO_READ_MESSAGE_FLAG_NONE)); + core()->ReadMessage(h[0], nullptr, &message)); // Write to |h[1]|. const uintptr_t kTestMessageContext = 123; @@ -176,16 +168,14 @@ TEST_F(CoreTest, MessagePipe) { ASSERT_EQ(MOJO_RESULT_OK, core()->SetMessageContext(message, kTestMessageContext, nullptr, nullptr, nullptr)); - ASSERT_EQ(MOJO_RESULT_OK, - core()->WriteMessage(h[1], message, MOJO_WRITE_MESSAGE_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h[1], message, nullptr)); // Wait for |h[0]| to become readable. EXPECT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(h[0]), MOJO_HANDLE_SIGNAL_READABLE, &hss[0])); // Read from |h[0]|. - ASSERT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h[0], &message, MOJO_READ_MESSAGE_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_OK, core()->ReadMessage(h[0], nullptr, &message)); uintptr_t context; ASSERT_EQ(MOJO_RESULT_OK, core()->GetMessageContext(message, nullptr, &context)); @@ -205,8 +195,7 @@ TEST_F(CoreTest, MessagePipe) { ASSERT_EQ(MOJO_RESULT_OK, core()->SetMessageContext(message, kTestMessageContext, nullptr, nullptr, nullptr)); - ASSERT_EQ(MOJO_RESULT_OK, - core()->WriteMessage(h[0], message, MOJO_WRITE_MESSAGE_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h[0], message, nullptr)); // Close |h[0]|. ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h[0])); @@ -229,8 +218,7 @@ TEST_F(CoreTest, MessagePipe) { hss[1].satisfiable_signals); // Discard a message from |h[1]|. - ASSERT_EQ(MOJO_RESULT_OK, - core()->ReadMessage(h[1], &message, MOJO_READ_MESSAGE_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_OK, core()->ReadMessage(h[1], nullptr, &message)); ASSERT_EQ(MOJO_RESULT_OK, core()->DestroyMessage(message)); // |h[1]| is no longer readable (and will never be). @@ -245,7 +233,7 @@ TEST_F(CoreTest, MessagePipe) { core()->SetMessageContext(message, kTestMessageContext, nullptr, nullptr, nullptr)); ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - core()->WriteMessage(h[1], message, MOJO_WRITE_MESSAGE_FLAG_NONE)); + core()->WriteMessage(h[1], message, nullptr)); ASSERT_EQ(MOJO_RESULT_OK, core()->Close(h[1])); } @@ -264,8 +252,8 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) { ASSERT_EQ(MOJO_RESULT_OK, core()->SetMessageContext(message, kTestMessageContext, nullptr, nullptr, nullptr)); - ASSERT_EQ(MOJO_RESULT_OK, core()->WriteMessage(h_passing[0], message, - MOJO_WRITE_MESSAGE_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_OK, + core()->WriteMessage(h_passing[0], message, nullptr)); hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(h_passing[1]), MOJO_HANDLE_SIGNAL_READABLE, &hss)); @@ -273,8 +261,8 @@ TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) { hss.satisfied_signals); ASSERT_EQ(kAllSignals, hss.satisfiable_signals); MojoMessageHandle message_handle; - ASSERT_EQ(MOJO_RESULT_OK, core()->ReadMessage(h_passing[1], &message_handle, - MOJO_READ_MESSAGE_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_OK, + core()->ReadMessage(h_passing[1], nullptr, &message_handle)); uintptr_t context; ASSERT_EQ(MOJO_RESULT_OK, core()->GetMessageContext(message_handle, nullptr, &context)); @@ -317,8 +305,8 @@ TEST_F(CoreTest, DataPipe) { // Write. signed char elements[2] = {'A', 'B'}; uint32_t num_bytes = 2u; - ASSERT_EQ(MOJO_RESULT_OK, core()->WriteData(ph, elements, &num_bytes, - MOJO_WRITE_DATA_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_OK, + core()->WriteData(ph, elements, &num_bytes, nullptr)); ASSERT_EQ(2u, num_bytes); // Wait for the data to arrive to the consumer. @@ -339,9 +327,11 @@ TEST_F(CoreTest, DataPipe) { elements[0] = -1; elements[1] = -1; num_bytes = 1u; - ASSERT_EQ(MOJO_RESULT_OK, core()->ReadData(ch, elements, &num_bytes, - MOJO_READ_DATA_FLAG_NONE | - MOJO_READ_DATA_FLAG_PEEK)); + MojoReadDataOptions read_options; + read_options.struct_size = sizeof(read_options); + read_options.flags = MOJO_READ_DATA_FLAG_NONE | MOJO_READ_DATA_FLAG_PEEK; + ASSERT_EQ(MOJO_RESULT_OK, + core()->ReadData(ch, &read_options, elements, &num_bytes)); ASSERT_EQ('A', elements[0]); ASSERT_EQ(-1, elements[1]); @@ -349,30 +339,31 @@ TEST_F(CoreTest, DataPipe) { elements[0] = -1; elements[1] = -1; num_bytes = 1u; - ASSERT_EQ(MOJO_RESULT_OK, core()->ReadData(ch, elements, &num_bytes, - MOJO_READ_DATA_FLAG_NONE)); + read_options.flags = MOJO_READ_DATA_FLAG_NONE; + ASSERT_EQ(MOJO_RESULT_OK, + core()->ReadData(ch, &read_options, elements, &num_bytes)); ASSERT_EQ('A', elements[0]); ASSERT_EQ(-1, elements[1]); // Two-phase write. void* write_ptr = nullptr; num_bytes = 0u; - ASSERT_EQ(MOJO_RESULT_OK, core()->BeginWriteData(ph, &write_ptr, &num_bytes, - MOJO_WRITE_DATA_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_OK, + core()->BeginWriteData(ph, nullptr, &write_ptr, &num_bytes)); // We count on the default options providing a decent buffer size. ASSERT_GE(num_bytes, 3u); // Trying to do a normal write during a two-phase write should fail. elements[0] = 'X'; num_bytes = 1u; - ASSERT_EQ(MOJO_RESULT_BUSY, core()->WriteData(ph, elements, &num_bytes, - MOJO_WRITE_DATA_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_BUSY, + core()->WriteData(ph, elements, &num_bytes, nullptr)); // Actually write the data, and complete it now. static_cast<char*>(write_ptr)[0] = 'C'; static_cast<char*>(write_ptr)[1] = 'D'; static_cast<char*>(write_ptr)[2] = 'E'; - ASSERT_EQ(MOJO_RESULT_OK, core()->EndWriteData(ph, 3u)); + ASSERT_EQ(MOJO_RESULT_OK, core()->EndWriteData(ph, 3u, nullptr)); // Wait for the data to arrive to the consumer. ASSERT_EQ(MOJO_RESULT_OK, @@ -380,73 +371,61 @@ TEST_F(CoreTest, DataPipe) { // Query how much data we have. num_bytes = 0; - ASSERT_EQ(MOJO_RESULT_OK, core()->ReadData(ch, nullptr, &num_bytes, - MOJO_READ_DATA_FLAG_QUERY)); + read_options.flags = MOJO_READ_DATA_FLAG_QUERY; + ASSERT_EQ(MOJO_RESULT_OK, + core()->ReadData(ch, &read_options, nullptr, &num_bytes)); ASSERT_GE(num_bytes, 1u); // Try to query with peek. Should fail. num_bytes = 0; - ASSERT_EQ( - MOJO_RESULT_INVALID_ARGUMENT, - core()->ReadData(ch, nullptr, &num_bytes, - MOJO_READ_DATA_FLAG_QUERY | MOJO_READ_DATA_FLAG_PEEK)); + read_options.flags = MOJO_READ_DATA_FLAG_QUERY | MOJO_READ_DATA_FLAG_PEEK; + ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + core()->ReadData(ch, &read_options, nullptr, &num_bytes)); ASSERT_EQ(0u, num_bytes); // Try to discard ten characters, in all-or-none mode. Should fail. num_bytes = 10; + read_options.flags = + MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE; ASSERT_EQ(MOJO_RESULT_OUT_OF_RANGE, - core()->ReadData( - ch, nullptr, &num_bytes, - MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE)); + core()->ReadData(ch, &read_options, nullptr, &num_bytes)); // Try to discard two characters, in peek mode. Should fail. num_bytes = 2; - ASSERT_EQ( - MOJO_RESULT_INVALID_ARGUMENT, - core()->ReadData(ch, nullptr, &num_bytes, - MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_PEEK)); + read_options.flags = MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_PEEK; + ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + core()->ReadData(ch, &read_options, nullptr, &num_bytes)); // Discard a character. num_bytes = 1; + read_options.flags = + MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE; ASSERT_EQ(MOJO_RESULT_OK, - core()->ReadData( - ch, nullptr, &num_bytes, - MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE)); + core()->ReadData(ch, &read_options, nullptr, &num_bytes)); // Ensure the 3 bytes were read. ASSERT_EQ(MOJO_RESULT_OK, mojo::Wait(mojo::Handle(ch), MOJO_HANDLE_SIGNAL_READABLE, &hss)); - // Try a two-phase read of the remaining three bytes with peek. Should fail. - const void* read_ptr = nullptr; - num_bytes = 3; - ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->BeginReadData(ch, &read_ptr, &num_bytes, - MOJO_READ_DATA_FLAG_PEEK)); - - // Try a two-phase read of the remaining two bytes with all-or-none. Should - // fail. - ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - core()->BeginReadData(ch, &read_ptr, &num_bytes, - MOJO_READ_DATA_FLAG_ALL_OR_NONE)); - // Read the remaining three characters, in two-phase mode. + const void* read_ptr = nullptr; num_bytes = 3; - ASSERT_EQ(MOJO_RESULT_OK, core()->BeginReadData(ch, &read_ptr, &num_bytes, - MOJO_READ_DATA_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_OK, + core()->BeginReadData(ch, nullptr, &read_ptr, &num_bytes)); // Note: Count on still being able to do the contiguous read here. ASSERT_EQ(3u, num_bytes); // Discarding right now should fail. num_bytes = 1; - ASSERT_EQ(MOJO_RESULT_BUSY, core()->ReadData(ch, nullptr, &num_bytes, - MOJO_READ_DATA_FLAG_DISCARD)); + read_options.flags = MOJO_READ_DATA_FLAG_DISCARD; + ASSERT_EQ(MOJO_RESULT_BUSY, + core()->ReadData(ch, &read_options, nullptr, &num_bytes)); // Actually check our data and end the two-phase read. ASSERT_EQ('C', static_cast<const char*>(read_ptr)[0]); ASSERT_EQ('D', static_cast<const char*>(read_ptr)[1]); ASSERT_EQ('E', static_cast<const char*>(read_ptr)[2]); - ASSERT_EQ(MOJO_RESULT_OK, core()->EndReadData(ch, 3u)); + ASSERT_EQ(MOJO_RESULT_OK, core()->EndReadData(ch, 3u, nullptr)); // Consumer should now be no longer readable. hss = kFullMojoHandleSignalsState; diff --git a/chromium/mojo/edk/system/data_pipe_consumer_dispatcher.cc b/chromium/mojo/edk/system/data_pipe_consumer_dispatcher.cc index f5c0c7e6b25..78d6d129e86 100644 --- a/chromium/mojo/edk/system/data_pipe_consumer_dispatcher.cc +++ b/chromium/mojo/edk/system/data_pipe_consumer_dispatcher.cc @@ -14,8 +14,7 @@ #include "base/bind.h" #include "base/logging.h" #include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "mojo/edk/embedder/platform_shared_buffer.h" +#include "mojo/edk/embedder/platform_handle_utils.h" #include "mojo/edk/system/core.h" #include "mojo/edk/system/data_pipe_control_message.h" #include "mojo/edk/system/node_controller.h" @@ -74,12 +73,13 @@ class DataPipeConsumerDispatcher::PortObserverThunk scoped_refptr<DataPipeConsumerDispatcher> DataPipeConsumerDispatcher::Create( NodeController* node_controller, const ports::PortRef& control_port, - scoped_refptr<PlatformSharedBuffer> shared_ring_buffer, + base::UnsafeSharedMemoryRegion shared_ring_buffer, const MojoCreateDataPipeOptions& options, uint64_t pipe_id) { scoped_refptr<DataPipeConsumerDispatcher> consumer = new DataPipeConsumerDispatcher(node_controller, control_port, - shared_ring_buffer, options, pipe_id); + std::move(shared_ring_buffer), options, + pipe_id); base::AutoLock lock(consumer->lock_); if (!consumer->InitializeNoLock()) return nullptr; @@ -96,12 +96,13 @@ MojoResult DataPipeConsumerDispatcher::Close() { return CloseNoLock(); } -MojoResult DataPipeConsumerDispatcher::ReadData(void* elements, - uint32_t* num_bytes, - MojoReadDataFlags flags) { +MojoResult DataPipeConsumerDispatcher::ReadData( + const MojoReadDataOptions& options, + void* elements, + uint32_t* num_bytes) { base::AutoLock lock(lock_); - if (!shared_ring_buffer_ || in_transit_) + if (!shared_ring_buffer_.IsValid() || in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; if (in_two_phase_read_) @@ -110,11 +111,11 @@ MojoResult DataPipeConsumerDispatcher::ReadData(void* elements, const bool had_new_data = new_data_available_; new_data_available_ = false; - if ((flags & MOJO_READ_DATA_FLAG_QUERY)) { - if ((flags & MOJO_READ_DATA_FLAG_PEEK) || - (flags & MOJO_READ_DATA_FLAG_DISCARD)) + if ((options.flags & MOJO_READ_DATA_FLAG_QUERY)) { + if ((options.flags & MOJO_READ_DATA_FLAG_PEEK) || + (options.flags & MOJO_READ_DATA_FLAG_DISCARD)) return MOJO_RESULT_INVALID_ARGUMENT; - DCHECK(!(flags & MOJO_READ_DATA_FLAG_DISCARD)); // Handled above. + DCHECK(!(options.flags & MOJO_READ_DATA_FLAG_DISCARD)); // Handled above. DVLOG_IF(2, elements) << "Query mode: ignoring non-null |elements|"; *num_bytes = static_cast<uint32_t>(bytes_available_); @@ -124,9 +125,9 @@ MojoResult DataPipeConsumerDispatcher::ReadData(void* elements, } bool discard = false; - if ((flags & MOJO_READ_DATA_FLAG_DISCARD)) { + if ((options.flags & MOJO_READ_DATA_FLAG_DISCARD)) { // These flags are mutally exclusive. - if (flags & MOJO_READ_DATA_FLAG_PEEK) + if (options.flags & MOJO_READ_DATA_FLAG_PEEK) return MOJO_RESULT_INVALID_ARGUMENT; DVLOG_IF(2, elements) << "Discard mode: ignoring non-null |elements|"; discard = true; @@ -136,7 +137,7 @@ MojoResult DataPipeConsumerDispatcher::ReadData(void* elements, if (max_num_bytes_to_read % options_.element_num_bytes != 0) return MOJO_RESULT_INVALID_ARGUMENT; - bool all_or_none = flags & MOJO_READ_DATA_FLAG_ALL_OR_NONE; + bool all_or_none = options.flags & MOJO_READ_DATA_FLAG_ALL_OR_NONE; uint32_t min_num_bytes_to_read = all_or_none ? max_num_bytes_to_read : 0; if (min_num_bytes_to_read > bytes_available_) { @@ -155,7 +156,8 @@ MojoResult DataPipeConsumerDispatcher::ReadData(void* elements, } if (!discard) { - uint8_t* data = static_cast<uint8_t*>(ring_buffer_mapping_->GetBase()); + const uint8_t* data = + static_cast<const uint8_t*>(ring_buffer_mapping_.memory()); CHECK(data); uint8_t* destination = static_cast<uint8_t*>(elements); @@ -172,7 +174,7 @@ MojoResult DataPipeConsumerDispatcher::ReadData(void* elements, } *num_bytes = bytes_to_read; - bool peek = !!(flags & MOJO_READ_DATA_FLAG_PEEK); + bool peek = !!(options.flags & MOJO_READ_DATA_FLAG_PEEK); if (discard || !peek) { read_offset_ = (read_offset_ + bytes_to_read) % options_.capacity_num_bytes; bytes_available_ -= bytes_to_read; @@ -188,23 +190,16 @@ MojoResult DataPipeConsumerDispatcher::ReadData(void* elements, return MOJO_RESULT_OK; } -MojoResult DataPipeConsumerDispatcher::BeginReadData(const void** buffer, - uint32_t* buffer_num_bytes, - MojoReadDataFlags flags) { +MojoResult DataPipeConsumerDispatcher::BeginReadData( + const void** buffer, + uint32_t* buffer_num_bytes) { base::AutoLock lock(lock_); - if (!shared_ring_buffer_ || in_transit_) + if (!shared_ring_buffer_.IsValid() || in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; if (in_two_phase_read_) return MOJO_RESULT_BUSY; - // These flags may not be used in two-phase mode. - if ((flags & MOJO_READ_DATA_FLAG_DISCARD) || - (flags & MOJO_READ_DATA_FLAG_QUERY) || - (flags & MOJO_READ_DATA_FLAG_PEEK) || - (flags & MOJO_READ_DATA_FLAG_ALL_OR_NONE)) - return MOJO_RESULT_INVALID_ARGUMENT; - const bool had_new_data = new_data_available_; new_data_available_ = false; @@ -219,8 +214,8 @@ MojoResult DataPipeConsumerDispatcher::BeginReadData(const void** buffer, uint32_t bytes_to_read = std::min(bytes_available_, options_.capacity_num_bytes - read_offset_); - CHECK(ring_buffer_mapping_); - uint8_t* data = static_cast<uint8_t*>(ring_buffer_mapping_->GetBase()); + CHECK(ring_buffer_mapping_.IsValid()); + uint8_t* data = static_cast<uint8_t*>(ring_buffer_mapping_.memory()); CHECK(data); in_two_phase_read_ = true; @@ -242,7 +237,7 @@ MojoResult DataPipeConsumerDispatcher::EndReadData(uint32_t num_bytes_read) { if (in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; - CHECK(shared_ring_buffer_); + CHECK(shared_ring_buffer_.IsValid()); MojoResult rv; if (num_bytes_read > two_phase_max_bytes_read_ || @@ -304,7 +299,7 @@ void DataPipeConsumerDispatcher::StartSerialize(uint32_t* num_bytes, bool DataPipeConsumerDispatcher::EndSerialize( void* destination, ports::PortName* ports, - ScopedPlatformHandle* platform_handles) { + ScopedInternalPlatformHandle* platform_handles) { SerializedState* state = static_cast<SerializedState*>(destination); memcpy(&state->options, &options_, sizeof(MojoCreateDataPipeOptions)); memset(state->padding, 0, sizeof(state->padding)); @@ -316,14 +311,20 @@ bool DataPipeConsumerDispatcher::EndSerialize( state->bytes_available = bytes_available_; state->flags = peer_closed_ ? kFlagPeerClosed : 0; - base::UnguessableToken guid = shared_ring_buffer_->GetGUID(); + auto region_handle = + base::UnsafeSharedMemoryRegion::TakeHandleForSerialization( + std::move(shared_ring_buffer_)); + const base::UnguessableToken& guid = region_handle.GetGUID(); state->buffer_guid_high = guid.GetHighForSerialization(); state->buffer_guid_low = guid.GetLowForSerialization(); ports[0] = control_port_.name(); - platform_handles[0] = shared_ring_buffer_->DuplicatePlatformHandle(); - if (!platform_handles[0].is_valid()) + ScopedInternalPlatformHandle ignored_handle; + ExtractInternalPlatformHandlesFromSharedMemoryRegionHandle( + region_handle.PassPlatformHandle(), &platform_handles[0], + &ignored_handle); + if (!platform_handles[0].is_valid() || ignored_handle.is_valid()) return false; return true; @@ -360,7 +361,7 @@ DataPipeConsumerDispatcher::Deserialize(const void* data, size_t num_bytes, const ports::PortName* ports, size_t num_ports, - ScopedPlatformHandle* handles, + ScopedInternalPlatformHandle* handles, size_t num_handles) { if (num_ports != 1 || num_handles != 1 || num_bytes != sizeof(SerializedState)) { @@ -378,22 +379,28 @@ DataPipeConsumerDispatcher::Deserialize(const void* data, if (node_controller->node()->GetPort(ports[0], &port) != ports::OK) return nullptr; - base::UnguessableToken guid = base::UnguessableToken::Deserialize( - state->buffer_guid_high, state->buffer_guid_low); - ScopedPlatformHandle buffer_handle; + ScopedInternalPlatformHandle buffer_handle; std::swap(buffer_handle, handles[0]); - scoped_refptr<PlatformSharedBuffer> ring_buffer = - PlatformSharedBuffer::CreateFromPlatformHandle( - state->options.capacity_num_bytes, false /* read_only */, guid, - std::move(buffer_handle)); - if (!ring_buffer) { + auto region_handle = + CreateSharedMemoryRegionHandleFromInternalPlatformHandles( + std::move(buffer_handle), ScopedInternalPlatformHandle()); + auto region = base::subtle::PlatformSharedMemoryRegion::Take( + std::move(region_handle), + base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe, + state->options.capacity_num_bytes, + base::UnguessableToken::Deserialize(state->buffer_guid_high, + state->buffer_guid_low)); + auto ring_buffer = + base::UnsafeSharedMemoryRegion::Deserialize(std::move(region)); + if (!ring_buffer.IsValid()) { DLOG(ERROR) << "Failed to deserialize shared buffer handle."; return nullptr; } scoped_refptr<DataPipeConsumerDispatcher> dispatcher = - new DataPipeConsumerDispatcher(node_controller, port, ring_buffer, - state->options, state->pipe_id); + new DataPipeConsumerDispatcher(node_controller, port, + std::move(ring_buffer), state->options, + state->pipe_id); { base::AutoLock lock(dispatcher->lock_); @@ -412,7 +419,7 @@ DataPipeConsumerDispatcher::Deserialize(const void* data, DataPipeConsumerDispatcher::DataPipeConsumerDispatcher( NodeController* node_controller, const ports::PortRef& control_port, - scoped_refptr<PlatformSharedBuffer> shared_ring_buffer, + base::UnsafeSharedMemoryRegion shared_ring_buffer, const MojoCreateDataPipeOptions& options, uint64_t pipe_id) : options_(options), @@ -420,24 +427,23 @@ DataPipeConsumerDispatcher::DataPipeConsumerDispatcher( control_port_(control_port), pipe_id_(pipe_id), watchers_(this), - shared_ring_buffer_(shared_ring_buffer) {} + shared_ring_buffer_(std::move(shared_ring_buffer)) {} DataPipeConsumerDispatcher::~DataPipeConsumerDispatcher() { - DCHECK(is_closed_ && !shared_ring_buffer_ && !ring_buffer_mapping_ && - !in_transit_); + DCHECK(is_closed_ && !shared_ring_buffer_.IsValid() && + !ring_buffer_mapping_.IsValid() && !in_transit_); } bool DataPipeConsumerDispatcher::InitializeNoLock() { lock_.AssertAcquired(); - if (!shared_ring_buffer_) + if (!shared_ring_buffer_.IsValid()) return false; - DCHECK(!ring_buffer_mapping_); - ring_buffer_mapping_ = - shared_ring_buffer_->Map(0, options_.capacity_num_bytes); - if (!ring_buffer_mapping_) { + DCHECK(!ring_buffer_mapping_.IsValid()); + ring_buffer_mapping_ = shared_ring_buffer_.Map(); + if (!ring_buffer_mapping_.IsValid()) { DLOG(ERROR) << "Failed to map shared buffer."; - shared_ring_buffer_ = nullptr; + shared_ring_buffer_ = base::UnsafeSharedMemoryRegion(); return false; } @@ -453,8 +459,8 @@ MojoResult DataPipeConsumerDispatcher::CloseNoLock() { if (is_closed_ || in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; is_closed_ = true; - ring_buffer_mapping_.reset(); - shared_ring_buffer_ = nullptr; + ring_buffer_mapping_ = base::WritableSharedMemoryMapping(); + shared_ring_buffer_ = base::UnsafeSharedMemoryRegion(); watchers_.NotifyClosed(); if (!transferred_) { @@ -470,18 +476,18 @@ HandleSignalsState DataPipeConsumerDispatcher::GetHandleSignalsStateNoLock() lock_.AssertAcquired(); HandleSignalsState rv; - if (shared_ring_buffer_ && bytes_available_) { + if (shared_ring_buffer_.IsValid() && bytes_available_) { if (!in_two_phase_read_) { rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_READABLE; if (new_data_available_) rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE; } rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE; - } else if (!peer_closed_ && shared_ring_buffer_) { + } else if (!peer_closed_ && shared_ring_buffer_.IsValid()) { rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE; } - if (shared_ring_buffer_) { + if (shared_ring_buffer_.IsValid()) { if (new_data_available_ || !peer_closed_) rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE; } diff --git a/chromium/mojo/edk/system/data_pipe_consumer_dispatcher.h b/chromium/mojo/edk/system/data_pipe_consumer_dispatcher.h index 15cce6d9286..48a63f1ba4a 100644 --- a/chromium/mojo/edk/system/data_pipe_consumer_dispatcher.h +++ b/chromium/mojo/edk/system/data_pipe_consumer_dispatcher.h @@ -12,8 +12,9 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/shared_memory_mapping.h" +#include "base/memory/unsafe_shared_memory_region.h" #include "base/synchronization/lock.h" -#include "mojo/edk/embedder/platform_shared_buffer.h" #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/dispatcher.h" #include "mojo/edk/system/ports/port_ref.h" @@ -34,19 +35,18 @@ class MOJO_SYSTEM_IMPL_EXPORT DataPipeConsumerDispatcher final static scoped_refptr<DataPipeConsumerDispatcher> Create( NodeController* node_controller, const ports::PortRef& control_port, - scoped_refptr<PlatformSharedBuffer> shared_ring_buffer, + base::UnsafeSharedMemoryRegion shared_ring_buffer, const MojoCreateDataPipeOptions& options, uint64_t pipe_id); // Dispatcher: Type GetType() const override; MojoResult Close() override; - MojoResult ReadData(void* elements, - uint32_t* num_bytes, - MojoReadDataFlags flags) override; + MojoResult ReadData(const MojoReadDataOptions& validated_options, + void* elements, + uint32_t* num_bytes) override; MojoResult BeginReadData(const void** buffer, - uint32_t* buffer_num_bytes, - MojoReadDataFlags flags) override; + uint32_t* buffer_num_bytes) override; MojoResult EndReadData(uint32_t num_bytes_read) override; HandleSignalsState GetHandleSignalsState() const override; MojoResult AddWatcherRef(const scoped_refptr<WatcherDispatcher>& watcher, @@ -58,7 +58,7 @@ class MOJO_SYSTEM_IMPL_EXPORT DataPipeConsumerDispatcher final uint32_t* num_handles) override; bool EndSerialize(void* destination, ports::PortName* ports, - ScopedPlatformHandle* handles) override; + ScopedInternalPlatformHandle* handles) override; bool BeginTransit() override; void CompleteTransitAndClose() override; void CancelTransit() override; @@ -68,19 +68,18 @@ class MOJO_SYSTEM_IMPL_EXPORT DataPipeConsumerDispatcher final size_t num_bytes, const ports::PortName* ports, size_t num_ports, - ScopedPlatformHandle* handles, + ScopedInternalPlatformHandle* handles, size_t num_handles); private: class PortObserverThunk; friend class PortObserverThunk; - DataPipeConsumerDispatcher( - NodeController* node_controller, - const ports::PortRef& control_port, - scoped_refptr<PlatformSharedBuffer> shared_ring_buffer, - const MojoCreateDataPipeOptions& options, - uint64_t pipe_id); + DataPipeConsumerDispatcher(NodeController* node_controller, + const ports::PortRef& control_port, + base::UnsafeSharedMemoryRegion shared_ring_buffer, + const MojoCreateDataPipeOptions& options, + uint64_t pipe_id); ~DataPipeConsumerDispatcher() override; bool InitializeNoLock(); @@ -100,8 +99,11 @@ class MOJO_SYSTEM_IMPL_EXPORT DataPipeConsumerDispatcher final WatcherSet watchers_; - scoped_refptr<PlatformSharedBuffer> shared_ring_buffer_; - std::unique_ptr<PlatformSharedBufferMapping> ring_buffer_mapping_; + base::UnsafeSharedMemoryRegion shared_ring_buffer_; + + // We don't really write to it, and it's safe because we're the only consumer + // of this buffer. + base::WritableSharedMemoryMapping ring_buffer_mapping_; bool in_two_phase_read_ = false; uint32_t two_phase_max_bytes_read_ = 0; diff --git a/chromium/mojo/edk/system/data_pipe_producer_dispatcher.cc b/chromium/mojo/edk/system/data_pipe_producer_dispatcher.cc index 987e4d61de2..caa76d959ef 100644 --- a/chromium/mojo/edk/system/data_pipe_producer_dispatcher.cc +++ b/chromium/mojo/edk/system/data_pipe_producer_dispatcher.cc @@ -12,8 +12,7 @@ #include "base/bind.h" #include "base/logging.h" #include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" -#include "mojo/edk/embedder/platform_shared_buffer.h" +#include "mojo/edk/embedder/platform_handle_utils.h" #include "mojo/edk/system/configuration.h" #include "mojo/edk/system/core.h" #include "mojo/edk/system/data_pipe_control_message.h" @@ -73,12 +72,13 @@ class DataPipeProducerDispatcher::PortObserverThunk scoped_refptr<DataPipeProducerDispatcher> DataPipeProducerDispatcher::Create( NodeController* node_controller, const ports::PortRef& control_port, - scoped_refptr<PlatformSharedBuffer> shared_ring_buffer, + base::UnsafeSharedMemoryRegion shared_ring_buffer, const MojoCreateDataPipeOptions& options, uint64_t pipe_id) { scoped_refptr<DataPipeProducerDispatcher> producer = new DataPipeProducerDispatcher(node_controller, control_port, - shared_ring_buffer, options, pipe_id); + std::move(shared_ring_buffer), options, + pipe_id); base::AutoLock lock(producer->lock_); if (!producer->InitializeNoLock()) return nullptr; @@ -95,11 +95,12 @@ MojoResult DataPipeProducerDispatcher::Close() { return CloseNoLock(); } -MojoResult DataPipeProducerDispatcher::WriteData(const void* elements, - uint32_t* num_bytes, - MojoWriteDataFlags flags) { +MojoResult DataPipeProducerDispatcher::WriteData( + const void* elements, + uint32_t* num_bytes, + const MojoWriteDataOptions& options) { base::AutoLock lock(lock_); - if (!shared_ring_buffer_ || in_transit_) + if (!shared_ring_buffer_.IsValid() || in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; if (in_two_phase_write_) @@ -113,7 +114,7 @@ MojoResult DataPipeProducerDispatcher::WriteData(const void* elements, if (*num_bytes == 0) return MOJO_RESULT_OK; // Nothing to do. - if ((flags & MOJO_WRITE_DATA_FLAG_ALL_OR_NONE) && + if ((options.flags & MOJO_WRITE_DATA_FLAG_ALL_OR_NONE) && (*num_bytes > available_capacity_)) { // Don't return "should wait" since you can't wait for a specified amount of // data. @@ -127,8 +128,8 @@ MojoResult DataPipeProducerDispatcher::WriteData(const void* elements, *num_bytes = num_bytes_to_write; - CHECK(ring_buffer_mapping_); - uint8_t* data = static_cast<uint8_t*>(ring_buffer_mapping_->GetBase()); + CHECK(ring_buffer_mapping_.IsValid()); + uint8_t* data = static_cast<uint8_t*>(ring_buffer_mapping_.memory()); CHECK(data); const uint8_t* source = static_cast<const uint8_t*>(elements); @@ -159,14 +160,9 @@ MojoResult DataPipeProducerDispatcher::WriteData(const void* elements, MojoResult DataPipeProducerDispatcher::BeginWriteData( void** buffer, - uint32_t* buffer_num_bytes, - MojoWriteDataFlags flags) { + uint32_t* buffer_num_bytes) { base::AutoLock lock(lock_); - if (!shared_ring_buffer_ || in_transit_) - return MOJO_RESULT_INVALID_ARGUMENT; - - // These flags may not be used in two-phase mode. - if (flags & MOJO_WRITE_DATA_FLAG_ALL_OR_NONE) + if (!shared_ring_buffer_.IsValid() || in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; if (in_two_phase_write_) @@ -184,8 +180,8 @@ MojoResult DataPipeProducerDispatcher::BeginWriteData( available_capacity_); DCHECK_GT(*buffer_num_bytes, 0u); - CHECK(ring_buffer_mapping_); - uint8_t* data = static_cast<uint8_t*>(ring_buffer_mapping_->GetBase()); + CHECK(ring_buffer_mapping_.IsValid()); + uint8_t* data = static_cast<uint8_t*>(ring_buffer_mapping_.memory()); *buffer = data + write_offset_; return MOJO_RESULT_OK; @@ -200,9 +196,6 @@ MojoResult DataPipeProducerDispatcher::EndWriteData( if (!in_two_phase_write_) return MOJO_RESULT_FAILED_PRECONDITION; - DCHECK(shared_ring_buffer_); - DCHECK(ring_buffer_mapping_); - // Note: Allow successful completion of the two-phase write even if the other // side has been closed. MojoResult rv = MOJO_RESULT_OK; @@ -265,7 +258,7 @@ void DataPipeProducerDispatcher::StartSerialize(uint32_t* num_bytes, bool DataPipeProducerDispatcher::EndSerialize( void* destination, ports::PortName* ports, - ScopedPlatformHandle* platform_handles) { + ScopedInternalPlatformHandle* platform_handles) { SerializedState* state = static_cast<SerializedState*>(destination); memcpy(&state->options, &options_, sizeof(MojoCreateDataPipeOptions)); memset(state->padding, 0, sizeof(state->padding)); @@ -277,14 +270,20 @@ bool DataPipeProducerDispatcher::EndSerialize( state->available_capacity = available_capacity_; state->flags = peer_closed_ ? kFlagPeerClosed : 0; - base::UnguessableToken guid = shared_ring_buffer_->GetGUID(); + auto region_handle = + base::UnsafeSharedMemoryRegion::TakeHandleForSerialization( + std::move(shared_ring_buffer_)); + const base::UnguessableToken& guid = region_handle.GetGUID(); state->buffer_guid_high = guid.GetHighForSerialization(); state->buffer_guid_low = guid.GetLowForSerialization(); ports[0] = control_port_.name(); - platform_handles[0] = shared_ring_buffer_->DuplicatePlatformHandle(); - if (!platform_handles[0].is_valid()) + ScopedInternalPlatformHandle ignored_handle; + ExtractInternalPlatformHandlesFromSharedMemoryRegionHandle( + region_handle.PassPlatformHandle(), &platform_handles[0], + &ignored_handle); + if (!platform_handles[0].is_valid() || ignored_handle.is_valid()) return false; return true; @@ -323,7 +322,7 @@ DataPipeProducerDispatcher::Deserialize(const void* data, size_t num_bytes, const ports::PortName* ports, size_t num_ports, - ScopedPlatformHandle* handles, + ScopedInternalPlatformHandle* handles, size_t num_handles) { if (num_ports != 1 || num_handles != 1 || num_bytes != sizeof(SerializedState)) { @@ -341,22 +340,28 @@ DataPipeProducerDispatcher::Deserialize(const void* data, if (node_controller->node()->GetPort(ports[0], &port) != ports::OK) return nullptr; - base::UnguessableToken guid = base::UnguessableToken::Deserialize( - state->buffer_guid_high, state->buffer_guid_low); - ScopedPlatformHandle buffer_handle; + ScopedInternalPlatformHandle buffer_handle; std::swap(buffer_handle, handles[0]); - scoped_refptr<PlatformSharedBuffer> ring_buffer = - PlatformSharedBuffer::CreateFromPlatformHandle( - state->options.capacity_num_bytes, false /* read_only */, guid, - std::move(buffer_handle)); - if (!ring_buffer) { + auto region_handle = + CreateSharedMemoryRegionHandleFromInternalPlatformHandles( + std::move(buffer_handle), ScopedInternalPlatformHandle()); + auto region = base::subtle::PlatformSharedMemoryRegion::Take( + std::move(region_handle), + base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe, + state->options.capacity_num_bytes, + base::UnguessableToken::Deserialize(state->buffer_guid_high, + state->buffer_guid_low)); + auto ring_buffer = + base::UnsafeSharedMemoryRegion::Deserialize(std::move(region)); + if (!ring_buffer.IsValid()) { DLOG(ERROR) << "Failed to deserialize shared buffer handle."; return nullptr; } scoped_refptr<DataPipeProducerDispatcher> dispatcher = - new DataPipeProducerDispatcher(node_controller, port, ring_buffer, - state->options, state->pipe_id); + new DataPipeProducerDispatcher(node_controller, port, + std::move(ring_buffer), state->options, + state->pipe_id); { base::AutoLock lock(dispatcher->lock_); @@ -374,7 +379,7 @@ DataPipeProducerDispatcher::Deserialize(const void* data, DataPipeProducerDispatcher::DataPipeProducerDispatcher( NodeController* node_controller, const ports::PortRef& control_port, - scoped_refptr<PlatformSharedBuffer> shared_ring_buffer, + base::UnsafeSharedMemoryRegion shared_ring_buffer, const MojoCreateDataPipeOptions& options, uint64_t pipe_id) : options_(options), @@ -382,25 +387,24 @@ DataPipeProducerDispatcher::DataPipeProducerDispatcher( control_port_(control_port), pipe_id_(pipe_id), watchers_(this), - shared_ring_buffer_(shared_ring_buffer), + shared_ring_buffer_(std::move(shared_ring_buffer)), available_capacity_(options_.capacity_num_bytes) {} DataPipeProducerDispatcher::~DataPipeProducerDispatcher() { - DCHECK(is_closed_ && !in_transit_ && !shared_ring_buffer_ && - !ring_buffer_mapping_); + DCHECK(is_closed_ && !in_transit_ && !shared_ring_buffer_.IsValid() && + !ring_buffer_mapping_.IsValid()); } bool DataPipeProducerDispatcher::InitializeNoLock() { lock_.AssertAcquired(); - if (!shared_ring_buffer_) + if (!shared_ring_buffer_.IsValid()) return false; - DCHECK(!ring_buffer_mapping_); - ring_buffer_mapping_ = - shared_ring_buffer_->Map(0, options_.capacity_num_bytes); - if (!ring_buffer_mapping_) { + DCHECK(!ring_buffer_mapping_.IsValid()); + ring_buffer_mapping_ = shared_ring_buffer_.Map(); + if (!ring_buffer_mapping_.IsValid()) { DLOG(ERROR) << "Failed to map shared buffer."; - shared_ring_buffer_ = nullptr; + shared_ring_buffer_ = base::UnsafeSharedMemoryRegion(); return false; } @@ -416,8 +420,8 @@ MojoResult DataPipeProducerDispatcher::CloseNoLock() { if (is_closed_ || in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; is_closed_ = true; - ring_buffer_mapping_.reset(); - shared_ring_buffer_ = nullptr; + ring_buffer_mapping_ = base::WritableSharedMemoryMapping(); + shared_ring_buffer_ = base::UnsafeSharedMemoryRegion(); watchers_.NotifyClosed(); if (!transferred_) { @@ -433,7 +437,8 @@ HandleSignalsState DataPipeProducerDispatcher::GetHandleSignalsStateNoLock() lock_.AssertAcquired(); HandleSignalsState rv; if (!peer_closed_) { - if (!in_two_phase_write_ && shared_ring_buffer_ && available_capacity_ > 0) + if (!in_two_phase_write_ && shared_ring_buffer_.IsValid() && + available_capacity_ > 0) rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_WRITABLE; if (peer_remote_) rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_REMOTE; diff --git a/chromium/mojo/edk/system/data_pipe_producer_dispatcher.h b/chromium/mojo/edk/system/data_pipe_producer_dispatcher.h index 735d72a2261..4ee72c8e426 100644 --- a/chromium/mojo/edk/system/data_pipe_producer_dispatcher.h +++ b/chromium/mojo/edk/system/data_pipe_producer_dispatcher.h @@ -12,8 +12,9 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/shared_memory_mapping.h" +#include "base/memory/unsafe_shared_memory_region.h" #include "base/synchronization/lock.h" -#include "mojo/edk/embedder/platform_shared_buffer.h" #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/dispatcher.h" #include "mojo/edk/system/ports/port_ref.h" @@ -34,7 +35,7 @@ class MOJO_SYSTEM_IMPL_EXPORT DataPipeProducerDispatcher final static scoped_refptr<DataPipeProducerDispatcher> Create( NodeController* node_controller, const ports::PortRef& control_port, - scoped_refptr<PlatformSharedBuffer> shared_ring_buffer, + base::UnsafeSharedMemoryRegion shared_ring_buffer, const MojoCreateDataPipeOptions& options, uint64_t pipe_id); @@ -43,10 +44,8 @@ class MOJO_SYSTEM_IMPL_EXPORT DataPipeProducerDispatcher final MojoResult Close() override; MojoResult WriteData(const void* elements, uint32_t* num_bytes, - MojoReadDataFlags flags) override; - MojoResult BeginWriteData(void** buffer, - uint32_t* buffer_num_bytes, - MojoWriteDataFlags flags) override; + const MojoWriteDataOptions& options) override; + MojoResult BeginWriteData(void** buffer, uint32_t* buffer_num_bytes) override; MojoResult EndWriteData(uint32_t num_bytes_written) override; HandleSignalsState GetHandleSignalsState() const override; MojoResult AddWatcherRef(const scoped_refptr<WatcherDispatcher>& watcher, @@ -58,7 +57,7 @@ class MOJO_SYSTEM_IMPL_EXPORT DataPipeProducerDispatcher final uint32_t* num_handles) override; bool EndSerialize(void* destination, ports::PortName* ports, - ScopedPlatformHandle* handles) override; + ScopedInternalPlatformHandle* handles) override; bool BeginTransit() override; void CompleteTransitAndClose() override; void CancelTransit() override; @@ -68,22 +67,20 @@ class MOJO_SYSTEM_IMPL_EXPORT DataPipeProducerDispatcher final size_t num_bytes, const ports::PortName* ports, size_t num_ports, - ScopedPlatformHandle* handles, + ScopedInternalPlatformHandle* handles, size_t num_handles); private: class PortObserverThunk; friend class PortObserverThunk; - DataPipeProducerDispatcher( - NodeController* node_controller, - const ports::PortRef& port, - scoped_refptr<PlatformSharedBuffer> shared_ring_buffer, - const MojoCreateDataPipeOptions& options, - uint64_t pipe_id); + DataPipeProducerDispatcher(NodeController* node_controller, + const ports::PortRef& port, + base::UnsafeSharedMemoryRegion shared_ring_buffer, + const MojoCreateDataPipeOptions& options, + uint64_t pipe_id); ~DataPipeProducerDispatcher() override; - void OnSharedBufferCreated(const scoped_refptr<PlatformSharedBuffer>& buffer); bool InitializeNoLock(); MojoResult CloseNoLock(); HandleSignalsState GetHandleSignalsStateNoLock() const; @@ -101,10 +98,8 @@ class MOJO_SYSTEM_IMPL_EXPORT DataPipeProducerDispatcher final WatcherSet watchers_; - bool buffer_requested_ = false; - - scoped_refptr<PlatformSharedBuffer> shared_ring_buffer_; - std::unique_ptr<PlatformSharedBufferMapping> ring_buffer_mapping_; + base::UnsafeSharedMemoryRegion shared_ring_buffer_; + base::WritableSharedMemoryMapping ring_buffer_mapping_; bool in_transit_ = false; bool is_closed_ = false; diff --git a/chromium/mojo/edk/system/data_pipe_unittest.cc b/chromium/mojo/edk/system/data_pipe_unittest.cc index a8a65f85791..dbee3ed8b45 100644 --- a/chromium/mojo/edk/system/data_pipe_unittest.cc +++ b/chromium/mojo/edk/system/data_pipe_unittest.cc @@ -80,9 +80,11 @@ class DataPipeTest : public test::MojoTestBase { MojoResult WriteData(const void* elements, uint32_t* num_bytes, bool all_or_none = false) { - return MojoWriteData(producer_, elements, num_bytes, - all_or_none ? MOJO_WRITE_DATA_FLAG_ALL_OR_NONE - : MOJO_WRITE_DATA_FLAG_NONE); + MojoWriteDataOptions options; + options.struct_size = sizeof(options); + options.flags = all_or_none ? MOJO_WRITE_DATA_FLAG_ALL_OR_NONE + : MOJO_WRITE_DATA_FLAG_NONE; + return MojoWriteData(producer_, elements, num_bytes, &options); } MojoResult ReadData(void* elements, @@ -94,41 +96,44 @@ class DataPipeTest : public test::MojoTestBase { flags |= MOJO_READ_DATA_FLAG_ALL_OR_NONE; if (peek) flags |= MOJO_READ_DATA_FLAG_PEEK; - return MojoReadData(consumer_, elements, num_bytes, flags); + + MojoReadDataOptions options; + options.struct_size = sizeof(options); + options.flags = flags; + return MojoReadData(consumer_, &options, elements, num_bytes); } MojoResult QueryData(uint32_t* num_bytes) { - return MojoReadData(consumer_, nullptr, num_bytes, - MOJO_READ_DATA_FLAG_QUERY); + MojoReadDataOptions options; + options.struct_size = sizeof(options); + options.flags = MOJO_READ_DATA_FLAG_QUERY; + return MojoReadData(consumer_, &options, nullptr, num_bytes); } MojoResult DiscardData(uint32_t* num_bytes, bool all_or_none = false) { MojoReadDataFlags flags = MOJO_READ_DATA_FLAG_DISCARD; if (all_or_none) flags |= MOJO_READ_DATA_FLAG_ALL_OR_NONE; - return MojoReadData(consumer_, nullptr, num_bytes, flags); + MojoReadDataOptions options; + options.struct_size = sizeof(options); + options.flags = flags; + return MojoReadData(consumer_, &options, nullptr, num_bytes); } MojoResult BeginReadData(const void** elements, uint32_t* num_bytes) { - return MojoBeginReadData(consumer_, elements, num_bytes, - MOJO_READ_DATA_FLAG_NONE); + return MojoBeginReadData(consumer_, nullptr, elements, num_bytes); } MojoResult EndReadData(uint32_t num_bytes_read) { - return MojoEndReadData(consumer_, num_bytes_read); + return MojoEndReadData(consumer_, num_bytes_read, nullptr); } - MojoResult BeginWriteData(void** elements, - uint32_t* num_bytes, - bool all_or_none = false) { - MojoReadDataFlags flags = MOJO_WRITE_DATA_FLAG_NONE; - if (all_or_none) - flags |= MOJO_WRITE_DATA_FLAG_ALL_OR_NONE; - return MojoBeginWriteData(producer_, elements, num_bytes, flags); + MojoResult BeginWriteData(void** elements, uint32_t* num_bytes) { + return MojoBeginWriteData(producer_, nullptr, elements, num_bytes); } MojoResult EndWriteData(uint32_t num_bytes_written) { - return MojoEndWriteData(producer_, num_bytes_written); + return MojoEndWriteData(producer_, num_bytes_written, nullptr); } MojoResult CloseProducer() { @@ -151,10 +156,10 @@ class DataPipeTest : public test::MojoTestBase { TEST_F(DataPipeTest, Basic) { const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 1000 * sizeof(int32_t) // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 1000 * sizeof(int32_t) // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); @@ -191,20 +196,20 @@ TEST_F(DataPipeTest, CreateAndMaybeTransfer) { // Default options. {}, // Trivial element size, non-default capacity. - {kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 1, // |element_num_bytes|. - 1000}, // |capacity_num_bytes|. + {kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + 1, // |element_num_bytes|. + 1000}, // |capacity_num_bytes|. // Nontrivial element size, non-default capacity. - {kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 4, // |element_num_bytes|. - 4000}, // |capacity_num_bytes|. + {kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + 4, // |element_num_bytes|. + 4000}, // |capacity_num_bytes|. // Nontrivial element size, default capacity. - {kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 100, // |element_num_bytes|. - 0} // |capacity_num_bytes|. + {kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + 100, // |element_num_bytes|. + 0} // |capacity_num_bytes|. }; for (size_t i = 0; i < arraysize(test_options); i++) { MojoHandle producer_handle, consumer_handle; @@ -218,10 +223,10 @@ TEST_F(DataPipeTest, CreateAndMaybeTransfer) { TEST_F(DataPipeTest, SimpleReadWrite) { const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 1000 * sizeof(int32_t) // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 1000 * sizeof(int32_t) // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); @@ -337,10 +342,10 @@ TEST_F(DataPipeTest, BasicProducerWaiting) { // the API. const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 2 * sizeof(int32_t) // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 2 * sizeof(int32_t) // |capacity_num_bytes|. }; Create(&options); MojoHandleSignalsState hss; @@ -427,10 +432,10 @@ TEST_F(DataPipeTest, BasicProducerWaiting) { TEST_F(DataPipeTest, PeerClosedProducerWaiting) { const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 2 * sizeof(int32_t) // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 2 * sizeof(int32_t) // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); MojoHandleSignalsState hss; @@ -448,10 +453,10 @@ TEST_F(DataPipeTest, PeerClosedProducerWaiting) { TEST_F(DataPipeTest, PeerClosedConsumerWaiting) { const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 2 * sizeof(int32_t) // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 2 * sizeof(int32_t) // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); MojoHandleSignalsState hss; @@ -469,10 +474,10 @@ TEST_F(DataPipeTest, PeerClosedConsumerWaiting) { TEST_F(DataPipeTest, BasicConsumerWaiting) { const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 1000 * sizeof(int32_t) // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 1000 * sizeof(int32_t) // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); MojoHandleSignalsState hss; @@ -604,13 +609,13 @@ TEST_F(DataPipeTest, BasicConsumerWaiting) { } TEST_F(DataPipeTest, ConsumerNewDataReadable) { - const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 1000 * sizeof(int32_t) // |capacity_num_bytes|. + const MojoCreateDataPipeOptions create_options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 1000 * sizeof(int32_t) // |capacity_num_bytes|. }; - EXPECT_EQ(MOJO_RESULT_OK, Create(&options)); + EXPECT_EQ(MOJO_RESULT_OK, Create(&create_options)); int32_t elements[2] = {123, 456}; uint32_t num_bytes = static_cast<uint32_t>(2u * sizeof(elements[0])); @@ -625,9 +630,12 @@ TEST_F(DataPipeTest, ConsumerNewDataReadable) { // Now try to read a minimum of 6 elements. int32_t read_elements[6]; uint32_t num_read_bytes = sizeof(read_elements); - EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - MojoReadData(consumer_, read_elements, &num_read_bytes, - MOJO_READ_DATA_FLAG_ALL_OR_NONE)); + MojoReadDataOptions read_options; + read_options.struct_size = sizeof(read_options); + read_options.flags = MOJO_READ_DATA_FLAG_ALL_OR_NONE; + EXPECT_EQ( + MOJO_RESULT_OUT_OF_RANGE, + MojoReadData(consumer_, &read_options, read_elements, &num_read_bytes)); // The consumer should still appear to be readable but not with new data. EXPECT_TRUE(GetSignalsState(consumer_).satisfied_signals & @@ -644,9 +652,8 @@ TEST_F(DataPipeTest, ConsumerNewDataReadable) { WaitForSignals(consumer_, MOJO_HANDLE_SIGNAL_READABLE)); // Try again to read a minimum of 6 elements. Should succeed this time. - EXPECT_EQ(MOJO_RESULT_OK, - MojoReadData(consumer_, read_elements, &num_read_bytes, - MOJO_READ_DATA_FLAG_ALL_OR_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoReadData(consumer_, &read_options, + read_elements, &num_read_bytes)); // And now the consumer is unreadable. EXPECT_FALSE(GetSignalsState(consumer_).satisfied_signals & @@ -659,10 +666,10 @@ TEST_F(DataPipeTest, ConsumerNewDataReadable) { // consumer waiter. TEST_F(DataPipeTest, ConsumerWaitingTwoPhase) { const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 1000 * sizeof(int32_t) // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 1000 * sizeof(int32_t) // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); MojoHandleSignalsState hss; @@ -672,7 +679,7 @@ TEST_F(DataPipeTest, ConsumerWaitingTwoPhase) { void* buffer = nullptr; // Request room for three (but we'll only write two). uint32_t num_bytes = static_cast<uint32_t>(3u * sizeof(elements[0])); - ASSERT_EQ(MOJO_RESULT_OK, BeginWriteData(&buffer, &num_bytes, false)); + ASSERT_EQ(MOJO_RESULT_OK, BeginWriteData(&buffer, &num_bytes)); EXPECT_TRUE(buffer); EXPECT_GE(num_bytes, static_cast<uint32_t>(3u * sizeof(elements[0]))); elements = static_cast<int32_t*>(buffer); @@ -736,10 +743,10 @@ TEST_F(DataPipeTest, ConsumerWaitingTwoPhase) { // Tests that data pipes aren't writable/readable during two-phase writes/reads. TEST_F(DataPipeTest, BasicTwoPhaseWaiting) { const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 1000 * sizeof(int32_t) // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 1000 * sizeof(int32_t) // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); MojoHandleSignalsState hss; @@ -856,10 +863,10 @@ void Seq(int32_t start, size_t count, int32_t* out) { TEST_F(DataPipeTest, AllOrNone) { const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 10 * sizeof(int32_t) // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 10 * sizeof(int32_t) // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); MojoHandleSignalsState hss; @@ -1026,10 +1033,10 @@ TEST_F(DataPipeTest, WrapAround) { test_data[i] = static_cast<unsigned char>(i); const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 1u, // |element_num_bytes|. - 100u // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + 1u, // |element_num_bytes|. + 100u // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); @@ -1060,8 +1067,7 @@ TEST_F(DataPipeTest, WrapAround) { // checks an implementation detail; this behavior is not guaranteed.) void* write_buffer_ptr = nullptr; num_bytes = 0u; - ASSERT_EQ(MOJO_RESULT_OK, - BeginWriteData(&write_buffer_ptr, &num_bytes, false)); + ASSERT_EQ(MOJO_RESULT_OK, BeginWriteData(&write_buffer_ptr, &num_bytes)); EXPECT_TRUE(write_buffer_ptr); ASSERT_EQ(80u, num_bytes); ASSERT_EQ(MOJO_RESULT_OK, EndWriteData(0)); @@ -1114,10 +1120,10 @@ TEST_F(DataPipeTest, WriteCloseProducerRead) { const uint32_t kTestDataSize = static_cast<uint32_t>(sizeof(kTestData)); const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 1u, // |element_num_bytes|. - 1000u // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + 1u, // |element_num_bytes|. + 1000u // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); @@ -1134,8 +1140,7 @@ TEST_F(DataPipeTest, WriteCloseProducerRead) { // Start two-phase write. void* write_buffer_ptr = nullptr; num_bytes = 0u; - ASSERT_EQ(MOJO_RESULT_OK, - BeginWriteData(&write_buffer_ptr, &num_bytes, false)); + ASSERT_EQ(MOJO_RESULT_OK, BeginWriteData(&write_buffer_ptr, &num_bytes)); EXPECT_TRUE(write_buffer_ptr); EXPECT_GT(num_bytes, 0u); @@ -1179,10 +1184,10 @@ TEST_F(DataPipeTest, TwoPhaseWriteReadCloseConsumer) { const uint32_t kTestDataSize = static_cast<uint32_t>(sizeof(kTestData)); const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 1u, // |element_num_bytes|. - 1000u // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + 1u, // |element_num_bytes|. + 1000u // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); MojoHandleSignalsState hss; @@ -1252,10 +1257,10 @@ TEST_F(DataPipeTest, TwoPhaseWriteCloseBoth) { const uint32_t kTestDataSize = 15u; const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 1u, // |element_num_bytes|. - 1000u // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + 1u, // |element_num_bytes|. + 1000u // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); @@ -1274,10 +1279,10 @@ TEST_F(DataPipeTest, WriteCloseProducerReadNoData) { const uint32_t kTestDataSize = static_cast<uint32_t>(sizeof(kTestData)); const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 1u, // |element_num_bytes|. - 1000u // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + 1u, // |element_num_bytes|. + 1000u // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); MojoHandleSignalsState hss; @@ -1338,10 +1343,10 @@ TEST_F(DataPipeTest, TwoPhaseReadMemoryStable) { const uint32_t kTestDataSize = static_cast<uint32_t>(sizeof(kTestData)); const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 1u, // |element_num_bytes|. - 1000u // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + 1u, // |element_num_bytes|. + 1000u // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); MojoHandleSignalsState hss; @@ -1396,10 +1401,10 @@ TEST_F(DataPipeTest, TwoPhaseReadMemoryStable) { // arguments. TEST_F(DataPipeTest, TwoPhaseMoreInvalidArguments) { const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 10 * sizeof(int32_t) // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 10 * sizeof(int32_t) // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); MojoHandleSignalsState hss; @@ -1522,10 +1527,10 @@ TEST_F(DataPipeTest, SendProducer) { const uint32_t kTestDataSize = static_cast<uint32_t>(sizeof(kTestData)); const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 1u, // |element_num_bytes|. - 1000u // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + 1u, // |element_num_bytes|. + 1000u // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); MojoHandleSignalsState hss; @@ -1598,10 +1603,10 @@ TEST_F(DataPipeTest, SendProducer) { // peer. TEST_F(DataPipeTest, ConsumerWithClosedProducerSent) { const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. - 1000 * sizeof(int32_t) // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 1000 * sizeof(int32_t) // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); @@ -1659,8 +1664,8 @@ bool WriteAllData(MojoHandle producer, for (size_t i = 0; i < kMaxPoll; i++) { // Write as much data as we can. uint32_t write_bytes = num_bytes; - MojoResult result = MojoWriteData(producer, elements, &write_bytes, - MOJO_WRITE_DATA_FLAG_NONE); + MojoResult result = + MojoWriteData(producer, elements, &write_bytes, nullptr); if (result == MOJO_RESULT_OK) { num_bytes -= write_bytes; elements = static_cast<const uint8_t*>(elements) + write_bytes; @@ -1690,8 +1695,7 @@ bool ReadAllData(MojoHandle consumer, for (size_t i = 0; i < kMaxPoll; i++) { // Read as much data as we can. uint32_t read_bytes = num_bytes; - MojoResult result = - MojoReadData(consumer, elements, &read_bytes, MOJO_READ_DATA_FLAG_NONE); + MojoResult result = MojoReadData(consumer, nullptr, elements, &read_bytes); if (result == MOJO_RESULT_OK) { num_bytes -= read_bytes; elements = static_cast<uint8_t*>(elements) + read_bytes; @@ -1699,8 +1703,10 @@ bool ReadAllData(MojoHandle consumer, if (expect_empty) { // Expect no more data. test::Sleep(test::TinyDeadline()); - MojoReadData(consumer, nullptr, &num_bytes, - MOJO_READ_DATA_FLAG_QUERY); + MojoReadDataOptions options; + options.struct_size = sizeof(options); + options.flags = MOJO_READ_DATA_FLAG_QUERY; + MojoReadData(consumer, &options, nullptr, &num_bytes); EXPECT_EQ(0u, num_bytes); } return true; @@ -1727,10 +1733,10 @@ TEST_F(DataPipeTest, Multiprocess) { const uint32_t kTestDataSize = static_cast<uint32_t>(sizeof(kMultiprocessTestData)); const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 1, // |element_num_bytes|. - kMultiprocessCapacity // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + 1, // |element_num_bytes|. + kMultiprocessCapacity // |capacity_num_bytes|. }; ASSERT_EQ(MOJO_RESULT_OK, Create(&options)); @@ -1848,8 +1854,8 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(WriteAndCloseProducer, DataPipeTest, h) { // Write some data to the producer and close it. uint32_t num_bytes = static_cast<uint32_t>(message.size()); - EXPECT_EQ(MOJO_RESULT_OK, MojoWriteData(p, message.data(), &num_bytes, - MOJO_WRITE_DATA_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWriteData(p, message.data(), &num_bytes, nullptr)); EXPECT_EQ(num_bytes, static_cast<uint32_t>(message.size())); // Close the producer before quitting. @@ -1869,8 +1875,7 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadAndCloseConsumer, DataPipeTest, h) { // Drain the consumer and expect to find the given message. uint32_t num_bytes = static_cast<uint32_t>(expected_message.size()); std::vector<char> bytes(expected_message.size()); - EXPECT_EQ(MOJO_RESULT_OK, MojoReadData(c, bytes.data(), &num_bytes, - MOJO_READ_DATA_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoReadData(c, nullptr, bytes.data(), &num_bytes)); EXPECT_EQ(num_bytes, static_cast<uint32_t>(bytes.size())); std::string message(bytes.data(), bytes.size()); @@ -1902,10 +1907,10 @@ TEST_F(DataPipeTest, SendConsumerAndCloseProducer) { DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndWrite, DataPipeTest, h) { const MojoCreateDataPipeOptions options = { - kSizeOfOptions, // |struct_size|. - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. - 1, // |element_num_bytes|. - kMultiprocessCapacity // |capacity_num_bytes|. + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|. + 1, // |element_num_bytes|. + kMultiprocessCapacity // |capacity_num_bytes|. }; MojoHandle p, c; @@ -1916,8 +1921,8 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateAndWrite, DataPipeTest, h) { // Write some data to the producer and close it. uint32_t num_bytes = static_cast<uint32_t>(kMessage.size()); - EXPECT_EQ(MOJO_RESULT_OK, MojoWriteData(p, kMessage.data(), &num_bytes, - MOJO_WRITE_DATA_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoWriteData(p, kMessage.data(), &num_bytes, nullptr)); EXPECT_EQ(num_bytes, static_cast<uint32_t>(kMessage.size())); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(p)); @@ -1936,8 +1941,8 @@ TEST_F(DataPipeTest, CreateInChild) { // Drain the consumer and expect to find the given message. uint32_t num_bytes = static_cast<uint32_t>(expected_message.size()); std::vector<char> bytes(expected_message.size()); - EXPECT_EQ(MOJO_RESULT_OK, MojoReadData(c, bytes.data(), &num_bytes, - MOJO_READ_DATA_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, + MojoReadData(c, nullptr, bytes.data(), &num_bytes)); EXPECT_EQ(num_bytes, static_cast<uint32_t>(bytes.size())); std::string message(bytes.data(), bytes.size()); @@ -1998,8 +2003,7 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(DataPipeStatusChangeInTransitClient, MojoResult result; do { uint32_t num_bytes = 0; - result = MojoWriteData(producers[2], nullptr, &num_bytes, - MOJO_WRITE_DATA_FLAG_NONE); + result = MojoWriteData(producers[2], nullptr, &num_bytes, nullptr); } while (result == MOJO_RESULT_OK); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); @@ -2007,8 +2011,7 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(DataPipeStatusChangeInTransitClient, do { char byte; uint32_t num_bytes = 1; - result = - MojoReadData(consumers[2], &byte, &num_bytes, MOJO_READ_DATA_FLAG_NONE); + result = MojoReadData(consumers[2], nullptr, &byte, &num_bytes); } while (result == MOJO_RESULT_SHOULD_WAIT); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); diff --git a/chromium/mojo/edk/system/dispatcher.cc b/chromium/mojo/edk/system/dispatcher.cc index e736276dfd3..6d9f875a1c0 100644 --- a/chromium/mojo/edk/system/dispatcher.cc +++ b/chromium/mojo/edk/system/dispatcher.cc @@ -42,8 +42,7 @@ MojoResult Dispatcher::Arm(uint32_t* num_ready_contexts, } MojoResult Dispatcher::WriteMessage( - std::unique_ptr<ports::UserMessageEvent> message, - MojoWriteMessageFlags flags) { + std::unique_ptr<ports::UserMessageEvent> message) { return MOJO_RESULT_INVALID_ARGUMENT; } @@ -61,8 +60,7 @@ MojoResult Dispatcher::DuplicateBufferHandle( MojoResult Dispatcher::MapBuffer( uint64_t offset, uint64_t num_bytes, - MojoMapBufferFlags flags, - std::unique_ptr<PlatformSharedBufferMapping>* mapping) { + std::unique_ptr<PlatformSharedMemoryMapping>* mapping) { return MOJO_RESULT_INVALID_ARGUMENT; } @@ -70,15 +68,14 @@ MojoResult Dispatcher::GetBufferInfo(MojoSharedBufferInfo* info) { return MOJO_RESULT_INVALID_ARGUMENT; } -MojoResult Dispatcher::ReadData(void* elements, - uint32_t* num_bytes, - MojoReadDataFlags flags) { +MojoResult Dispatcher::ReadData(const MojoReadDataOptions& options, + void* elements, + uint32_t* num_bytes) { return MOJO_RESULT_INVALID_ARGUMENT; } MojoResult Dispatcher::BeginReadData(const void** buffer, - uint32_t* buffer_num_bytes, - MojoReadDataFlags flags) { + uint32_t* buffer_num_bytes) { return MOJO_RESULT_INVALID_ARGUMENT; } @@ -88,13 +85,12 @@ MojoResult Dispatcher::EndReadData(uint32_t num_bytes_read) { MojoResult Dispatcher::WriteData(const void* elements, uint32_t* num_bytes, - MojoWriteDataFlags flags) { + const MojoWriteDataOptions& options) { return MOJO_RESULT_INVALID_ARGUMENT; } MojoResult Dispatcher::BeginWriteData(void** buffer, - uint32_t* buffer_num_bytes, - MojoWriteDataFlags flags) { + uint32_t* buffer_num_bytes) { return MOJO_RESULT_INVALID_ARGUMENT; } @@ -102,22 +98,13 @@ MojoResult Dispatcher::EndWriteData(uint32_t num_bytes_written) { return MOJO_RESULT_INVALID_ARGUMENT; } -MojoResult Dispatcher::AddWaitingDispatcher( - const scoped_refptr<Dispatcher>& dispatcher, - MojoHandleSignals signals, - uintptr_t context) { - return MOJO_RESULT_INVALID_ARGUMENT; -} - -MojoResult Dispatcher::RemoveWaitingDispatcher( - const scoped_refptr<Dispatcher>& dispatcher) { +MojoResult Dispatcher::AttachMessagePipe(base::StringPiece name, + ports::PortRef remote_peer_port) { return MOJO_RESULT_INVALID_ARGUMENT; } -MojoResult Dispatcher::GetReadyDispatchers(uint32_t* count, - DispatcherVector* dispatchers, - MojoResult* results, - uintptr_t* contexts) { +MojoResult Dispatcher::ExtractMessagePipe(base::StringPiece name, + MojoHandle* message_pipe_handle) { return MOJO_RESULT_INVALID_ARGUMENT; } @@ -146,7 +133,7 @@ void Dispatcher::StartSerialize(uint32_t* num_bytes, bool Dispatcher::EndSerialize(void* destination, ports::PortName* ports, - ScopedPlatformHandle* handles) { + ScopedInternalPlatformHandle* handles) { LOG(ERROR) << "Attempting to serialize a non-transferrable dispatcher."; return true; } @@ -166,7 +153,7 @@ scoped_refptr<Dispatcher> Dispatcher::Deserialize( size_t num_bytes, const ports::PortName* ports, size_t num_ports, - ScopedPlatformHandle* platform_handles, + ScopedInternalPlatformHandle* platform_handles, size_t num_platform_handles) { switch (type) { case Type::MESSAGE_PIPE: diff --git a/chromium/mojo/edk/system/dispatcher.h b/chromium/mojo/edk/system/dispatcher.h index 3e13c1bd143..3776be2e812 100644 --- a/chromium/mojo/edk/system/dispatcher.h +++ b/chromium/mojo/edk/system/dispatcher.h @@ -14,12 +14,13 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/strings/string_piece.h" #include "base/synchronization/lock.h" #include "mojo/edk/embedder/platform_handle.h" -#include "mojo/edk/embedder/platform_shared_buffer.h" #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/handle_signals_state.h" #include "mojo/edk/system/ports/name.h" +#include "mojo/edk/system/ports/port_ref.h" #include "mojo/edk/system/system_impl_export.h" #include "mojo/edk/system/watch.h" #include "mojo/public/c/system/buffer.h" @@ -36,6 +37,7 @@ class UserMessageEvent; } class Dispatcher; +class PlatformSharedMemoryMapping; using DispatcherVector = std::vector<scoped_refptr<Dispatcher>>; @@ -60,6 +62,7 @@ class MOJO_SYSTEM_IMPL_EXPORT Dispatcher DATA_PIPE_CONSUMER, SHARED_BUFFER, WATCHER, + INVITATION, // "Private" types (not exposed via the public interface): PLATFORM_HANDLE = -1, @@ -85,8 +88,7 @@ class MOJO_SYSTEM_IMPL_EXPORT Dispatcher ///////////// Message pipe API ///////////// virtual MojoResult WriteMessage( - std::unique_ptr<ports::UserMessageEvent> message, - MojoWriteMessageFlags flags); + std::unique_ptr<ports::UserMessageEvent> message); virtual MojoResult ReadMessage( std::unique_ptr<ports::UserMessageEvent>* message); @@ -103,20 +105,18 @@ class MOJO_SYSTEM_IMPL_EXPORT Dispatcher virtual MojoResult MapBuffer( uint64_t offset, uint64_t num_bytes, - MojoMapBufferFlags flags, - std::unique_ptr<PlatformSharedBufferMapping>* mapping); + std::unique_ptr<PlatformSharedMemoryMapping>* mapping); virtual MojoResult GetBufferInfo(MojoSharedBufferInfo* info); ///////////// Data pipe consumer API ///////////// - virtual MojoResult ReadData(void* elements, - uint32_t* num_bytes, - MojoReadDataFlags flags); + virtual MojoResult ReadData(const MojoReadDataOptions& options, + void* elements, + uint32_t* num_bytes); virtual MojoResult BeginReadData(const void** buffer, - uint32_t* buffer_num_bytes, - MojoReadDataFlags flags); + uint32_t* buffer_num_bytes); virtual MojoResult EndReadData(uint32_t num_bytes_read); @@ -124,37 +124,17 @@ class MOJO_SYSTEM_IMPL_EXPORT Dispatcher virtual MojoResult WriteData(const void* elements, uint32_t* num_bytes, - MojoWriteDataFlags flags); + const MojoWriteDataOptions& options); - virtual MojoResult BeginWriteData(void** buffer, - uint32_t* buffer_num_bytes, - MojoWriteDataFlags flags); + virtual MojoResult BeginWriteData(void** buffer, uint32_t* buffer_num_bytes); virtual MojoResult EndWriteData(uint32_t num_bytes_written); - ///////////// Wait set API ///////////// - - // Adds a dispatcher to wait on. When the dispatcher satisfies |signals|, it - // will be returned in the next call to |GetReadyDispatchers()|. If - // |dispatcher| has been added, it must be removed before adding again, - // otherwise |MOJO_RESULT_ALREADY_EXISTS| will be returned. - virtual MojoResult AddWaitingDispatcher( - const scoped_refptr<Dispatcher>& dispatcher, - MojoHandleSignals signals, - uintptr_t context); - - // Removes a dispatcher to wait on. If |dispatcher| has not been added, - // |MOJO_RESULT_NOT_FOUND| will be returned. - virtual MojoResult RemoveWaitingDispatcher( - const scoped_refptr<Dispatcher>& dispatcher); - - // Returns a set of ready dispatchers. |*count| is the maximum number of - // dispatchers to return, and will contain the number of dispatchers returned - // in |dispatchers| on completion. - virtual MojoResult GetReadyDispatchers(uint32_t* count, - DispatcherVector* dispatchers, - MojoResult* results, - uintptr_t* contexts); + // Invitation API. + virtual MojoResult AttachMessagePipe(base::StringPiece name, + ports::PortRef remote_peer_port); + virtual MojoResult ExtractMessagePipe(base::StringPiece name, + MojoHandle* message_pipe_handle); ///////////// General-purpose API for all handle types ///////// @@ -197,13 +177,13 @@ class MOJO_SYSTEM_IMPL_EXPORT Dispatcher // will close. // // NOTE: Transit MAY still fail after this call returns. Implementations - // should not assume PlatformHandle ownership has transferred until + // should not assume InternalPlatformHandle ownership has transferred until // CompleteTransitAndClose() is called. In other words, if CancelTransit() is - // called, the implementation should retain its PlatformHandles in working - // condition. + // called, the implementation should retain its InternalPlatformHandles in + // working condition. virtual bool EndSerialize(void* destination, ports::PortName* ports, - ScopedPlatformHandle* handles); + ScopedInternalPlatformHandle* handles); // Does whatever is necessary to begin transit of the dispatcher. This // should return |true| if transit is OK, or false if the underlying resource @@ -226,7 +206,7 @@ class MOJO_SYSTEM_IMPL_EXPORT Dispatcher size_t num_bytes, const ports::PortName* ports, size_t num_ports, - ScopedPlatformHandle* platform_handles, + ScopedInternalPlatformHandle* platform_handles, size_t platform_handle_count); protected: diff --git a/chromium/mojo/edk/system/handle_table.cc b/chromium/mojo/edk/system/handle_table.cc index 91ed4694303..a9fcc651414 100644 --- a/chromium/mojo/edk/system/handle_table.cc +++ b/chromium/mojo/edk/system/handle_table.cc @@ -31,6 +31,8 @@ const char* GetNameForDispatcherType(Dispatcher::Type type) { return "watcher"; case Dispatcher::Type::PLATFORM_HANDLE: return "platform_handle"; + case Dispatcher::Type::INVITATION: + return "invitation"; } NOTREACHED(); return "unknown"; diff --git a/chromium/mojo/edk/system/invitation_dispatcher.cc b/chromium/mojo/edk/system/invitation_dispatcher.cc new file mode 100644 index 00000000000..aa684bc0409 --- /dev/null +++ b/chromium/mojo/edk/system/invitation_dispatcher.cc @@ -0,0 +1,78 @@ +// 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. + +#include "mojo/edk/system/invitation_dispatcher.h" + +#include "mojo/edk/system/core.h" + +namespace mojo { +namespace edk { + +InvitationDispatcher::InvitationDispatcher() = default; + +Dispatcher::Type InvitationDispatcher::GetType() const { + return Type::INVITATION; +} + +MojoResult InvitationDispatcher::Close() { + PortMapping attached_ports; + { + base::AutoLock lock(lock_); + if (is_closed_) + return MOJO_RESULT_INVALID_ARGUMENT; + is_closed_ = true; + std::swap(attached_ports, attached_ports_); + } + for (auto& entry : attached_ports) + Core::Get()->GetNodeController()->ClosePort(entry.second); + return MOJO_RESULT_OK; +} + +MojoResult InvitationDispatcher::AttachMessagePipe( + base::StringPiece name, + ports::PortRef remote_peer_port) { + base::AutoLock lock(lock_); + auto result = attached_ports_.emplace(name.as_string(), remote_peer_port); + if (!result.second) { + Core::Get()->GetNodeController()->ClosePort(remote_peer_port); + return MOJO_RESULT_ALREADY_EXISTS; + } + return MOJO_RESULT_OK; +} + +MojoResult InvitationDispatcher::ExtractMessagePipe( + base::StringPiece name, + MojoHandle* message_pipe_handle) { + ports::PortRef remote_peer_port; + { + base::AutoLock lock(lock_); + auto it = attached_ports_.find(name.as_string()); + if (it == attached_ports_.end()) + return MOJO_RESULT_NOT_FOUND; + remote_peer_port = std::move(it->second); + attached_ports_.erase(it); + } + + *message_pipe_handle = + Core::Get()->CreatePartialMessagePipe(remote_peer_port); + if (*message_pipe_handle == MOJO_HANDLE_INVALID) + return MOJO_RESULT_RESOURCE_EXHAUSTED; + return MOJO_RESULT_OK; +} + +InvitationDispatcher::PortMapping InvitationDispatcher::TakeAttachedPorts() { + PortMapping attached_ports; + { + base::AutoLock lock(lock_); + std::swap(attached_ports, attached_ports_); + } + return attached_ports; +} + +InvitationDispatcher::~InvitationDispatcher() { + DCHECK(is_closed_); +} + +} // namespace edk +} // namespace mojo diff --git a/chromium/mojo/edk/system/invitation_dispatcher.h b/chromium/mojo/edk/system/invitation_dispatcher.h new file mode 100644 index 00000000000..21c530be02a --- /dev/null +++ b/chromium/mojo/edk/system/invitation_dispatcher.h @@ -0,0 +1,50 @@ +// 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_EDK_SYSTEM_INVITATION_DISPATCHER_H_ +#define MOJO_EDK_SYSTEM_INVITATION_DISPATCHER_H_ + +#include <stdint.h> + +#include "base/containers/flat_map.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" +#include "mojo/edk/embedder/scoped_platform_handle.h" +#include "mojo/edk/system/dispatcher.h" +#include "mojo/edk/system/ports/port_ref.h" +#include "mojo/edk/system/system_impl_export.h" + +namespace mojo { +namespace edk { + +class MOJO_SYSTEM_IMPL_EXPORT InvitationDispatcher : public Dispatcher { + public: + InvitationDispatcher(); + + // Dispatcher: + Type GetType() const override; + MojoResult Close() override; + MojoResult AttachMessagePipe(base::StringPiece name, + ports::PortRef remote_peer_port) override; + MojoResult ExtractMessagePipe(base::StringPiece name, + MojoHandle* message_pipe_handle) override; + + using PortMapping = base::flat_map<std::string, ports::PortRef>; + PortMapping TakeAttachedPorts(); + + private: + ~InvitationDispatcher() override; + + base::Lock lock_; + bool is_closed_ = false; + PortMapping attached_ports_; + + DISALLOW_COPY_AND_ASSIGN(InvitationDispatcher); +}; + +} // namespace edk +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_INVITATION_DISPATCHER_H diff --git a/chromium/mojo/edk/system/invitation_unittest.cc b/chromium/mojo/edk/system/invitation_unittest.cc new file mode 100644 index 00000000000..ddb86ae0659 --- /dev/null +++ b/chromium/mojo/edk/system/invitation_unittest.cc @@ -0,0 +1,610 @@ +// 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. + +#include <cstdint> +#include <string> + +#include "base/base_paths.h" +#include "base/bind.h" +#include "base/callback.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/optional.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "base/synchronization/lock.h" +#include "base/test/multiprocess_test.h" +#include "base/test/scoped_task_environment.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "build/build_config.h" +#include "mojo/edk/test/mojo_test_base.h" +#include "mojo/public/c/system/invitation.h" +#include "mojo/public/cpp/platform/named_platform_channel.h" +#include "mojo/public/cpp/platform/platform_channel.h" +#include "mojo/public/cpp/system/platform_handle.h" + +namespace mojo { +namespace edk { +namespace { + +enum class TransportType { + kChannel, + kChannelServer, +}; + +class InvitationTest : public test::MojoTestBase { + public: + InvitationTest() = default; + ~InvitationTest() override = default; + + protected: + static base::Process LaunchChildTestClient( + const std::string& test_client_name, + MojoHandle* primordial_pipes, + size_t num_primordial_pipes, + TransportType transport_type, + MojoProcessErrorHandler error_handler = nullptr, + uintptr_t error_handler_context = 0); + + private: + base::test::ScopedTaskEnvironment task_environment_; + + DISALLOW_COPY_AND_ASSIGN(InvitationTest); +}; + +TEST_F(InvitationTest, Create) { + MojoHandle invitation; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateInvitation(nullptr, &invitation)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(invitation)); + + MojoCreateInvitationOptions options; + options.struct_size = sizeof(options); + options.flags = MOJO_CREATE_INVITATION_FLAG_NONE; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateInvitation(&options, &invitation)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(invitation)); +} + +TEST_F(InvitationTest, InvalidArguments) { + MojoHandle invitation; + MojoCreateInvitationOptions invalid_create_options; + invalid_create_options.struct_size = 0; + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoCreateInvitation(&invalid_create_options, &invitation)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoCreateInvitation(nullptr, nullptr)); + + // We need a valid invitation handle to exercise some of the other invalid + // argument cases below. + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateInvitation(nullptr, &invitation)); + + MojoHandle pipe; + MojoAttachMessagePipeToInvitationOptions invalid_attach_options; + invalid_attach_options.struct_size = 0; + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoAttachMessagePipeToInvitation(MOJO_HANDLE_INVALID, "x", 1, + nullptr, &pipe)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoAttachMessagePipeToInvitation(invitation, "x", 1, + &invalid_attach_options, &pipe)); + EXPECT_EQ( + MOJO_RESULT_INVALID_ARGUMENT, + MojoAttachMessagePipeToInvitation(invitation, "x", 1, nullptr, nullptr)); + + MojoExtractMessagePipeFromInvitationOptions invalid_extract_options; + invalid_extract_options.struct_size = 0; + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoExtractMessagePipeFromInvitation(MOJO_HANDLE_INVALID, "x", 1, + nullptr, &pipe)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoExtractMessagePipeFromInvitation( + invitation, "x", 1, &invalid_extract_options, &pipe)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoExtractMessagePipeFromInvitation(invitation, "x", 1, nullptr, + nullptr)); + + PlatformChannel channel; + MojoPlatformHandle endpoint_handle; + endpoint_handle.struct_size = sizeof(endpoint_handle); + PlatformHandleToMojoPlatformHandle( + channel.TakeLocalEndpoint().TakePlatformHandle(), &endpoint_handle); + ASSERT_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID); + + MojoInvitationTransportEndpoint valid_endpoint; + valid_endpoint.struct_size = sizeof(valid_endpoint); + valid_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL; + valid_endpoint.num_platform_handles = 1; + valid_endpoint.platform_handles = &endpoint_handle; + + MojoSendInvitationOptions invalid_send_options; + invalid_send_options.struct_size = 0; + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoSendInvitation(MOJO_HANDLE_INVALID, nullptr, &valid_endpoint, + nullptr, 0, nullptr)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoSendInvitation(invitation, nullptr, &valid_endpoint, nullptr, 0, + &invalid_send_options)); + + MojoInvitationTransportEndpoint invalid_endpoint; + invalid_endpoint.struct_size = 0; + invalid_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL; + invalid_endpoint.num_platform_handles = 1; + invalid_endpoint.platform_handles = &endpoint_handle; + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoSendInvitation(invitation, nullptr, &invalid_endpoint, nullptr, + 0, nullptr)); + + invalid_endpoint.struct_size = sizeof(invalid_endpoint); + invalid_endpoint.num_platform_handles = 0; + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoSendInvitation(invitation, nullptr, &invalid_endpoint, nullptr, + 0, nullptr)); + + MojoPlatformHandle invalid_platform_handle; + invalid_platform_handle.struct_size = 0; + invalid_endpoint.num_platform_handles = 1; + invalid_endpoint.platform_handles = &invalid_platform_handle; + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoSendInvitation(invitation, nullptr, &invalid_endpoint, nullptr, + 0, nullptr)); + invalid_platform_handle.struct_size = sizeof(invalid_platform_handle); + invalid_platform_handle.type = MOJO_PLATFORM_HANDLE_TYPE_INVALID; + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoSendInvitation(invitation, nullptr, &invalid_endpoint, nullptr, + 0, nullptr)); + + invalid_endpoint.num_platform_handles = 1; + invalid_endpoint.platform_handles = nullptr; + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoSendInvitation(invitation, nullptr, &invalid_endpoint, nullptr, + 0, nullptr)); + + MojoHandle accepted_invitation; + MojoAcceptInvitationOptions invalid_accept_options; + invalid_accept_options.struct_size = 0; + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoAcceptInvitation(nullptr, nullptr, &accepted_invitation)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoAcceptInvitation(&valid_endpoint, &invalid_accept_options, + &accepted_invitation)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, + MojoAcceptInvitation(&valid_endpoint, nullptr, nullptr)); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(invitation)); +} + +TEST_F(InvitationTest, AttachAndExtractLocally) { + MojoHandle invitation; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateInvitation(nullptr, &invitation)); + + MojoHandle pipe0 = MOJO_HANDLE_INVALID; + EXPECT_EQ(MOJO_RESULT_OK, MojoAttachMessagePipeToInvitation( + invitation, "x", 1, nullptr, &pipe0)); + EXPECT_NE(MOJO_HANDLE_INVALID, pipe0); + + MojoHandle pipe1 = MOJO_HANDLE_INVALID; + EXPECT_EQ(MOJO_RESULT_OK, MojoExtractMessagePipeFromInvitation( + invitation, "x", 1, nullptr, &pipe1)); + EXPECT_NE(MOJO_HANDLE_INVALID, pipe1); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(invitation)); + + // Should be able to communicate over the pipe. + const std::string kMessage = "RSVP LOL"; + WriteMessage(pipe0, kMessage); + EXPECT_EQ(kMessage, ReadMessage(pipe1)); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe0)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe1)); +} + +TEST_F(InvitationTest, ClosedInvitationClosesAttachments) { + MojoHandle invitation; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateInvitation(nullptr, &invitation)); + + MojoHandle pipe = MOJO_HANDLE_INVALID; + EXPECT_EQ(MOJO_RESULT_OK, MojoAttachMessagePipeToInvitation( + invitation, "x", 1, nullptr, &pipe)); + EXPECT_NE(MOJO_HANDLE_INVALID, pipe); + + // Closing the invitation should close |pipe|'s peer. + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(invitation)); + + EXPECT_EQ(MOJO_RESULT_OK, + WaitForSignals(pipe, MOJO_HANDLE_SIGNAL_PEER_CLOSED)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe)); +} + +TEST_F(InvitationTest, AttachNameInUse) { + MojoHandle invitation; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateInvitation(nullptr, &invitation)); + + MojoHandle pipe0 = MOJO_HANDLE_INVALID; + EXPECT_EQ(MOJO_RESULT_OK, MojoAttachMessagePipeToInvitation( + invitation, "x", 1, nullptr, &pipe0)); + EXPECT_NE(MOJO_HANDLE_INVALID, pipe0); + + MojoHandle pipe1 = MOJO_HANDLE_INVALID; + EXPECT_EQ( + MOJO_RESULT_ALREADY_EXISTS, + MojoAttachMessagePipeToInvitation(invitation, "x", 1, nullptr, &pipe1)); + EXPECT_EQ(MOJO_HANDLE_INVALID, pipe1); + EXPECT_EQ(MOJO_RESULT_OK, MojoAttachMessagePipeToInvitation( + invitation, "y", 1, nullptr, &pipe1)); + EXPECT_NE(MOJO_HANDLE_INVALID, pipe1); + + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(invitation)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe0)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe1)); +} + +// static +base::Process InvitationTest::LaunchChildTestClient( + const std::string& test_client_name, + MojoHandle* primordial_pipes, + size_t num_primordial_pipes, + TransportType transport_type, + MojoProcessErrorHandler error_handler, + uintptr_t error_handler_context) { + base::CommandLine command_line( + base::GetMultiProcessTestChildBaseCommandLine()); + + base::LaunchOptions launch_options; + base::Optional<PlatformChannel> channel; + base::Optional<NamedPlatformChannel> named_channel; + PlatformHandle local_endpoint_handle; + if (transport_type == TransportType::kChannel) { + channel.emplace(); +#if defined(OS_FUCHSIA) + channel->PrepareToPassRemoteEndpoint(&launch_options.handles_to_transfer, + &command_line); +#elif defined(OS_POSIX) + channel->PrepareToPassRemoteEndpoint(&launch_options.fds_to_remap, + &command_line); +#elif defined(OS_WIN) + launch_options.start_hidden = true; + channel->PrepareToPassRemoteEndpoint(&launch_options.handles_to_inherit, + &command_line); +#else +#error "Platform not yet supported." +#endif + local_endpoint_handle = channel->TakeLocalEndpoint().TakePlatformHandle(); + } else { +#if defined(OS_FUCHSIA) + NOTREACHED() << "Named pipe support does not exist for Mojo on Fuchsia."; +#else + NamedPlatformChannel::Options named_channel_options; +#if !defined(OS_WIN) + CHECK(base::PathService::Get(base::DIR_TEMP, + &named_channel_options.socket_dir)); +#endif + named_channel.emplace(named_channel_options); + named_channel->PassServerNameOnCommandLine(&command_line); + local_endpoint_handle = + named_channel->TakeServerEndpoint().TakePlatformHandle(); +#endif + } + + MojoPlatformHandle endpoint_handle; + PlatformHandleToMojoPlatformHandle(std::move(local_endpoint_handle), + &endpoint_handle); + CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID); + + MojoHandle invitation; + CHECK_EQ(MOJO_RESULT_OK, MojoCreateInvitation(nullptr, &invitation)); + for (uint32_t name = 0; name < num_primordial_pipes; ++name) { + CHECK_EQ(MOJO_RESULT_OK, + MojoAttachMessagePipeToInvitation(invitation, &name, 4, nullptr, + &primordial_pipes[name])); + } + + base::Process child_process = base::SpawnMultiProcessTestChild( + test_client_name, command_line, launch_options); + if (channel) + channel->RemoteProcessLaunched(); + + MojoPlatformProcessHandle process_handle; + process_handle.struct_size = sizeof(process_handle); +#if defined(OS_WIN) + process_handle.value = static_cast<uint64_t>( + reinterpret_cast<uintptr_t>(child_process.Handle())); +#else + process_handle.value = static_cast<uint64_t>(child_process.Handle()); +#endif + + MojoInvitationTransportEndpoint transport_endpoint; + transport_endpoint.struct_size = sizeof(transport_endpoint); + if (transport_type == TransportType::kChannel) + transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL; + else + transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER; + transport_endpoint.num_platform_handles = 1; + transport_endpoint.platform_handles = &endpoint_handle; + CHECK_EQ(MOJO_RESULT_OK, + MojoSendInvitation(invitation, &process_handle, &transport_endpoint, + error_handler, error_handler_context, nullptr)); + return child_process; +} + +class TestClientBase : public InvitationTest { + public: + static MojoHandle AcceptInvitation() { + const auto& command_line = *base::CommandLine::ForCurrentProcess(); + PlatformChannelEndpoint channel_endpoint = + NamedPlatformChannel::ConnectToServer(command_line); + if (!channel_endpoint.is_valid()) { + channel_endpoint = + PlatformChannel::RecoverPassedEndpointFromCommandLine(command_line); + } + MojoPlatformHandle endpoint_handle; + PlatformHandleToMojoPlatformHandle(channel_endpoint.TakePlatformHandle(), + &endpoint_handle); + CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID); + + MojoInvitationTransportEndpoint transport_endpoint; + transport_endpoint.struct_size = sizeof(transport_endpoint); + transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL; + transport_endpoint.num_platform_handles = 1; + transport_endpoint.platform_handles = &endpoint_handle; + + MojoHandle invitation; + CHECK_EQ(MOJO_RESULT_OK, + MojoAcceptInvitation(&transport_endpoint, nullptr, &invitation)); + return invitation; + } + + private: + DISALLOW_COPY_AND_ASSIGN(TestClientBase); +}; + +#define DEFINE_TEST_CLIENT(name) \ + class name##Impl : public TestClientBase { \ + public: \ + static void Run(); \ + }; \ + MULTIPROCESS_TEST_MAIN(name) { \ + name##Impl::Run(); \ + return 0; \ + } \ + void name##Impl::Run() + +const std::string kTestMessage1 = "i am the pusher robot"; +const std::string kTestMessage2 = "i push the messages down the pipe"; +const std::string kTestMessage3 = "i am the shover robot"; +const std::string kTestMessage4 = "i shove the messages down the pipe"; + +TEST_F(InvitationTest, SendInvitation) { + MojoHandle primordial_pipe; + base::Process child_process = LaunchChildTestClient( + "SendInvitationClient", &primordial_pipe, 1, TransportType::kChannel); + + WriteMessage(primordial_pipe, kTestMessage1); + EXPECT_EQ(MOJO_RESULT_OK, + WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_READABLE)); + EXPECT_EQ(kTestMessage3, ReadMessage(primordial_pipe)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(primordial_pipe)); + + int wait_result = -1; + base::WaitForMultiprocessTestChildExit( + child_process, TestTimeouts::action_timeout(), &wait_result); + child_process.Close(); + EXPECT_EQ(0, wait_result); +} + +DEFINE_TEST_CLIENT(SendInvitationClient) { + MojoHandle primordial_pipe; + MojoHandle invitation = AcceptInvitation(); + const uint32_t pipe_name = 0; + ASSERT_EQ(MOJO_RESULT_OK, + MojoExtractMessagePipeFromInvitation(invitation, &pipe_name, 4, + nullptr, &primordial_pipe)); + ASSERT_EQ(MOJO_RESULT_OK, MojoClose(invitation)); + + WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_READABLE); + ASSERT_EQ(kTestMessage1, ReadMessage(primordial_pipe)); + WriteMessage(primordial_pipe, kTestMessage3); + WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_PEER_CLOSED); + + ASSERT_EQ(MOJO_RESULT_OK, MojoClose(primordial_pipe)); +} + +TEST_F(InvitationTest, SendInvitationMultiplePipes) { + MojoHandle pipes[2]; + base::Process child_process = LaunchChildTestClient( + "SendInvitationMultiplePipesClient", pipes, 2, TransportType::kChannel); + + WriteMessage(pipes[0], kTestMessage1); + WriteMessage(pipes[1], kTestMessage2); + EXPECT_EQ(MOJO_RESULT_OK, + WaitForSignals(pipes[0], MOJO_HANDLE_SIGNAL_READABLE)); + EXPECT_EQ(MOJO_RESULT_OK, + WaitForSignals(pipes[1], MOJO_HANDLE_SIGNAL_READABLE)); + EXPECT_EQ(kTestMessage3, ReadMessage(pipes[0])); + EXPECT_EQ(kTestMessage4, ReadMessage(pipes[1])); + + ASSERT_EQ(MOJO_RESULT_OK, MojoClose(pipes[0])); + ASSERT_EQ(MOJO_RESULT_OK, MojoClose(pipes[1])); + + int wait_result = -1; + base::WaitForMultiprocessTestChildExit( + child_process, TestTimeouts::action_timeout(), &wait_result); + child_process.Close(); + EXPECT_EQ(0, wait_result); +} + +DEFINE_TEST_CLIENT(SendInvitationMultiplePipesClient) { + MojoHandle pipes[2]; + MojoHandle invitation = AcceptInvitation(); + const uint32_t pipe_names[] = {0, 1}; + ASSERT_EQ(MOJO_RESULT_OK, + MojoExtractMessagePipeFromInvitation(invitation, &pipe_names[0], 4, + nullptr, &pipes[0])); + ASSERT_EQ(MOJO_RESULT_OK, + MojoExtractMessagePipeFromInvitation(invitation, &pipe_names[1], 4, + nullptr, &pipes[1])); + + WaitForSignals(pipes[0], MOJO_HANDLE_SIGNAL_READABLE); + WaitForSignals(pipes[1], MOJO_HANDLE_SIGNAL_READABLE); + ASSERT_EQ(kTestMessage1, ReadMessage(pipes[0])); + ASSERT_EQ(kTestMessage2, ReadMessage(pipes[1])); + WriteMessage(pipes[0], kTestMessage3); + WriteMessage(pipes[1], kTestMessage4); + WaitForSignals(pipes[0], MOJO_HANDLE_SIGNAL_PEER_CLOSED); + WaitForSignals(pipes[1], MOJO_HANDLE_SIGNAL_PEER_CLOSED); +} + +#if !defined(OS_FUCHSIA) +TEST_F(InvitationTest, SendInvitationWithServer) { + MojoHandle primordial_pipe; + base::Process child_process = + LaunchChildTestClient("SendInvitationWithServerClient", &primordial_pipe, + 1, TransportType::kChannelServer); + + WriteMessage(primordial_pipe, kTestMessage1); + EXPECT_EQ(MOJO_RESULT_OK, + WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_READABLE)); + EXPECT_EQ(kTestMessage3, ReadMessage(primordial_pipe)); + EXPECT_EQ(MOJO_RESULT_OK, MojoClose(primordial_pipe)); + + int wait_result = -1; + base::WaitForMultiprocessTestChildExit( + child_process, TestTimeouts::action_timeout(), &wait_result); + child_process.Close(); + EXPECT_EQ(0, wait_result); +} + +DEFINE_TEST_CLIENT(SendInvitationWithServerClient) { + MojoHandle primordial_pipe; + MojoHandle invitation = AcceptInvitation(); + const uint32_t pipe_name = 0; + ASSERT_EQ(MOJO_RESULT_OK, + MojoExtractMessagePipeFromInvitation(invitation, &pipe_name, 4, + nullptr, &primordial_pipe)); + ASSERT_EQ(MOJO_RESULT_OK, MojoClose(invitation)); + + WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_READABLE); + ASSERT_EQ(kTestMessage1, ReadMessage(primordial_pipe)); + WriteMessage(primordial_pipe, kTestMessage3); + WaitForSignals(primordial_pipe, MOJO_HANDLE_SIGNAL_PEER_CLOSED); + + ASSERT_EQ(MOJO_RESULT_OK, MojoClose(primordial_pipe)); +} +#endif // !defined(OS_FUCHSIA) + +const char kErrorMessage[] = "ur bad :("; +const char kDisconnectMessage[] = "go away plz"; + +class RemoteProcessState { + public: + RemoteProcessState() + : callback_task_runner_(base::SequencedTaskRunnerHandle::Get()) {} + ~RemoteProcessState() = default; + + bool disconnected() { + base::AutoLock lock(lock_); + return disconnected_; + } + + void set_error_callback(base::RepeatingClosure callback) { + error_callback_ = std::move(callback); + } + + void set_expected_error_message(const std::string& expected) { + expected_error_message_ = expected; + } + + void NotifyError(const std::string& error_message, bool disconnected) { + base::AutoLock lock(lock_); + CHECK(!disconnected_); + EXPECT_NE(error_message.find(expected_error_message_), std::string::npos); + disconnected_ = disconnected; + ++call_count_; + if (error_callback_) + callback_task_runner_->PostTask(FROM_HERE, error_callback_); + } + + private: + const scoped_refptr<base::SequencedTaskRunner> callback_task_runner_; + + base::Lock lock_; + int call_count_ = 0; + bool disconnected_ = false; + std::string expected_error_message_; + base::RepeatingClosure error_callback_; + + DISALLOW_COPY_AND_ASSIGN(RemoteProcessState); +}; + +void TestProcessErrorHandler(uintptr_t context, + const MojoProcessErrorDetails* details) { + auto* state = reinterpret_cast<RemoteProcessState*>(context); + std::string error_message; + if (details->error_message) { + error_message = + std::string(details->error_message, details->error_message_length - 1); + } + state->NotifyError(error_message, + details->flags & MOJO_PROCESS_ERROR_FLAG_DISCONNECTED); +} + +TEST_F(InvitationTest, ProcessErrors) { + RemoteProcessState process_state; + MojoHandle pipe; + base::Process child_process = LaunchChildTestClient( + "ProcessErrorsClient", &pipe, 1, TransportType::kChannel, + &TestProcessErrorHandler, reinterpret_cast<uintptr_t>(&process_state)); + + MojoMessageHandle message; + WaitForSignals(pipe, MOJO_HANDLE_SIGNAL_READABLE); + EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(pipe, nullptr, &message)); + + base::RunLoop error_loop; + process_state.set_error_callback(error_loop.QuitClosure()); + + // Report this message as "bad". This should cause the error handler to be + // invoked and the RunLoop to be quit. + process_state.set_expected_error_message(kErrorMessage); + EXPECT_EQ(MOJO_RESULT_OK, + MojoNotifyBadMessage(message, kErrorMessage, sizeof(kErrorMessage), + nullptr)); + error_loop.Run(); + EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message)); + + // Now tell the child it can exit, and wait for it to disconnect. + base::RunLoop disconnect_loop; + process_state.set_error_callback(disconnect_loop.QuitClosure()); + process_state.set_expected_error_message(std::string()); + WriteMessage(pipe, kDisconnectMessage); + disconnect_loop.Run(); + + EXPECT_TRUE(process_state.disconnected()); + + int wait_result = -1; + base::WaitForMultiprocessTestChildExit( + child_process, TestTimeouts::action_timeout(), &wait_result); + child_process.Close(); + EXPECT_EQ(0, wait_result); +} + +DEFINE_TEST_CLIENT(ProcessErrorsClient) { + MojoHandle pipe; + MojoHandle invitation = AcceptInvitation(); + const uint32_t pipe_name = 0; + ASSERT_EQ(MOJO_RESULT_OK, MojoExtractMessagePipeFromInvitation( + invitation, &pipe_name, 4, nullptr, &pipe)); + ASSERT_EQ(MOJO_RESULT_OK, MojoClose(invitation)); + + // Send a message. Contents are irrelevant, the test process is just going to + // flag it as a bad. + WriteMessage(pipe, "doesn't matter"); + + // Wait for our goodbye before exiting. + WaitForSignals(pipe, MOJO_HANDLE_SIGNAL_READABLE); + EXPECT_EQ(kDisconnectMessage, ReadMessage(pipe)); +} + +} // namespace +} // namespace edk +} // namespace mojo diff --git a/chromium/mojo/edk/system/mach_port_relay.cc b/chromium/mojo/edk/system/mach_port_relay.cc index a9cc48029c9..b3380a86d29 100644 --- a/chromium/mojo/edk/system/mach_port_relay.cc +++ b/chromium/mojo/edk/system/mach_port_relay.cc @@ -65,22 +65,23 @@ void ReportChildError(ChildUMAError error) { } // namespace // static -void MachPortRelay::ReceivePorts(std::vector<ScopedPlatformHandle>* handles) { +void MachPortRelay::ReceivePorts( + std::vector<ScopedInternalPlatformHandle>* handles) { DCHECK(handles); for (auto& handle : *handles) { - DCHECK(handle.get().type != PlatformHandle::Type::MACH); - if (handle.get().type != PlatformHandle::Type::MACH_NAME) + DCHECK(handle.get().type != InternalPlatformHandle::Type::MACH); + if (handle.get().type != InternalPlatformHandle::Type::MACH_NAME) continue; - handle.get().type = PlatformHandle::Type::MACH; + handle.get().type = InternalPlatformHandle::Type::MACH; // MACH_PORT_NULL doesn't need translation. if (handle.get().port == MACH_PORT_NULL) continue; // TODO(wez): Wrapping handle.get().port in this way causes it to be - // Free()d via mach_port_mod_refs() - should PlatformHandle also do + // Free()d via mach_port_mod_refs() - should InternalPlatformHandle also do // that if the handle never reaches here, or should this code not be // wrapping it? base::mac::ScopedMachReceiveRight message_port(handle.get().port); @@ -112,17 +113,17 @@ void MachPortRelay::SendPortsToProcess(Channel::Message* message, DCHECK(message); mach_port_t task_port = port_provider_->TaskForPid(process); - std::vector<ScopedPlatformHandle> handles = message->TakeHandles(); + std::vector<ScopedInternalPlatformHandle> handles = message->TakeHandles(); // Message should have handles, otherwise there's no point in calling this // function. DCHECK(!handles.empty()); for (auto& handle : handles) { - DCHECK(handle.get().type != PlatformHandle::Type::MACH_NAME); - if (handle.get().type != PlatformHandle::Type::MACH) + DCHECK(handle.get().type != InternalPlatformHandle::Type::MACH_NAME); + if (handle.get().type != InternalPlatformHandle::Type::MACH) continue; if (!handle.is_valid()) { - handle.get().type = PlatformHandle::Type::MACH_NAME; + handle.get().type = InternalPlatformHandle::Type::MACH_NAME; continue; } @@ -169,15 +170,15 @@ void MachPortRelay::SendPortsToProcess(Channel::Message* message, ReportBrokerError(BrokerUMAError::SUCCESS); handle.get().port = intermediate_port; - handle.get().type = PlatformHandle::Type::MACH_NAME; + handle.get().type = InternalPlatformHandle::Type::MACH_NAME; } message->SetHandles(std::move(handles)); } -void MachPortRelay::ExtractPort(ScopedPlatformHandle* handle, +void MachPortRelay::ExtractPort(ScopedInternalPlatformHandle* handle, base::ProcessHandle process) { - DCHECK_EQ(handle->get().type, PlatformHandle::Type::MACH_NAME); - handle->get().type = PlatformHandle::Type::MACH; + DCHECK_EQ(handle->get().type, InternalPlatformHandle::Type::MACH_NAME); + handle->get().type = InternalPlatformHandle::Type::MACH; // No extraction necessary for MACH_PORT_NULL. if (!handle->is_valid()) diff --git a/chromium/mojo/edk/system/mach_port_relay.h b/chromium/mojo/edk/system/mach_port_relay.h index b24264452ec..b8d232f20c3 100644 --- a/chromium/mojo/edk/system/mach_port_relay.h +++ b/chromium/mojo/edk/system/mach_port_relay.h @@ -44,7 +44,7 @@ class MachPortRelay : public base::PortProvider::Observer { // // See SendPortsToProcess() for the definition of intermediate and final Mach // ports. - static void ReceivePorts(std::vector<ScopedPlatformHandle>* handles); + static void ReceivePorts(std::vector<ScopedInternalPlatformHandle>* handles); explicit MachPortRelay(base::PortProvider* port_provider); ~MachPortRelay() override; @@ -59,11 +59,12 @@ class MachPortRelay : public base::PortProvider::Observer { void SendPortsToProcess(Channel::Message* message, base::ProcessHandle process); - // Given a PlatformHandle of Type::MACH_NAME, extracts the Mach port, and - // updates the contents of the PlatformHandle to have Type::MACH and have the - // actual Mach port. On failure, replaces the contents with Type::MACH and - // MACH_PORT_NULL. - void ExtractPort(ScopedPlatformHandle* handle, base::ProcessHandle process); + // Given a InternalPlatformHandle of Type::MACH_NAME, extracts the Mach port, + // and updates the contents of the InternalPlatformHandle to have Type::MACH + // and have the actual Mach port. On failure, replaces the contents with + // Type::MACH and MACH_PORT_NULL. + void ExtractPort(ScopedInternalPlatformHandle* handle, + base::ProcessHandle process); // Observer interface. void AddObserver(Observer* observer); diff --git a/chromium/mojo/edk/system/mapping_table.cc b/chromium/mojo/edk/system/mapping_table.cc deleted file mode 100644 index 4b28282ea58..00000000000 --- a/chromium/mojo/edk/system/mapping_table.cc +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/edk/system/mapping_table.h" - -#include "base/logging.h" -#include "mojo/edk/embedder/platform_shared_buffer.h" -#include "mojo/edk/system/configuration.h" - -namespace mojo { -namespace edk { - -MappingTable::MappingTable() { -} - -MappingTable::~MappingTable() { - // This should usually not be reached (the only instance should be owned by - // the singleton |Core|, which lives forever), except in tests. -} - -MojoResult MappingTable::AddMapping( - std::unique_ptr<PlatformSharedBufferMapping> mapping) { - DCHECK(mapping); - - if (address_to_mapping_map_.size() >= - GetConfiguration().max_mapping_table_size) - return MOJO_RESULT_RESOURCE_EXHAUSTED; - - void* address = mapping->GetBase(); - DCHECK(address_to_mapping_map_.find(address) == - address_to_mapping_map_.end()); - address_to_mapping_map_[address] = mapping.release(); - return MOJO_RESULT_OK; -} - -MojoResult MappingTable::RemoveMapping( - void* address, - std::unique_ptr<PlatformSharedBufferMapping>* mapping) { - AddressToMappingMap::iterator it = address_to_mapping_map_.find(address); - if (it == address_to_mapping_map_.end()) - return MOJO_RESULT_INVALID_ARGUMENT; - mapping->reset(it->second); - address_to_mapping_map_.erase(it); - return MOJO_RESULT_OK; -} - -} // namespace edk -} // namespace mojo diff --git a/chromium/mojo/edk/system/mapping_table.h b/chromium/mojo/edk/system/mapping_table.h deleted file mode 100644 index a9498201977..00000000000 --- a/chromium/mojo/edk/system/mapping_table.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MOJO_EDK_SYSTEM_MAPPING_TABLE_H_ -#define MOJO_EDK_SYSTEM_MAPPING_TABLE_H_ - -#include <stdint.h> - -#include <memory> -#include <vector> - -#include "base/containers/hash_tables.h" -#include "base/macros.h" -#include "mojo/edk/system/system_impl_export.h" -#include "mojo/public/c/system/types.h" - -namespace mojo { - -namespace edk { -class Core; -class PlatformSharedBufferMapping; - -// This class provides the (global) table of memory mappings (owned by |Core|), -// which maps mapping base addresses to |PlatformSharedBufferMapping|s. -// -// This class is NOT thread-safe; locking is left to |Core|. -class MOJO_SYSTEM_IMPL_EXPORT MappingTable { - public: - MappingTable(); - ~MappingTable(); - - // Tries to add a mapping. (Takes ownership of the mapping in all cases; on - // failure, it will be destroyed.) - MojoResult AddMapping(std::unique_ptr<PlatformSharedBufferMapping> mapping); - MojoResult RemoveMapping( - void* address, - std::unique_ptr<PlatformSharedBufferMapping>* mapping); - - private: - using AddressToMappingMap = - base::hash_map<void*, PlatformSharedBufferMapping*>; - AddressToMappingMap address_to_mapping_map_; - - DISALLOW_COPY_AND_ASSIGN(MappingTable); -}; - -} // namespace edk -} // namespace mojo - -#endif // MOJO_EDK_SYSTEM_MAPPING_TABLE_H_ diff --git a/chromium/mojo/edk/system/message_pipe_dispatcher.cc b/chromium/mojo/edk/system/message_pipe_dispatcher.cc index a095ab4e497..219ad4ccab8 100644 --- a/chromium/mojo/edk/system/message_pipe_dispatcher.cc +++ b/chromium/mojo/edk/system/message_pipe_dispatcher.cc @@ -136,8 +136,7 @@ MojoResult MessagePipeDispatcher::Close() { } MojoResult MessagePipeDispatcher::WriteMessage( - std::unique_ptr<ports::UserMessageEvent> message, - MojoWriteMessageFlags flags) { + std::unique_ptr<ports::UserMessageEvent> message) { if (port_closed_ || in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; @@ -224,9 +223,10 @@ void MessagePipeDispatcher::StartSerialize(uint32_t* num_bytes, *num_handles = 0; } -bool MessagePipeDispatcher::EndSerialize(void* destination, - ports::PortName* ports, - ScopedPlatformHandle* handles) { +bool MessagePipeDispatcher::EndSerialize( + void* destination, + ports::PortName* ports, + ScopedInternalPlatformHandle* handles) { SerializedState* state = static_cast<SerializedState*>(destination); state->pipe_id = pipe_id_; state->endpoint = static_cast<int8_t>(endpoint_); @@ -266,7 +266,7 @@ scoped_refptr<Dispatcher> MessagePipeDispatcher::Deserialize( size_t num_bytes, const ports::PortName* ports, size_t num_ports, - ScopedPlatformHandle* handles, + ScopedInternalPlatformHandle* handles, size_t num_handles) { if (num_ports != 1 || num_handles || num_bytes != sizeof(SerializedState)) return nullptr; diff --git a/chromium/mojo/edk/system/message_pipe_dispatcher.h b/chromium/mojo/edk/system/message_pipe_dispatcher.h index 141e8450996..64ad3d70a05 100644 --- a/chromium/mojo/edk/system/message_pipe_dispatcher.h +++ b/chromium/mojo/edk/system/message_pipe_dispatcher.h @@ -47,8 +47,8 @@ class MessagePipeDispatcher : public Dispatcher { // Dispatcher: Type GetType() const override; MojoResult Close() override; - MojoResult WriteMessage(std::unique_ptr<ports::UserMessageEvent> message, - MojoWriteMessageFlags flags) override; + MojoResult WriteMessage( + std::unique_ptr<ports::UserMessageEvent> message) override; MojoResult ReadMessage( std::unique_ptr<ports::UserMessageEvent>* message) override; HandleSignalsState GetHandleSignalsState() const override; @@ -61,17 +61,18 @@ class MessagePipeDispatcher : public Dispatcher { uint32_t* num_handles) override; bool EndSerialize(void* destination, ports::PortName* ports, - ScopedPlatformHandle* handles) override; + ScopedInternalPlatformHandle* handles) override; bool BeginTransit() override; void CompleteTransitAndClose() override; void CancelTransit() override; - static scoped_refptr<Dispatcher> Deserialize(const void* data, - size_t num_bytes, - const ports::PortName* ports, - size_t num_ports, - ScopedPlatformHandle* handles, - size_t num_handles); + static scoped_refptr<Dispatcher> Deserialize( + const void* data, + size_t num_bytes, + const ports::PortName* ports, + size_t num_ports, + ScopedInternalPlatformHandle* handles, + size_t num_handles); private: class PortObserverThunk; diff --git a/chromium/mojo/edk/system/message_pipe_unittest.cc b/chromium/mojo/edk/system/message_pipe_unittest.cc index 6ec0bfb077d..2cdc58edd3a 100644 --- a/chromium/mojo/edk/system/message_pipe_unittest.cc +++ b/chromium/mojo/edk/system/message_pipe_unittest.cc @@ -54,8 +54,8 @@ class MessagePipeTest : public test::MojoTestBase { uint32_t* num_bytes, bool may_discard = false) { MojoMessageHandle message_handle; - MojoResult rv = MojoReadMessage(message_pipe_handle, &message_handle, - MOJO_READ_MESSAGE_FLAG_NONE); + MojoResult rv = + MojoReadMessage(message_pipe_handle, nullptr, &message_handle); if (rv != MOJO_RESULT_OK) return rv; @@ -318,7 +318,7 @@ TEST_F(MessagePipeTest, BasicWaiting) { #if !defined(OS_IOS) -const size_t kPingPongHandlesPerIteration = 50; +const size_t kPingPongHandlesPerIteration = 30; const size_t kPingPongIterations = 500; DEFINE_TEST_CLIENT_TEST_WITH_PIPE(HandlePingPong, MessagePipeTest, h) { @@ -376,7 +376,7 @@ TEST_F(MessagePipeTest, DISABLED_DataPipeProducerHandlePingPong) { TEST_F(MessagePipeTest, SharedBufferHandlePingPong) { MojoHandle buffers[kPingPongHandlesPerIteration]; for (size_t i = 0; i < kPingPongHandlesPerIteration; ++i) - EXPECT_EQ(MOJO_RESULT_OK, MojoCreateSharedBuffer(nullptr, 1, &buffers[i])); + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateSharedBuffer(1, nullptr, &buffers[i])); RunTestClient("HandlePingPong", [&](MojoHandle h) { for (size_t i = 0; i < kPingPongIterations; i++) { @@ -398,7 +398,7 @@ TEST_F(FuseMessagePipeTest, Basic) { CreateMessagePipe(&a, &b); CreateMessagePipe(&c, &d); - EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c)); + EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c, nullptr)); // Handles b and c should be closed. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b)); @@ -429,7 +429,7 @@ TEST_F(FuseMessagePipeTest, FuseAfterPeerWrite) { WriteMessage(a, kTestMessage1); WriteMessage(d, kTestMessage2); - EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c)); + EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c, nullptr)); // Handles b and c should be closed. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b)); @@ -450,7 +450,8 @@ TEST_F(FuseMessagePipeTest, NoFuseAfterWrite) { CreateMessagePipe(&c, &d); WriteMessage(b, "shouldn't have done that!"); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, MojoFuseMessagePipes(b, c)); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoFuseMessagePipes(b, c, nullptr)); // Handles b and c should be closed. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b)); @@ -466,7 +467,8 @@ TEST_F(FuseMessagePipeTest, NoFuseSelf) { MojoHandle a, b; CreateMessagePipe(&a, &b); - EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, MojoFuseMessagePipes(a, b)); + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + MojoFuseMessagePipes(a, b, nullptr)); // Handles a and b should be closed. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(a)); @@ -481,7 +483,7 @@ TEST_F(FuseMessagePipeTest, FuseInvalidArguments) { EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b)); // Can't fuse an invalid handle. - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoFuseMessagePipes(b, c)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoFuseMessagePipes(b, c, nullptr)); // Handle c should be closed. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(c)); @@ -490,7 +492,7 @@ TEST_F(FuseMessagePipeTest, FuseInvalidArguments) { MojoHandle e, f; CreateDataPipe(&e, &f, 16); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoFuseMessagePipes(e, d)); + EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoFuseMessagePipes(e, d, nullptr)); // Handles d and e should be closed. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(d)); @@ -508,7 +510,7 @@ TEST_F(FuseMessagePipeTest, FuseAfterPeerClosure) { CreateMessagePipe(&c, &d); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); - EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c)); + EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c, nullptr)); // Handles b and c should be closed. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b)); @@ -530,7 +532,7 @@ TEST_F(FuseMessagePipeTest, FuseAfterPeerWriteAndClosure) { WriteMessage(a, kTestMessage); EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a)); - EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c)); + EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(b, c, nullptr)); // Handles b and c should be closed. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(b)); diff --git a/chromium/mojo/edk/system/message_unittest.cc b/chromium/mojo/edk/system/message_unittest.cc index 8a3df875e8a..b493bad3166 100644 --- a/chromium/mojo/edk/system/message_unittest.cc +++ b/chromium/mojo/edk/system/message_unittest.cc @@ -193,15 +193,14 @@ TEST_F(MessageTest, SendLocalMessageWithContext) { MojoHandle a, b; CreateMessagePipe(&a, &b); - EXPECT_EQ(MOJO_RESULT_OK, - MojoWriteMessage( - a, TestMessageBase::MakeMessageHandle(std::move(message)), - MOJO_WRITE_MESSAGE_FLAG_NONE)); + EXPECT_EQ( + MOJO_RESULT_OK, + MojoWriteMessage( + a, TestMessageBase::MakeMessageHandle(std::move(message)), nullptr)); EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(b, MOJO_HANDLE_SIGNAL_READABLE)); MojoMessageHandle read_message_handle; - EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(b, &read_message_handle, - MOJO_READ_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(b, nullptr, &read_message_handle)); message = TestMessageBase::UnwrapMessageHandle<NeverSerializedMessage>( &read_message_handle); EXPECT_EQ(original_message, message.get()); @@ -240,7 +239,7 @@ TEST_F(MessageTest, SerializeSimpleMessageNoHandlesWithContext) { RunTestClient("ReceiveMessageNoHandles", [&](MojoHandle h) { auto message = std::make_unique<SimpleMessage>(kTestMessageWithContext1); MojoWriteMessage(h, TestMessageBase::MakeMessageHandle(std::move(message)), - MOJO_WRITE_MESSAGE_FLAG_NONE); + nullptr); }); } @@ -264,7 +263,7 @@ TEST_F(MessageTest, SerializeDynamicallySizedMessage) { memcpy(buffer, kTestMessageWithContext1, sizeof(kTestMessageWithContext1) - 1); - MojoWriteMessage(h, message, MOJO_WRITE_MESSAGE_FLAG_NONE); + MojoWriteMessage(h, message, nullptr); }); } @@ -282,7 +281,7 @@ TEST_F(MessageTest, SerializeSimpleMessageOneHandleWithContext) { mojo::MessagePipe pipe; message->AddMessagePipe(std::move(pipe.handle0)); MojoWriteMessage(h, TestMessageBase::MakeMessageHandle(std::move(message)), - MOJO_WRITE_MESSAGE_FLAG_NONE); + nullptr); EXPECT_EQ(kTestMessageWithContext2, MojoTestBase::ReadMessage(pipe.handle1.get().value())); }); @@ -308,7 +307,7 @@ TEST_F(MessageTest, SerializeSimpleMessageWithHandlesWithContext) { message->AddMessagePipe(std::move(pipes[2].handle0)); message->AddMessagePipe(std::move(pipes[3].handle0)); MojoWriteMessage(h, TestMessageBase::MakeMessageHandle(std::move(message)), - MOJO_WRITE_MESSAGE_FLAG_NONE); + nullptr); EXPECT_EQ(kTestMessageWithContext1, MojoTestBase::ReadMessage(pipes[0].handle1.get().value())); EXPECT_EQ(kTestMessageWithContext2, @@ -337,15 +336,14 @@ TEST_F(MessageTest, SendLocalSimpleMessageWithHandlesWithContext) { MojoHandle a, b; CreateMessagePipe(&a, &b); - EXPECT_EQ(MOJO_RESULT_OK, - MojoWriteMessage( - a, TestMessageBase::MakeMessageHandle(std::move(message)), - MOJO_WRITE_MESSAGE_FLAG_NONE)); + EXPECT_EQ( + MOJO_RESULT_OK, + MojoWriteMessage( + a, TestMessageBase::MakeMessageHandle(std::move(message)), nullptr)); EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(b, MOJO_HANDLE_SIGNAL_READABLE)); MojoMessageHandle read_message_handle; - EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(b, &read_message_handle, - MOJO_READ_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(b, nullptr, &read_message_handle)); message = TestMessageBase::UnwrapMessageHandle<SimpleMessage>(&read_message_handle); EXPECT_EQ(original_message, message.get()); @@ -373,10 +371,10 @@ TEST_F(MessageTest, DropUnreadLocalMessageWithContext) { message->AddMessagePipe(std::move(pipe.handle0)); MojoHandle a, b; CreateMessagePipe(&a, &b); - EXPECT_EQ(MOJO_RESULT_OK, - MojoWriteMessage( - a, TestMessageBase::MakeMessageHandle(std::move(message)), - MOJO_WRITE_MESSAGE_FLAG_NONE)); + EXPECT_EQ( + MOJO_RESULT_OK, + MojoWriteMessage( + a, TestMessageBase::MakeMessageHandle(std::move(message)), nullptr)); MojoClose(a); MojoClose(b); @@ -441,15 +439,14 @@ TEST_F(MessageTest, ReadMessageWithContextAsSerializedMessage) { MojoHandle a, b; CreateMessagePipe(&a, &b); - EXPECT_EQ(MOJO_RESULT_OK, - MojoWriteMessage( - a, TestMessageBase::MakeMessageHandle(std::move(message)), - MOJO_WRITE_MESSAGE_FLAG_NONE)); + EXPECT_EQ( + MOJO_RESULT_OK, + MojoWriteMessage( + a, TestMessageBase::MakeMessageHandle(std::move(message)), nullptr)); EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(b, MOJO_HANDLE_SIGNAL_READABLE)); MojoMessageHandle message_handle; - EXPECT_EQ(MOJO_RESULT_OK, - MojoReadMessage(b, &message_handle, MOJO_READ_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(b, nullptr, &message_handle)); EXPECT_FALSE(message_was_destroyed); // Not a serialized message, so we can't get serialized contents. @@ -475,8 +472,7 @@ TEST_F(MessageTest, ReadSerializedMessageAsMessageWithContext) { EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(b, MOJO_HANDLE_SIGNAL_READABLE)); MojoMessageHandle message_handle; - EXPECT_EQ(MOJO_RESULT_OK, - MojoReadMessage(b, &message_handle, MOJO_READ_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoReadMessage(b, nullptr, &message_handle)); uintptr_t context; EXPECT_EQ(MOJO_RESULT_NOT_FOUND, MojoGetMessageContext(message_handle, nullptr, &context)); @@ -569,13 +565,11 @@ TEST_F(MessageTest, DoubleSerialize) { // message object from a pipe. MessagePipe pipe; EXPECT_EQ(MOJO_RESULT_OK, - MojoWriteMessage(pipe.handle0->value(), message_handle, - MOJO_WRITE_MESSAGE_FLAG_NONE)); + MojoWriteMessage(pipe.handle0->value(), message_handle, nullptr)); EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(pipe.handle1->value(), MOJO_HANDLE_SIGNAL_READABLE)); EXPECT_EQ(MOJO_RESULT_OK, - MojoReadMessage(pipe.handle1->value(), &message_handle, - MOJO_READ_MESSAGE_FLAG_NONE)); + MojoReadMessage(pipe.handle1->value(), nullptr, &message_handle)); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, MojoSerializeMessage(message_handle, nullptr)); @@ -822,9 +816,9 @@ TEST_F(MessageTest, ExtendPayloadWithHandlesAttached) { MojoHandle handles[5]; CreateMessagePipe(&handles[0], &handles[1]); PlatformChannelPair channel; - ASSERT_EQ(MOJO_RESULT_OK, CreatePlatformHandleWrapper( + ASSERT_EQ(MOJO_RESULT_OK, CreateInternalPlatformHandleWrapper( channel.PassServerHandle(), &handles[2])); - ASSERT_EQ(MOJO_RESULT_OK, CreatePlatformHandleWrapper( + ASSERT_EQ(MOJO_RESULT_OK, CreateInternalPlatformHandleWrapper( channel.PassClientHandle(), &handles[3])); handles[4] = SharedBufferHandle::Create(64).release().value(); @@ -854,8 +848,7 @@ TEST_F(MessageTest, ExtendPayloadWithHandlesAttached) { // Send the message out of process to exercise the regression path where // internally cached, stale payload pointers may be dereferenced and written // into. - EXPECT_EQ(MOJO_RESULT_OK, - MojoWriteMessage(h, message, MOJO_WRITE_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWriteMessage(h, message, nullptr)); }); } @@ -872,9 +865,9 @@ TEST_F(MessageTest, ExtendPayloadWithHandlesAttachedViaExtension) { MojoHandle handles[5]; CreateMessagePipe(&handles[0], &handles[4]); PlatformChannelPair channel; - ASSERT_EQ(MOJO_RESULT_OK, CreatePlatformHandleWrapper( + ASSERT_EQ(MOJO_RESULT_OK, CreateInternalPlatformHandleWrapper( channel.PassServerHandle(), &handles[1])); - ASSERT_EQ(MOJO_RESULT_OK, CreatePlatformHandleWrapper( + ASSERT_EQ(MOJO_RESULT_OK, CreateInternalPlatformHandleWrapper( channel.PassClientHandle(), &handles[2])); handles[3] = SharedBufferHandle::Create(64).release().value(); @@ -904,8 +897,7 @@ TEST_F(MessageTest, ExtendPayloadWithHandlesAttachedViaExtension) { // Send the message out of process to exercise the regression path where // internally cached, stale payload pointers may be dereferenced and written // into. - EXPECT_EQ(MOJO_RESULT_OK, - MojoWriteMessage(h, message, MOJO_WRITE_MESSAGE_FLAG_NONE)); + EXPECT_EQ(MOJO_RESULT_OK, MojoWriteMessage(h, message, nullptr)); }); } diff --git a/chromium/mojo/edk/system/multiprocess_message_pipe_unittest.cc b/chromium/mojo/edk/system/multiprocess_message_pipe_unittest.cc index c9a00de91d3..946a21a53b2 100644 --- a/chromium/mojo/edk/system/multiprocess_message_pipe_unittest.cc +++ b/chromium/mojo/edk/system/multiprocess_message_pipe_unittest.cc @@ -284,9 +284,7 @@ DEFINE_TEST_CLIENT_WITH_PIPE(CheckSharedBuffer, // Make a mapping. void* buffer; - CHECK_EQ(MojoMapBuffer(handles[0], 0, 100, &buffer, - MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE), - MOJO_RESULT_OK); + CHECK_EQ(MojoMapBuffer(handles[0], 0, 100, nullptr, &buffer), MOJO_RESULT_OK); // Write some stuff to the shared buffer. static const char kHello[] = "hello"; @@ -333,16 +331,16 @@ TEST_F(MultiprocessMessagePipeTest, SharedBufferPassing) { // Make a shared buffer. MojoCreateSharedBufferOptions options; options.struct_size = sizeof(options); - options.flags = MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE; + options.flags = MOJO_CREATE_SHARED_BUFFER_FLAG_NONE; MojoHandle shared_buffer; ASSERT_EQ(MOJO_RESULT_OK, - MojoCreateSharedBuffer(&options, 100, &shared_buffer)); + MojoCreateSharedBuffer(100, &options, &shared_buffer)); MojoSharedBufferInfo buffer_info; buffer_info.struct_size = sizeof(buffer_info); ASSERT_EQ(MOJO_RESULT_OK, MojoGetBufferInfo(shared_buffer, nullptr, &buffer_info)); - EXPECT_EQ(100U, buffer_info.size); + EXPECT_GE(buffer_info.size, 100U); // Send the shared buffer. const std::string go1("go 1"); @@ -354,7 +352,7 @@ TEST_F(MultiprocessMessagePipeTest, SharedBufferPassing) { buffer_info.size = 0; ASSERT_EQ(MOJO_RESULT_OK, MojoGetBufferInfo(shared_buffer, nullptr, &buffer_info)); - EXPECT_EQ(100U, buffer_info.size); + EXPECT_GE(buffer_info.size, 100U); MojoHandle handles[1]; handles[0] = duplicated_shared_buffer; ASSERT_EQ(MOJO_RESULT_OK, @@ -381,8 +379,7 @@ TEST_F(MultiprocessMessagePipeTest, SharedBufferPassing) { // buffer. static const char kHello[] = "hello"; void* buffer; - CHECK_EQ(MojoMapBuffer(shared_buffer, 0, 100, &buffer, - MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE), + CHECK_EQ(MojoMapBuffer(shared_buffer, 0, 100, nullptr, &buffer), MOJO_RESULT_OK); ASSERT_EQ(0, memcmp(buffer, kHello, sizeof(kHello))); @@ -405,7 +402,7 @@ TEST_F(MultiprocessMessagePipeTest, SharedBufferPassing) { }); } -DEFINE_TEST_CLIENT_WITH_PIPE(CheckPlatformHandleFile, +DEFINE_TEST_CLIENT_WITH_PIPE(CheckInternalPlatformHandleFile, MultiprocessMessagePipeTest, h) { HandleSignalsState hss; @@ -434,12 +431,13 @@ DEFINE_TEST_CLIENT_WITH_PIPE(CheckPlatformHandleFile, CHECK_GT(num_handles, 0); for (int i = 0; i < num_handles; ++i) { - ScopedPlatformHandle h; - CHECK_EQ(PassWrappedPlatformHandle(handles[i], &h), MOJO_RESULT_OK); + ScopedInternalPlatformHandle h; + CHECK_EQ(PassWrappedInternalPlatformHandle(handles[i], &h), MOJO_RESULT_OK); CHECK(h.is_valid()); MojoClose(handles[i]); - base::ScopedFILE fp(test::FILEFromPlatformHandle(std::move(h), "r")); + base::ScopedFILE fp( + test::FILEFromInternalPlatformHandle(std::move(h), "r")); CHECK(fp); std::string fread_buffer(100, '\0'); size_t bytes_read = @@ -455,11 +453,12 @@ class MultiprocessMessagePipeTestWithPipeCount : public MultiprocessMessagePipeTest, public testing::WithParamInterface<size_t> {}; -TEST_P(MultiprocessMessagePipeTestWithPipeCount, PlatformHandlePassing) { +TEST_P(MultiprocessMessagePipeTestWithPipeCount, + InternalPlatformHandlePassing) { base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - RunTestClient("CheckPlatformHandleFile", [&](MojoHandle h) { + RunTestClient("CheckInternalPlatformHandleFile", [&](MojoHandle h) { std::vector<MojoHandle> handles; size_t pipe_count = GetParam(); @@ -472,11 +471,11 @@ TEST_P(MultiprocessMessagePipeTestWithPipeCount, PlatformHandlePassing) { fflush(fp.get()); rewind(fp.get()); MojoHandle handle; - ASSERT_EQ( - CreatePlatformHandleWrapper( - ScopedPlatformHandle(test::PlatformHandleFromFILE(std::move(fp))), - &handle), - MOJO_RESULT_OK); + ASSERT_EQ(CreateInternalPlatformHandleWrapper( + ScopedInternalPlatformHandle( + test::InternalPlatformHandleFromFILE(std::move(fp))), + &handle), + MOJO_RESULT_OK); handles.push_back(handle); } @@ -561,7 +560,7 @@ TEST_P(MultiprocessMessagePipeTestWithPeerSupport, MessagePipePassing) { RunTestClient("CheckMessagePipe", [&](MojoHandle h) { MojoCreateSharedBufferOptions options; options.struct_size = sizeof(options); - options.flags = MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE; + options.flags = MOJO_CREATE_SHARED_BUFFER_FLAG_NONE; MojoHandle mp1, mp2; ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &mp1, &mp2)); @@ -679,7 +678,7 @@ TEST_F(MultiprocessMessagePipeTest, DataPipeConsumer) { RunTestClient("DataPipeConsumer", [&](MojoHandle h) { MojoCreateSharedBufferOptions options; options.struct_size = sizeof(options); - options.flags = MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE; + options.flags = MOJO_CREATE_SHARED_BUFFER_FLAG_NONE; MojoHandle mp1, mp2; ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &mp2, &mp1)); @@ -1374,20 +1373,21 @@ TEST_F(MultiprocessMessagePipeTest, NotifyBadMessage) { // Read a message from the pipe we sent to child1 and flag it as bad. ASSERT_EQ(MOJO_RESULT_OK, WaitForSignals(a, MOJO_HANDLE_SIGNAL_READABLE)); MojoMessageHandle message; - ASSERT_EQ(MOJO_RESULT_OK, - ::MojoReadMessage(a, &message, MOJO_READ_MESSAGE_FLAG_NONE)); + ASSERT_EQ(MOJO_RESULT_OK, ::MojoReadMessage(a, nullptr, &message)); EXPECT_EQ(MOJO_RESULT_OK, - MojoNotifyBadMessage(message, kFirstErrorMessage.data(), - kFirstErrorMessage.size())); + MojoNotifyBadMessage( + message, kFirstErrorMessage.data(), + static_cast<uint32_t>(kFirstErrorMessage.size()), nullptr)); EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message)); // Read a message from the pipe we sent to child2 and flag it as bad. ASSERT_EQ(MOJO_RESULT_OK, WaitForSignals(c, MOJO_HANDLE_SIGNAL_READABLE)); - ASSERT_EQ(MOJO_RESULT_OK, - ::MojoReadMessage(c, &message, MOJO_READ_MESSAGE_FLAG_NONE)); - EXPECT_EQ(MOJO_RESULT_OK, - MojoNotifyBadMessage(message, kSecondErrorMessage.data(), - kSecondErrorMessage.size())); + ASSERT_EQ(MOJO_RESULT_OK, ::MojoReadMessage(c, nullptr, &message)); + EXPECT_EQ( + MOJO_RESULT_OK, + MojoNotifyBadMessage( + message, kSecondErrorMessage.data(), + static_cast<uint32_t>(kSecondErrorMessage.size()), nullptr)); EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message)); WriteMessage(child2, "bye"); diff --git a/chromium/mojo/edk/system/node_channel.cc b/chromium/mojo/edk/system/node_channel.cc index 70312f5d322..f2e4ade4298 100644 --- a/chromium/mojo/edk/system/node_channel.cc +++ b/chromium/mojo/edk/system/node_channel.cc @@ -232,41 +232,24 @@ void NodeChannel::NotifyBadMessage(const std::string& error) { process_error_callback_.Run("Received bad user message: " + error); } -void NodeChannel::SetRemoteProcessHandle(base::ProcessHandle process_handle) { +void NodeChannel::SetRemoteProcessHandle(ScopedProcessHandle process_handle) { DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); base::AutoLock lock(remote_process_handle_lock_); - DCHECK_EQ(base::kNullProcessHandle, remote_process_handle_); - CHECK_NE(remote_process_handle_, base::GetCurrentProcessHandle()); - remote_process_handle_ = process_handle; -#if defined(OS_WIN) - DCHECK(!scoped_remote_process_handle_.is_valid()); - scoped_remote_process_handle_.reset(PlatformHandle(process_handle)); -#endif + DCHECK(!remote_process_handle_.is_valid()); + CHECK_NE(remote_process_handle_.get(), base::GetCurrentProcessHandle()); + remote_process_handle_ = std::move(process_handle); } bool NodeChannel::HasRemoteProcessHandle() { base::AutoLock lock(remote_process_handle_lock_); - return remote_process_handle_ != base::kNullProcessHandle; + return remote_process_handle_.is_valid(); } -base::ProcessHandle NodeChannel::CopyRemoteProcessHandle() { +ScopedProcessHandle NodeChannel::CloneRemoteProcessHandle() { base::AutoLock lock(remote_process_handle_lock_); -#if defined(OS_WIN) - if (remote_process_handle_ != base::kNullProcessHandle) { - // Privileged nodes use this to pass their invitees' process handles to the - // broker on launch. - HANDLE handle = remote_process_handle_; - BOOL result = DuplicateHandle( - base::GetCurrentProcessHandle(), remote_process_handle_, - base::GetCurrentProcessHandle(), &handle, 0, FALSE, - DUPLICATE_SAME_ACCESS); - DPCHECK(result); - return handle; - } - return base::kNullProcessHandle; -#else - return remote_process_handle_; -#endif + if (!remote_process_handle_.is_valid()) + return ScopedProcessHandle(); + return remote_process_handle_.Clone(); } void NodeChannel::SetRemoteNodeName(const ports::NodeName& name) { @@ -307,11 +290,12 @@ void NodeChannel::AcceptPeer(const ports::NodeName& sender_name, } void NodeChannel::AddBrokerClient(const ports::NodeName& client_name, - base::ProcessHandle process_handle) { + ScopedProcessHandle process_handle) { AddBrokerClientData* data; - std::vector<ScopedPlatformHandle> handles; + std::vector<ScopedInternalPlatformHandle> handles; #if defined(OS_WIN) - handles.emplace_back(ScopedPlatformHandle(PlatformHandle(process_handle))); + handles.emplace_back(ScopedInternalPlatformHandle( + InternalPlatformHandle(process_handle.release()))); #endif Channel::MessagePtr message = CreateMessage(MessageType::ADD_BROKER_CLIENT, sizeof(AddBrokerClientData), @@ -319,16 +303,17 @@ void NodeChannel::AddBrokerClient(const ports::NodeName& client_name, message->SetHandles(std::move(handles)); data->client_name = client_name; #if !defined(OS_WIN) - data->process_handle = process_handle; + data->process_handle = process_handle.get(); data->padding = 0; #endif WriteChannelMessage(std::move(message)); } -void NodeChannel::BrokerClientAdded(const ports::NodeName& client_name, - ScopedPlatformHandle broker_channel) { +void NodeChannel::BrokerClientAdded( + const ports::NodeName& client_name, + ScopedInternalPlatformHandle broker_channel) { BrokerClientAddedData* data; - std::vector<ScopedPlatformHandle> handles; + std::vector<ScopedInternalPlatformHandle> handles; if (broker_channel.is_valid()) handles.push_back(std::move(broker_channel)); Channel::MessagePtr message = @@ -339,10 +324,11 @@ void NodeChannel::BrokerClientAdded(const ports::NodeName& client_name, WriteChannelMessage(std::move(message)); } -void NodeChannel::AcceptBrokerClient(const ports::NodeName& broker_name, - ScopedPlatformHandle broker_channel) { +void NodeChannel::AcceptBrokerClient( + const ports::NodeName& broker_name, + ScopedInternalPlatformHandle broker_channel) { AcceptBrokerClientData* data; - std::vector<ScopedPlatformHandle> handles; + std::vector<ScopedInternalPlatformHandle> handles; if (broker_channel.is_valid()) handles.push_back(std::move(broker_channel)); Channel::MessagePtr message = @@ -373,9 +359,9 @@ void NodeChannel::RequestIntroduction(const ports::NodeName& name) { } void NodeChannel::Introduce(const ports::NodeName& name, - ScopedPlatformHandle channel_handle) { + ScopedInternalPlatformHandle channel_handle) { IntroductionData* data; - std::vector<ScopedPlatformHandle> handles; + std::vector<ScopedInternalPlatformHandle> handles; if (channel_handle.is_valid()) handles.push_back(std::move(channel_handle)); Channel::MessagePtr message = CreateMessage( @@ -423,7 +409,7 @@ void NodeChannel::RelayEventMessage(const ports::NodeName& destination, // above stated assumption. We should not leak handles in cases where we // outlive the broker, as we may continue existing and eventually accept a new // broker invitation. - std::vector<ScopedPlatformHandle> handles = message->TakeHandles(); + std::vector<ScopedInternalPlatformHandle> handles = message->TakeHandles(); for (auto& handle : handles) ignore_result(handle.release()); @@ -435,7 +421,7 @@ void NodeChannel::RelayEventMessage(const ports::NodeName& destination, // moves them back to the relayed message. This is necessary because the // message may contain fds which need to be attached to the outer message so // that they can be transferred to the broker. - std::vector<ScopedPlatformHandle> handles = message->TakeHandles(); + std::vector<ScopedInternalPlatformHandle> handles = message->TakeHandles(); size_t num_bytes = sizeof(RelayEventMessageData) + message->data_num_bytes(); RelayEventMessageData* data; Channel::MessagePtr relay_message = CreateMessage( @@ -483,9 +469,10 @@ NodeChannel::~NodeChannel() { ShutDown(); } -void NodeChannel::OnChannelMessage(const void* payload, - size_t payload_size, - std::vector<ScopedPlatformHandle> handles) { +void NodeChannel::OnChannelMessage( + const void* payload, + size_t payload_size, + std::vector<ScopedInternalPlatformHandle> handles) { DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); RequestContext request_context(RequestContext::Source::SYSTEM); @@ -501,14 +488,13 @@ void NodeChannel::OnChannelMessage(const void* payload, // from a privileged descendant. { base::AutoLock lock(remote_process_handle_lock_); - if (!handles.empty() && - remote_process_handle_ != base::kNullProcessHandle) { + if (!handles.empty() && remote_process_handle_.is_valid()) { // Note that we explicitly mark the handles as being owned by the sending // process before rewriting them, in order to accommodate RewriteHandles' // internal sanity checks. for (auto& handle : handles) - handle.get().owning_process = remote_process_handle_; - if (!Channel::Message::RewriteHandles(remote_process_handle_, + handle.get().owning_process = remote_process_handle_.get(); + if (!Channel::Message::RewriteHandles(remote_process_handle_.get(), base::GetCurrentProcessHandle(), &handles)) { DLOG(ERROR) << "Received one or more invalid handles."; @@ -598,7 +584,7 @@ void NodeChannel::OnChannelMessage(const void* payload, case MessageType::ACCEPT_BROKER_CLIENT: { const AcceptBrokerClientData* data; if (GetMessagePayload(payload, payload_size, &data)) { - ScopedPlatformHandle broker_channel; + ScopedInternalPlatformHandle broker_channel; if (handles.size() > 1) { DLOG(ERROR) << "Dropping invalid AcceptBrokerClient message."; break; @@ -653,7 +639,7 @@ void NodeChannel::OnChannelMessage(const void* payload, DLOG(ERROR) << "Dropping invalid introduction message."; break; } - ScopedPlatformHandle channel_handle; + ScopedInternalPlatformHandle channel_handle; if (handles.size() == 1) { channel_handle = std::move(handles.at(0)); } @@ -669,7 +655,10 @@ void NodeChannel::OnChannelMessage(const void* payload, base::ProcessHandle from_process; { base::AutoLock lock(remote_process_handle_lock_); - from_process = remote_process_handle_; + // NOTE: It's safe to retain a weak reference to this process handle + // through the extent of this call because |this| is kept alive and + // |remote_process_handle_| is never reset once set. + from_process = remote_process_handle_.get(); } const RelayEventMessageData* data; if (GetMessagePayload(payload, payload_size, &data)) { @@ -800,7 +789,7 @@ void NodeChannel::ProcessPendingMessagesWithMachPorts() { base::ProcessHandle remote_process_handle; { base::AutoLock lock(remote_process_handle_lock_); - remote_process_handle = remote_process_handle_; + remote_process_handle = remote_process_handle_.get(); } PendingMessageQueue pending_writes; PendingRelayMessageQueue pending_relays; @@ -846,17 +835,15 @@ void NodeChannel::WriteChannelMessage(Channel::MessagePtr message) { // here (they'll be unpacked and duplicated by the broker). if (message->has_handles()) { - base::ProcessHandle remote_process_handle; - { - base::AutoLock lock(remote_process_handle_lock_); - remote_process_handle = remote_process_handle_; - } + base::AutoLock lock(remote_process_handle_lock_); // Rewrite outgoing handles if we have a handle to the destination process. - if (remote_process_handle != base::kNullProcessHandle) { - std::vector<ScopedPlatformHandle> handles = message->TakeHandles(); + if (remote_process_handle_.is_valid()) { + std::vector<ScopedInternalPlatformHandle> handles = + message->TakeHandles(); if (!Channel::Message::RewriteHandles(base::GetCurrentProcessHandle(), - remote_process_handle, &handles)) { + remote_process_handle_.get(), + &handles)) { DLOG(ERROR) << "Failed to duplicate one or more outgoing handles."; } message->SetHandles(std::move(handles)); @@ -868,16 +855,11 @@ void NodeChannel::WriteChannelMessage(Channel::MessagePtr message) { if (message->has_mach_ports()) { MachPortRelay* relay = delegate_->GetMachPortRelay(); if (relay) { - base::ProcessHandle remote_process_handle; - { - base::AutoLock lock(remote_process_handle_lock_); - // Expect that the receiving node is a known process. - DCHECK(remote_process_handle_ != base::kNullProcessHandle); - remote_process_handle = remote_process_handle_; - } + base::AutoLock lock(remote_process_handle_lock_); + DCHECK(remote_process_handle_.is_valid()); { base::AutoLock lock(pending_mach_messages_lock_); - if (relay->port_provider()->TaskForPid(remote_process_handle) == + if (relay->port_provider()->TaskForPid(remote_process_handle_.get()) == MACH_PORT_NULL) { // It is also possible for TaskForPid() to return MACH_PORT_NULL when // the process has started, then died. In that case, the queued @@ -888,7 +870,7 @@ void NodeChannel::WriteChannelMessage(Channel::MessagePtr message) { } } - relay->SendPortsToProcess(message.get(), remote_process_handle); + relay->SendPortsToProcess(message.get(), remote_process_handle_.get()); } } #endif diff --git a/chromium/mojo/edk/system/node_channel.h b/chromium/mojo/edk/system/node_channel.h index 864ed1c45bf..95fd6ed6410 100644 --- a/chromium/mojo/edk/system/node_channel.h +++ b/chromium/mojo/edk/system/node_channel.h @@ -21,6 +21,7 @@ #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/channel.h" #include "mojo/edk/system/ports/name.h" +#include "mojo/edk/system/scoped_process_handle.h" #if defined(OS_MACOSX) && !defined(OS_IOS) #include "mojo/edk/system/mach_port_relay.h" @@ -49,12 +50,14 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>, virtual void OnAddBrokerClient(const ports::NodeName& from_node, const ports::NodeName& client_name, base::ProcessHandle process_handle) = 0; - virtual void OnBrokerClientAdded(const ports::NodeName& from_node, - const ports::NodeName& client_name, - ScopedPlatformHandle broker_channel) = 0; - virtual void OnAcceptBrokerClient(const ports::NodeName& from_node, - const ports::NodeName& broker_name, - ScopedPlatformHandle broker_channel) = 0; + virtual void OnBrokerClientAdded( + const ports::NodeName& from_node, + const ports::NodeName& client_name, + ScopedInternalPlatformHandle broker_channel) = 0; + virtual void OnAcceptBrokerClient( + const ports::NodeName& from_node, + const ports::NodeName& broker_name, + ScopedInternalPlatformHandle broker_channel) = 0; virtual void OnEventMessage(const ports::NodeName& from_node, Channel::MessagePtr message) = 0; virtual void OnRequestPortMerge(const ports::NodeName& from_node, @@ -64,7 +67,7 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>, const ports::NodeName& name) = 0; virtual void OnIntroduce(const ports::NodeName& from_node, const ports::NodeName& name, - ScopedPlatformHandle channel_handle) = 0; + ScopedInternalPlatformHandle channel_handle) = 0; virtual void OnBroadcast(const ports::NodeName& from_node, Channel::MessagePtr message) = 0; #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) @@ -115,12 +118,9 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>, // Invokes the bad message callback for this channel, if any. void NotifyBadMessage(const std::string& error); - // Note: On Windows, we take ownership of the remote process handle. - void SetRemoteProcessHandle(base::ProcessHandle process_handle); + void SetRemoteProcessHandle(ScopedProcessHandle process_handle); bool HasRemoteProcessHandle(); - // Note: The returned |ProcessHandle| is owned by the caller and should be - // freed if necessary. - base::ProcessHandle CopyRemoteProcessHandle(); + ScopedProcessHandle CloneRemoteProcessHandle(); // Used for context in Delegate calls (via |from_node| arguments.) void SetRemoteNodeName(const ports::NodeName& name); @@ -133,16 +133,16 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>, const ports::NodeName& token, const ports::PortName& port_name); void AddBrokerClient(const ports::NodeName& client_name, - base::ProcessHandle process_handle); + ScopedProcessHandle process_handle); void BrokerClientAdded(const ports::NodeName& client_name, - ScopedPlatformHandle broker_channel); + ScopedInternalPlatformHandle broker_channel); void AcceptBrokerClient(const ports::NodeName& broker_name, - ScopedPlatformHandle broker_channel); + ScopedInternalPlatformHandle broker_channel); void RequestPortMerge(const ports::PortName& connector_port_name, const std::string& token); void RequestIntroduction(const ports::NodeName& name); void Introduce(const ports::NodeName& name, - ScopedPlatformHandle channel_handle); + ScopedInternalPlatformHandle channel_handle); void SendChannelMessage(Channel::MessagePtr message); void Broadcast(Channel::MessagePtr message); @@ -175,9 +175,10 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>, ~NodeChannel() override; // Channel::Delegate: - void OnChannelMessage(const void* payload, - size_t payload_size, - std::vector<ScopedPlatformHandle> handles) override; + void OnChannelMessage( + const void* payload, + size_t payload_size, + std::vector<ScopedInternalPlatformHandle> handles) override; void OnChannelError(Channel::Error error) override; #if defined(OS_MACOSX) && !defined(OS_IOS) @@ -200,10 +201,7 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>, ports::NodeName remote_node_name_; base::Lock remote_process_handle_lock_; - base::ProcessHandle remote_process_handle_ = base::kNullProcessHandle; -#if defined(OS_WIN) - ScopedPlatformHandle scoped_remote_process_handle_; -#endif + ScopedProcessHandle remote_process_handle_; #if defined(OS_MACOSX) && !defined(OS_IOS) base::Lock pending_mach_messages_lock_; diff --git a/chromium/mojo/edk/system/node_controller.cc b/chromium/mojo/edk/system/node_controller.cc index b8638a55f08..ee602c46340 100644 --- a/chromium/mojo/edk/system/node_controller.cc +++ b/chromium/mojo/edk/system/node_controller.cc @@ -13,7 +13,7 @@ #include "base/location.h" #include "base/logging.h" #include "base/macros.h" -#include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_current.h" #include "base/metrics/histogram_macros.h" #include "base/process/process_handle.h" #include "base/rand_util.h" @@ -103,8 +103,8 @@ ports::ScopedEvent DeserializeEventMessage( // Used by NodeController to watch for shutdown. Since no IO can happen once // the IO thread is killed, the NodeController can cleanly drop all its peers // at that time. -class ThreadDestructionObserver : - public base::MessageLoop::DestructionObserver { +class ThreadDestructionObserver + : public base::MessageLoopCurrent::DestructionObserver { public: static void Create(scoped_refptr<base::TaskRunner> task_runner, const base::Closure& callback) { @@ -120,14 +120,14 @@ class ThreadDestructionObserver : private: explicit ThreadDestructionObserver(const base::Closure& callback) : callback_(callback) { - base::MessageLoop::current()->AddDestructionObserver(this); + base::MessageLoopCurrent::Get()->AddDestructionObserver(this); } ~ThreadDestructionObserver() override { - base::MessageLoop::current()->RemoveDestructionObserver(this); + base::MessageLoopCurrent::Get()->RemoveDestructionObserver(this); } - // base::MessageLoop::DestructionObserver: + // base::MessageLoopCurrent::DestructionObserver: void WillDestroyCurrentMessageLoop() override { callback_.Run(); delete this; @@ -185,22 +185,12 @@ void NodeController::SendBrokerClientInvitation( } } -#if defined(OS_WIN) - // On Windows, we need to duplicate the process handle because we have no - // control over its lifetime and it may become invalid by the time the posted - // task runs. - HANDLE dup_handle = INVALID_HANDLE_VALUE; - BOOL ok = ::DuplicateHandle(base::GetCurrentProcessHandle(), target_process, - base::GetCurrentProcessHandle(), &dup_handle, 0, - FALSE, DUPLICATE_SAME_ACCESS); - DPCHECK(ok); - target_process = dup_handle; -#endif - + ScopedProcessHandle scoped_target_process = + ScopedProcessHandle::CloneFrom(target_process); io_task_runner_->PostTask( FROM_HERE, base::BindOnce(&NodeController::SendBrokerClientInvitationOnIOThread, - base::Unretained(this), target_process, + base::Unretained(this), std::move(scoped_target_process), std::move(connection_params), temporary_node_name, process_error_callback)); } @@ -213,7 +203,8 @@ void NodeController::AcceptBrokerClientInvitation( // synchronously as the first message from the broker. base::ElapsedTimer timer; broker_.reset(new Broker(connection_params.TakeChannelHandle())); - ScopedPlatformHandle platform_handle = broker_->GetInviterPlatformHandle(); + ScopedInternalPlatformHandle platform_handle = + broker_->GetInviterInternalPlatformHandle(); if (!platform_handle.is_valid()) { // Most likely the inviter's side of the channel has already been closed and @@ -303,15 +294,15 @@ int NodeController::MergeLocalPorts(const ports::PortRef& port0, return node_->MergeLocalPorts(port0, port1); } -scoped_refptr<PlatformSharedBuffer> NodeController::CreateSharedBuffer( +base::WritableSharedMemoryRegion NodeController::CreateSharedBuffer( size_t num_bytes) { #if !defined(OS_MACOSX) && !defined(OS_NACL_SFI) && !defined(OS_FUCHSIA) // Shared buffer creation failure is fatal, so always use the broker when we // have one; unless of course the embedder forces us not to. if (!GetConfiguration().force_direct_shared_memory_allocation && broker_) - return broker_->GetSharedBuffer(num_bytes); + return broker_->GetWritableSharedMemoryRegion(num_bytes); #endif - return PlatformSharedBuffer::Create(num_bytes); + return base::WritableSharedMemoryRegion::Create(num_bytes); } void NodeController::RequestShutdown(const base::Closure& callback) { @@ -332,7 +323,7 @@ void NodeController::NotifyBadMessageFrom(const ports::NodeName& source_node, } void NodeController::SendBrokerClientInvitationOnIOThread( - base::ProcessHandle target_process, + ScopedProcessHandle target_process, ConnectionParams connection_params, ports::NodeName temporary_node_name, const ProcessErrorCallback& process_error_callback) { @@ -340,11 +331,11 @@ void NodeController::SendBrokerClientInvitationOnIOThread( #if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_FUCHSIA) PlatformChannelPair node_channel; - ScopedPlatformHandle server_handle = node_channel.PassServerHandle(); + ScopedInternalPlatformHandle server_handle = node_channel.PassServerHandle(); // BrokerHost owns itself. - BrokerHost* broker_host = - new BrokerHost(target_process, connection_params.TakeChannelHandle(), - process_error_callback); + BrokerHost* broker_host = new BrokerHost( + target_process.get(), connection_params.TakeChannelHandle(), + process_error_callback); bool channel_ok = broker_host->SendChannel(node_channel.PassClientHandle()); #if defined(OS_WIN) @@ -378,7 +369,7 @@ void NodeController::SendBrokerClientInvitationOnIOThread( pending_invitations_.insert(std::make_pair(temporary_node_name, channel)); channel->SetRemoteNodeName(temporary_node_name); - channel->SetRemoteProcessHandle(target_process); + channel->SetRemoteProcessHandle(std::move(target_process)); channel->Start(); channel->AcceptInvitee(name_, temporary_node_name); @@ -796,7 +787,7 @@ void NodeController::OnAcceptInvitation(const ports::NodeName& from_node, scoped_refptr<NodeChannel> broker = GetBrokerChannel(); if (broker) { // Inform the broker of this new client. - broker->AddBrokerClient(invitee_name, channel->CopyRemoteProcessHandle()); + broker->AddBrokerClient(invitee_name, channel->CloneRemoteProcessHandle()); } else { // If we have no broker, either we need to wait for one, or we *are* the // broker. @@ -808,7 +799,7 @@ void NodeController::OnAcceptInvitation(const ports::NodeName& from_node, if (!inviter) { // Yes, we're the broker. We can initialize the client directly. - channel->AcceptBrokerClient(name_, ScopedPlatformHandle()); + channel->AcceptBrokerClient(name_, ScopedInternalPlatformHandle()); } else { // We aren't the broker, so wait for a broker connection. base::AutoLock lock(broker_lock_); @@ -820,11 +811,8 @@ void NodeController::OnAcceptInvitation(const ports::NodeName& from_node, void NodeController::OnAddBrokerClient(const ports::NodeName& from_node, const ports::NodeName& client_name, base::ProcessHandle process_handle) { -#if defined(OS_WIN) - // Scoped handle to avoid leaks on error. - ScopedPlatformHandle scoped_process_handle = - ScopedPlatformHandle(PlatformHandle(process_handle)); -#endif + ScopedProcessHandle scoped_process_handle(process_handle); + scoped_refptr<NodeChannel> sender = GetPeerChannel(from_node); if (!sender) { DLOG(ERROR) << "Ignoring AddBrokerClient from unknown sender."; @@ -851,10 +839,8 @@ void NodeController::OnAddBrokerClient(const ports::NodeName& from_node, DLOG(ERROR) << "Broker rejecting client with invalid process handle."; return; } - client->SetRemoteProcessHandle(scoped_process_handle.release().handle); -#else - client->SetRemoteProcessHandle(process_handle); #endif + client->SetRemoteProcessHandle(std::move(scoped_process_handle)); AddPeer(client_name, client, true /* start_channel */); @@ -864,9 +850,10 @@ void NodeController::OnAddBrokerClient(const ports::NodeName& from_node, sender->BrokerClientAdded(client_name, broker_channel.PassClientHandle()); } -void NodeController::OnBrokerClientAdded(const ports::NodeName& from_node, - const ports::NodeName& client_name, - ScopedPlatformHandle broker_channel) { +void NodeController::OnBrokerClientAdded( + const ports::NodeName& from_node, + const ports::NodeName& client_name, + ScopedInternalPlatformHandle broker_channel) { scoped_refptr<NodeChannel> client = GetPeerChannel(client_name); if (!client) { DLOG(ERROR) << "BrokerClientAdded for unknown client " << client_name; @@ -884,9 +871,10 @@ void NodeController::OnBrokerClientAdded(const ports::NodeName& from_node, client->AcceptBrokerClient(from_node, std::move(broker_channel)); } -void NodeController::OnAcceptBrokerClient(const ports::NodeName& from_node, - const ports::NodeName& broker_name, - ScopedPlatformHandle broker_channel) { +void NodeController::OnAcceptBrokerClient( + const ports::NodeName& from_node, + const ports::NodeName& broker_name, + ScopedInternalPlatformHandle broker_channel) { DCHECK(!GetConfiguration().is_broker_process); // This node should already have an inviter in bootstrap mode. @@ -941,9 +929,13 @@ void NodeController::OnAcceptBrokerClient(const ports::NodeName& from_node, while (!pending_broker_clients.empty()) { const ports::NodeName& invitee_name = pending_broker_clients.front(); auto it = pending_invitations_.find(invitee_name); - DCHECK(it != pending_invitations_.end()); - broker->AddBrokerClient(invitee_name, - it->second->CopyRemoteProcessHandle()); + // If for any reason we don't have a pending invitation for the invitee, + // there's nothing left to do: we've already swapped the relevant state into + // the stack. + if (it != pending_invitations_.end()) { + broker->AddBrokerClient(invitee_name, + it->second->CloneRemoteProcessHandle()); + } pending_broker_clients.pop(); } @@ -992,6 +984,11 @@ void NodeController::OnRequestPortMerge( { base::AutoLock lock(reserved_ports_lock_); auto it = reserved_ports_.find(from_node); + // TODO(https://crbug.com/822034): We should send a notification back to the + // requestor so they can clean up their dangling port in this failure case. + // This requires changes to the internal protocol, which can't be made yet. + // Until this is done, pipes from |MojoExtractMessagePipeFromInvitation()| + // will never break if the given name was invalid. if (it == reserved_ports_.end()) { DVLOG(1) << "Ignoring port merge request from node " << from_node << ". " << "No ports reserved for that node."; @@ -1031,7 +1028,7 @@ void NodeController::OnRequestIntroduction(const ports::NodeName& from_node, scoped_refptr<NodeChannel> new_friend = GetPeerChannel(name); if (!new_friend) { // We don't know who they're talking about! - requestor->Introduce(name, ScopedPlatformHandle()); + requestor->Introduce(name, ScopedInternalPlatformHandle()); } else { PlatformChannelPair new_channel; requestor->Introduce(name, new_channel.PassServerHandle()); @@ -1041,7 +1038,7 @@ void NodeController::OnRequestIntroduction(const ports::NodeName& from_node, void NodeController::OnIntroduce(const ports::NodeName& from_node, const ports::NodeName& name, - ScopedPlatformHandle channel_handle) { + ScopedInternalPlatformHandle channel_handle) { DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); if (!channel_handle.is_valid()) { @@ -1118,7 +1115,7 @@ void NodeController::OnRelayEventMessage(const ports::NodeName& from_node, // Note that we explicitly mark the handles as being owned by the sending // process before rewriting them, in order to accommodate RewriteHandles' // internal sanity checks. - std::vector<ScopedPlatformHandle> handles = message->TakeHandles(); + std::vector<ScopedInternalPlatformHandle> handles = message->TakeHandles(); for (auto& handle : handles) handle.get().owning_process = from_process; if (!Channel::Message::RewriteHandles( @@ -1127,12 +1124,12 @@ void NodeController::OnRelayEventMessage(const ports::NodeName& from_node, } message->SetHandles(std::move(handles)); #else - std::vector<ScopedPlatformHandle> handles = message->TakeHandles(); + std::vector<ScopedInternalPlatformHandle> handles = message->TakeHandles(); for (auto& handle : handles) { - if (handle.get().type == PlatformHandle::Type::MACH_NAME) { + if (handle.get().type == InternalPlatformHandle::Type::MACH_NAME) { MachPortRelay* relay = GetMachPortRelay(); if (!relay) { - handle.get().type = PlatformHandle::Type::MACH; + handle.get().type = InternalPlatformHandle::Type::MACH; handle.get().port = MACH_PORT_NULL; DLOG(ERROR) << "Receiving Mach ports without a port relay from " << from_node << "."; diff --git a/chromium/mojo/edk/system/node_controller.h b/chromium/mojo/edk/system/node_controller.h index 853442da197..e6ccd428aa8 100644 --- a/chromium/mojo/edk/system/node_controller.h +++ b/chromium/mojo/edk/system/node_controller.h @@ -18,9 +18,9 @@ #include "base/containers/queue.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/writable_shared_memory_region.h" #include "base/task_runner.h" #include "build/build_config.h" -#include "mojo/edk/embedder/platform_shared_buffer.h" #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/atomic_flag.h" #include "mojo/edk/system/node_channel.h" @@ -28,6 +28,7 @@ #include "mojo/edk/system/ports/name.h" #include "mojo/edk/system/ports/node.h" #include "mojo/edk/system/ports/node_delegate.h" +#include "mojo/edk/system/scoped_process_handle.h" #include "mojo/edk/system/system_impl_export.h" namespace base { @@ -116,7 +117,7 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate, int MergeLocalPorts(const ports::PortRef& port0, const ports::PortRef& port1); // Creates a new shared buffer for use in the current process. - scoped_refptr<PlatformSharedBuffer> CreateSharedBuffer(size_t num_bytes); + base::WritableSharedMemoryRegion CreateSharedBuffer(size_t num_bytes); // Request that the Node be shut down cleanly. This may take an arbitrarily // long time to complete, at which point |callback| will be called. @@ -159,7 +160,7 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate, }; void SendBrokerClientInvitationOnIOThread( - base::ProcessHandle target_process, + ScopedProcessHandle target_process, ConnectionParams connection_params, ports::NodeName token, const ProcessErrorCallback& process_error_callback); @@ -198,12 +199,14 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate, void OnAddBrokerClient(const ports::NodeName& from_node, const ports::NodeName& client_name, base::ProcessHandle process_handle) override; - void OnBrokerClientAdded(const ports::NodeName& from_node, - const ports::NodeName& client_name, - ScopedPlatformHandle broker_channel) override; - void OnAcceptBrokerClient(const ports::NodeName& from_node, - const ports::NodeName& broker_name, - ScopedPlatformHandle broker_channel) override; + void OnBrokerClientAdded( + const ports::NodeName& from_node, + const ports::NodeName& client_name, + ScopedInternalPlatformHandle broker_channel) override; + void OnAcceptBrokerClient( + const ports::NodeName& from_node, + const ports::NodeName& broker_name, + ScopedInternalPlatformHandle broker_channel) override; void OnEventMessage(const ports::NodeName& from_node, Channel::MessagePtr message) override; void OnRequestPortMerge(const ports::NodeName& from_node, @@ -213,7 +216,7 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate, const ports::NodeName& name) override; void OnIntroduce(const ports::NodeName& from_node, const ports::NodeName& name, - ScopedPlatformHandle channel_handle) override; + ScopedInternalPlatformHandle channel_handle) override; void OnBroadcast(const ports::NodeName& from_node, Channel::MessagePtr message) override; #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) diff --git a/chromium/mojo/edk/system/platform_handle_dispatcher.cc b/chromium/mojo/edk/system/platform_handle_dispatcher.cc index 02df31f3bcd..19b1ed3fb19 100644 --- a/chromium/mojo/edk/system/platform_handle_dispatcher.cc +++ b/chromium/mojo/edk/system/platform_handle_dispatcher.cc @@ -12,11 +12,12 @@ namespace edk { // static scoped_refptr<PlatformHandleDispatcher> PlatformHandleDispatcher::Create( - ScopedPlatformHandle platform_handle) { + ScopedInternalPlatformHandle platform_handle) { return new PlatformHandleDispatcher(std::move(platform_handle)); } -ScopedPlatformHandle PlatformHandleDispatcher::PassPlatformHandle() { +ScopedInternalPlatformHandle +PlatformHandleDispatcher::PassInternalPlatformHandle() { return std::move(platform_handle_); } @@ -41,13 +42,14 @@ void PlatformHandleDispatcher::StartSerialize(uint32_t* num_bytes, *num_handles = 1; } -bool PlatformHandleDispatcher::EndSerialize(void* destination, - ports::PortName* ports, - ScopedPlatformHandle* handles) { +bool PlatformHandleDispatcher::EndSerialize( + void* destination, + ports::PortName* ports, + ScopedInternalPlatformHandle* handles) { base::AutoLock lock(lock_); if (is_closed_) return false; - handles[0] = ScopedPlatformHandle(platform_handle_.get()); + handles[0] = ScopedInternalPlatformHandle(platform_handle_.get()); return true; } @@ -80,7 +82,7 @@ scoped_refptr<PlatformHandleDispatcher> PlatformHandleDispatcher::Deserialize( size_t num_bytes, const ports::PortName* ports, size_t num_ports, - ScopedPlatformHandle* handles, + ScopedInternalPlatformHandle* handles, size_t num_handles) { if (num_bytes || num_ports || num_handles != 1) return nullptr; @@ -89,7 +91,7 @@ scoped_refptr<PlatformHandleDispatcher> PlatformHandleDispatcher::Deserialize( } PlatformHandleDispatcher::PlatformHandleDispatcher( - ScopedPlatformHandle platform_handle) + ScopedInternalPlatformHandle platform_handle) : platform_handle_(std::move(platform_handle)) {} PlatformHandleDispatcher::~PlatformHandleDispatcher() { diff --git a/chromium/mojo/edk/system/platform_handle_dispatcher.h b/chromium/mojo/edk/system/platform_handle_dispatcher.h index e13c79a1a43..8a377e47fa7 100644 --- a/chromium/mojo/edk/system/platform_handle_dispatcher.h +++ b/chromium/mojo/edk/system/platform_handle_dispatcher.h @@ -18,9 +18,9 @@ namespace edk { class MOJO_SYSTEM_IMPL_EXPORT PlatformHandleDispatcher : public Dispatcher { public: static scoped_refptr<PlatformHandleDispatcher> Create( - ScopedPlatformHandle platform_handle); + ScopedInternalPlatformHandle platform_handle); - ScopedPlatformHandle PassPlatformHandle(); + ScopedInternalPlatformHandle PassInternalPlatformHandle(); // Dispatcher: Type GetType() const override; @@ -30,7 +30,7 @@ class MOJO_SYSTEM_IMPL_EXPORT PlatformHandleDispatcher : public Dispatcher { uint32_t* num_handles) override; bool EndSerialize(void* destination, ports::PortName* ports, - ScopedPlatformHandle* handles) override; + ScopedInternalPlatformHandle* handles) override; bool BeginTransit() override; void CompleteTransitAndClose() override; void CancelTransit() override; @@ -40,17 +40,17 @@ class MOJO_SYSTEM_IMPL_EXPORT PlatformHandleDispatcher : public Dispatcher { size_t num_bytes, const ports::PortName* ports, size_t num_ports, - ScopedPlatformHandle* handles, + ScopedInternalPlatformHandle* handles, size_t num_handles); private: - PlatformHandleDispatcher(ScopedPlatformHandle platform_handle); + PlatformHandleDispatcher(ScopedInternalPlatformHandle platform_handle); ~PlatformHandleDispatcher() override; base::Lock lock_; bool in_transit_ = false; bool is_closed_ = false; - ScopedPlatformHandle platform_handle_; + ScopedInternalPlatformHandle platform_handle_; DISALLOW_COPY_AND_ASSIGN(PlatformHandleDispatcher); }; diff --git a/chromium/mojo/edk/system/platform_handle_dispatcher_unittest.cc b/chromium/mojo/edk/system/platform_handle_dispatcher_unittest.cc index 5a86decf16f..0313b8fdccf 100644 --- a/chromium/mojo/edk/system/platform_handle_dispatcher_unittest.cc +++ b/chromium/mojo/edk/system/platform_handle_dispatcher_unittest.cc @@ -33,7 +33,8 @@ TEST(PlatformHandleDispatcherTest, Basic) { EXPECT_EQ(sizeof(kHelloWorld), fwrite(kHelloWorld, 1, sizeof(kHelloWorld), fp.get())); - ScopedPlatformHandle h(test::PlatformHandleFromFILE(std::move(fp))); + ScopedInternalPlatformHandle h( + test::InternalPlatformHandleFromFILE(std::move(fp))); EXPECT_FALSE(fp); ASSERT_TRUE(h.is_valid()); @@ -42,10 +43,10 @@ TEST(PlatformHandleDispatcherTest, Basic) { EXPECT_FALSE(h.is_valid()); EXPECT_EQ(Dispatcher::Type::PLATFORM_HANDLE, dispatcher->GetType()); - h = dispatcher->PassPlatformHandle(); + h = dispatcher->PassInternalPlatformHandle(); EXPECT_TRUE(h.is_valid()); - fp = test::FILEFromPlatformHandle(std::move(h), "rb"); + fp = test::FILEFromInternalPlatformHandle(std::move(h), "rb"); EXPECT_FALSE(h.is_valid()); EXPECT_TRUE(fp); @@ -56,7 +57,7 @@ TEST(PlatformHandleDispatcherTest, Basic) { EXPECT_STREQ(kHelloWorld, read_buffer); // Try getting the handle again. (It should fail cleanly.) - h = dispatcher->PassPlatformHandle(); + h = dispatcher->PassInternalPlatformHandle(); EXPECT_FALSE(h.is_valid()); EXPECT_EQ(MOJO_RESULT_OK, dispatcher->Close()); @@ -75,7 +76,7 @@ TEST(PlatformHandleDispatcherTest, Serialization) { scoped_refptr<PlatformHandleDispatcher> dispatcher = PlatformHandleDispatcher::Create( - test::PlatformHandleFromFILE(std::move(fp))); + test::InternalPlatformHandleFromFILE(std::move(fp))); uint32_t num_bytes = 0; uint32_t num_ports = 0; @@ -87,14 +88,15 @@ TEST(PlatformHandleDispatcherTest, Serialization) { EXPECT_EQ(0u, num_ports); EXPECT_EQ(1u, num_handles); - ScopedPlatformHandle received_handle; + ScopedInternalPlatformHandle received_handle; EXPECT_TRUE(dispatcher->EndSerialize(nullptr, nullptr, &received_handle)); dispatcher->CompleteTransitAndClose(); EXPECT_TRUE(received_handle.is_valid()); - ScopedPlatformHandle handle = dispatcher->PassPlatformHandle(); + ScopedInternalPlatformHandle handle = + dispatcher->PassInternalPlatformHandle(); EXPECT_FALSE(handle.is_valid()); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, dispatcher->Close()); @@ -108,7 +110,8 @@ TEST(PlatformHandleDispatcherTest, Serialization) { EXPECT_FALSE(received_handle.is_valid()); EXPECT_TRUE(dispatcher->GetType() == Dispatcher::Type::PLATFORM_HANDLE); - fp = test::FILEFromPlatformHandle(dispatcher->PassPlatformHandle(), "rb"); + fp = test::FILEFromInternalPlatformHandle( + dispatcher->PassInternalPlatformHandle(), "rb"); EXPECT_TRUE(fp); rewind(fp.get()); diff --git a/chromium/mojo/edk/system/platform_shared_memory_mapping.cc b/chromium/mojo/edk/system/platform_shared_memory_mapping.cc new file mode 100644 index 00000000000..80f14f6546c --- /dev/null +++ b/chromium/mojo/edk/system/platform_shared_memory_mapping.cc @@ -0,0 +1,104 @@ +// 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. + +#include "mojo/edk/system/platform_shared_memory_mapping.h" + +#include <utility> + +#include "base/logging.h" +#include "base/memory/read_only_shared_memory_region.h" +#include "base/memory/unsafe_shared_memory_region.h" +#include "base/memory/writable_shared_memory_region.h" +#include "base/sys_info.h" +#include "build/build_config.h" + +#if defined(OS_NACL) +// For getpagesize() on NaCl. +#include <unistd.h> +#endif + +namespace mojo { +namespace edk { + +namespace { + +size_t GetPageSize() { +#if defined(OS_NACL) + // base::SysInfo isn't available under NaCl. + return getpagesize(); +#else + return base::SysInfo::VMAllocationGranularity(); +#endif +} + +} // namespace + +PlatformSharedMemoryMapping::PlatformSharedMemoryMapping( + base::subtle::PlatformSharedMemoryRegion* region, + size_t offset, + size_t length) + : type_(region->GetMode() == + base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly + ? Type::kReadOnly + : Type::kWritable), + offset_(offset), + length_(length) { + // Mojo shared buffers can be mapped at any offset, but //base shared memory + // regions must be mapped at a page boundary. We calculate the nearest whole + // page offset and map from there. + size_t offset_rounding = offset_ % GetPageSize(); + off_t real_offset = static_cast<off_t>(offset_ - offset_rounding); + size_t real_length = length_ + offset_rounding; + void* mapped_memory = nullptr; + if (type_ == Type::kReadOnly) { + auto read_only_region = + base::ReadOnlySharedMemoryRegion::Deserialize(std::move(*region)); + auto read_only_mapping = read_only_region.MapAt(real_offset, real_length); + mapped_memory = const_cast<void*>(read_only_mapping.memory()); + mapping_ = std::make_unique<base::ReadOnlySharedMemoryMapping>( + std::move(read_only_mapping)); + *region = base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization( + std::move(read_only_region)); + } else if (region->GetMode() == + base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe) { + auto unsafe_region = + base::UnsafeSharedMemoryRegion::Deserialize(std::move(*region)); + auto writable_mapping = unsafe_region.MapAt(real_offset, real_length); + mapped_memory = writable_mapping.memory(); + mapping_ = std::make_unique<base::WritableSharedMemoryMapping>( + std::move(writable_mapping)); + *region = base::UnsafeSharedMemoryRegion::TakeHandleForSerialization( + std::move(unsafe_region)); + } else { + DCHECK_EQ(region->GetMode(), + base::subtle::PlatformSharedMemoryRegion::Mode::kWritable); + auto writable_region = + base::WritableSharedMemoryRegion::Deserialize(std::move(*region)); + auto writable_mapping = writable_region.MapAt(real_offset, real_length); + mapped_memory = writable_mapping.memory(); + mapping_ = std::make_unique<base::WritableSharedMemoryMapping>( + std::move(writable_mapping)); + *region = base::WritableSharedMemoryRegion::TakeHandleForSerialization( + std::move(writable_region)); + } + + base_ = static_cast<char*>(mapped_memory) + offset_rounding; +} + +PlatformSharedMemoryMapping::~PlatformSharedMemoryMapping() = default; + +bool PlatformSharedMemoryMapping::IsValid() const { + return mapping_ && mapping_->IsValid(); +} + +void* PlatformSharedMemoryMapping::GetBase() const { + return base_; +} + +size_t PlatformSharedMemoryMapping::GetLength() const { + return length_; +} + +} // namespace edk +} // namespace mojo diff --git a/chromium/mojo/edk/system/platform_shared_memory_mapping.h b/chromium/mojo/edk/system/platform_shared_memory_mapping.h new file mode 100644 index 00000000000..764fe4f4c1e --- /dev/null +++ b/chromium/mojo/edk/system/platform_shared_memory_mapping.h @@ -0,0 +1,60 @@ +// 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_EDK_SYSTEM_PLATFORM_SHARED_MEMORY_MAPPING_H_ +#define MOJO_EDK_SYSTEM_PLATFORM_SHARED_MEMORY_MAPPING_H_ + +#include <stddef.h> + +#include <memory> + +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/platform_shared_memory_region.h" +#include "base/memory/shared_memory_mapping.h" +#include "mojo/edk/system/system_impl_export.h" + +namespace mojo { +namespace edk { + +// A mapping of a |base::subtle::PlatformSharedMemoryRegion|, created +// exclusively by |SharedBufferDispatcher::MapBuffer()|. Automatically maps +// upon construction and unmaps upon destruction. +// +// Mappings are NOT thread-safe. +// +// This may represent either a |base::ReadOnlySharedMemoryMapping| OR a +// |base::WritableSharedMemoryMapping|, and it supports non-page-aligned base +// offsets for convenience. +class MOJO_SYSTEM_IMPL_EXPORT PlatformSharedMemoryMapping { + public: + enum class Type { + kReadOnly, + kWritable, + }; + + PlatformSharedMemoryMapping(base::subtle::PlatformSharedMemoryRegion* region, + size_t offset, + size_t length); + ~PlatformSharedMemoryMapping(); + + bool IsValid() const; + + void* GetBase() const; + size_t GetLength() const; + + private: + const Type type_; + const size_t offset_; + const size_t length_; + void* base_ = nullptr; + std::unique_ptr<base::SharedMemoryMapping> mapping_; + + DISALLOW_COPY_AND_ASSIGN(PlatformSharedMemoryMapping); +}; + +} // namespace edk +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_PLATFORM_SHARED_MEMORY_MAPPING_H_ diff --git a/chromium/mojo/edk/system/platform_wrapper_unittest.cc b/chromium/mojo/edk/system/platform_wrapper_unittest.cc index 6ed99667ee6..f7770ba711c 100644 --- a/chromium/mojo/edk/system/platform_wrapper_unittest.cc +++ b/chromium/mojo/edk/system/platform_wrapper_unittest.cc @@ -14,7 +14,6 @@ #include "base/memory/shared_memory.h" #include "base/process/process_handle.h" #include "build/build_config.h" -#include "mojo/edk/embedder/platform_shared_buffer.h" #include "mojo/edk/test/mojo_test_base.h" #include "mojo/public/c/system/platform_handle.h" #include "mojo/public/cpp/system/message_pipe.h" @@ -24,33 +23,33 @@ #include <windows.h> #endif -#if defined(OS_POSIX) -#define SIMPLE_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR -#elif defined(OS_WIN) +#if defined(OS_WIN) #define SIMPLE_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) +#define SIMPLE_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR #endif -#if defined(OS_MACOSX) && !defined(OS_IOS) -#define SHARED_BUFFER_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT -#elif defined(OS_FUCHSIA) +#if defined(OS_FUCHSIA) #define SHARED_BUFFER_PLATFORM_HANDLE_TYPE \ MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE -#else +#elif defined(OS_MACOSX) && !defined(OS_IOS) +#define SHARED_BUFFER_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT +#elif defined(OS_WIN) || defined(OS_POSIX) #define SHARED_BUFFER_PLATFORM_HANDLE_TYPE SIMPLE_PLATFORM_HANDLE_TYPE #endif -uint64_t PlatformHandleValueFromPlatformFile(base::PlatformFile file) { +uint64_t InternalPlatformHandleValueFromPlatformFile(base::PlatformFile file) { #if defined(OS_WIN) return reinterpret_cast<uint64_t>(file); -#else +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) return static_cast<uint64_t>(file); #endif } -base::PlatformFile PlatformFileFromPlatformHandleValue(uint64_t value) { +base::PlatformFile PlatformFileFromInternalPlatformHandleValue(uint64_t value) { #if defined(OS_WIN) return reinterpret_cast<base::PlatformFile>(value); -#else +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) return static_cast<base::PlatformFile>(value); #endif } @@ -61,7 +60,7 @@ namespace { using PlatformWrapperTest = test::MojoTestBase; -TEST_F(PlatformWrapperTest, WrapPlatformHandle) { +TEST_F(PlatformWrapperTest, WrapInternalPlatformHandle) { // Create a temporary file and write a message to it. base::FilePath temp_file_path; ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path)); @@ -82,9 +81,9 @@ TEST_F(PlatformWrapperTest, WrapPlatformHandle) { os_file.struct_size = sizeof(MojoPlatformHandle); os_file.type = SIMPLE_PLATFORM_HANDLE_TYPE; os_file.value = - PlatformHandleValueFromPlatformFile(file.TakePlatformFile()); + InternalPlatformHandleValueFromPlatformFile(file.TakePlatformFile()); EXPECT_EQ(MOJO_RESULT_OK, - MojoWrapPlatformHandle(&os_file, &wrapped_handle)); + MojoWrapPlatformHandle(&os_file, nullptr, &wrapped_handle)); WriteMessageWithHandles(h, kMessage, &wrapped_handle, 1); }); @@ -99,10 +98,11 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformFile, PlatformWrapperTest, h) { MojoPlatformHandle platform_handle; platform_handle.struct_size = sizeof(MojoPlatformHandle); - ASSERT_EQ(MOJO_RESULT_OK, - MojoUnwrapPlatformHandle(wrapped_handle, &platform_handle)); + ASSERT_EQ(MOJO_RESULT_OK, MojoUnwrapPlatformHandle(wrapped_handle, nullptr, + &platform_handle)); EXPECT_EQ(SIMPLE_PLATFORM_HANDLE_TYPE, platform_handle.type); - base::File file(PlatformFileFromPlatformHandleValue(platform_handle.value)); + base::File file( + PlatformFileFromInternalPlatformHandleValue(platform_handle.value)); // Expect to read the same message from the file. std::vector<char> data(message.size()); @@ -111,7 +111,7 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformFile, PlatformWrapperTest, h) { EXPECT_TRUE(std::equal(message.begin(), message.end(), data.begin())); } -TEST_F(PlatformWrapperTest, WrapPlatformSharedBufferHandle) { +TEST_F(PlatformWrapperTest, WrapPlatformSharedMemoryRegion) { // Allocate a new platform shared buffer and write a message into it. const std::string kMessage = "Hello, world!"; base::SharedMemory buffer; @@ -127,12 +127,14 @@ TEST_F(PlatformWrapperTest, WrapPlatformSharedBufferHandle) { MojoPlatformHandle os_buffer; os_buffer.struct_size = sizeof(MojoPlatformHandle); os_buffer.type = SHARED_BUFFER_PLATFORM_HANDLE_TYPE; -#if defined(OS_MACOSX) && !defined(OS_IOS) - os_buffer.value = static_cast<uint64_t>(memory_handle.GetMemoryObject()); -#elif defined(OS_WIN) +#if defined(OS_WIN) os_buffer.value = reinterpret_cast<uint64_t>(memory_handle.GetHandle()); -#else +#elif defined(OS_MACOSX) && !defined(OS_IOS) + os_buffer.value = static_cast<uint64_t>(memory_handle.GetMemoryObject()); +#elif defined(OS_POSIX) || defined(OS_FUCHSIA) os_buffer.value = static_cast<uint64_t>(memory_handle.GetHandle()); +#else +#error Unsupported platform #endif MojoSharedBufferGuid mojo_guid; @@ -141,10 +143,11 @@ TEST_F(PlatformWrapperTest, WrapPlatformSharedBufferHandle) { mojo_guid.low = guid.GetLowForSerialization(); MojoHandle wrapped_handle; - ASSERT_EQ(MOJO_RESULT_OK, MojoWrapPlatformSharedBufferHandle( - &os_buffer, kMessage.size(), &mojo_guid, - MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_NONE, - &wrapped_handle)); + ASSERT_EQ(MOJO_RESULT_OK, + MojoWrapPlatformSharedMemoryRegion( + &os_buffer, 1, kMessage.size(), &mojo_guid, + MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE, + nullptr, &wrapped_handle)); WriteMessageWithHandles(h, kMessage, &wrapped_handle, 1); // As a sanity check, send the GUID explicitly in a second message. We'll @@ -169,37 +172,37 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformSharedBuffer, // works as expected. MojoPlatformHandle os_buffer; os_buffer.struct_size = sizeof(MojoPlatformHandle); - size_t size; + uint32_t num_handles = 1; + uint64_t size; MojoSharedBufferGuid mojo_guid; - MojoPlatformSharedBufferHandleFlags flags; - ASSERT_EQ(MOJO_RESULT_OK, - MojoUnwrapPlatformSharedBufferHandle(wrapped_handle, &os_buffer, - &size, &mojo_guid, &flags)); - bool read_only = flags & MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_NONE; - EXPECT_FALSE(read_only); + MojoPlatformSharedMemoryRegionAccessMode access_mode; + ASSERT_EQ(MOJO_RESULT_OK, MojoUnwrapPlatformSharedMemoryRegion( + wrapped_handle, nullptr, &os_buffer, + &num_handles, &size, &mojo_guid, &access_mode)); + EXPECT_EQ(MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE, access_mode); base::UnguessableToken guid = base::UnguessableToken::Deserialize(mojo_guid.high, mojo_guid.low); -#if defined(OS_MACOSX) && !defined(OS_IOS) - ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT, os_buffer.type); +#if defined(OS_WIN) + ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE, os_buffer.type); base::SharedMemoryHandle memory_handle( - static_cast<mach_port_t>(os_buffer.value), size, guid); + reinterpret_cast<HANDLE>(os_buffer.value), size, guid); #elif defined(OS_FUCHSIA) ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE, os_buffer.type); base::SharedMemoryHandle memory_handle( static_cast<zx_handle_t>(os_buffer.value), size, guid); +#elif defined(OS_MACOSX) && !defined(OS_IOS) + ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT, os_buffer.type); + base::SharedMemoryHandle memory_handle( + static_cast<mach_port_t>(os_buffer.value), size, guid); #elif defined(OS_POSIX) ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR, os_buffer.type); base::SharedMemoryHandle memory_handle( base::FileDescriptor(static_cast<int>(os_buffer.value), false), size, guid); -#elif defined(OS_WIN) - ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE, os_buffer.type); - base::SharedMemoryHandle memory_handle( - reinterpret_cast<HANDLE>(os_buffer.value), size, guid); #endif - base::SharedMemory memory(memory_handle, read_only); + base::SharedMemory memory(memory_handle, false); memory.Map(message.size()); ASSERT_TRUE(memory.memory()); @@ -227,9 +230,9 @@ TEST_F(PlatformWrapperTest, InvalidHandle) { invalid_handle.struct_size = sizeof(MojoPlatformHandle); invalid_handle.type = MOJO_PLATFORM_HANDLE_TYPE_INVALID; EXPECT_EQ(MOJO_RESULT_OK, - MojoWrapPlatformHandle(&invalid_handle, &wrapped_handle)); + MojoWrapPlatformHandle(&invalid_handle, nullptr, &wrapped_handle)); EXPECT_EQ(MOJO_RESULT_OK, - MojoUnwrapPlatformHandle(wrapped_handle, &invalid_handle)); + MojoUnwrapPlatformHandle(wrapped_handle, nullptr, &invalid_handle)); EXPECT_EQ(MOJO_PLATFORM_HANDLE_TYPE_INVALID, invalid_handle.type); } @@ -239,7 +242,7 @@ TEST_F(PlatformWrapperTest, InvalidArgument) { MojoPlatformHandle platform_handle; platform_handle.struct_size = 0; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - MojoWrapPlatformHandle(&platform_handle, &wrapped_handle)); + MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle)); } } // namespace diff --git a/chromium/mojo/edk/system/scoped_process_handle.cc b/chromium/mojo/edk/system/scoped_process_handle.cc new file mode 100644 index 00000000000..43d719df410 --- /dev/null +++ b/chromium/mojo/edk/system/scoped_process_handle.cc @@ -0,0 +1,45 @@ +// 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. + +#include "mojo/edk/system/scoped_process_handle.h" + +#include "build/build_config.h" + +#if defined(OS_WIN) +#include <windows.h> +#endif + +namespace mojo { +namespace edk { + +ScopedProcessHandle::ScopedProcessHandle() = default; + +ScopedProcessHandle::ScopedProcessHandle(base::ProcessHandle handle) + : handle_(handle) {} + +ScopedProcessHandle::ScopedProcessHandle(ScopedProcessHandle&&) = default; + +ScopedProcessHandle::~ScopedProcessHandle() = default; + +// static +ScopedProcessHandle ScopedProcessHandle::CloneFrom(base::ProcessHandle handle) { +#if defined(OS_WIN) + BOOL ok = ::DuplicateHandle(base::GetCurrentProcessHandle(), handle, + base::GetCurrentProcessHandle(), &handle, 0, + FALSE, DUPLICATE_SAME_ACCESS); + DCHECK(ok); +#endif + return ScopedProcessHandle(handle); +} + +ScopedProcessHandle& ScopedProcessHandle::operator=(ScopedProcessHandle&&) = + default; + +ScopedProcessHandle ScopedProcessHandle::Clone() const { + DCHECK(is_valid()); + return CloneFrom(get()); +} + +} // namespace edk +} // namespace mojo diff --git a/chromium/mojo/edk/system/scoped_process_handle.h b/chromium/mojo/edk/system/scoped_process_handle.h new file mode 100644 index 00000000000..dbefdfe0593 --- /dev/null +++ b/chromium/mojo/edk/system/scoped_process_handle.h @@ -0,0 +1,81 @@ +// 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_EDK_SYSTEM_SCOPED_PROCESS_HANDLE_H_ +#define MOJO_EDK_SYSTEM_SCOPED_PROCESS_HANDLE_H_ + +#include "base/macros.h" +#include "base/process/process_handle.h" +#include "build/build_config.h" + +#if defined(OS_WIN) +#include "base/win/scoped_handle.h" +#endif + +namespace mojo { +namespace edk { + +// Wraps a |base::ProcessHandle| with additional scoped lifetime semantics on +// applicable platforms. For platforms where process handles aren't ownable +// references, this is just a wrapper around |base::ProcessHandle|. +// +// This essentially exists to support passing around process handles internally +// in a generic way while also supporting Windows process handle ownership +// semantics. +class ScopedProcessHandle { + public: + ScopedProcessHandle(); + + // Assumes ownership of |handle|. + explicit ScopedProcessHandle(base::ProcessHandle handle); + + ScopedProcessHandle(ScopedProcessHandle&&); + + ~ScopedProcessHandle(); + + // Creates a new ScopedProcessHandle from a clone of |handle|. + static ScopedProcessHandle CloneFrom(base::ProcessHandle handle); + + ScopedProcessHandle& operator=(ScopedProcessHandle&&); + + bool is_valid() const { +#if defined(OS_WIN) + return handle_.IsValid(); +#else + return handle_ != base::kNullProcessHandle; +#endif + } + + base::ProcessHandle get() const { +#if defined(OS_WIN) + return handle_.Get(); +#else + return handle_; +#endif + } + + base::ProcessHandle release() { +#if defined(OS_WIN) + return handle_.Take(); +#else + return handle_; +#endif + } + + ScopedProcessHandle Clone() const; + + private: +#if defined(OS_WIN) + base::win::ScopedHandle handle_; +#else + base::ProcessHandle handle_ = base::kNullProcessHandle; +#endif + + DISALLOW_COPY_AND_ASSIGN(ScopedProcessHandle); +}; + +} // namespace edk +} // namespace mojo + +#endif // MOJO_EDK_SYSTEM_SCOPED_PROCESS_HANDLE_H_ diff --git a/chromium/mojo/edk/system/shared_buffer_dispatcher.cc b/chromium/mojo/edk/system/shared_buffer_dispatcher.cc index ca9a1a84359..73b2c03d624 100644 --- a/chromium/mojo/edk/system/shared_buffer_dispatcher.cc +++ b/chromium/mojo/edk/system/shared_buffer_dispatcher.cc @@ -12,9 +12,14 @@ #include <utility> #include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "build/build_config.h" +#include "mojo/edk/embedder/platform_handle_utils.h" #include "mojo/edk/system/configuration.h" #include "mojo/edk/system/node_controller.h" #include "mojo/edk/system/options_validation.h" +#include "mojo/edk/system/platform_shared_memory_mapping.h" +#include "mojo/public/c/system/platform_handle.h" namespace mojo { namespace edk { @@ -25,14 +30,12 @@ namespace { struct SerializedState { uint64_t num_bytes; - uint32_t flags; + uint32_t access_mode; uint64_t guid_high; uint64_t guid_low; uint32_t padding; }; -const uint32_t kSerializedStateFlagsReadOnly = 1 << 0; - #pragma pack(pop) static_assert(sizeof(SerializedState) % 8 == 0, @@ -44,14 +47,14 @@ static_assert(sizeof(SerializedState) % 8 == 0, const MojoCreateSharedBufferOptions SharedBufferDispatcher::kDefaultCreateOptions = { static_cast<uint32_t>(sizeof(MojoCreateSharedBufferOptions)), - MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE}; + MOJO_CREATE_SHARED_BUFFER_FLAG_NONE}; // static MojoResult SharedBufferDispatcher::ValidateCreateOptions( const MojoCreateSharedBufferOptions* in_options, MojoCreateSharedBufferOptions* out_options) { - const MojoCreateSharedBufferOptionsFlags kKnownFlags = - MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE; + const MojoCreateSharedBufferFlags kKnownFlags = + MOJO_CREATE_SHARED_BUFFER_FLAG_NONE; *out_options = kDefaultCreateOptions; if (!in_options) @@ -85,29 +88,31 @@ MojoResult SharedBufferDispatcher::Create( if (num_bytes > GetConfiguration().max_shared_memory_num_bytes) return MOJO_RESULT_RESOURCE_EXHAUSTED; - scoped_refptr<PlatformSharedBuffer> shared_buffer; + base::WritableSharedMemoryRegion writable_region; if (node_controller) { - shared_buffer = + writable_region = node_controller->CreateSharedBuffer(static_cast<size_t>(num_bytes)); } else { - shared_buffer = - PlatformSharedBuffer::Create(static_cast<size_t>(num_bytes)); + writable_region = base::WritableSharedMemoryRegion::Create( + static_cast<size_t>(num_bytes)); } - if (!shared_buffer) + if (!writable_region.IsValid()) return MOJO_RESULT_RESOURCE_EXHAUSTED; - *result = CreateInternal(std::move(shared_buffer)); + *result = CreateInternal( + base::WritableSharedMemoryRegion::TakeHandleForSerialization( + std::move(writable_region))); return MOJO_RESULT_OK; } // static -MojoResult SharedBufferDispatcher::CreateFromPlatformSharedBuffer( - const scoped_refptr<PlatformSharedBuffer>& shared_buffer, +MojoResult SharedBufferDispatcher::CreateFromPlatformSharedMemoryRegion( + base::subtle::PlatformSharedMemoryRegion region, scoped_refptr<SharedBufferDispatcher>* result) { - if (!shared_buffer) + if (!region.IsValid()) return MOJO_RESULT_INVALID_ARGUMENT; - *result = CreateInternal(shared_buffer); + *result = CreateInternal(std::move(region)); return MOJO_RESULT_OK; } @@ -117,7 +122,7 @@ scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::Deserialize( size_t num_bytes, const ports::PortName* ports, size_t num_ports, - ScopedPlatformHandle* platform_handles, + ScopedInternalPlatformHandle* platform_handles, size_t num_platform_handles) { if (num_bytes != sizeof(SerializedState)) { LOG(ERROR) << "Invalid serialized shared buffer dispatcher (bad size)"; @@ -132,38 +137,65 @@ scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::Deserialize( return nullptr; } - if (num_platform_handles != 1 || num_ports) { - LOG(ERROR) - << "Invalid serialized shared buffer dispatcher (missing handles)"; + if (num_ports) return nullptr; + + ScopedInternalPlatformHandle handles[2]; +#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA) && \ + (!defined(OS_MACOSX) || defined(OS_IOS)) + if (serialized_state->access_mode == + MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE) { + if (num_platform_handles != 2) + return nullptr; + handles[1] = std::move(platform_handles[1]); + } else { + if (num_platform_handles != 1) + return nullptr; } +#else + if (num_platform_handles != 1) + return nullptr; +#endif + handles[0] = std::move(platform_handles[0]); base::UnguessableToken guid = base::UnguessableToken::Deserialize( serialized_state->guid_high, serialized_state->guid_low); - bool read_only = (serialized_state->flags & kSerializedStateFlagsReadOnly); - scoped_refptr<PlatformSharedBuffer> shared_buffer( - PlatformSharedBuffer::CreateFromPlatformHandle( - static_cast<size_t>(serialized_state->num_bytes), read_only, guid, - std::move(platform_handles[0]))); - if (!shared_buffer) { + base::subtle::PlatformSharedMemoryRegion::Mode mode; + switch (serialized_state->access_mode) { + case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY: + mode = base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly; + break; + case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE: + mode = base::subtle::PlatformSharedMemoryRegion::Mode::kWritable; + break; + case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE: + mode = base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe; + break; + default: + LOG(ERROR) << "Invalid serialized shared buffer access mode."; + return nullptr; + } + auto region = base::subtle::PlatformSharedMemoryRegion::Take( + CreateSharedMemoryRegionHandleFromInternalPlatformHandles( + std::move(handles[0]), std::move(handles[1])), + mode, static_cast<size_t>(serialized_state->num_bytes), guid); + if (!region.IsValid()) { LOG(ERROR) << "Invalid serialized shared buffer dispatcher (invalid num_bytes?)"; return nullptr; } - return CreateInternal(std::move(shared_buffer)); + return CreateInternal(std::move(region)); } -scoped_refptr<PlatformSharedBuffer> -SharedBufferDispatcher::PassPlatformSharedBuffer() { +base::subtle::PlatformSharedMemoryRegion +SharedBufferDispatcher::PassPlatformSharedMemoryRegion() { base::AutoLock lock(lock_); - if (!shared_buffer_ || in_transit_) - return nullptr; + if (!region_.IsValid() || in_transit_) + return base::subtle::PlatformSharedMemoryRegion(); - scoped_refptr<PlatformSharedBuffer> retval = shared_buffer_; - shared_buffer_ = nullptr; - return retval; + return std::move(region_); } Dispatcher::Type SharedBufferDispatcher::GetType() const { @@ -175,7 +207,7 @@ MojoResult SharedBufferDispatcher::Close() { if (in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; - shared_buffer_ = nullptr; + region_ = base::subtle::PlatformSharedMemoryRegion(); return MOJO_RESULT_OK; } @@ -187,52 +219,76 @@ MojoResult SharedBufferDispatcher::DuplicateBufferHandle( if (result != MOJO_RESULT_OK) return result; - // Note: Since this is "duplicate", we keep our ref to |shared_buffer_|. base::AutoLock lock(lock_); if (in_transit_) return MOJO_RESULT_INVALID_ARGUMENT; - if ((validated_options.flags & - MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY) && - (!shared_buffer_->IsReadOnly())) { - // If a read-only duplicate is requested and |shared_buffer_| is not - // read-only, make a read-only duplicate of |shared_buffer_|. - scoped_refptr<PlatformSharedBuffer> read_only_buffer = - shared_buffer_->CreateReadOnlyDuplicate(); - if (!read_only_buffer) + if ((validated_options.flags & MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_READ_ONLY)) { + // If a read-only duplicate is requested and this handle is not already + // read-only, we need to make it read-only before duplicating. If it's + // unsafe it can't be made read-only, and we must fail instead. + if (region_.GetMode() == + base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe) { return MOJO_RESULT_FAILED_PRECONDITION; - DCHECK(read_only_buffer->IsReadOnly()); - *new_dispatcher = CreateInternal(std::move(read_only_buffer)); - return MOJO_RESULT_OK; + } else if (region_.GetMode() == + base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) { + region_ = base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization( + base::WritableSharedMemoryRegion::ConvertToReadOnly( + base::WritableSharedMemoryRegion::Deserialize( + std::move(region_)))); + } + + DCHECK_EQ(region_.GetMode(), + base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly); + } else { + // A writable duplicate was requested. If this is already a read-only handle + // we have to reject. Otherwise we have to convert to unsafe to ensure that + // no future read-only duplication requests can succeed. + if (region_.GetMode() == + base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly) { + return MOJO_RESULT_FAILED_PRECONDITION; + } else if (region_.GetMode() == + base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) { + auto handle = region_.PassPlatformHandle(); +#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA) && \ + (!defined(OS_MACOSX) || defined(OS_IOS)) + // On POSIX systems excluding Android, Fuchsia, and OSX, we explicitly + // wipe out the secondary (read-only) FD from the platform handle to + // repurpose it for exclusive unsafe usage. + handle.readonly_fd.reset(); +#endif + region_ = base::subtle::PlatformSharedMemoryRegion::Take( + std::move(handle), + base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe, + region_.GetSize(), region_.GetGUID()); + } } - *new_dispatcher = CreateInternal(shared_buffer_); + *new_dispatcher = CreateInternal(region_.Duplicate()); return MOJO_RESULT_OK; } MojoResult SharedBufferDispatcher::MapBuffer( uint64_t offset, uint64_t num_bytes, - MojoMapBufferFlags flags, - std::unique_ptr<PlatformSharedBufferMapping>* mapping) { + std::unique_ptr<PlatformSharedMemoryMapping>* mapping) { if (offset > static_cast<uint64_t>(std::numeric_limits<size_t>::max())) return MOJO_RESULT_INVALID_ARGUMENT; if (num_bytes > static_cast<uint64_t>(std::numeric_limits<size_t>::max())) return MOJO_RESULT_INVALID_ARGUMENT; base::AutoLock lock(lock_); - DCHECK(shared_buffer_); - if (in_transit_ || - !shared_buffer_->IsValidMap(static_cast<size_t>(offset), - static_cast<size_t>(num_bytes))) { + DCHECK(region_.IsValid()); + if (in_transit_ || num_bytes == 0 || + static_cast<size_t>(offset + num_bytes) > region_.GetSize()) { return MOJO_RESULT_INVALID_ARGUMENT; } DCHECK(mapping); - *mapping = shared_buffer_->MapNoCheck(static_cast<size_t>(offset), - static_cast<size_t>(num_bytes)); - if (!*mapping) { - LOG(ERROR) << "Unable to map: read_only" << shared_buffer_->IsReadOnly(); + *mapping = std::make_unique<PlatformSharedMemoryMapping>( + ®ion_, static_cast<size_t>(offset), static_cast<size_t>(num_bytes)); + if (!(*mapping)->IsValid()) { + LOG(ERROR) << "Failed to map shared memory region."; return MOJO_RESULT_RESOURCE_EXHAUSTED; } @@ -244,7 +300,8 @@ MojoResult SharedBufferDispatcher::GetBufferInfo(MojoSharedBufferInfo* info) { return MOJO_RESULT_INVALID_ARGUMENT; base::AutoLock lock(lock_); - info->size = shared_buffer_->GetNumBytes(); + info->struct_size = sizeof(*info); + info->size = region_.GetSize(); return MOJO_RESULT_OK; } @@ -254,28 +311,60 @@ void SharedBufferDispatcher::StartSerialize(uint32_t* num_bytes, *num_bytes = sizeof(SerializedState); *num_ports = 0; *num_platform_handles = 1; +#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA) && \ + (!defined(OS_MACOSX) || defined(OS_IOS)) + if (region_.GetMode() == + base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) { + *num_platform_handles = 2; + } +#endif } -bool SharedBufferDispatcher::EndSerialize(void* destination, - ports::PortName* ports, - ScopedPlatformHandle* handles) { +bool SharedBufferDispatcher::EndSerialize( + void* destination, + ports::PortName* ports, + ScopedInternalPlatformHandle* handles) { SerializedState* serialized_state = static_cast<SerializedState*>(destination); base::AutoLock lock(lock_); - serialized_state->num_bytes = - static_cast<uint64_t>(shared_buffer_->GetNumBytes()); - serialized_state->flags = - (shared_buffer_->IsReadOnly() ? kSerializedStateFlagsReadOnly : 0); - base::UnguessableToken guid = shared_buffer_->GetGUID(); + serialized_state->num_bytes = region_.GetSize(); + switch (region_.GetMode()) { + case base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly: + serialized_state->access_mode = + MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY; + break; + case base::subtle::PlatformSharedMemoryRegion::Mode::kWritable: + serialized_state->access_mode = + MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE; + break; + case base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe: + serialized_state->access_mode = + MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE; + break; + default: + NOTREACHED(); + return false; + } + + const base::UnguessableToken& guid = region_.GetGUID(); serialized_state->guid_high = guid.GetHighForSerialization(); serialized_state->guid_low = guid.GetLowForSerialization(); serialized_state->padding = 0; - handles[0] = shared_buffer_->DuplicatePlatformHandleForIPC(); - if (!handles[0].is_valid()) { - shared_buffer_ = nullptr; - return false; + auto region = std::move(region_); +#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA) && \ + (!defined(OS_MACOSX) || defined(OS_IOS)) + if (region.GetMode() == + base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) { + ExtractInternalPlatformHandlesFromSharedMemoryRegionHandle( + region.PassPlatformHandle(), &handles[0], &handles[1]); + return true; } +#endif + + ScopedInternalPlatformHandle ignored_handle; + ExtractInternalPlatformHandlesFromSharedMemoryRegionHandle( + region.PassPlatformHandle(), &handles[0], &ignored_handle); return true; } @@ -283,42 +372,46 @@ bool SharedBufferDispatcher::BeginTransit() { base::AutoLock lock(lock_); if (in_transit_) return false; - in_transit_ = static_cast<bool>(shared_buffer_); + in_transit_ = region_.IsValid(); return in_transit_; } void SharedBufferDispatcher::CompleteTransitAndClose() { base::AutoLock lock(lock_); in_transit_ = false; - shared_buffer_ = nullptr; - ignore_result(handle_for_transit_.release()); + region_ = base::subtle::PlatformSharedMemoryRegion(); } void SharedBufferDispatcher::CancelTransit() { base::AutoLock lock(lock_); in_transit_ = false; - handle_for_transit_.reset(); } SharedBufferDispatcher::SharedBufferDispatcher( - scoped_refptr<PlatformSharedBuffer> shared_buffer) - : shared_buffer_(shared_buffer) { - DCHECK(shared_buffer_); + base::subtle::PlatformSharedMemoryRegion region) + : region_(std::move(region)) { + DCHECK(region_.IsValid()); } SharedBufferDispatcher::~SharedBufferDispatcher() { - DCHECK(!shared_buffer_ && !in_transit_); + DCHECK(!region_.IsValid() && !in_transit_); +} + +// static +scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::CreateInternal( + base::subtle::PlatformSharedMemoryRegion region) { + return base::WrapRefCounted(new SharedBufferDispatcher(std::move(region))); } // static MojoResult SharedBufferDispatcher::ValidateDuplicateOptions( const MojoDuplicateBufferHandleOptions* in_options, MojoDuplicateBufferHandleOptions* out_options) { - const MojoDuplicateBufferHandleOptionsFlags kKnownFlags = - MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY; + const MojoDuplicateBufferHandleFlags kKnownFlags = + MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_READ_ONLY; static const MojoDuplicateBufferHandleOptions kDefaultOptions = { static_cast<uint32_t>(sizeof(MojoDuplicateBufferHandleOptions)), - MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE}; + MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_NONE}; *out_options = kDefaultOptions; if (!in_options) diff --git a/chromium/mojo/edk/system/shared_buffer_dispatcher.h b/chromium/mojo/edk/system/shared_buffer_dispatcher.h index fcaf5c19139..30c0dd6f60e 100644 --- a/chromium/mojo/edk/system/shared_buffer_dispatcher.h +++ b/chromium/mojo/edk/system/shared_buffer_dispatcher.h @@ -11,7 +11,7 @@ #include <utility> #include "base/macros.h" -#include "mojo/edk/embedder/platform_shared_buffer.h" +#include "base/memory/platform_shared_memory_region.h" #include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/edk/system/dispatcher.h" #include "mojo/edk/system/system_impl_export.h" @@ -19,7 +19,9 @@ namespace mojo { namespace edk { + class NodeController; +class PlatformSharedMemoryMapping; class MOJO_SYSTEM_IMPL_EXPORT SharedBufferDispatcher final : public Dispatcher { public: @@ -48,8 +50,8 @@ class MOJO_SYSTEM_IMPL_EXPORT SharedBufferDispatcher final : public Dispatcher { scoped_refptr<SharedBufferDispatcher>* result); // Create a |SharedBufferDispatcher| from |shared_buffer|. - static MojoResult CreateFromPlatformSharedBuffer( - const scoped_refptr<PlatformSharedBuffer>& shared_buffer, + static MojoResult CreateFromPlatformSharedMemoryRegion( + base::subtle::PlatformSharedMemoryRegion region, scoped_refptr<SharedBufferDispatcher>* result); // The "opposite" of SerializeAndClose(). Called by Dispatcher::Deserialize(). @@ -58,12 +60,17 @@ class MOJO_SYSTEM_IMPL_EXPORT SharedBufferDispatcher final : public Dispatcher { size_t num_bytes, const ports::PortName* ports, size_t num_ports, - ScopedPlatformHandle* platform_handles, + ScopedInternalPlatformHandle* platform_handles, size_t num_handles); - // Passes the underlying platform shared buffer. This dispatcher must be + // Passes the underlying PlatformSharedMemoryRegion. This dispatcher must be // closed after calling this function. - scoped_refptr<PlatformSharedBuffer> PassPlatformSharedBuffer(); + base::subtle::PlatformSharedMemoryRegion PassPlatformSharedMemoryRegion(); + + // NOTE: This is not thread-safe. Definitely never use it outside of tests. + base::subtle::PlatformSharedMemoryRegion& GetRegionForTesting() { + return region_; + } // Dispatcher: Type GetType() const override; @@ -74,30 +81,26 @@ class MOJO_SYSTEM_IMPL_EXPORT SharedBufferDispatcher final : public Dispatcher { MojoResult MapBuffer( uint64_t offset, uint64_t num_bytes, - MojoMapBufferFlags flags, - std::unique_ptr<PlatformSharedBufferMapping>* mapping) override; + std::unique_ptr<PlatformSharedMemoryMapping>* mapping) override; MojoResult GetBufferInfo(MojoSharedBufferInfo* info) override; void StartSerialize(uint32_t* num_bytes, uint32_t* num_ports, uint32_t* num_platform_handles) override; bool EndSerialize(void* destination, ports::PortName* ports, - ScopedPlatformHandle* handles) override; + ScopedInternalPlatformHandle* handles) override; bool BeginTransit() override; void CompleteTransitAndClose() override; void CancelTransit() override; private: - static scoped_refptr<SharedBufferDispatcher> CreateInternal( - scoped_refptr<PlatformSharedBuffer> shared_buffer) { - return base::WrapRefCounted( - new SharedBufferDispatcher(std::move(shared_buffer))); - } - explicit SharedBufferDispatcher( - scoped_refptr<PlatformSharedBuffer> shared_buffer); + base::subtle::PlatformSharedMemoryRegion region); ~SharedBufferDispatcher() override; + static scoped_refptr<SharedBufferDispatcher> CreateInternal( + base::subtle::PlatformSharedMemoryRegion region); + // Validates and/or sets default options for // |MojoDuplicateBufferHandleOptions|. If non-null, |in_options| must point to // a struct of at least |in_options->struct_size| bytes. |out_options| must @@ -107,16 +110,11 @@ class MOJO_SYSTEM_IMPL_EXPORT SharedBufferDispatcher final : public Dispatcher { const MojoDuplicateBufferHandleOptions* in_options, MojoDuplicateBufferHandleOptions* out_options); - // Guards access to |shared_buffer_|. + // Guards access to the fields below. base::Lock lock_; bool in_transit_ = false; - - // We keep a copy of the buffer's platform handle during transit so we can - // close it if something goes wrong. - ScopedPlatformHandle handle_for_transit_; - - scoped_refptr<PlatformSharedBuffer> shared_buffer_; + base::subtle::PlatformSharedMemoryRegion region_; DISALLOW_COPY_AND_ASSIGN(SharedBufferDispatcher); }; diff --git a/chromium/mojo/edk/system/shared_buffer_dispatcher_unittest.cc b/chromium/mojo/edk/system/shared_buffer_dispatcher_unittest.cc index 5348c5f18e4..768c7aa7475 100644 --- a/chromium/mojo/edk/system/shared_buffer_dispatcher_unittest.cc +++ b/chromium/mojo/edk/system/shared_buffer_dispatcher_unittest.cc @@ -10,9 +10,11 @@ #include <limits> #include "base/macros.h" +#include "base/memory/platform_shared_memory_region.h" #include "base/memory/ref_counted.h" -#include "mojo/edk/embedder/platform_shared_buffer.h" +#include "base/memory/writable_shared_memory_region.h" #include "mojo/edk/system/dispatcher.h" +#include "mojo/edk/system/platform_shared_memory_mapping.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { @@ -62,10 +64,10 @@ TEST_F(SharedBufferDispatcherTest, ValidateCreateOptionsValid) { } // Different flags. - MojoCreateSharedBufferOptionsFlags flags_values[] = { - MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE}; + MojoCreateSharedBufferFlags flags_values[] = { + MOJO_CREATE_SHARED_BUFFER_FLAG_NONE}; for (size_t i = 0; i < arraysize(flags_values); i++) { - const MojoCreateSharedBufferOptionsFlags flags = flags_values[i]; + const MojoCreateSharedBufferFlags flags = flags_values[i]; // Different capacities (size 1). for (uint32_t capacity = 1; capacity <= 100 * 1000 * 1000; capacity *= 10) { @@ -88,8 +90,8 @@ TEST_F(SharedBufferDispatcherTest, ValidateCreateOptionsInvalid) { // Invalid |struct_size|. { MojoCreateSharedBufferOptions options = { - 1, // |struct_size|. - MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE // |flags|. + 1, // |struct_size|. + MOJO_CREATE_SHARED_BUFFER_FLAG_NONE // |flags|. }; MojoCreateSharedBufferOptions unused; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, @@ -119,18 +121,16 @@ TEST_F(SharedBufferDispatcherTest, CreateAndMapBuffer) { EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER, dispatcher->GetType()); // Make a couple of mappings. - std::unique_ptr<PlatformSharedBufferMapping> mapping1; - EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer( - 0, 100, MOJO_MAP_BUFFER_FLAG_NONE, &mapping1)); + std::unique_ptr<PlatformSharedMemoryMapping> mapping1; + EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer(0, 100, &mapping1)); ASSERT_TRUE(mapping1); ASSERT_TRUE(mapping1->GetBase()); EXPECT_EQ(100u, mapping1->GetLength()); // Write something. static_cast<char*>(mapping1->GetBase())[50] = 'x'; - std::unique_ptr<PlatformSharedBufferMapping> mapping2; - EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer( - 50, 50, MOJO_MAP_BUFFER_FLAG_NONE, &mapping2)); + std::unique_ptr<PlatformSharedMemoryMapping> mapping2; + EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer(50, 50, &mapping2)); ASSERT_TRUE(mapping2); ASSERT_TRUE(mapping2->GetBase()); EXPECT_EQ(50u, mapping2->GetLength()); @@ -145,29 +145,29 @@ TEST_F(SharedBufferDispatcherTest, CreateAndMapBuffer) { } TEST_F(SharedBufferDispatcherTest, CreateAndMapBufferFromPlatformBuffer) { - scoped_refptr<PlatformSharedBuffer> platform_shared_buffer = - PlatformSharedBuffer::Create(100); - ASSERT_TRUE(platform_shared_buffer); + base::WritableSharedMemoryRegion region = + base::WritableSharedMemoryRegion::Create(100); + ASSERT_TRUE(region.IsValid()); scoped_refptr<SharedBufferDispatcher> dispatcher; EXPECT_EQ(MOJO_RESULT_OK, - SharedBufferDispatcher::CreateFromPlatformSharedBuffer( - platform_shared_buffer, &dispatcher)); + SharedBufferDispatcher::CreateFromPlatformSharedMemoryRegion( + base::WritableSharedMemoryRegion::TakeHandleForSerialization( + std::move(region)), + &dispatcher)); ASSERT_TRUE(dispatcher); EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER, dispatcher->GetType()); // Make a couple of mappings. - std::unique_ptr<PlatformSharedBufferMapping> mapping1; - EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer( - 0, 100, MOJO_MAP_BUFFER_FLAG_NONE, &mapping1)); + std::unique_ptr<PlatformSharedMemoryMapping> mapping1; + EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer(0, 100, &mapping1)); ASSERT_TRUE(mapping1); ASSERT_TRUE(mapping1->GetBase()); EXPECT_EQ(100u, mapping1->GetLength()); // Write something. static_cast<char*>(mapping1->GetBase())[50] = 'x'; - std::unique_ptr<PlatformSharedBufferMapping> mapping2; - EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer( - 50, 50, MOJO_MAP_BUFFER_FLAG_NONE, &mapping2)); + std::unique_ptr<PlatformSharedMemoryMapping> mapping2; + EXPECT_EQ(MOJO_RESULT_OK, dispatcher->MapBuffer(50, 50, &mapping2)); ASSERT_TRUE(mapping2); ASSERT_TRUE(mapping2->GetBase()); EXPECT_EQ(50u, mapping2->GetLength()); @@ -188,9 +188,8 @@ TEST_F(SharedBufferDispatcherTest, DuplicateBufferHandle) { nullptr, 100, &dispatcher1)); // Map and write something. - std::unique_ptr<PlatformSharedBufferMapping> mapping; - EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->MapBuffer( - 0, 100, MOJO_MAP_BUFFER_FLAG_NONE, &mapping)); + std::unique_ptr<PlatformSharedMemoryMapping> mapping; + EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->MapBuffer(0, 100, &mapping)); static_cast<char*>(mapping->GetBase())[0] = 'x'; mapping.reset(); @@ -204,8 +203,7 @@ TEST_F(SharedBufferDispatcherTest, DuplicateBufferHandle) { EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->Close()); // Map |dispatcher2| and read something. - EXPECT_EQ(MOJO_RESULT_OK, dispatcher2->MapBuffer( - 0, 100, MOJO_MAP_BUFFER_FLAG_NONE, &mapping)); + EXPECT_EQ(MOJO_RESULT_OK, dispatcher2->MapBuffer(0, 100, &mapping)); EXPECT_EQ('x', static_cast<char*>(mapping->GetBase())[0]); EXPECT_EQ(MOJO_RESULT_OK, dispatcher2->Close()); @@ -217,29 +215,57 @@ TEST_F(SharedBufferDispatcherTest, DuplicateBufferHandleOptionsValid) { SharedBufferDispatcher::kDefaultCreateOptions, nullptr, 100, &dispatcher1)); - // NOTE: On Android, once a region has been mapped read-only, it cannot - // be mapped writable anymore, so ensure that the READ_ONLY case - // appears last in the options[] table below. - MojoDuplicateBufferHandleOptions options[] = { - {sizeof(MojoDuplicateBufferHandleOptionsFlags), ~0u}, - {sizeof(MojoDuplicateBufferHandleOptions), - MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE}, - {sizeof(MojoDuplicateBufferHandleOptions), - MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY}}; - for (size_t i = 0; i < arraysize(options); i++) { - scoped_refptr<Dispatcher> dispatcher2; - EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->DuplicateBufferHandle( - &options[i], &dispatcher2)); - ASSERT_TRUE(dispatcher2); - EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER, dispatcher2->GetType()); - { - std::unique_ptr<PlatformSharedBufferMapping> mapping; - EXPECT_EQ(MOJO_RESULT_OK, dispatcher2->MapBuffer(0, 100, 0, &mapping)); - } - EXPECT_EQ(MOJO_RESULT_OK, dispatcher2->Close()); + scoped_refptr<SharedBufferDispatcher> dispatcher2; + EXPECT_EQ(MOJO_RESULT_OK, SharedBufferDispatcher::Create( + SharedBufferDispatcher::kDefaultCreateOptions, + nullptr, 100, &dispatcher2)); + + MojoDuplicateBufferHandleOptions kReadOnlyOptions = { + sizeof(MojoCreateSharedBufferOptions), + MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_READ_ONLY}; + + // NOTE: We forbid handles from being duplicated read-only after they've been + // duplicated non-read-only; conversely we also forbid handles from being + // duplicated non-read-only after they've been duplicated read-only. + scoped_refptr<Dispatcher> writable_duped_dispatcher1; + scoped_refptr<Dispatcher> read_only_duped_dispatcher1; + EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->DuplicateBufferHandle( + nullptr, &writable_duped_dispatcher1)); + EXPECT_TRUE(writable_duped_dispatcher1); + EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER, + writable_duped_dispatcher1->GetType()); + { + std::unique_ptr<PlatformSharedMemoryMapping> mapping; + EXPECT_EQ(MOJO_RESULT_OK, + writable_duped_dispatcher1->MapBuffer(0, 100, &mapping)); } + EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, + dispatcher1->DuplicateBufferHandle(&kReadOnlyOptions, + &read_only_duped_dispatcher1)); + EXPECT_FALSE(read_only_duped_dispatcher1); + + scoped_refptr<Dispatcher> read_only_duped_dispatcher2; + scoped_refptr<Dispatcher> writable_duped_dispatcher2; + EXPECT_EQ(MOJO_RESULT_OK, + dispatcher2->DuplicateBufferHandle(&kReadOnlyOptions, + &read_only_duped_dispatcher2)); + EXPECT_TRUE(read_only_duped_dispatcher2); + EXPECT_EQ(Dispatcher::Type::SHARED_BUFFER, + read_only_duped_dispatcher2->GetType()); + { + std::unique_ptr<PlatformSharedMemoryMapping> mapping; + EXPECT_EQ(MOJO_RESULT_OK, + read_only_duped_dispatcher2->MapBuffer(0, 100, &mapping)); + } + EXPECT_EQ( + MOJO_RESULT_FAILED_PRECONDITION, + dispatcher2->DuplicateBufferHandle(nullptr, &writable_duped_dispatcher2)); + EXPECT_FALSE(writable_duped_dispatcher2); EXPECT_EQ(MOJO_RESULT_OK, dispatcher1->Close()); + EXPECT_EQ(MOJO_RESULT_OK, writable_duped_dispatcher1->Close()); + EXPECT_EQ(MOJO_RESULT_OK, dispatcher2->Close()); + EXPECT_EQ(MOJO_RESULT_OK, read_only_duped_dispatcher2->Close()); } TEST_F(SharedBufferDispatcherTest, DuplicateBufferHandleOptionsInvalid) { @@ -251,7 +277,7 @@ TEST_F(SharedBufferDispatcherTest, DuplicateBufferHandleOptionsInvalid) { // Invalid |struct_size|. { MojoDuplicateBufferHandleOptions options = { - 1u, MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE}; + 1u, MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_NONE}; scoped_refptr<Dispatcher> dispatcher2; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, dispatcher1->DuplicateBufferHandle(&options, &dispatcher2)); @@ -294,17 +320,20 @@ TEST_F(SharedBufferDispatcherTest, MapBufferInvalidArguments) { SharedBufferDispatcher::kDefaultCreateOptions, nullptr, 100, &dispatcher)); - std::unique_ptr<PlatformSharedBufferMapping> mapping; + MojoSharedBufferInfo info = {sizeof(info), 0u}; + EXPECT_EQ(MOJO_RESULT_OK, dispatcher->GetBufferInfo(&info)); + + std::unique_ptr<PlatformSharedMemoryMapping> mapping; EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - dispatcher->MapBuffer(0, 101, MOJO_MAP_BUFFER_FLAG_NONE, &mapping)); + dispatcher->MapBuffer(0, info.size + 1, &mapping)); EXPECT_FALSE(mapping); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - dispatcher->MapBuffer(1, 100, MOJO_MAP_BUFFER_FLAG_NONE, &mapping)); + dispatcher->MapBuffer(1, info.size, &mapping)); EXPECT_FALSE(mapping); EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, - dispatcher->MapBuffer(0, 0, MOJO_MAP_BUFFER_FLAG_NONE, &mapping)); + dispatcher->MapBuffer(0, 0, &mapping)); EXPECT_FALSE(mapping); EXPECT_EQ(MOJO_RESULT_OK, dispatcher->Close()); diff --git a/chromium/mojo/edk/system/shared_buffer_unittest.cc b/chromium/mojo/edk/system/shared_buffer_unittest.cc index af2c7beb570..2e09b60059d 100644 --- a/chromium/mojo/edk/system/shared_buffer_unittest.cc +++ b/chromium/mojo/edk/system/shared_buffer_unittest.cc @@ -10,6 +10,8 @@ #include "base/logging.h" #include "base/memory/shared_memory.h" #include "base/strings/string_piece.h" +#include "mojo/edk/system/core.h" +#include "mojo/edk/system/shared_buffer_dispatcher.h" #include "mojo/edk/test/mojo_test_base.h" #include "mojo/public/c/system/types.h" #include "testing/gtest/include/gtest/gtest.h" @@ -238,14 +240,13 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadAndMapWriteSharedBuffer, // Read from the bufer. ExpectBufferContents(b, 0, "hello"); - // Extract the shared memory handle and try to map it writable. - base::SharedMemoryHandle shm_handle; - bool read_only = false; - ASSERT_EQ(MOJO_RESULT_OK, - PassSharedMemoryHandle(b, &shm_handle, nullptr, &read_only)); - base::SharedMemory shared_memory(shm_handle, false); - EXPECT_TRUE(read_only); - EXPECT_FALSE(shared_memory.Map(1234)); + // Extract the shared memory handle and verify that it is read-only. + auto* dispatcher = + static_cast<SharedBufferDispatcher*>(Core::Get()->GetDispatcher(b).get()); + base::subtle::PlatformSharedMemoryRegion& region = + dispatcher->GetRegionForTesting(); + EXPECT_EQ(region.GetMode(), + base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly); EXPECT_EQ("quit", ReadMessage(h)); WriteMessage(h, "ok"); @@ -301,14 +302,13 @@ TEST_F(SharedBufferTest, MAYBE_CreateAndPassFromChildReadOnlyBuffer) { EXPECT_EQ("", ReadMessageWithHandles(h, &b, 1)); ExpectBufferContents(b, 0, "hello"); - // Extract the shared memory handle and try to map it writable. - base::SharedMemoryHandle shm_handle; - bool read_only = false; - ASSERT_EQ(MOJO_RESULT_OK, - PassSharedMemoryHandle(b, &shm_handle, nullptr, &read_only)); - base::SharedMemory shared_memory(shm_handle, false); - EXPECT_TRUE(read_only); - EXPECT_FALSE(shared_memory.Map(1234)); + // Extract the shared memory handle and verify that it is read-only. + auto* dispatcher = static_cast<SharedBufferDispatcher*>( + Core::Get()->GetDispatcher(b).get()); + base::subtle::PlatformSharedMemoryRegion& region = + dispatcher->GetRegionForTesting(); + EXPECT_EQ(region.GetMode(), + base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly); WriteMessage(h, "quit"); EXPECT_EQ("ok", ReadMessage(h)); diff --git a/chromium/mojo/edk/system/signals_unittest.cc b/chromium/mojo/edk/system/signals_unittest.cc index becba29e6ff..34f2105ea94 100644 --- a/chromium/mojo/edk/system/signals_unittest.cc +++ b/chromium/mojo/edk/system/signals_unittest.cc @@ -159,7 +159,7 @@ TEST_F(SignalsTest, RemotePeers) { // And so should |c| after we fuse |d| to |a|. MojoHandle c, d; CreateMessagePipe(&c, &d); - EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(d, a)); + EXPECT_EQ(MOJO_RESULT_OK, MojoFuseMessagePipes(d, a, nullptr)); EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(c, MOJO_HANDLE_SIGNAL_PEER_REMOTE, MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED)); diff --git a/chromium/mojo/edk/system/trap_unittest.cc b/chromium/mojo/edk/system/trap_unittest.cc index 3081a223019..011f988020e 100644 --- a/chromium/mojo/edk/system/trap_unittest.cc +++ b/chromium/mojo/edk/system/trap_unittest.cc @@ -448,9 +448,11 @@ TEST_F(WatcherTest, WatchDataPipeConsumerNewDataReadable) { // NEW_DATA_READABLE signal. char large_buffer[512]; uint32_t large_read_size = 512; + MojoReadDataOptions options; + options.struct_size = sizeof(options); + options.flags = MOJO_READ_DATA_FLAG_ALL_OR_NONE; EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE, - MojoReadData(consumer, large_buffer, &large_read_size, - MOJO_READ_DATA_FLAG_ALL_OR_NONE)); + MojoReadData(consumer, &options, large_buffer, &large_read_size)); // Attempt to arm again. Should succeed. EXPECT_EQ(MOJO_RESULT_OK, @@ -1746,10 +1748,8 @@ void ReadAllMessages(const MojoTrapEvent* event) { if (event->result == MOJO_RESULT_OK) { MojoHandle handle = static_cast<MojoHandle>(event->trigger_context); MojoMessageHandle message; - while (MojoReadMessage(handle, &message, MOJO_READ_MESSAGE_FLAG_NONE) == - MOJO_RESULT_OK) { + while (MojoReadMessage(handle, nullptr, &message) == MOJO_RESULT_OK) MojoDestroyMessage(message); - } } constexpr size_t kNumRandomThingsToDoOnNotify = 5; @@ -1780,7 +1780,7 @@ void DoRandomThing(MojoHandle* watchers, ASSERT_EQ(MOJO_RESULT_OK, MojoSetMessageContext(message, 1, nullptr, nullptr, nullptr)); MojoWriteMessage(RandomHandle(watched_handles, num_watched_handles), - message, MOJO_WRITE_MESSAGE_FLAG_NONE); + message, nullptr); break; } case 5: diff --git a/chromium/mojo/edk/system/user_message_impl.cc b/chromium/mojo/edk/system/user_message_impl.cc index c894aa5e740..dc36c1f99e7 100644 --- a/chromium/mojo/edk/system/user_message_impl.cc +++ b/chromium/mojo/edk/system/user_message_impl.cc @@ -152,7 +152,7 @@ MojoResult CreateOrExtendSerializedEventMessage( DispatcherHeader* new_dispatcher_headers; char* new_dispatcher_data; size_t total_num_dispatchers = num_new_dispatchers; - std::vector<ScopedPlatformHandle> handles; + std::vector<ScopedInternalPlatformHandle> handles; if (original_message) { DCHECK(original_header); size_t original_dispatcher_headers_size = @@ -582,7 +582,7 @@ MojoResult UserMessageImpl::ExtractSerializedHandles( dispatcher_headers + header->num_dispatchers); size_t port_index = 0; size_t platform_handle_index = 0; - std::vector<ScopedPlatformHandle> msg_handles = + std::vector<ScopedInternalPlatformHandle> msg_handles = channel_message_->TakeHandles(); for (size_t i = 0; i < header->num_dispatchers; ++i) { const DispatcherHeader& dh = dispatcher_headers[i]; @@ -610,7 +610,7 @@ MojoResult UserMessageImpl::ExtractSerializedHandles( return MOJO_RESULT_ABORTED; } - ScopedPlatformHandle* out_handles = + ScopedInternalPlatformHandle* out_handles = !msg_handles.empty() ? msg_handles.data() + platform_handle_index : nullptr; dispatchers[i].dispatcher = Dispatcher::Deserialize( |