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/core.cc | |
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/core.cc')
-rw-r--r-- | chromium/mojo/edk/system/core.cc | 849 |
1 files changed, 576 insertions, 273 deletions
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) { |