diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-20 15:06:40 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-22 11:48:58 +0000 |
commit | daa093eea7c773db06799a13bd7e4e2e2a9f8f14 (patch) | |
tree | 96cc5e7b9194c1b29eab927730bfa419e7111c25 /chromium/mojo | |
parent | be59a35641616a4cf23c4a13fa0632624b021c1b (diff) | |
download | qtwebengine-chromium-daa093eea7c773db06799a13bd7e4e2e2a9f8f14.tar.gz |
BASELINE: Update Chromium to 63.0.3239.58
Change-Id: Ia93b322a00ba4dd4004f3bcf1254063ba90e1605
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/mojo')
88 files changed, 1453 insertions, 537 deletions
diff --git a/chromium/mojo/OWNERS b/chromium/mojo/OWNERS index f233345fc5a..b9a26a0461b 100644 --- a/chromium/mojo/OWNERS +++ b/chromium/mojo/OWNERS @@ -4,4 +4,7 @@ rockot@chromium.org sky@chromium.org yzshen@chromium.org +# For Fuchsia-specific changes: +per-file *_fuchsia*=file://build/fuchsia/OWNERS + # COMPONENT: Internals>Mojo diff --git a/chromium/mojo/common/BUILD.gn b/chromium/mojo/common/BUILD.gn index cef26db8ed6..70a55c630b3 100644 --- a/chromium/mojo/common/BUILD.gn +++ b/chromium/mojo/common/BUILD.gn @@ -15,6 +15,7 @@ group("common") { mojom("common_custom_types") { sources = [ "file.mojom", + "file_info.mojom", "file_path.mojom", "memory_allocator_dump_cross_process_uid.mojom", "process_id.mojom", diff --git a/chromium/mojo/common/file_info.mojom b/chromium/mojo/common/file_info.mojom new file mode 100644 index 00000000000..9777a2a63cf --- /dev/null +++ b/chromium/mojo/common/file_info.mojom @@ -0,0 +1,8 @@ +// Copyright 2017 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. + +module mojo.common.mojom; + +[Native] +struct FileInfo; diff --git a/chromium/mojo/common/file_info.typemap b/chromium/mojo/common/file_info.typemap new file mode 100644 index 00000000000..77b2ae20146 --- /dev/null +++ b/chromium/mojo/common/file_info.typemap @@ -0,0 +1,12 @@ +# Copyright 2017 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. + +mojom = "//mojo/common/file_info.mojom" +public_headers = [ "//base/files/file.h" ] +traits_headers = [ "//ipc/ipc_message_utils.h" ] +public_deps = [ + "//ipc", +] + +type_mappings = [ "mojo.common.mojom.FileInfo=base::File::Info" ] diff --git a/chromium/mojo/common/typemaps.gni b/chromium/mojo/common/typemaps.gni index b1d54a5af94..7a37beec4f9 100644 --- a/chromium/mojo/common/typemaps.gni +++ b/chromium/mojo/common/typemaps.gni @@ -4,6 +4,7 @@ typemaps = [ "//mojo/common/file.typemap", + "//mojo/common/file_info.typemap", "//mojo/common/file_path.typemap", "//mojo/common/memory_allocator_dump_cross_process_uid.typemap", "//mojo/common/process_id.typemap", diff --git a/chromium/mojo/common/values_struct_traits.h b/chromium/mojo/common/values_struct_traits.h index a4f618b107d..264e71245e6 100644 --- a/chromium/mojo/common/values_struct_traits.h +++ b/chromium/mojo/common/values_struct_traits.h @@ -128,7 +128,7 @@ struct StructTraits<common::mojom::NullValueDataView, void*> { template <> struct UnionTraits<common::mojom::ValueDataView, base::Value> { static common::mojom::ValueDataView::Tag GetTag(const base::Value& data) { - switch (data.GetType()) { + switch (data.type()) { case base::Value::Type::NONE: return common::mojom::ValueDataView::Tag::NULL_VALUE; case base::Value::Type::BOOLEAN: diff --git a/chromium/mojo/edk/embedder/platform_channel_pair_fuchsia.cc b/chromium/mojo/edk/embedder/platform_channel_pair_fuchsia.cc index 480545c8abe..e0f31b900aa 100644 --- a/chromium/mojo/edk/embedder/platform_channel_pair_fuchsia.cc +++ b/chromium/mojo/edk/embedder/platform_channel_pair_fuchsia.cc @@ -4,9 +4,9 @@ #include "mojo/edk/embedder/platform_channel_pair.h" -#include <magenta/process.h> -#include <magenta/processargs.h> -#include <magenta/syscalls.h> +#include <zircon/process.h> +#include <zircon/processargs.h> +#include <zircon/syscalls.h> #include "base/command_line.h" #include "base/logging.h" @@ -33,9 +33,9 @@ std::string PrepareToPassHandleToChildProcessAsString( } // namespace PlatformChannelPair::PlatformChannelPair(bool client_is_blocking) { - mx_handle_t handles[2] = {}; - mx_status_t result = mx_channel_create(0, &handles[0], &handles[1]); - CHECK_EQ(MX_OK, result); + zx_handle_t handles[2] = {}; + zx_status_t result = zx_channel_create(0, &handles[0], &handles[1]); + CHECK_EQ(ZX_OK, result); server_handle_.reset(PlatformHandle::ForHandle(handles[0])); DCHECK(server_handle_.is_valid()); @@ -60,7 +60,7 @@ PlatformChannelPair::PassClientHandleFromParentProcessFromString( return ScopedPlatformHandle(); } return ScopedPlatformHandle(PlatformHandle::ForHandle( - mx_get_startup_handle(base::checked_cast<uint32_t>(id)))); + zx_get_startup_handle(base::checked_cast<uint32_t>(id)))); } void PlatformChannelPair::PrepareToPassClientHandleToChildProcess( diff --git a/chromium/mojo/edk/embedder/platform_handle.cc b/chromium/mojo/edk/embedder/platform_handle.cc index 9505cf53569..50bc2a7740a 100644 --- a/chromium/mojo/edk/embedder/platform_handle.cc +++ b/chromium/mojo/edk/embedder/platform_handle.cc @@ -6,8 +6,8 @@ #include "build/build_config.h" #if defined(OS_FUCHSIA) -#include <magenta/status.h> -#include <magenta/syscalls.h> +#include <zircon/status.h> +#include <zircon/syscalls.h> #endif #if defined(OS_POSIX) #include <unistd.h> @@ -27,11 +27,11 @@ void PlatformHandle::CloseIfNecessary() { return; #if defined(OS_FUCHSIA) - if (handle != MX_HANDLE_INVALID) { - mx_status_t result = mx_handle_close(handle); - DCHECK_EQ(MX_OK, result) << "CloseIfNecessary(mx_handle_close): " - << mx_status_get_string(result); - handle = MX_HANDLE_INVALID; + if (handle != ZX_HANDLE_INVALID) { + zx_status_t result = zx_handle_close(handle); + DCHECK_EQ(ZX_OK, result) << "CloseIfNecessary(zx_handle_close): " + << zx_status_get_string(result); + handle = ZX_HANDLE_INVALID; } if (fd >= 0) { bool success = (close(fd) == 0); diff --git a/chromium/mojo/edk/embedder/platform_handle.h b/chromium/mojo/edk/embedder/platform_handle.h index aa866219c4d..cfd88a8f5a8 100644 --- a/chromium/mojo/edk/embedder/platform_handle.h +++ b/chromium/mojo/edk/embedder/platform_handle.h @@ -15,8 +15,8 @@ #elif defined(OS_MACOSX) && !defined(OS_IOS) #include <mach/mach.h> #elif defined(OS_FUCHSIA) -#include <magenta/syscalls.h> -#include <mxio/limits.h> +#include <fdio/limits.h> +#include <zircon/syscalls.h> #endif #include "base/logging.h" @@ -26,31 +26,31 @@ namespace edk { #if defined(OS_FUCHSIA) // TODO(fuchsia): Find a clean way to share this with the POSIX version. -// |mx_handle_t| is a typedef of |int|, so we only allow PlatformHandle to be +// |zx_handle_t| is a typedef of |int|, so we only allow PlatformHandle to be // created via explicit For<type>() creator functions. struct MOJO_SYSTEM_IMPL_EXPORT PlatformHandle { public: - static PlatformHandle ForHandle(mx_handle_t handle) { + static PlatformHandle ForHandle(zx_handle_t handle) { PlatformHandle platform_handle; platform_handle.handle = handle; return platform_handle; } static PlatformHandle ForFd(int fd) { PlatformHandle platform_handle; - DCHECK_LT(fd, MAX_MXIO_FD); + DCHECK_LT(fd, FDIO_MAX_FD); platform_handle.fd = fd; return platform_handle; } void CloseIfNecessary(); bool is_valid() const { return is_valid_fd() || is_valid_handle(); } - bool is_valid_handle() const { return handle != MX_HANDLE_INVALID && fd < 0; } - mx_handle_t as_handle() const { return handle; } - bool is_valid_fd() const { return fd >= 0 && handle == MX_HANDLE_INVALID; } + bool is_valid_handle() const { return handle != ZX_HANDLE_INVALID && fd < 0; } + zx_handle_t as_handle() const { return handle; } + bool is_valid_fd() const { return fd >= 0 && handle == ZX_HANDLE_INVALID; } int as_fd() const { return fd; } private: - mx_handle_t handle = MX_HANDLE_INVALID; + zx_handle_t handle = ZX_HANDLE_INVALID; int fd = -1; }; #elif defined(OS_POSIX) diff --git a/chromium/mojo/edk/embedder/platform_handle_utils_fuchsia.cc b/chromium/mojo/edk/embedder/platform_handle_utils_fuchsia.cc index 6bc238317fe..5ba0ad3c88b 100644 --- a/chromium/mojo/edk/embedder/platform_handle_utils_fuchsia.cc +++ b/chromium/mojo/edk/embedder/platform_handle_utils_fuchsia.cc @@ -11,11 +11,11 @@ namespace edk { ScopedPlatformHandle DuplicatePlatformHandle(PlatformHandle platform_handle) { DCHECK(platform_handle.is_valid()); - mx_handle_t duped; - // mx_handle_duplicate won't touch |duped| in case of failure. - mx_status_t result = mx_handle_duplicate(platform_handle.as_handle(), - MX_RIGHT_SAME_RIGHTS, &duped); - DLOG_IF(ERROR, result != MX_OK) << "mx_duplicate_handle failed: " << result; + zx_handle_t duped; + // zx_handle_duplicate won't touch |duped| in case of failure. + zx_status_t result = zx_handle_duplicate(platform_handle.as_handle(), + ZX_RIGHT_SAME_RIGHTS, &duped); + DLOG_IF(ERROR, result != ZX_OK) << "zx_duplicate_handle failed: " << result; return ScopedPlatformHandle(PlatformHandle::ForHandle(duped)); } diff --git a/chromium/mojo/edk/system/channel.cc b/chromium/mojo/edk/system/channel.cc index f4ff1cac415..168463848ae 100644 --- a/chromium/mojo/edk/system/channel.cc +++ b/chromium/mojo/edk/system/channel.cc @@ -57,7 +57,7 @@ const size_t kMaxUnusedReadBufferCapacity = 4096; // TODO(rockot): Increase this if/when Channel implementations support more. // Linux: The platform imposes a limit of 253 handles per sendmsg(). -// Fuchsia: The mx_channel_write() API supports up to 64 handles. +// Fuchsia: The zx_channel_write() API supports up to 64 handles. const size_t kMaxAttachedHandles = 64; Channel::Message::Message(size_t payload_size, size_t max_handles) diff --git a/chromium/mojo/edk/system/channel.h b/chromium/mojo/edk/system/channel.h index 4084436ee01..8156a348b26 100644 --- a/chromium/mojo/edk/system/channel.h +++ b/chromium/mojo/edk/system/channel.h @@ -112,11 +112,11 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel "sizeof(MachPortsExtraHeader) must be 2 bytes"); #elif defined(OS_FUCHSIA) struct HandleInfoEntry { - // The MXIO type associated with one or more handles, or zero for handles - // that do not belong to MXIO. + // The FDIO type associated with one or more handles, or zero for handles + // that do not belong to FDIO. uint8_t type; - // Zero for non-MXIO handles, otherwise the number of handles to consume - // to generate an MXIO file-descriptor wrapper. + // Zero for non-FDIO handles, otherwise the number of handles to consume + // to generate an FDIO file-descriptor wrapper. uint8_t count; }; #elif defined(OS_WIN) diff --git a/chromium/mojo/edk/system/channel_fuchsia.cc b/chromium/mojo/edk/system/channel_fuchsia.cc index fb3579e9fc5..b94920e8fcd 100644 --- a/chromium/mojo/edk/system/channel_fuchsia.cc +++ b/chromium/mojo/edk/system/channel_fuchsia.cc @@ -4,15 +4,15 @@ #include "mojo/edk/system/channel.h" -#include <magenta/processargs.h> -#include <magenta/status.h> -#include <magenta/syscalls.h> -#include <mxio/limits.h> -#include <mxio/util.h> +#include <fdio/limits.h> +#include <fdio/util.h> +#include <zircon/processargs.h> +#include <zircon/status.h> +#include <zircon/syscalls.h> #include <algorithm> -#include <deque> #include "base/bind.h" +#include "base/containers/circular_deque.h" #include "base/files/scoped_file.h" #include "base/location.h" #include "base/macros.h" @@ -40,19 +40,19 @@ bool UnwrapPlatformHandle(ScopedPlatformHandle handle, return true; } - // Each MXIO file descriptor is implemented using one or more native resources + // Each FDIO file descriptor is implemented using one or more native resources // and can be un-wrapped into a set of |handle| and |info| pairs, with |info| - // consisting of an MXIO-defined type & arguments (see magenta/processargs.h). - mx_handle_t handles[MXIO_MAX_HANDLES] = {}; - uint32_t info[MXIO_MAX_HANDLES] = {}; - mx_status_t result = mxio_transfer_fd(handle.get().as_fd(), 0, handles, info); - DCHECK_LE(result, MXIO_MAX_HANDLES); + // consisting of an FDIO-defined type & arguments (see zircon/processargs.h). + zx_handle_t handles[FDIO_MAX_HANDLES] = {}; + uint32_t info[FDIO_MAX_HANDLES] = {}; + zx_status_t result = fdio_transfer_fd(handle.get().as_fd(), 0, handles, info); + DCHECK_LE(result, FDIO_MAX_HANDLES); if (result <= 0) { - DLOG(ERROR) << "mxio_transfer_fd: " << mx_status_get_string(result); + DLOG(ERROR) << "fdio_transfer_fd: " << zx_status_get_string(result); return false; } - // The supplied file-descriptor was released by mxio_transfer_fd(). + // The supplied file-descriptor was released by fdio_transfer_fd(). ignore_result(handle.release()); // We assume here that only the |PA_HND_TYPE| of the |info| really matters, @@ -69,33 +69,33 @@ bool UnwrapPlatformHandle(ScopedPlatformHandle handle, ScopedPlatformHandle WrapPlatformHandles( Channel::Message::HandleInfoEntry info, - std::deque<base::ScopedMxHandle>* handles) { + base::circular_deque<base::ScopedZxHandle>* handles) { ScopedPlatformHandle out_handle; if (!info.type) { out_handle.reset(PlatformHandle::ForHandle(handles->front().release())); handles->pop_front(); } else { - if (info.count > MXIO_MAX_HANDLES) + if (info.count > FDIO_MAX_HANDLES) return ScopedPlatformHandle(); // Fetch the required number of handles from |handles| and set up type info. - mx_handle_t fd_handles[MXIO_MAX_HANDLES] = {}; - uint32_t fd_infos[MXIO_MAX_HANDLES] = {}; + zx_handle_t fd_handles[FDIO_MAX_HANDLES] = {}; + uint32_t fd_infos[FDIO_MAX_HANDLES] = {}; for (int i = 0; i < info.count; ++i) { fd_handles[i] = (*handles)[i].get(); fd_infos[i] = PA_HND(info.type, 0); } - // Try to wrap the handles into an MXIO file descriptor. + // Try to wrap the handles into an FDIO file descriptor. base::ScopedFD out_fd; - mx_status_t result = - mxio_create_fd(fd_handles, fd_infos, info.count, out_fd.receive()); - if (result != MX_OK) { - DLOG(ERROR) << "mxio_create_fd: " << mx_status_get_string(result); + zx_status_t result = + 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(); } - // The handles are owned by MXIO now, so |release()| them before removing + // The handles are owned by FDIO now, so |release()| them before removing // the entries from |handles|. for (int i = 0; i < info.count; ++i) { ignore_result(handles->front().release()); @@ -144,7 +144,7 @@ class MessageView { ScopedPlatformHandleVectorPtr TakeHandles() { if (handles_) { - // We can only pass Fuchsia handles via IPC, so unwrap any MXIO file- + // We can only pass Fuchsia handles via IPC, so unwrap any FDIO file- // descriptors in |handles_| into the underlying handles, and serialize // the metadata, if any, into the extra header. auto* handles_info = reinterpret_cast<Channel::Message::HandleInfoEntry*>( @@ -176,7 +176,7 @@ class MessageView { class ChannelFuchsia : public Channel, public base::MessageLoop::DestructionObserver, - public base::MessageLoopForIO::MxHandleWatcher { + public base::MessageLoopForIO::ZxHandleWatcher { public: ChannelFuchsia(Delegate* delegate, ConnectionParams connection_params, @@ -244,7 +244,7 @@ class ChannelFuchsia : public Channel, if (handles_info_size > extra_header_size) return false; - // Some caller-supplied handles may be MXIO file-descriptors, which were + // Some caller-supplied handles may be FDIO file-descriptors, which were // un-wrapped to more than one native platform resource handle for transfer. // We may therefore need to expect more than |num_handles| handles to have // been accumulated in |incoming_handles_|, based on the handle info. @@ -277,10 +277,10 @@ class ChannelFuchsia : public Channel, base::MessageLoop::current()->AddDestructionObserver(this); read_watch_.reset( - new base::MessageLoopForIO::MxHandleWatchController(FROM_HERE)); - base::MessageLoopForIO::current()->WatchMxHandle( + new base::MessageLoopForIO::ZxHandleWatchController(FROM_HERE)); + base::MessageLoopForIO::current()->WatchZxHandle( handle_.get().as_handle(), true /* persistent */, - MX_CHANNEL_READABLE | MX_CHANNEL_PEER_CLOSED, read_watch_.get(), this); + ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, read_watch_.get(), this); } void ShutDownOnIOThread() { @@ -302,13 +302,13 @@ class ChannelFuchsia : public Channel, ShutDownOnIOThread(); } - // base::MessageLoopForIO::MxHandleWatcher: - void OnMxHandleSignalled(mx_handle_t handle, mx_signals_t signals) override { + // base::MessageLoopForIO::ZxHandleWatcher: + void OnZxHandleSignalled(zx_handle_t handle, zx_signals_t signals) override { DCHECK(io_task_runner_->RunsTasksInCurrentSequence()); CHECK_EQ(handle, handle_.get().as_handle()); - DCHECK((MX_CHANNEL_READABLE | MX_CHANNEL_PEER_CLOSED) & signals); + DCHECK((ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED) & signals); - // We always try to read message(s), even if MX_CHANNEL_PEER_CLOSED, since + // We always try to read message(s), even if ZX_CHANNEL_PEER_CLOSED, since // the peer may have closed while messages were still unread, in the pipe. bool validation_error = false; @@ -323,14 +323,14 @@ class ChannelFuchsia : public Channel, uint32_t bytes_read = 0; uint32_t handles_read = 0; - mx_handle_t handles[MX_CHANNEL_MAX_MSG_HANDLES] = {}; + zx_handle_t handles[ZX_CHANNEL_MAX_MSG_HANDLES] = {}; - mx_status_t read_result = mx_channel_read( + zx_status_t read_result = zx_channel_read( handle_.get().as_handle(), 0, buffer, handles, buffer_capacity, arraysize(handles), &bytes_read, &handles_read); - if (read_result == MX_OK) { + if (read_result == ZX_OK) { for (size_t i = 0; i < handles_read; ++i) { - incoming_handles_.push_back(base::ScopedMxHandle(handles[i])); + incoming_handles_.push_back(base::ScopedZxHandle(handles[i])); } total_bytes_read += bytes_read; if (!OnReadComplete(bytes_read, &next_read_size)) { @@ -338,14 +338,14 @@ class ChannelFuchsia : public Channel, validation_error = true; break; } - } else if (read_result == MX_ERR_BUFFER_TOO_SMALL) { + } else if (read_result == ZX_ERR_BUFFER_TOO_SMALL) { DCHECK_LE(handles_read, arraysize(handles)); next_read_size = bytes_read; - } else if (read_result == MX_ERR_SHOULD_WAIT) { + } else if (read_result == ZX_ERR_SHOULD_WAIT) { break; } else { - DLOG_IF(ERROR, read_result != MX_ERR_PEER_CLOSED) - << "mx_channel_read: " << mx_status_get_string(read_result); + DLOG_IF(ERROR, read_result != ZX_ERR_PEER_CLOSED) + << "zx_channel_read: " << zx_status_get_string(read_result); read_error = true; break; } @@ -371,7 +371,7 @@ class ChannelFuchsia : public Channel, ScopedPlatformHandleVectorPtr outgoing_handles = message_view.TakeHandles(); size_t handles_count = 0; - mx_handle_t handles[MX_CHANNEL_MAX_MSG_HANDLES] = {}; + zx_handle_t handles[ZX_CHANNEL_MAX_MSG_HANDLES] = {}; if (outgoing_handles) { DCHECK_LE(outgoing_handles->size(), arraysize(handles)); @@ -383,16 +383,16 @@ class ChannelFuchsia : public Channel, } write_bytes = std::min(message_view.data_num_bytes(), - static_cast<size_t>(MX_CHANNEL_MAX_MSG_BYTES)); - mx_status_t result = - mx_channel_write(handle_.get().as_handle(), 0, message_view.data(), + static_cast<size_t>(ZX_CHANNEL_MAX_MSG_BYTES)); + zx_status_t result = + zx_channel_write(handle_.get().as_handle(), 0, message_view.data(), write_bytes, handles, handles_count); - if (result != MX_OK) { - // TODO(fuchsia): Handle MX_ERR_SHOULD_WAIT flow-control errors, once + if (result != ZX_OK) { + // TODO(fuchsia): Handle ZX_ERR_SHOULD_WAIT flow-control errors, once // the platform starts generating them. See crbug.com/754084. - DLOG_IF(ERROR, result != MX_ERR_PEER_CLOSED) - << "WriteNoLock(mx_channel_write): " - << mx_status_get_string(result); + DLOG_IF(ERROR, result != ZX_ERR_PEER_CLOSED) + << "WriteNoLock(zx_channel_write): " + << zx_status_get_string(result); return false; } @@ -415,8 +415,8 @@ class ChannelFuchsia : public Channel, scoped_refptr<base::TaskRunner> io_task_runner_; // These members are only used on the IO thread. - std::unique_ptr<base::MessageLoopForIO::MxHandleWatchController> read_watch_; - std::deque<base::ScopedMxHandle> incoming_handles_; + std::unique_ptr<base::MessageLoopForIO::ZxHandleWatchController> read_watch_; + base::circular_deque<base::ScopedZxHandle> incoming_handles_; bool leak_handle_ = false; base::Lock write_lock_; diff --git a/chromium/mojo/edk/system/core.cc b/chromium/mojo/edk/system/core.cc index bf289bf66d9..c40601c8ff3 100644 --- a/chromium/mojo/edk/system/core.cc +++ b/chromium/mojo/edk/system/core.cc @@ -799,6 +799,10 @@ MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options, create_options.capacity_num_bytes = options && options->capacity_num_bytes ? options->capacity_num_bytes : 64 * 1024; + if (!create_options.element_num_bytes || !create_options.capacity_num_bytes || + create_options.capacity_num_bytes < create_options.element_num_bytes) { + return MOJO_RESULT_INVALID_ARGUMENT; + } scoped_refptr<PlatformSharedBuffer> ring_buffer = GetNodeController()->CreateSharedBuffer( diff --git a/chromium/mojo/edk/system/core_test_base.cc b/chromium/mojo/edk/system/core_test_base.cc index 05a7f456818..9f8637c4a9a 100644 --- a/chromium/mojo/edk/system/core_test_base.cc +++ b/chromium/mojo/edk/system/core_test_base.cc @@ -30,7 +30,7 @@ class MockDispatcher : public Dispatcher { public: static scoped_refptr<MockDispatcher> Create( CoreTestBase::MockHandleInfo* info) { - return make_scoped_refptr(new MockDispatcher(info)); + return base::WrapRefCounted(new MockDispatcher(info)); } // Dispatcher: diff --git a/chromium/mojo/edk/system/data_pipe_consumer_dispatcher.cc b/chromium/mojo/edk/system/data_pipe_consumer_dispatcher.cc index ad32846c2f0..aed5944be85 100644 --- a/chromium/mojo/edk/system/data_pipe_consumer_dispatcher.cc +++ b/chromium/mojo/edk/system/data_pipe_consumer_dispatcher.cc @@ -372,6 +372,10 @@ DataPipeConsumerDispatcher::Deserialize(const void* data, } const SerializedState* state = static_cast<const SerializedState*>(data); + if (!state->options.capacity_num_bytes || !state->options.element_num_bytes || + state->options.capacity_num_bytes < state->options.element_num_bytes) { + return nullptr; + } NodeController* node_controller = internal::g_core->GetNodeController(); ports::PortRef port; @@ -443,7 +447,7 @@ bool DataPipeConsumerDispatcher::InitializeNoLock() { base::AutoUnlock unlock(lock_); node_controller_->SetPortObserver( - control_port_, make_scoped_refptr(new PortObserverThunk(this))); + control_port_, base::MakeRefCounted<PortObserverThunk>(this)); return true; } diff --git a/chromium/mojo/edk/system/data_pipe_producer_dispatcher.cc b/chromium/mojo/edk/system/data_pipe_producer_dispatcher.cc index 0edfc586742..53cc5267661 100644 --- a/chromium/mojo/edk/system/data_pipe_producer_dispatcher.cc +++ b/chromium/mojo/edk/system/data_pipe_producer_dispatcher.cc @@ -335,6 +335,10 @@ DataPipeProducerDispatcher::Deserialize(const void* data, } const SerializedState* state = static_cast<const SerializedState*>(data); + if (!state->options.capacity_num_bytes || !state->options.element_num_bytes || + state->options.capacity_num_bytes < state->options.element_num_bytes) { + return nullptr; + } NodeController* node_controller = internal::g_core->GetNodeController(); ports::PortRef port; @@ -406,7 +410,7 @@ bool DataPipeProducerDispatcher::InitializeNoLock() { base::AutoUnlock unlock(lock_); node_controller_->SetPortObserver( - control_port_, make_scoped_refptr(new PortObserverThunk(this))); + control_port_, base::MakeRefCounted<PortObserverThunk>(this)); return true; } diff --git a/chromium/mojo/edk/system/handle_table_unittest.cc b/chromium/mojo/edk/system/handle_table_unittest.cc index 1e7234210f1..32f6425586b 100644 --- a/chromium/mojo/edk/system/handle_table_unittest.cc +++ b/chromium/mojo/edk/system/handle_table_unittest.cc @@ -12,8 +12,15 @@ #include "base/trace_event/process_memory_dump.h" #include "base/trace_event/trace_event_argument.h" #include "mojo/edk/system/dispatcher.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using base::trace_event::MemoryAllocatorDump; +using testing::Contains; +using testing::Eq; +using testing::Contains; +using testing::ByRef; + namespace mojo { namespace edk { namespace { @@ -33,23 +40,13 @@ class FakeMessagePipeDispatcher : public Dispatcher { void CheckNameAndValue(base::trace_event::ProcessMemoryDump* pmd, const std::string& name, - const std::string& value) { + uint64_t value) { base::trace_event::MemoryAllocatorDump* mad = pmd->GetAllocatorDump(name); ASSERT_TRUE(mad); - std::unique_ptr<base::Value> dict_value = - mad->attributes_for_testing()->ToBaseValue(); - ASSERT_TRUE(dict_value->is_dict()); - - base::DictionaryValue* dict; - ASSERT_TRUE(dict_value->GetAsDictionary(&dict)); - - base::DictionaryValue* inner_dict; - ASSERT_TRUE(dict->GetDictionary("object_count", &inner_dict)); - - std::string output; - ASSERT_TRUE(inner_dict->GetString("value", &output)); - EXPECT_EQ(value, output); + MemoryAllocatorDump::Entry expected( + "object_count", MemoryAllocatorDump::kUnitsObjects, value); + EXPECT_THAT(mad->entries(), Contains(Eq(ByRef(expected)))); } } // namespace @@ -69,8 +66,8 @@ TEST(HandleTableTest, OnMemoryDump) { base::trace_event::ProcessMemoryDump pmd(nullptr, args); ht.OnMemoryDump(args, &pmd); - CheckNameAndValue(&pmd, "mojo/message_pipe", "1"); - CheckNameAndValue(&pmd, "mojo/data_pipe_consumer", "0"); + CheckNameAndValue(&pmd, "mojo/message_pipe", 1); + CheckNameAndValue(&pmd, "mojo/data_pipe_consumer", 0); } } // namespace edk diff --git a/chromium/mojo/edk/system/message_pipe_dispatcher.cc b/chromium/mojo/edk/system/message_pipe_dispatcher.cc index 1861df47ed7..5dc7dd1a5bf 100644 --- a/chromium/mojo/edk/system/message_pipe_dispatcher.cc +++ b/chromium/mojo/edk/system/message_pipe_dispatcher.cc @@ -97,7 +97,7 @@ MessagePipeDispatcher::MessagePipeDispatcher(NodeController* node_controller, << " [pipe_id=" << pipe_id << "; endpoint=" << endpoint << "]"; node_controller_->SetPortObserver( - port_, make_scoped_refptr(new PortObserverThunk(this))); + port_, base::MakeRefCounted<PortObserverThunk>(this)); } bool MessagePipeDispatcher::Fuse(MessagePipeDispatcher* other) { @@ -287,10 +287,7 @@ scoped_refptr<Dispatcher> MessagePipeDispatcher::Deserialize( state->pipe_id, state->endpoint); } -MessagePipeDispatcher::~MessagePipeDispatcher() { - // TODO(crbug.com/740044): Remove this CHECK. - CHECK(port_closed_ && !in_transit_); -} +MessagePipeDispatcher::~MessagePipeDispatcher() = default; MojoResult MessagePipeDispatcher::CloseNoLock() { signal_lock_.AssertAcquired(); diff --git a/chromium/mojo/edk/system/message_unittest.cc b/chromium/mojo/edk/system/message_unittest.cc index ea051a8c17f..bc126f13812 100644 --- a/chromium/mojo/edk/system/message_unittest.cc +++ b/chromium/mojo/edk/system/message_unittest.cc @@ -899,6 +899,35 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadMessageAndCheckPipe, MessageTest, h) { #endif // !defined(OS_IOS) +TEST_F(MessageTest, PartiallySerializedMessagesDontLeakHandles) { + MojoMessageHandle message; + EXPECT_EQ(MOJO_RESULT_OK, MojoCreateMessage(&message)); + + MojoHandle handles[2]; + CreateMessagePipe(&handles[0], &handles[1]); + + const std::string kTestMessagePart1("hello i am message."); + void* buffer; + uint32_t buffer_size; + EXPECT_EQ(MOJO_RESULT_OK, + MojoAttachSerializedMessageBuffer( + message, static_cast<uint32_t>(kTestMessagePart1.size()), + nullptr, 0, &buffer, &buffer_size)); + ASSERT_GE(buffer_size, static_cast<uint32_t>(kTestMessagePart1.size())); + memcpy(buffer, kTestMessagePart1.data(), kTestMessagePart1.size()); + + EXPECT_EQ(MOJO_RESULT_OK, + MojoExtendSerializedMessagePayload( + message, static_cast<uint32_t>(kTestMessagePart1.size()), + handles, 1, &buffer, &buffer_size)); + + // This must close |handles[0]|, which we can detect by observing the + // signal state of |handles[1]. + EXPECT_EQ(MOJO_RESULT_OK, MojoDestroyMessage(message)); + EXPECT_EQ(MOJO_RESULT_OK, + WaitForSignals(handles[1], MOJO_HANDLE_SIGNAL_PEER_CLOSED)); +} + } // namespace } // namespace edk } // namespace mojo diff --git a/chromium/mojo/edk/system/node_channel.h b/chromium/mojo/edk/system/node_channel.h index b3eac19d0c2..2e5e645cb19 100644 --- a/chromium/mojo/edk/system/node_channel.h +++ b/chromium/mojo/edk/system/node_channel.h @@ -5,11 +5,11 @@ #ifndef MOJO_EDK_SYSTEM_NODE_CHANNEL_H_ #define MOJO_EDK_SYSTEM_NODE_CHANNEL_H_ -#include <queue> #include <unordered_map> #include <utility> #include "base/callback.h" +#include "base/containers/queue.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/process/process_handle.h" @@ -165,9 +165,9 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>, private: friend class base::RefCountedThreadSafe<NodeChannel>; - using PendingMessageQueue = std::queue<Channel::MessagePtr>; + using PendingMessageQueue = base::queue<Channel::MessagePtr>; using PendingRelayMessageQueue = - std::queue<std::pair<ports::NodeName, Channel::MessagePtr>>; + base::queue<std::pair<ports::NodeName, Channel::MessagePtr>>; NodeChannel(Delegate* delegate, ConnectionParams connection_params, diff --git a/chromium/mojo/edk/system/node_controller.cc b/chromium/mojo/edk/system/node_controller.cc index d48ea882a29..ee5ffd1b4ee 100644 --- a/chromium/mojo/edk/system/node_controller.cc +++ b/chromium/mojo/edk/system/node_controller.cc @@ -8,6 +8,7 @@ #include <limits> #include "base/bind.h" +#include "base/containers/queue.h" #include "base/location.h" #include "base/logging.h" #include "base/macros.h" @@ -928,7 +929,7 @@ void NodeController::OnAcceptBrokerClient(const ports::NodeName& from_node, DCHECK(parent_name == from_node); DCHECK(parent); - std::queue<ports::NodeName> pending_broker_clients; + base::queue<ports::NodeName> pending_broker_clients; std::unordered_map<ports::NodeName, OutgoingMessageQueue> pending_relay_messages; { diff --git a/chromium/mojo/edk/system/node_controller.h b/chromium/mojo/edk/system/node_controller.h index e8e6f18201b..359a5c9e4fe 100644 --- a/chromium/mojo/edk/system/node_controller.h +++ b/chromium/mojo/edk/system/node_controller.h @@ -7,7 +7,6 @@ #include <map> #include <memory> -#include <queue> #include <string> #include <unordered_map> #include <unordered_set> @@ -16,6 +15,7 @@ #include "base/callback.h" #include "base/containers/hash_tables.h" +#include "base/containers/queue.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/task_runner.h" @@ -135,7 +135,7 @@ class NodeController : public ports::NodeDelegate, using NodeMap = std::unordered_map<ports::NodeName, scoped_refptr<NodeChannel>>; - using OutgoingMessageQueue = std::queue<Channel::MessagePtr>; + using OutgoingMessageQueue = base::queue<Channel::MessagePtr>; using PortMap = std::map<std::string, ports::PortRef>; struct PeerConnection { @@ -300,7 +300,7 @@ class NodeController : public ports::NodeDelegate, ports::NodeName broker_name_; // A queue of remote broker clients waiting to be connected to the broker. - std::queue<ports::NodeName> pending_broker_clients_; + base::queue<ports::NodeName> pending_broker_clients_; // Messages waiting to be relayed by the broker once it's known. std::unordered_map<ports::NodeName, OutgoingMessageQueue> diff --git a/chromium/mojo/edk/system/platform_wrapper_unittest.cc b/chromium/mojo/edk/system/platform_wrapper_unittest.cc index 418282df8db..6ed99667ee6 100644 --- a/chromium/mojo/edk/system/platform_wrapper_unittest.cc +++ b/chromium/mojo/edk/system/platform_wrapper_unittest.cc @@ -187,7 +187,7 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformSharedBuffer, #elif defined(OS_FUCHSIA) ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE, os_buffer.type); base::SharedMemoryHandle memory_handle( - static_cast<mx_handle_t>(os_buffer.value), size, guid); + static_cast<zx_handle_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( diff --git a/chromium/mojo/edk/system/ports/event.h b/chromium/mojo/edk/system/ports/event.h index 43f91e58bd4..27dc4fdda86 100644 --- a/chromium/mojo/edk/system/ports/event.h +++ b/chromium/mojo/edk/system/ports/event.h @@ -22,14 +22,38 @@ class Event; using ScopedEvent = std::unique_ptr<Event>; +// A Event is the fundamental unit of operation and communication within and +// between Nodes. class Event { public: enum Type : uint32_t { + // A user message event contains arbitrary user-specified payload data + // which may include any number of ports and/or system handles (e.g. FDs). kUserMessage, + + // When a Node receives a user message with one or more ports attached, it + // sends back an instance of this event for every attached port to indicate + // that the port has been accepted by its destination node. kPortAccepted, + + // This event begins circulation any time a port enters a proxying state. It + // may be re-circulated in certain edge cases, but the ultimate purpose of + // the event is to ensure that every port along a route is (if necessary) + // aware that the proxying port is indeed proxying (and to where) so that it + // can begin to be bypassed along the route. kObserveProxy, + + // An event used to acknowledge to a proxy that all concerned nodes and + // ports are aware of its proxying state and that no more user messages will + // be routed to it beyond a given final sequence number. kObserveProxyAck, + + // Indicates that a port has been closed. This event fully circulates a + // route to ensure that all ports are aware of closure. kObserveClosure, + + // Used to request the merging of two routes via two sacrificial receiving + // ports, one from each route. kMergePort, }; diff --git a/chromium/mojo/edk/system/ports/node.cc b/chromium/mojo/edk/system/ports/node.cc index 7c2859cef64..76787aaa4da 100644 --- a/chromium/mojo/edk/system/ports/node.cc +++ b/chromium/mojo/edk/system/ports/node.cc @@ -114,10 +114,8 @@ bool Node::CanShutdownCleanly(ShutdownPolicy policy) { #if DCHECK_IS_ON() for (auto& entry : ports_) { DVLOG(2) << "Port " << entry.first << " referencing node " - << entry.second.port->peer_node_name - << " is blocking shutdown of " - << "node " << name_ << " (state=" << entry.second.port->state - << ")"; + << entry.second->peer_node_name << " is blocking shutdown of " + << "node " << name_ << " (state=" << entry.second->state << ")"; } #endif return ports_.empty(); @@ -130,7 +128,7 @@ bool Node::CanShutdownCleanly(ShutdownPolicy policy) { // need to be blazingly fast. bool can_shutdown = true; for (auto& entry : ports_) { - PortRef port_ref(entry.first, entry.second.port); + PortRef port_ref(entry.first, entry.second); SinglePortLocker locker(&port_ref); auto* port = locker.port(); if (port->peer_node_name != name_ && port->state != Port::kReceiving) { @@ -161,7 +159,7 @@ int Node::GetPort(const PortName& port_name, PortRef* port_ref) { base::subtle::MemoryBarrier(); #endif - *port_ref = PortRef(port_name, iter->second.port); + *port_ref = PortRef(port_name, iter->second); return OK; } @@ -171,14 +169,8 @@ int Node::CreateUninitializedPort(PortRef* port_ref) { scoped_refptr<Port> port(new Port(kInitialSequenceNum, kInitialSequenceNum)); int rv = AddPortWithName(port_name, port); - if (rv != OK) { - // TODO(crbug.com/725605): Remove this CHECK. This is testing whether or not - // random port name generation is somehow resulting in insufficiently random - // and thus colliding names in the wild, which would be one explanation for - // some of the weird behavior we're seeing. - CHECK(false); + if (rv != OK) return rv; - } *port_ref = PortRef(port_name, std::move(port)); return OK; @@ -789,7 +781,7 @@ int Node::OnMergePort(std::unique_ptr<MergePortEvent> event) { int Node::AddPortWithName(const PortName& port_name, scoped_refptr<Port> port) { PortLocker::AssertNoPortsLockedOnCurrentThread(); base::AutoLock lock(ports_lock_); - if (!ports_.emplace(port_name, PortTableEntry(std::move(port))).second) + if (!ports_.emplace(port_name, std::move(port)).second) return OOPS(ERROR_PORT_EXISTS); // Suggests a bad UUID generator. DVLOG(2) << "Created port " << port_name << "@" << name_; return OK; @@ -803,7 +795,7 @@ void Node::ErasePort(const PortName& port_name) { auto it = ports_.find(port_name); if (it == ports_.end()) return; - port = std::move(it->second.port); + port = std::move(it->second); ports_.erase(it); } // NOTE: We are careful not to release the port's messages while holding any @@ -1001,9 +993,9 @@ void Node::ConvertToProxy(Port* port, int Node::AcceptPort(const PortName& port_name, const Event::PortDescriptor& port_descriptor) { - scoped_refptr<Port> port = make_scoped_refptr( - new Port(port_descriptor.next_sequence_num_to_send, - port_descriptor.next_sequence_num_to_receive)); + scoped_refptr<Port> port = + base::MakeRefCounted<Port>(port_descriptor.next_sequence_num_to_send, + port_descriptor.next_sequence_num_to_receive); port->state = Port::kReceiving; port->peer_node_name = port_descriptor.peer_node_name; port->peer_port_name = port_descriptor.peer_port_name; @@ -1299,7 +1291,7 @@ void Node::DestroyAllPortsWithPeer(const NodeName& node_name, base::AutoLock ports_lock(ports_lock_); for (auto iter = ports_.begin(); iter != ports_.end(); ++iter) { - PortRef port_ref(iter->first, iter->second.port); + PortRef port_ref(iter->first, iter->second); { SinglePortLocker locker(&port_ref); auto* port = locker.port(); @@ -1329,7 +1321,7 @@ void Node::DestroyAllPortsWithPeer(const NodeName& node_name, if (port->state != Port::kReceiving) { dead_proxies_to_broadcast.push_back(iter->first); std::vector<std::unique_ptr<UserMessageEvent>> messages; - iter->second.port->message_queue.TakeAllMessages(&messages); + iter->second->message_queue.TakeAllMessages(&messages); for (auto& message : messages) undelivered_messages.emplace_back(std::move(message)); } @@ -1384,23 +1376,6 @@ void Node::DelegateHolder::EnsureSafeDelegateAccess() const { } #endif -Node::PortTableEntry::PortTableEntry(scoped_refptr<Port> port) - : port(std::move(port)) {} - -Node::PortTableEntry::PortTableEntry(PortTableEntry&& other) = default; - -Node::PortTableEntry::~PortTableEntry() { - // We don't really anticipate hitting this CHECK given that we should be - // effectively working around memory corruption. Still it's a potentially - // useful signal if anything continues to go wrong, and it forces the value to - // be used. - CHECK_EQ(0x1827364554637281ULL, sentinel_value_); - sentinel_value_ = 0x8127364554637281ULL; -} - -Node::PortTableEntry& Node::PortTableEntry::operator=(PortTableEntry&& other) = - default; - } // namespace ports } // namespace edk } // namespace mojo diff --git a/chromium/mojo/edk/system/ports/node.h b/chromium/mojo/edk/system/ports/node.h index c8553113ab9..5bc8a12b737 100644 --- a/chromium/mojo/edk/system/ports/node.h +++ b/chromium/mojo/edk/system/ports/node.h @@ -45,6 +45,22 @@ struct PortStatus { class MessageFilter; class NodeDelegate; +// A Node maintains a collection of Ports (see port.h) indexed by unique 128-bit +// addresses (names), performing routing and processing of events among the +// Ports within the Node and to or from other Nodes in the system. Typically +// (and practically, in all uses today) there is a single Node per system +// process. Thus a Node boundary effectively models a process boundary. +// +// New Ports can be created uninitialized using CreateUninitializedPort (and +// later initialized using InitializePort), or created in a fully initialized +// state using CreatePortPair(). Initialized ports have exactly one conjugate +// port which is the ultimate receiver of any user messages sent by that port. +// See SendUserMessage(). +// +// In addition to routing user message events, various control events are used +// by Nodes to coordinate Port behavior and lifetime within and across Nodes. +// See Event documentation for description of different types of events used by +// a Node to coordinate behavior. class Node { public: enum class ShutdownPolicy { @@ -211,24 +227,6 @@ class Node { const NodeName name_; const DelegateHolder delegate_; - // A wrapper structure for Port table entries. https://crbug.com/725605 likely - // indicates memory corruption stomping on the Port table, and there is no - // clue as to where the corruption is coming from. Changing the size of the - // map entry allocations should effectively work around the bug, as it did for - // https://crbug.com/740044. - struct PortTableEntry { - explicit PortTableEntry(scoped_refptr<Port> port); - PortTableEntry(const PortTableEntry&) = delete; - PortTableEntry(PortTableEntry&& other); - ~PortTableEntry(); - - PortTableEntry& operator=(const PortTableEntry&) = delete; - PortTableEntry& operator=(PortTableEntry&& other); - - uint64_t sentinel_value_ = 0x1827364554637281ULL; - scoped_refptr<Port> port; - }; - // Guards |ports_|. This must never be acquired while an individual port's // lock is held on the same thread. Conversely, individual port locks may be // acquired while this one is held. @@ -237,7 +235,7 @@ class Node { // destruction, it is also important to ensure that such events are never // destroyed while this (or any individual Port) lock is held. base::Lock ports_lock_; - std::unordered_map<PortName, PortTableEntry> ports_; + std::unordered_map<PortName, scoped_refptr<Port>> ports_; DISALLOW_COPY_AND_ASSIGN(Node); }; diff --git a/chromium/mojo/edk/system/ports/port.h b/chromium/mojo/edk/system/ports/port.h index 514aa491b87..e10bfebe41d 100644 --- a/chromium/mojo/edk/system/ports/port.h +++ b/chromium/mojo/edk/system/ports/port.h @@ -23,25 +23,129 @@ namespace ports { class PortLocker; +// A Port is essentially a node in a circular list of addresses. For the sake of +// this documentation such a list will henceforth be referred to as a "route." +// Routes are the fundamental medium upon which all Node event circulation takes +// place and are thus the backbone of all Mojo message passing. +// +// Each Port is identified by a 128-bit address within a Node (see node.h). A +// Port doesn't really *do* anything per se: it's a named collection of state, +// and its owning Node manages all event production, transmission, routing, and +// processing logic. See Node for more details on how Ports may be used to +// transmit arbitrary user messages as well as other Ports. +// +// Ports may be in any of a handful of states (see State below) which dictate +// how they react to system events targeting them. In the simplest and most +// common case, Ports are initially created as an entangled pair (i.e. a simple +// cycle consisting of two Ports) both in the |kReceiving| State. Consider Ports +// we'll label |A| and |B| here, which may be created using +// Node::CreatePortPair(): +// +// +-----+ +-----+ +// | |--------->| | +// | A | | B | +// | |<---------| | +// +-----+ +-----+ +// +// |A| references |B| via |peer_node_name| and |peer_port_name|, while |B| in +// turn references |A|. Note that a Node is NEVER aware of who is sending events +// to a given Port; it is only aware of where it must route events FROM a given +// Port. +// +// For the sake of documentation, we refer to one receiving port in a route as +// the "conjugate" of the other. A receiving port's conjugate is also its peer +// upon initial creation, but because of proxying this may not be the case at a +// later time. +// +// ALL access to this data structure must be guarded by |lock_| acquisition, +// which is only possible using a PortLocker. PortLocker ensures that +// overlapping Port lock acquisitions on a single thread are always acquired in +// a globally consistent order. class Port : public base::RefCountedThreadSafe<Port> { public: + // The state of a given Port. A Port may only exist in one of these states at + // any given time. enum State { + // The Port is not yet paired with a peer and is therefore unusable. See + // Node::CreateUninitializedPort and Node::InitializePort for motivation. kUninitialized, + + // The Port is publicly visible outside of its Node and may be used to send + // and receive user messages. There are always AT MOST two |kReceiving| + // Ports along any given route. A user message event sent from a receiving + // port is always circulated along the Port's route until it reaches either + // a dead-end -- in which case the route is broken -- or it reaches the + // other receiving Port in the route -- in which case it lands in that + // Port's incoming message queue which can by read by user code. kReceiving, + + // The Port has been taken out of the |kReceiving| state in preparation for + // proxying to a new destination. A Port enters this state immediately when + // it's attached to a user message and may only leave this state when + // transitioning to |kProxying|. See Node for more details. kBuffering, + + // The Port is forwarding all user messages (and most other events) to its + // peer without discretion. Ports in the |kProxying| state may never leave + // this state and only exist temporarily until their owning Node has + // established that no more events will target them. See Node for more + // details. kProxying, + + // The Port has been closed and is now permanently unusable. Only + // |kReceiving| ports can be closed. kClosed }; + // The current State of the Port. State state; + + // The Node and Port address to which events should be routed FROM this Port. + // Note that this is NOT necessarily the address of the Port currently sending + // events TO this Port. NodeName peer_node_name; PortName peer_port_name; + + // The next available sequence number to use for outgoing user message events + // originating from this port. uint64_t next_sequence_num_to_send; + + // The sequence number of the last message this Port should ever expect to + // receive in its lifetime. May be used to determine that a proxying port is + // ready to be destroyed or that a receiving port's conjugate has been closed + // and we know the sequence number of the last message it sent. uint64_t last_sequence_num_to_receive; + + // The queue of incoming user messages received by this Port. Only non-empty + // for buffering or receiving Ports. When a buffering port enters the proxying + // state, it flushes its queue and the proxy then bypasses the queue + // indefinitely. + // + // A receiving port's queue only has elements removed by user code reading + // messages from the port. + // + // Note that this is a priority queue which only exposes messages to consumers + // in strict sequential order. MessageQueue message_queue; + + // In some edge cases, a Node may need to remember to route a single special + // event upon destruction of this (proxying) Port. That event is stashed here + // in the interim. std::unique_ptr<std::pair<NodeName, ScopedEvent>> send_on_proxy_removal; + + // Arbitrary user data attached to the Port. In practice, Mojo uses this to + // stash an observer interface which can be notified about various Port state + // changes. scoped_refptr<UserData> user_data; + + // Indicates that this (proxying) Port has received acknowledgement that no + // new user messages will be routed to it. If |true|, the proxy will be + // removed once it has received and forwarded all sequenced messages up to and + // including the one numbered |last_sequence_num_to_receive|. bool remove_proxy_on_last_message; + + // Indicates that this Port is aware that its nearest (in terms of forward, + // non-zero cyclic routing distance) receiving Port has been closed. bool peer_closed; Port(uint64_t next_sequence_num_to_send, diff --git a/chromium/mojo/edk/system/ports/ports_unittest.cc b/chromium/mojo/edk/system/ports/ports_unittest.cc index 1d573950c25..e74e7c8069f 100644 --- a/chromium/mojo/edk/system/ports/ports_unittest.cc +++ b/chromium/mojo/edk/system/ports/ports_unittest.cc @@ -8,12 +8,12 @@ #include <string.h> #include <map> -#include <queue> #include <sstream> #include <utility> #include "base/bind.h" #include "base/callback.h" +#include "base/containers/queue.h" #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/strings/string_piece.h" @@ -292,8 +292,8 @@ class TestNode : public NodeDelegate { bool blocked_ = false; bool block_on_event_ = false; Event::Type blocked_event_type_; - std::queue<ScopedEvent> incoming_events_; - std::queue<ScopedMessage> saved_messages_; + base::queue<ScopedEvent> incoming_events_; + base::queue<ScopedMessage> saved_messages_; }; class PortsTest : public testing::Test, public MessageRouter { diff --git a/chromium/mojo/edk/system/shared_buffer_dispatcher.h b/chromium/mojo/edk/system/shared_buffer_dispatcher.h index 6015595317d..17cd4205be0 100644 --- a/chromium/mojo/edk/system/shared_buffer_dispatcher.h +++ b/chromium/mojo/edk/system/shared_buffer_dispatcher.h @@ -90,7 +90,7 @@ class MOJO_SYSTEM_IMPL_EXPORT SharedBufferDispatcher final : public Dispatcher { private: static scoped_refptr<SharedBufferDispatcher> CreateInternal( scoped_refptr<PlatformSharedBuffer> shared_buffer) { - return make_scoped_refptr( + return base::WrapRefCounted( new SharedBufferDispatcher(std::move(shared_buffer))); } diff --git a/chromium/mojo/edk/system/user_message_impl.cc b/chromium/mojo/edk/system/user_message_impl.cc index cc046ab6d33..a84a097568e 100644 --- a/chromium/mojo/edk/system/user_message_impl.cc +++ b/chromium/mojo/edk/system/user_message_impl.cc @@ -279,7 +279,9 @@ UserMessageImpl::~UserMessageImpl() { if (!pending_handle_attachments_.empty()) { internal::g_core->ReleaseDispatchersForTransit( - pending_handle_attachments_, true); + pending_handle_attachments_, false); + for (const auto& dispatcher : pending_handle_attachments_) + MojoClose(dispatcher.local_handle); } } } diff --git a/chromium/mojo/edk/system/watcher_dispatcher.cc b/chromium/mojo/edk/system/watcher_dispatcher.cc index 3bd3f6eb486..f84db482980 100644 --- a/chromium/mojo/edk/system/watcher_dispatcher.cc +++ b/chromium/mojo/edk/system/watcher_dispatcher.cc @@ -25,11 +25,6 @@ void WatcherDispatcher::NotifyHandleState(Dispatcher* dispatcher, if (it == watched_handles_.end()) return; - // TODO(crbug.com/740044): Remove this. - uint32_t sentinel = sentinel_value_for_debugging_; - base::debug::Alias(&sentinel); - CHECK_EQ(0x12345678u, sentinel); - // Maybe fire a notification to the watch associated with this dispatcher, // provided we're armed and it cares about the new state. if (it->second->NotifyState(state, armed_)) { @@ -58,11 +53,6 @@ void WatcherDispatcher::NotifyHandleClosed(Dispatcher* dispatcher) { watched_handles_.erase(it); } - // TODO(crbug.com/740044): Remove this. - uint32_t sentinel = sentinel_value_for_debugging_; - base::debug::Alias(&sentinel); - CHECK_EQ(0x12345678u, sentinel); - // NOTE: It's important that this is called outside of |lock_| since it // acquires internal Watch locks. watch->Cancel(); @@ -184,11 +174,6 @@ MojoResult WatcherDispatcher::CancelWatch(uintptr_t context) { watches_.erase(it); } - // TODO(crbug.com/740044): Remove this. - uint32_t sentinel = sentinel_value_for_debugging_; - base::debug::Alias(&sentinel); - CHECK_EQ(0x12345678u, sentinel); - // Mark the watch as cancelled so no further notifications get through. watch->Cancel(); @@ -268,10 +253,7 @@ MojoResult WatcherDispatcher::Arm( return MOJO_RESULT_FAILED_PRECONDITION; } -WatcherDispatcher::~WatcherDispatcher() { - // TODO(crbug.com/740044): Remove this. - sentinel_value_for_debugging_ = 0x87654321; -} +WatcherDispatcher::~WatcherDispatcher() = default; } // namespace edk } // namespace mojo diff --git a/chromium/mojo/edk/system/watcher_dispatcher.h b/chromium/mojo/edk/system/watcher_dispatcher.h index 145435a643b..4b681f743d3 100644 --- a/chromium/mojo/edk/system/watcher_dispatcher.h +++ b/chromium/mojo/edk/system/watcher_dispatcher.h @@ -95,9 +95,6 @@ class WatcherDispatcher : public Dispatcher { // an invalid object. It must therefore never be dereferenced. const Watch* last_watch_to_block_arming_ = nullptr; - // TODO(crbug.com/740044): Remove this. - uint32_t sentinel_value_for_debugging_ = 0x12345678; - DISALLOW_COPY_AND_ASSIGN(WatcherDispatcher); }; diff --git a/chromium/mojo/public/c/system/data_pipe.h b/chromium/mojo/public/c/system/data_pipe.h index aaeafcf21e7..62adbea1ea6 100644 --- a/chromium/mojo/public/c/system/data_pipe.h +++ b/chromium/mojo/public/c/system/data_pipe.h @@ -129,8 +129,9 @@ extern "C" { // // Returns: // |MOJO_RESULT_OK| on success. -// |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid (e.g., -// |*options| is invalid). +// |MOJO_RESULT_INVALID_ARGUMENT| if some argument was invalid, e.g., +// |*options| is invalid, specified capacity or element size is zero, or +// the specified element size exceeds the specified capacity. // |MOJO_RESULT_RESOURCE_EXHAUSTED| if a process/system/quota/etc. limit has // been reached (e.g., if the requested capacity was too large, or if the // maximum number of handles was exceeded). diff --git a/chromium/mojo/public/c/system/platform_handle.h b/chromium/mojo/public/c/system/platform_handle.h index b58b538750b..665d7f80c27 100644 --- a/chromium/mojo/public/c/system/platform_handle.h +++ b/chromium/mojo/public/c/system/platform_handle.h @@ -30,7 +30,7 @@ extern "C" { // |MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT| - A Mach port. Only valid on OS X. // |MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE| - A Windows HANDLE value. Only // valid on Windows. -// |MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE| - A Fuchsia mx_handle_t value. +// |MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE| - A Fuchsia zx_handle_t value. // Only valid on Fuchsia. typedef uint32_t MojoPlatformHandleType; diff --git a/chromium/mojo/public/cpp/bindings/BUILD.gn b/chromium/mojo/public/cpp/bindings/BUILD.gn index b732b54c266..5f584d994d1 100644 --- a/chromium/mojo/public/cpp/bindings/BUILD.gn +++ b/chromium/mojo/public/cpp/bindings/BUILD.gn @@ -2,8 +2,19 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/buildflag_header.gni") interfaces_bindings_gen_dir = "$root_gen_dir/mojo/public/interfaces/bindings" +declare_args() { + enable_mojo_tracing = false +} + +buildflag_header("mojo_features") { + header = "mojo_features.h" + + flags = [ "MOJO_TRACE_ENABLED=$enable_mojo_tracing" ] +} + component("bindings") { sources = [ # Normally, targets should depend on the source_sets generated by mojom @@ -16,6 +27,11 @@ component("bindings") { "$interfaces_bindings_gen_dir/interface_control_messages.mojom-shared.h", "$interfaces_bindings_gen_dir/interface_control_messages.mojom.cc", "$interfaces_bindings_gen_dir/interface_control_messages.mojom.h", + "$interfaces_bindings_gen_dir/native_struct.mojom-shared-internal.h", + "$interfaces_bindings_gen_dir/native_struct.mojom-shared.cc", + "$interfaces_bindings_gen_dir/native_struct.mojom-shared.h", + "$interfaces_bindings_gen_dir/native_struct.mojom.cc", + "$interfaces_bindings_gen_dir/native_struct.mojom.h", "$interfaces_bindings_gen_dir/pipe_control_messages.mojom-shared-internal.h", "$interfaces_bindings_gen_dir/pipe_control_messages.mojom-shared.cc", "$interfaces_bindings_gen_dir/pipe_control_messages.mojom-shared.h", @@ -86,9 +102,6 @@ component("bindings") { "lib/multiplex_router.h", "lib/native_enum_data.h", "lib/native_enum_serialization.h", - "lib/native_struct.cc", - "lib/native_struct_data.cc", - "lib/native_struct_data.h", "lib/native_struct_serialization.cc", "lib/native_struct_serialization.h", "lib/pipe_control_message_handler.cc", @@ -122,8 +135,6 @@ component("bindings") { "message.h", "message_header_validator.h", "native_enum.h", - "native_struct.h", - "native_struct_data_view.h", "pipe_control_message_handler.h", "pipe_control_message_handler_delegate.h", "pipe_control_message_proxy.h", @@ -147,14 +158,17 @@ component("bindings") { ] public_deps = [ + ":mojo_features", ":struct_traits", "//base", + "//ipc:message_support", "//ipc:param_traits", "//mojo/public/cpp/system", ] deps = [ "//base", + "//ipc:native_handle_type_converters", "//mojo/public/interfaces/bindings:bindings__generator", "//mojo/public/interfaces/bindings:bindings_shared__generator", ] diff --git a/chromium/mojo/public/cpp/bindings/associated_binding.h b/chromium/mojo/public/cpp/bindings/associated_binding.h index c34e971b23a..c100a1dd423 100644 --- a/chromium/mojo/public/cpp/bindings/associated_binding.h +++ b/chromium/mojo/public/cpp/bindings/associated_binding.h @@ -135,6 +135,13 @@ class AssociatedBinding : public AssociatedBindingBase { // Returns the interface implementation that was previously specified. Interface* impl() { return ImplRefTraits::GetRawPointer(&stub_.sink()); } + // Allows test code to swap the interface implementation. + ImplPointerType SwapImplForTesting(ImplPointerType new_impl) { + Interface* old_impl = impl(); + stub_.set_sink(std::move(new_impl)); + return old_impl; + } + private: typename Interface::template Stub_<ImplRefTraits> stub_; diff --git a/chromium/mojo/public/cpp/bindings/binding.h b/chromium/mojo/public/cpp/bindings/binding.h index b0e22244c3e..409f9cd9323 100644 --- a/chromium/mojo/public/cpp/bindings/binding.h +++ b/chromium/mojo/public/cpp/bindings/binding.h @@ -229,6 +229,11 @@ class Binding { return internal_state_.RouterForTesting(); } + // Allows test code to swap the interface implementation. + ImplPointerType SwapImplForTesting(ImplPointerType new_impl) { + return internal_state_.SwapImplForTesting(new_impl); + } + private: internal::BindingState<Interface, ImplRefTraits> internal_state_; diff --git a/chromium/mojo/public/cpp/bindings/binding_set.h b/chromium/mojo/public/cpp/bindings/binding_set.h index 7e5ece27bb8..737affb0e29 100644 --- a/chromium/mojo/public/cpp/bindings/binding_set.h +++ b/chromium/mojo/public/cpp/bindings/binding_set.h @@ -123,6 +123,18 @@ class BindingSetBase { return true; } + // Swaps the interface implementation with a different one, to allow tests + // to modify behavior. + // + // Returns the existing interface implementation to the caller. + ImplPointerType SwapImplForTesting(BindingId id, ImplPointerType new_impl) { + auto it = bindings_.find(id); + if (it == bindings_.end()) + return nullptr; + + return it->second->SwapImplForTesting(new_impl); + } + void CloseAllBindings() { bindings_.clear(); } bool empty() const { return bindings_.empty(); } @@ -216,6 +228,10 @@ class BindingSetBase { void FlushForTesting() { binding_.FlushForTesting(); } + ImplPointerType SwapImplForTesting(ImplPointerType new_impl) { + return binding_.SwapImplForTesting(new_impl); + } + private: class DispatchFilter : public MessageReceiver { public: diff --git a/chromium/mojo/public/cpp/bindings/lib/binding_state.h b/chromium/mojo/public/cpp/bindings/lib/binding_state.h index 465951abe69..4d9be92fc50 100644 --- a/chromium/mojo/public/cpp/bindings/lib/binding_state.h +++ b/chromium/mojo/public/cpp/bindings/lib/binding_state.h @@ -121,6 +121,11 @@ class BindingState : public BindingStateBase { } Interface* impl() { return ImplRefTraits::GetRawPointer(&stub_.sink()); } + ImplPointerType SwapImplForTesting(ImplPointerType new_impl) { + Interface* old_impl = impl(); + stub_.set_sink(std::move(new_impl)); + return old_impl; + } private: typename Interface::template Stub_<ImplRefTraits> stub_; diff --git a/chromium/mojo/public/cpp/bindings/lib/bindings_internal.h b/chromium/mojo/public/cpp/bindings/lib/bindings_internal.h index f761145c31f..8bdb9c7b771 100644 --- a/chromium/mojo/public/cpp/bindings/lib/bindings_internal.h +++ b/chromium/mojo/public/cpp/bindings/lib/bindings_internal.h @@ -35,8 +35,6 @@ class InterfaceRequestDataView; template <typename K, typename V> class MapDataView; -class NativeStructDataView; - class StringDataView; namespace internal { @@ -55,8 +53,6 @@ class Array_Data; template <typename K, typename V> class Map_Data; -class NativeStruct_Data; - using String_Data = Array_Data<char>; inline size_t Align(size_t size) { @@ -300,14 +296,6 @@ struct MojomTypeTraits<MapDataView<K, V>, false> { }; template <> -struct MojomTypeTraits<NativeStructDataView, false> { - using Data = internal::NativeStruct_Data; - using DataAsArrayElement = Pointer<Data>; - - static const MojomTypeCategory category = MojomTypeCategory::STRUCT; -}; - -template <> struct MojomTypeTraits<StringDataView, false> { using Data = String_Data; using DataAsArrayElement = Pointer<Data>; diff --git a/chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc b/chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc index f32f5d4d6e1..9cac8cca093 100644 --- a/chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc +++ b/chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc @@ -287,8 +287,13 @@ bool InterfaceEndpointClient::AcceptWithResponder( DCHECK(base::ContainsKey(sync_responses_, request_id)); auto iter = sync_responses_.find(request_id); DCHECK_EQ(&response_received, iter->second->response_received); - if (response_received) + if (response_received) { ignore_result(responder->Accept(&iter->second->response)); + } else { + DVLOG(1) << "Mojo sync call returns without receiving a response. " + << "Typcially it is because the interface has been " + << "disconnected."; + } sync_responses_.erase(iter); } diff --git a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc index faa200488eb..851a833d5b8 100644 --- a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc +++ b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc @@ -659,16 +659,19 @@ void MultiplexRouter::OnPipeConnectionError() { encountered_error_ = true; - for (auto iter = endpoints_.begin(); iter != endpoints_.end();) { - InterfaceEndpoint* endpoint = iter->second.get(); - // Increment the iterator before calling UpdateEndpointStateMayRemove() - // because it may remove the corresponding value from the map. - ++iter; - + // Calling UpdateEndpointStateMayRemove() may remove the corresponding value + // from |endpoints_| and invalidate any iterator of |endpoints_|. Therefore, + // copy the endpoint pointers to a vector and iterate over it instead. + std::vector<scoped_refptr<InterfaceEndpoint>> endpoint_vector; + endpoint_vector.reserve(endpoints_.size()); + for (const auto& pair : endpoints_) + endpoint_vector.push_back(pair.second); + + for (const auto& endpoint : endpoint_vector) { if (endpoint->client()) - tasks_.push_back(Task::CreateNotifyErrorTask(endpoint)); + tasks_.push_back(Task::CreateNotifyErrorTask(endpoint.get())); - UpdateEndpointStateMayRemove(endpoint, PEER_ENDPOINT_CLOSED); + UpdateEndpointStateMayRemove(endpoint.get(), PEER_ENDPOINT_CLOSED); } ProcessTasks(connector_.during_sync_handle_watcher_callback() diff --git a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h index 1af0111f0a6..8c2e7c8b0fc 100644 --- a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h +++ b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h @@ -13,6 +13,7 @@ #include "base/compiler_specific.h" #include "base/containers/queue.h" +#include "base/containers/small_map.h" #include "base/logging.h" #include "base/macros.h" #include "base/memory/ref_counted.h" @@ -258,7 +259,8 @@ class MOJO_CPP_BINDINGS_EXPORT MultiplexRouter // NOTE: It is unsafe to call into this object while holding |lock_|. PipeControlMessageProxy control_message_proxy_; - std::map<InterfaceId, scoped_refptr<InterfaceEndpoint>> endpoints_; + base::small_map<std::map<InterfaceId, scoped_refptr<InterfaceEndpoint>>, 1> + endpoints_; uint32_t next_interface_id_value_ = 1; base::circular_deque<std::unique_ptr<Task>> tasks_; diff --git a/chromium/mojo/public/cpp/bindings/lib/native_struct.cc b/chromium/mojo/public/cpp/bindings/lib/native_struct.cc deleted file mode 100644 index 7b1a1a6c594..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/native_struct.cc +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/public/cpp/bindings/native_struct.h" - -#include "mojo/public/cpp/bindings/lib/hash_util.h" - -namespace mojo { - -// static -NativeStructPtr NativeStruct::New() { - return NativeStructPtr(base::in_place); -} - -NativeStruct::NativeStruct() {} - -NativeStruct::~NativeStruct() {} - -NativeStructPtr NativeStruct::Clone() const { - NativeStructPtr rv(New()); - rv->data = data; - return rv; -} - -bool NativeStruct::Equals(const NativeStruct& other) const { - return data == other.data; -} - -size_t NativeStruct::Hash(size_t seed) const { - return internal::Hash(seed, data); -} - -} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/native_struct_data.cc b/chromium/mojo/public/cpp/bindings/lib/native_struct_data.cc deleted file mode 100644 index 0e5d2456927..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/native_struct_data.cc +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/public/cpp/bindings/lib/native_struct_data.h" - -#include "mojo/public/cpp/bindings/lib/buffer.h" -#include "mojo/public/cpp/bindings/lib/validation_context.h" - -namespace mojo { -namespace internal { - -// static -bool NativeStruct_Data::Validate(const void* data, - ValidationContext* validation_context) { - const ContainerValidateParams data_validate_params(0, false, nullptr); - return Array_Data<uint8_t>::Validate(data, validation_context, - &data_validate_params); -} - -} // namespace internal -} // namespace mojo diff --git a/chromium/mojo/public/cpp/bindings/lib/native_struct_data.h b/chromium/mojo/public/cpp/bindings/lib/native_struct_data.h deleted file mode 100644 index bf3e8906f70..00000000000 --- a/chromium/mojo/public/cpp/bindings/lib/native_struct_data.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_STRUCT_DATA_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_STRUCT_DATA_H_ - -#include <vector> - -#include "base/macros.h" -#include "mojo/public/cpp/bindings/bindings_export.h" -#include "mojo/public/cpp/bindings/lib/array_internal.h" -#include "mojo/public/cpp/system/handle.h" - -namespace mojo { -namespace internal { - -class ValidationContext; - -class MOJO_CPP_BINDINGS_EXPORT NativeStruct_Data { - public: - class BufferWriter { - public: - BufferWriter() = default; - - void Allocate(size_t num_bytes, Buffer* buffer) { - array_writer_.Allocate(num_bytes, buffer); - } - - Array_Data<uint8_t>::BufferWriter& array_writer() { return array_writer_; } - - bool is_null() const { return array_writer_.is_null(); } - NativeStruct_Data* data() { - return reinterpret_cast<NativeStruct_Data*>(array_writer_.data()); - } - NativeStruct_Data* operator->() { return data(); } - - private: - Array_Data<uint8_t>::BufferWriter array_writer_; - - DISALLOW_COPY_AND_ASSIGN(BufferWriter); - }; - - static bool Validate(const void* data, ValidationContext* validation_context); - - // Unlike normal structs, the memory layout is exactly the same as an array - // of uint8_t. - Array_Data<uint8_t> data; - - private: - NativeStruct_Data() = delete; - ~NativeStruct_Data() = delete; -}; - -static_assert(sizeof(Array_Data<uint8_t>) == sizeof(NativeStruct_Data), - "Mismatched NativeStruct_Data and Array_Data<uint8_t> size"); - -} // namespace internal -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_NATIVE_STRUCT_DATA_H_ diff --git a/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.cc b/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.cc index 5834be7c053..a31f8e4ec82 100644 --- a/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.cc +++ b/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.cc @@ -4,42 +4,121 @@ #include "mojo/public/cpp/bindings/lib/native_struct_serialization.h" +#include "ipc/ipc_message_attachment.h" +#include "ipc/ipc_message_attachment_set.h" +#include "ipc/native_handle_type_converters.h" +#include "mojo/public/cpp/bindings/lib/handle_interface_serialization.h" #include "mojo/public/cpp/bindings/lib/serialization.h" +#include "mojo/public/cpp/bindings/lib/serialization_forward.h" namespace mojo { namespace internal { // static void UnmappedNativeStructSerializerImpl::Serialize( - const NativeStructPtr& input, + const native::NativeStructPtr& input, Buffer* buffer, - NativeStruct_Data::BufferWriter* writer, + native::internal::NativeStruct_Data::BufferWriter* writer, SerializationContext* context) { if (!input) return; - const ContainerValidateParams params(0, false, nullptr); - internal::Serialize<ArrayDataView<uint8_t>>( - input->data, buffer, &writer->array_writer(), ¶ms, context); + writer->Allocate(buffer); + + Array_Data<uint8_t>::BufferWriter data_writer; + const mojo::internal::ContainerValidateParams data_validate_params(0, false, + nullptr); + mojo::internal::Serialize<ArrayDataView<uint8_t>>( + input->data, buffer, &data_writer, &data_validate_params, context); + writer->data()->data.Set(data_writer.data()); + + mojo::internal::Array_Data<mojo::internal::Pointer< + native::internal::SerializedHandle_Data>>::BufferWriter handles_writer; + const mojo::internal::ContainerValidateParams handles_validate_params( + 0, false, nullptr); + mojo::internal::Serialize< + mojo::ArrayDataView<::mojo::native::SerializedHandleDataView>>( + input->handles, buffer, &handles_writer, &handles_validate_params, + context); + writer->data()->handles.Set(handles_writer.is_null() ? nullptr + : handles_writer.data()); } // static bool UnmappedNativeStructSerializerImpl::Deserialize( - NativeStruct_Data* input, - NativeStructPtr* output, + native::internal::NativeStruct_Data* input, + native::NativeStructPtr* output, + SerializationContext* context) { + if (!input) { + output->reset(); + return true; + } + + native::NativeStructDataView data_view(input, context); + return StructTraits<::mojo::native::NativeStructDataView, + native::NativeStructPtr>::Read(data_view, output); +} + +// static +void UnmappedNativeStructSerializerImpl::SerializeMessageContents( + IPC::Message* message, + Buffer* buffer, + native::internal::NativeStruct_Data::BufferWriter* writer, SerializationContext* context) { - Array_Data<uint8_t>* data = reinterpret_cast<Array_Data<uint8_t>*>(input); + writer->Allocate(buffer); + + // Allocate a uint8 array, initialize its header, and copy the Pickle in. + Array_Data<uint8_t>::BufferWriter data_writer; + data_writer.Allocate(message->payload_size(), buffer); + memcpy(data_writer->storage(), message->payload(), message->payload_size()); + writer->data()->data.Set(data_writer.data()); + + if (message->attachment_set()->empty()) { + writer->data()->handles.Set(nullptr); + return; + } + + mojo::internal::Array_Data<mojo::internal::Pointer< + native::internal::SerializedHandle_Data>>::BufferWriter handles_writer; + auto* attachments = message->attachment_set(); + handles_writer.Allocate(attachments->size(), buffer); + for (unsigned i = 0; i < attachments->size(); ++i) { + native::internal::SerializedHandle_Data::BufferWriter handle_writer; + handle_writer.Allocate(buffer); + + auto attachment = attachments->GetAttachmentAt(i); + ScopedHandle handle = attachment->TakeMojoHandle(); + internal::Serializer<ScopedHandle, ScopedHandle>::Serialize( + handle, &handle_writer->the_handle, context); + handle_writer->type = static_cast<int32_t>( + mojo::ConvertTo<native::SerializedHandle::Type>(attachment->GetType())); + handles_writer.data()->at(i).Set(handle_writer.data()); + } + writer->data()->handles.Set(handles_writer.data()); +} + +// static +bool UnmappedNativeStructSerializerImpl::DeserializeMessageAttachments( + native::internal::NativeStruct_Data* data, + SerializationContext* context, + IPC::Message* message) { + if (data->handles.is_null()) + return true; - NativeStructPtr result(NativeStruct::New()); - if (!internal::Deserialize<ArrayDataView<uint8_t>>(data, &result->data, - context)) { - output = nullptr; - return false; + auto* handles_data = data->handles.Get(); + for (size_t i = 0; i < handles_data->size(); ++i) { + auto* handle_data = handles_data->at(i).Get(); + if (!handle_data) + return false; + ScopedHandle handle; + internal::Serializer<ScopedHandle, ScopedHandle>::Deserialize( + &handle_data->the_handle, &handle, context); + auto attachment = IPC::MessageAttachment::CreateFromMojoHandle( + std::move(handle), + mojo::ConvertTo<IPC::MessageAttachment::Type>( + static_cast<native::SerializedHandle::Type>(handle_data->type))); + message->attachment_set()->AddAttachment(std::move(attachment)); } - if (!result->data) - *output = nullptr; - else - result.Swap(output); return true; } diff --git a/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.h b/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.h index 0bc3c6e9124..6aa4c3a4a85 100644 --- a/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.h +++ b/chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.h @@ -12,44 +12,63 @@ #include "base/logging.h" #include "base/pickle.h" +#include "ipc/ipc_message.h" #include "ipc/ipc_param_traits.h" #include "mojo/public/cpp/bindings/bindings_export.h" #include "mojo/public/cpp/bindings/lib/array_internal.h" #include "mojo/public/cpp/bindings/lib/bindings_internal.h" -#include "mojo/public/cpp/bindings/lib/native_struct_data.h" #include "mojo/public/cpp/bindings/lib/serialization_forward.h" #include "mojo/public/cpp/bindings/lib/serialization_util.h" -#include "mojo/public/cpp/bindings/native_struct.h" -#include "mojo/public/cpp/bindings/native_struct_data_view.h" +#include "mojo/public/interfaces/bindings/native_struct.mojom.h" namespace mojo { namespace internal { +// Base class for the templated native struct serialization interface below, +// used to consolidated some shared logic and provide a basic +// Serialize/Deserialize for [Native] mojom structs which do not have a +// registered typemap in the current configuration (i.e. structs that are +// represented by a raw native::NativeStruct mojom struct in C++ bindings.) +struct MOJO_CPP_BINDINGS_EXPORT UnmappedNativeStructSerializerImpl { + static void Serialize( + const native::NativeStructPtr& input, + Buffer* buffer, + native::internal::NativeStruct_Data::BufferWriter* writer, + SerializationContext* context); + + static bool Deserialize(native::internal::NativeStruct_Data* input, + native::NativeStructPtr* output, + SerializationContext* context); + + static void SerializeMessageContents( + IPC::Message* message, + Buffer* buffer, + native::internal::NativeStruct_Data::BufferWriter* writer, + SerializationContext* context); + + static bool DeserializeMessageAttachments( + native::internal::NativeStruct_Data* data, + SerializationContext* context, + IPC::Message* message); +}; + template <typename MaybeConstUserType> struct NativeStructSerializerImpl { using UserType = typename std::remove_const<MaybeConstUserType>::type; using Traits = IPC::ParamTraits<UserType>; - static void Serialize(MaybeConstUserType& value, - Buffer* buffer, - NativeStruct_Data::BufferWriter* writer, - SerializationContext* context) { - base::Pickle pickle; - Traits::Write(&pickle, value); - -#if DCHECK_IS_ON() - base::PickleSizer sizer; - Traits::GetSize(&sizer, value); - DCHECK_EQ(sizer.payload_size(), pickle.payload_size()); -#endif - - // Allocate a uint8 array, initialize its header, and copy the Pickle in. - writer->Allocate(pickle.payload_size(), buffer); - memcpy(writer->array_writer()->storage(), pickle.payload(), - pickle.payload_size()); + static void Serialize( + MaybeConstUserType& value, + Buffer* buffer, + native::internal::NativeStruct_Data::BufferWriter* writer, + SerializationContext* context) { + IPC::Message message; + Traits::Write(&message, value); + UnmappedNativeStructSerializerImpl::SerializeMessageContents( + &message, buffer, writer, context); } - static bool Deserialize(NativeStruct_Data* data, + static bool Deserialize(native::internal::NativeStruct_Data* data, UserType* out, SerializationContext* context) { if (!data) @@ -67,7 +86,7 @@ struct NativeStructSerializerImpl { // Because ArrayHeader's num_bytes includes the length of the header and // Pickle's payload_size does not, we need to adjust the stored value // momentarily so Pickle can view the data. - ArrayHeader* header = reinterpret_cast<ArrayHeader*>(data); + ArrayHeader* header = reinterpret_cast<ArrayHeader*>(data->data.Get()); DCHECK_GE(header->num_bytes, sizeof(ArrayHeader)); header->num_bytes -= sizeof(ArrayHeader); @@ -75,10 +94,15 @@ struct NativeStructSerializerImpl { // Construct a view over the full Array_Data, including our hacked up // header. Pickle will infer from this that the header is 8 bytes long, // and the payload will contain all of the pickled bytes. - base::Pickle pickle_view(reinterpret_cast<const char*>(header), - header->num_bytes + sizeof(ArrayHeader)); - base::PickleIterator iter(pickle_view); - if (!Traits::Read(&pickle_view, &iter, out)) + IPC::Message message_view(reinterpret_cast<const char*>(header), + header->num_bytes + sizeof(ArrayHeader)); + base::PickleIterator iter(message_view); + if (!UnmappedNativeStructSerializerImpl::DeserializeMessageAttachments( + data, context, &message_view)) { + return false; + } + + if (!Traits::Read(&message_view, &iter, out)) return false; } @@ -89,26 +113,16 @@ struct NativeStructSerializerImpl { } }; -struct MOJO_CPP_BINDINGS_EXPORT UnmappedNativeStructSerializerImpl { - static void Serialize(const NativeStructPtr& input, - Buffer* buffer, - NativeStruct_Data::BufferWriter* writer, - SerializationContext* context); - static bool Deserialize(NativeStruct_Data* input, - NativeStructPtr* output, - SerializationContext* context); -}; - template <> -struct NativeStructSerializerImpl<NativeStructPtr> +struct NativeStructSerializerImpl<native::NativeStructPtr> : public UnmappedNativeStructSerializerImpl {}; template <> -struct NativeStructSerializerImpl<const NativeStructPtr> +struct NativeStructSerializerImpl<const native::NativeStructPtr> : public UnmappedNativeStructSerializerImpl {}; template <typename MaybeConstUserType> -struct Serializer<NativeStructDataView, MaybeConstUserType> +struct Serializer<native::NativeStructDataView, MaybeConstUserType> : public NativeStructSerializerImpl<MaybeConstUserType> {}; } // namespace internal diff --git a/chromium/mojo/public/cpp/bindings/lib/serialization.h b/chromium/mojo/public/cpp/bindings/lib/serialization.h index f5e89e29334..90f64f3059f 100644 --- a/chromium/mojo/public/cpp/bindings/lib/serialization.h +++ b/chromium/mojo/public/cpp/bindings/lib/serialization.h @@ -15,7 +15,6 @@ #include "mojo/public/cpp/bindings/lib/handle_interface_serialization.h" #include "mojo/public/cpp/bindings/lib/map_serialization.h" #include "mojo/public/cpp/bindings/lib/native_enum_serialization.h" -#include "mojo/public/cpp/bindings/lib/native_struct_serialization.h" #include "mojo/public/cpp/bindings/lib/string_serialization.h" #include "mojo/public/cpp/bindings/lib/template_util.h" #include "mojo/public/cpp/bindings/map_traits_stl.h" diff --git a/chromium/mojo/public/cpp/bindings/native_struct.h b/chromium/mojo/public/cpp/bindings/native_struct.h deleted file mode 100644 index ac27250bcc4..00000000000 --- a/chromium/mojo/public/cpp/bindings/native_struct.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_H_ - -#include <vector> - -#include "base/optional.h" -#include "mojo/public/cpp/bindings/bindings_export.h" -#include "mojo/public/cpp/bindings/lib/native_struct_data.h" -#include "mojo/public/cpp/bindings/struct_ptr.h" -#include "mojo/public/cpp/bindings/type_converter.h" - -namespace mojo { - -class NativeStruct; -using NativeStructPtr = StructPtr<NativeStruct>; - -// Native-only structs correspond to "[Native] struct Foo;" definitions in -// mojom. -class MOJO_CPP_BINDINGS_EXPORT NativeStruct { - public: - using Data_ = internal::NativeStruct_Data; - - static NativeStructPtr New(); - - template <typename U> - static NativeStructPtr From(const U& u) { - return TypeConverter<NativeStructPtr, U>::Convert(u); - } - - template <typename U> - U To() const { - return TypeConverter<U, NativeStruct>::Convert(*this); - } - - NativeStruct(); - ~NativeStruct(); - - NativeStructPtr Clone() const; - bool Equals(const NativeStruct& other) const; - size_t Hash(size_t seed) const; - - base::Optional<std::vector<uint8_t>> data; -}; - -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_H_ diff --git a/chromium/mojo/public/cpp/bindings/native_struct_data_view.h b/chromium/mojo/public/cpp/bindings/native_struct_data_view.h deleted file mode 100644 index 613bd7a0b0e..00000000000 --- a/chromium/mojo/public/cpp/bindings/native_struct_data_view.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_DATA_VIEW_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_DATA_VIEW_H_ - -#include "mojo/public/cpp/bindings/lib/native_struct_data.h" -#include "mojo/public/cpp/bindings/lib/serialization_context.h" - -namespace mojo { - -class NativeStructDataView { - public: - using Data_ = internal::NativeStruct_Data; - - NativeStructDataView() {} - - NativeStructDataView(Data_* data, internal::SerializationContext* context) - : data_(data) {} - - bool is_null() const { return !data_; } - - size_t size() const { return data_->data.size(); } - - uint8_t operator[](size_t index) const { return data_->data.at(index); } - - const uint8_t* data() const { return data_->data.storage(); } - - private: - Data_* data_ = nullptr; -}; - -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_NATIVE_STRUCT_DATA_VIEW_H_ diff --git a/chromium/mojo/public/cpp/bindings/tests/BUILD.gn b/chromium/mojo/public/cpp/bindings/tests/BUILD.gn index 456da1300e3..136e8e6aec1 100644 --- a/chromium/mojo/public/cpp/bindings/tests/BUILD.gn +++ b/chromium/mojo/public/cpp/bindings/tests/BUILD.gn @@ -28,6 +28,7 @@ source_set("tests") { "message_queue.cc", "message_queue.h", "multiplex_router_unittest.cc", + "native_struct_unittest.cc", "report_bad_message_unittest.cc", "request_response_unittest.cc", "router_test_util.cc", diff --git a/chromium/mojo/public/cpp/bindings/tests/test_native_types_chromium.typemap b/chromium/mojo/public/cpp/bindings/tests/test_native_types_chromium.typemap index 50e8076a505..da99a1a8d7b 100644 --- a/chromium/mojo/public/cpp/bindings/tests/test_native_types_chromium.typemap +++ b/chromium/mojo/public/cpp/bindings/tests/test_native_types_chromium.typemap @@ -3,9 +3,13 @@ # found in the LICENSE file. mojom = "//mojo/public/interfaces/bindings/tests/test_native_types.mojom" -public_headers = [ "//mojo/public/cpp/bindings/tests/pickled_types_chromium.h" ] +public_headers = [ + "//mojo/public/cpp/bindings/tests/pickled_types_chromium.h", + "//mojo/public/cpp/bindings/tests/test_native_types.h", +] sources = [ "//mojo/public/cpp/bindings/tests/pickled_types_chromium.cc", + "//mojo/public/cpp/bindings/tests/test_native_types.cc", ] deps = [ "//ipc", @@ -14,4 +18,6 @@ deps = [ type_mappings = [ "mojo.test.PickledEnum=mojo::test::PickledEnumChromium", "mojo.test.PickledStruct=mojo::test::PickledStructChromium[move_only]", + "mojo.test.TestNativeStructMojom=mojo::test::TestNativeStruct", + "mojo.test.TestNativeStructWithAttachmentsMojom=mojo::test::TestNativeStructWithAttachments[move_only]", ] diff --git a/chromium/mojo/public/cpp/bindings/thread_safe_interface_ptr.h b/chromium/mojo/public/cpp/bindings/thread_safe_interface_ptr.h index 7ca8328311f..53182fb2578 100644 --- a/chromium/mojo/public/cpp/bindings/thread_safe_interface_ptr.h +++ b/chromium/mojo/public/cpp/bindings/thread_safe_interface_ptr.h @@ -133,7 +133,7 @@ class ThreadSafeForwarder : public MessageReceiverWithResponder { // If the InterfacePtr is bound on another sequence, post the call. // TODO(yzshen, watk): We block both this sequence and the InterfacePtr // sequence. Ideally only this sequence would block. - auto response = make_scoped_refptr(new SyncResponseInfo()); + auto response = base::MakeRefCounted<SyncResponseInfo>(); auto response_signaler = std::make_unique<SyncResponseSignaler>(response); task_runner_->PostTask( FROM_HERE, base::Bind(forward_with_responder_, base::Passed(message), diff --git a/chromium/mojo/public/cpp/system/BUILD.gn b/chromium/mojo/public/cpp/system/BUILD.gn index 5dbbd36e63f..71156a55061 100644 --- a/chromium/mojo/public/cpp/system/BUILD.gn +++ b/chromium/mojo/public/cpp/system/BUILD.gn @@ -27,6 +27,8 @@ component("system") { "buffer.h", "core.h", "data_pipe.h", + "file_data_pipe_producer.cc", + "file_data_pipe_producer.g", "functions.h", "handle.h", "handle_signal_tracker.cc", @@ -39,6 +41,8 @@ component("system") { "platform_handle.h", "simple_watcher.cc", "simple_watcher.h", + "string_data_pipe_producer.cc", + "string_data_pipe_producer.h", "system_export.h", "wait.cc", "wait.h", diff --git a/chromium/mojo/public/cpp/system/file_data_pipe_producer.cc b/chromium/mojo/public/cpp/system/file_data_pipe_producer.cc new file mode 100644 index 00000000000..ab511e1f874 --- /dev/null +++ b/chromium/mojo/public/cpp/system/file_data_pipe_producer.cc @@ -0,0 +1,215 @@ +// Copyright 2017 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/public/cpp/system/file_data_pipe_producer.h" + +#include <algorithm> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/location.h" +#include "base/memory/ptr_util.h" +#include "base/memory/ref_counted_delete_on_sequence.h" +#include "base/numerics/safe_conversions.h" +#include "base/sequenced_task_runner.h" +#include "base/synchronization/lock.h" +#include "base/task_scheduler/post_task.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "mojo/public/cpp/system/simple_watcher.h" + +namespace mojo { + +namespace { + +// No good reason not to attempt very large pipe transactions in case the data +// pipe in use has a very large capacity available, so we default to trying +// 64 MB chunks whenever a producer is writable. +constexpr uint32_t kDefaultMaxReadSize = 64 * 1024 * 1024; + +} // namespace + +class FileDataPipeProducer::FileSequenceState + : public base::RefCountedDeleteOnSequence<FileSequenceState> { + public: + using CompletionCallback = + base::OnceCallback<void(ScopedDataPipeProducerHandle producer, + MojoResult result)>; + + FileSequenceState( + ScopedDataPipeProducerHandle producer_handle, + scoped_refptr<base::SequencedTaskRunner> file_task_runner, + CompletionCallback callback, + scoped_refptr<base::SequencedTaskRunner> callback_task_runner) + : base::RefCountedDeleteOnSequence<FileSequenceState>(file_task_runner), + file_task_runner_(std::move(file_task_runner)), + callback_task_runner_(std::move(callback_task_runner)), + producer_handle_(std::move(producer_handle)), + callback_(std::move(callback)) {} + + void Cancel() { + base::AutoLock lock(lock_); + is_cancelled_ = true; + } + + void StartFromFile(base::File file) { + file_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&FileSequenceState::StartFromFileOnFileSequence, this, + std::move(file))); + } + + void StartFromPath(const base::FilePath& path) { + file_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&FileSequenceState::StartFromPathOnFileSequence, this, + path)); + } + + private: + friend class base::DeleteHelper<FileSequenceState>; + friend class base::RefCountedDeleteOnSequence<FileSequenceState>; + + ~FileSequenceState() = default; + + void StartFromFileOnFileSequence(base::File file) { + file_ = std::move(file); + TransferSomeBytes(); + if (producer_handle_.is_valid()) { + // If we didn't nail it all on the first transaction attempt, setup a + // watcher and complete the read asynchronously. + watcher_ = base::MakeUnique<SimpleWatcher>( + FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC); + watcher_->Watch(producer_handle_.get(), MOJO_HANDLE_SIGNAL_WRITABLE, + MOJO_WATCH_CONDITION_SATISFIED, + base::Bind(&FileSequenceState::OnHandleReady, this)); + } + } + + void StartFromPathOnFileSequence(const base::FilePath& path) { + StartFromFileOnFileSequence( + base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ)); + } + + void OnHandleReady(MojoResult result, const HandleSignalsState& state) { + { + // Stop ourselves from doing redundant work if we've been cancelled from + // another thread. Note that we do not rely on this for any kind of thread + // safety concerns. + base::AutoLock lock(lock_); + if (is_cancelled_) + return; + } + + if (result != MOJO_RESULT_OK) { + // Either the consumer pipe has been closed or something terrible + // happened. In any case, we'll never be able to write more data. + Finish(MOJO_RESULT_ABORTED); + return; + } + + TransferSomeBytes(); + } + + void TransferSomeBytes() { + while (true) { + // Lock as much of the pipe as we can. + void* pipe_buffer; + uint32_t size = kDefaultMaxReadSize; + MojoResult result = producer_handle_->BeginWriteData( + &pipe_buffer, &size, MOJO_WRITE_DATA_FLAG_NONE); + if (result == MOJO_RESULT_SHOULD_WAIT) + return; + if (result != MOJO_RESULT_OK) { + Finish(MOJO_RESULT_ABORTED); + return; + } + + // Attempt to read that many bytes from the file, directly into the data + // pipe. + DCHECK(base::IsValueInRangeForNumericType<int>(size)); + int attempted_read_size = static_cast<int>(size); + int read_size = file_.ReadAtCurrentPos(static_cast<char*>(pipe_buffer), + attempted_read_size); + producer_handle_->EndWriteData( + read_size >= 0 ? static_cast<uint32_t>(read_size) : 0); + + if (read_size < 0) { + Finish(MOJO_RESULT_ABORTED); + return; + } + + if (read_size < attempted_read_size) { + // ReadAtCurrentPos makes a best effort to read all requested bytes. We + // reasonably assume if it fails to read what we ask for, we've hit EOF. + Finish(MOJO_RESULT_OK); + return; + } + } + } + + void Finish(MojoResult result) { + watcher_.reset(); + callback_task_runner_->PostTask( + FROM_HERE, base::BindOnce(std::move(callback_), + std::move(producer_handle_), result)); + } + + const scoped_refptr<base::SequencedTaskRunner> file_task_runner_; + const scoped_refptr<base::SequencedTaskRunner> callback_task_runner_; + + // State which is effectively owned and used only on the file sequence. + ScopedDataPipeProducerHandle producer_handle_; + base::File file_; + CompletionCallback callback_; + std::unique_ptr<SimpleWatcher> watcher_; + + // Guards |is_cancelled_|. + base::Lock lock_; + bool is_cancelled_ = false; + + DISALLOW_COPY_AND_ASSIGN(FileSequenceState); +}; + +FileDataPipeProducer::FileDataPipeProducer( + ScopedDataPipeProducerHandle producer) + : producer_(std::move(producer)), weak_factory_(this) {} + +FileDataPipeProducer::~FileDataPipeProducer() { + if (file_sequence_state_) + file_sequence_state_->Cancel(); +} + +void FileDataPipeProducer::WriteFromFile(base::File file, + CompletionCallback callback) { + InitializeNewRequest(std::move(callback)); + file_sequence_state_->StartFromFile(std::move(file)); +} + +void FileDataPipeProducer::WriteFromPath(const base::FilePath& path, + CompletionCallback callback) { + InitializeNewRequest(std::move(callback)); + file_sequence_state_->StartFromPath(path); +} + +void FileDataPipeProducer::InitializeNewRequest(CompletionCallback callback) { + DCHECK(!file_sequence_state_); + auto file_task_runner = base::CreateSequencedTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::BACKGROUND}); + file_sequence_state_ = new FileSequenceState( + std::move(producer_), file_task_runner, + base::BindOnce(&FileDataPipeProducer::OnWriteComplete, + weak_factory_.GetWeakPtr(), std::move(callback)), + base::SequencedTaskRunnerHandle::Get()); +} + +void FileDataPipeProducer::OnWriteComplete( + CompletionCallback callback, + ScopedDataPipeProducerHandle producer, + MojoResult ready_result) { + producer_ = std::move(producer); + file_sequence_state_ = nullptr; + std::move(callback).Run(ready_result); +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/system/file_data_pipe_producer.h b/chromium/mojo/public/cpp/system/file_data_pipe_producer.h new file mode 100644 index 00000000000..15a808cda18 --- /dev/null +++ b/chromium/mojo/public/cpp/system/file_data_pipe_producer.h @@ -0,0 +1,76 @@ +// Copyright 2017 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_PUBLIC_CPP_SYSTEM_FILE_DATA_PIPE_PRODUCER_H_ +#define MOJO_PUBLIC_CPP_SYSTEM_FILE_DATA_PIPE_PRODUCER_H_ + +#include "base/callback_forward.h" +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "mojo/public/cpp/system/data_pipe.h" +#include "mojo/public/cpp/system/system_export.h" + +namespace mojo { + +// Helper class which takes ownership of a ScopedDataPipeProducerHandle and +// assumes responsibility for feeding it the contents of a given file. This +// takes care of waiting for pipe capacity as needed, and can notify callers +// asynchronously when the operation is complete. +// +// Note that the FileDataPipeProducer must be kept alive until notified of +// completion to ensure that all of the intended contents are written to the +// pipe. Premature destruction may result in partial or total truncation of data +// made available to the consumer. +class MOJO_CPP_SYSTEM_EXPORT FileDataPipeProducer { + public: + using CompletionCallback = base::OnceCallback<void(MojoResult result)>; + + // Constructs a new FileDataPipeProducer which will write data to |producer|. + explicit FileDataPipeProducer(ScopedDataPipeProducerHandle producer); + ~FileDataPipeProducer(); + + // Attempts to eventually write all of |file|'s contents to the pipe. Invokes + // |callback| asynchronously when done. Note that |callback| IS allowed to + // delete this FileDataPipeProducer. + // + // If the write is successful |result| will be |MOJO_RESULT_OK|. Otherwise + // (e.g. if the producer detects the consumer is closed and the pipe has no + // remaining capacity, or if file reads fail for any reason) |result| will be + // |MOJO_RESULT_ABORTED|. + // + // Note that if the FileDataPipeProducer is destroyed before |callback| can be + // invoked, |callback| is *never* invoked, and the write will be permanently + // interrupted (and the producer handle closed) after making potentially only + // partial progress. + // + // Multiple writes may be performed in sequence (each one after the last + // completes), but Write() must not be called before the |callback| for the + // previous call to Write() (if any) has returned. + void WriteFromFile(base::File file, CompletionCallback callback); + + // Same as above but takes a FilePath instead of an opened File. Opens the + // file on an appropriate sequence and then proceeds as WriteFromFile() would. + void WriteFromPath(const base::FilePath& path, CompletionCallback callback); + + private: + class FileSequenceState; + + void InitializeNewRequest(CompletionCallback callback); + void OnWriteComplete(CompletionCallback callback, + ScopedDataPipeProducerHandle producer, + MojoResult result); + + ScopedDataPipeProducerHandle producer_; + scoped_refptr<FileSequenceState> file_sequence_state_; + base::WeakPtrFactory<FileDataPipeProducer> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(FileDataPipeProducer); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_SYSTEM_FILE_DATA_PIPE_PRODUCER_H_ diff --git a/chromium/mojo/public/cpp/system/message.cc b/chromium/mojo/public/cpp/system/message.cc deleted file mode 100644 index 09d8d46e6dd..00000000000 --- a/chromium/mojo/public/cpp/system/message.cc +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/public/cpp/system/message.h" - -namespace mojo { - -ScopedMessageHandle::~ScopedMessageHandle() { - -} - -} // namespace mojo diff --git a/chromium/mojo/public/cpp/system/platform_handle.cc b/chromium/mojo/public/cpp/system/platform_handle.cc index 8017ba3a0c1..5e6c710f138 100644 --- a/chromium/mojo/public/cpp/system/platform_handle.cc +++ b/chromium/mojo/public/cpp/system/platform_handle.cc @@ -128,7 +128,7 @@ MojoResult UnwrapSharedMemoryHandle(ScopedSharedBufferHandle handle, #elif defined(OS_FUCHSIA) DCHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE); *memory_handle = base::SharedMemoryHandle( - static_cast<mx_handle_t>(platform_handle.value), num_bytes, guid); + static_cast<zx_handle_t>(platform_handle.value), num_bytes, guid); #elif defined(OS_POSIX) DCHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR); *memory_handle = base::SharedMemoryHandle( diff --git a/chromium/mojo/public/cpp/system/simple_watcher.cc b/chromium/mojo/public/cpp/system/simple_watcher.cc index 3654a0e5071..307e28818af 100644 --- a/chromium/mojo/public/cpp/system/simple_watcher.cc +++ b/chromium/mojo/public/cpp/system/simple_watcher.cc @@ -122,7 +122,7 @@ class SimpleWatcher::Context : public base::RefCountedThreadSafe<Context> { DISALLOW_COPY_AND_ASSIGN(Context); }; -SimpleWatcher::SimpleWatcher(const tracked_objects::Location& from_here, +SimpleWatcher::SimpleWatcher(const base::Location& from_here, ArmingPolicy arming_policy, scoped_refptr<base::SequencedTaskRunner> runner) : arming_policy_(arming_policy), diff --git a/chromium/mojo/public/cpp/system/simple_watcher.h b/chromium/mojo/public/cpp/system/simple_watcher.h index d5caf92eb2c..d329038d1fc 100644 --- a/chromium/mojo/public/cpp/system/simple_watcher.h +++ b/chromium/mojo/public/cpp/system/simple_watcher.h @@ -85,7 +85,7 @@ class MOJO_CPP_SYSTEM_EXPORT SimpleWatcher { MANUAL, }; - SimpleWatcher(const tracked_objects::Location& from_here, + SimpleWatcher(const base::Location& from_here, ArmingPolicy arming_policy, scoped_refptr<base::SequencedTaskRunner> runner = base::SequencedTaskRunnerHandle::Get()); @@ -159,8 +159,8 @@ class MOJO_CPP_SYSTEM_EXPORT SimpleWatcher { // state of the handle is placed in |*ready_state| if |ready_state| is // non-null. // - // If the watcher is successfully armed, this returns |MOJO_RESULT_OK| and - // |ready_result| and |ready_state| are ignored. + // If the watcher is successfully armed (or was already armed), this returns + // |MOJO_RESULT_OK| and |ready_result| and |ready_state| are ignored. MojoResult Arm(MojoResult* ready_result = nullptr, HandleSignalsState* ready_state = nullptr); diff --git a/chromium/mojo/public/cpp/system/string_data_pipe_producer.cc b/chromium/mojo/public/cpp/system/string_data_pipe_producer.cc new file mode 100644 index 00000000000..34b25d601fc --- /dev/null +++ b/chromium/mojo/public/cpp/system/string_data_pipe_producer.cc @@ -0,0 +1,131 @@ +// Copyright 2017 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/public/cpp/system/string_data_pipe_producer.h" + +#include <algorithm> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/location.h" +#include "base/task_scheduler/post_task.h" + +namespace mojo { + +namespace { + +// Attempts to write data to a producer handle. Outputs the actual number of +// bytes written in |*size|, and returns a result indicating the status of the +// last attempted write operation. +MojoResult WriteDataToProducerHandle(DataPipeProducerHandle producer, + const char* data, + size_t* size) { + void* dest; + uint32_t bytes_left = static_cast<uint32_t>(*size); + + // We loop here since the pipe's available capacity may be larger than its + // *contiguous* capacity, and hence two independent consecutive two-phase + // writes may succeed. The goal here is to write as much of |data| as possible + // until we either run out of data or run out of capacity. + MojoResult result; + do { + uint32_t capacity = bytes_left; + result = + producer.BeginWriteData(&dest, &capacity, MOJO_WRITE_DATA_FLAG_NONE); + if (result == MOJO_RESULT_SHOULD_WAIT) { + result = MOJO_RESULT_OK; + break; + } else if (result != MOJO_RESULT_OK) { + break; + } + + capacity = std::min(capacity, bytes_left); + memcpy(dest, data, capacity); + MojoResult end_result = producer.EndWriteData(capacity); + DCHECK_EQ(MOJO_RESULT_OK, end_result); + + data += capacity; + bytes_left -= capacity; + } while (bytes_left); + + *size -= bytes_left; + return result; +} + +} // namespace + +StringDataPipeProducer::StringDataPipeProducer( + ScopedDataPipeProducerHandle producer) + : producer_(std::move(producer)), + watcher_(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC), + weak_factory_(this) {} + +StringDataPipeProducer::~StringDataPipeProducer() = default; + +void StringDataPipeProducer::Write(const base::StringPiece& data, + CompletionCallback callback) { + DCHECK(!callback_); + callback_ = std::move(callback); + + // Immediately attempt to write data without making an extra copy. If we can + // get it all in one shot, we're done aleady. + size_t size = data.size(); + MojoResult result = + WriteDataToProducerHandle(producer_.get(), data.data(), &size); + if (result == MOJO_RESULT_OK && size == data.size()) { + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&StringDataPipeProducer::InvokeCallback, + weak_factory_.GetWeakPtr(), MOJO_RESULT_OK)); + } else { + // Copy whatever data didn't make the cut and try again when the pipe has + // some more capacity. + data_ = std::string(data.data() + size, data.size() - size); + data_view_ = data_; + watcher_.Watch(producer_.get(), MOJO_HANDLE_SIGNAL_WRITABLE, + MOJO_WATCH_CONDITION_SATISFIED, + base::Bind(&StringDataPipeProducer::OnProducerHandleReady, + base::Unretained(this))); + } +} + +void StringDataPipeProducer::InvokeCallback(MojoResult result) { + // May delete |this|. + std::move(callback_).Run(result); +} + +void StringDataPipeProducer::OnProducerHandleReady( + MojoResult ready_result, + const HandleSignalsState& state) { + bool failed = false; + size_t size = data_view_.size(); + if (ready_result == MOJO_RESULT_OK) { + MojoResult write_result = + WriteDataToProducerHandle(producer_.get(), data_view_.data(), &size); + if (write_result != MOJO_RESULT_OK) + failed = true; + } else { + failed = true; + } + + if (failed) { + watcher_.Cancel(); + + // May delete |this|. + std::move(callback_).Run(MOJO_RESULT_ABORTED); + return; + } + + if (size == data_view_.size()) { + watcher_.Cancel(); + + // May delete |this|. + std::move(callback_).Run(MOJO_RESULT_OK); + return; + } + + data_view_ = + base::StringPiece(data_view_.data() + size, data_view_.size() - size); +} + +} // namespace mojo diff --git a/chromium/mojo/public/cpp/system/string_data_pipe_producer.h b/chromium/mojo/public/cpp/system/string_data_pipe_producer.h new file mode 100644 index 00000000000..f35d8ff7aea --- /dev/null +++ b/chromium/mojo/public/cpp/system/string_data_pipe_producer.h @@ -0,0 +1,73 @@ +// Copyright 2017 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_PUBLIC_CPP_SYSTEM_STRING_DATA_PIPE_PRODUCER_H_ +#define MOJO_PUBLIC_CPP_SYSTEM_STRING_DATA_PIPE_PRODUCER_H_ + +#include <string> + +#include "base/callback_forward.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/strings/string_piece.h" +#include "mojo/public/cpp/system/data_pipe.h" +#include "mojo/public/cpp/system/simple_watcher.h" +#include "mojo/public/cpp/system/system_export.h" + +namespace mojo { + +// Helper class which takes ownership of a ScopedDataPipeProducerHandle and +// assumes responsibility for feeding it the contents of a given string. This +// takes care of waiting for pipe capacity as needed, and can notify callers +// asynchronously when the operation is complete. +// +// Note that the StringDataPipeProducer must be kept alive until notified of +// completion to ensure that all of the string's data is written to the pipe. +// Premature destruction may result in partial or total truncation of data made +// available to the consumer. +class MOJO_CPP_SYSTEM_EXPORT StringDataPipeProducer { + public: + using CompletionCallback = base::OnceCallback<void(MojoResult result)>; + + // Constructs a new StringDataPipeProducer which will write data to + // |producer|. + explicit StringDataPipeProducer(ScopedDataPipeProducerHandle producer); + ~StringDataPipeProducer(); + + // Attempts to eventually write all of |data|. Invokes |callback| + // asynchronously when done. Note that |callback| IS allowed to delete this + // StringDataPipeProducer. + // + // If the write is successful |result| will be |MOJO_RESULT_OK|. Otherwise + // (e.g. if the producer detects the consumer is closed and the pipe has no + // remaining capacity) |result| will be |MOJO_RESULT_ABORTED|. + // + // Note that if the StringDataPipeProducer is destroyed before |callback| can + // be invoked, |callback| is *never* invoked, and the write will be + // permanently interrupted (and the producer handle closed) after making + // potentially only partial progress. + // + // Multiple writes may be performed in sequence (each one after the last + // completes), but Write() must not be called before the |callback| for the + // previous call to Write() (if any) has returned. + void Write(const base::StringPiece& data, CompletionCallback callback); + + private: + void InvokeCallback(MojoResult result); + void OnProducerHandleReady(MojoResult ready_result, + const HandleSignalsState& state); + + ScopedDataPipeProducerHandle producer_; + std::string data_; + base::StringPiece data_view_; + CompletionCallback callback_; + SimpleWatcher watcher_; + base::WeakPtrFactory<StringDataPipeProducer> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(StringDataPipeProducer); +}; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_SYSTEM_STRING_DATA_PIPE_PRODUCER_H_ diff --git a/chromium/mojo/public/cpp/system/tests/BUILD.gn b/chromium/mojo/public/cpp/system/tests/BUILD.gn index 2cfa2098b36..f580601de71 100644 --- a/chromium/mojo/public/cpp/system/tests/BUILD.gn +++ b/chromium/mojo/public/cpp/system/tests/BUILD.gn @@ -7,9 +7,11 @@ source_set("tests") { sources = [ "core_unittest.cc", + "file_data_pipe_producer_unittest.cc", "handle_signal_tracker_unittest.cc", "handle_signals_state_unittest.cc", "simple_watcher_unittest.cc", + "string_data_pipe_producer_unittest.cc", "wait_set_unittest.cc", "wait_unittest.cc", ] diff --git a/chromium/mojo/public/cpp/system/wait_set.cc b/chromium/mojo/public/cpp/system/wait_set.cc index e73a9a4a2be..e2a26f8a900 100644 --- a/chromium/mojo/public/cpp/system/wait_set.cc +++ b/chromium/mojo/public/cpp/system/wait_set.cc @@ -296,7 +296,7 @@ class WaitSet::State : public base::RefCountedThreadSafe<State> { // // This vector is cleared on the WaitSet's own sequence every time // RemoveHandle is called. - cancelled_contexts_.emplace_back(make_scoped_refptr(context)); + cancelled_contexts_.emplace_back(base::WrapRefCounted(context)); // Balanced in State::AddHandle(). context->Release(); diff --git a/chromium/mojo/public/cpp/test_support/BUILD.gn b/chromium/mojo/public/cpp/test_support/BUILD.gn index efa1712fff3..b8324e594bc 100644 --- a/chromium/mojo/public/cpp/test_support/BUILD.gn +++ b/chromium/mojo/public/cpp/test_support/BUILD.gn @@ -9,6 +9,8 @@ static_library("test_utils") { "lib/test_support.cc", "lib/test_utils.cc", "test_utils.h", + "waiter.cc", + "waiter.h", ] deps = [ diff --git a/chromium/mojo/public/cpp/test_support/waiter.cc b/chromium/mojo/public/cpp/test_support/waiter.cc new file mode 100644 index 00000000000..030fad30abb --- /dev/null +++ b/chromium/mojo/public/cpp/test_support/waiter.cc @@ -0,0 +1,19 @@ +// Copyright 2017 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/public/cpp/test_support/waiter.h" + +namespace mojo { +namespace test { + +Waiter::Waiter() = default; + +Waiter::~Waiter() = default; + +void Waiter::Wait() { + loop_->Run(); +} + +} // namespace test +} // namespace mojo diff --git a/chromium/mojo/public/cpp/test_support/waiter.h b/chromium/mojo/public/cpp/test_support/waiter.h new file mode 100644 index 00000000000..96264220563 --- /dev/null +++ b/chromium/mojo/public/cpp/test_support/waiter.h @@ -0,0 +1,99 @@ +// Copyright 2017 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_PUBLIC_CPP_TEST_SUPPORT_WAITER_H_ +#define MOJO_PUBLIC_CPP_TEST_SUPPORT_WAITER_H_ + +#include <utility> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/run_loop.h" + +namespace mojo { +namespace test { + +namespace internal { + +template <typename CallbackType, typename OutArgTuple> +struct WaiterHelper; + +template <typename... InArgs, typename... OutArgs> +struct WaiterHelper<base::OnceCallback<void(InArgs...)>, + std::tuple<OutArgs...>> { + static void MoveOrCopyInputs(base::OnceClosure continuation, + OutArgs*... outputs, + InArgs... inputs) { + int ignored[] = {0, MoveOrCopy(std::forward<InArgs>(inputs), outputs)...}; + ALLOW_UNUSED_LOCAL(ignored); + std::move(continuation).Run(); + } + + private: + template <typename InputType> + using InputTypeToOutputType = typename std::remove_const< + typename std::remove_reference<InputType>::type>::type; + + template <typename InputType> + static int MoveOrCopy(InputType&& input, + InputTypeToOutputType<InputType>* output) { + *output = std::move(input); + return 0; + } +}; + +} // namespace internal + +// Waits for a mojo method callback and captures the results. Allows test code +// to be written in a synchronous style, but does not block the current thread +// like [Sync] mojo methods do. +// +// For mojom method: +// +// interface Foo { +// DoFoo() => (int32 i, bool b); +// }; +// +// TEST(FooBarTest) { +// Waiter waiter; +// int i = 0; +// bool b = false; +// interface_ptr->DoFoo( +// waiter.CaptureNext<mojom::Foo::DoFooCallback>(&i, &b)); +// waiter.Wait(); +// EXPECT_EQ(0, i); +// EXPECT_TRUE(b); +// } +class Waiter { + public: + Waiter(); + ~Waiter(); + + // Stores |outputs| to be captured later. Can be called more than once. + // Can be used with an empty argument list. + template <typename CallbackType, typename... OutArgs> + CallbackType CaptureNext(OutArgs*... outputs) { + DCHECK(!loop_ || !loop_->running()); + loop_ = std::make_unique<base::RunLoop>(); + using Helper = internal::WaiterHelper<CallbackType, std::tuple<OutArgs...>>; + return base::BindOnce(&Helper::MoveOrCopyInputs, loop_->QuitClosure(), + outputs...); + } + + // Runs the run loop to wait for results. + void Wait(); + + private: + std::unique_ptr<base::RunLoop> loop_; + + DISALLOW_COPY_AND_ASSIGN(Waiter); +}; + +} // namespace test +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_TEST_SUPPORT_WAITER_H_ diff --git a/chromium/mojo/public/interfaces/bindings/BUILD.gn b/chromium/mojo/public/interfaces/bindings/BUILD.gn index 3bd98de02f4..4608db085eb 100644 --- a/chromium/mojo/public/interfaces/bindings/BUILD.gn +++ b/chromium/mojo/public/interfaces/bindings/BUILD.gn @@ -8,9 +8,12 @@ mojom("bindings") { visibility = [] sources = [ "interface_control_messages.mojom", + "native_struct.mojom", "pipe_control_messages.mojom", ] + allow_native_structs = false + component_output_prefix = "mojo_public_interfaces_bindings" export_class_attribute = "MOJO_CPP_BINDINGS_EXPORT" export_define = "MOJO_CPP_BINDINGS_IMPLEMENTATION" diff --git a/chromium/mojo/public/interfaces/bindings/native_struct.mojom b/chromium/mojo/public/interfaces/bindings/native_struct.mojom new file mode 100644 index 00000000000..f2e869cf620 --- /dev/null +++ b/chromium/mojo/public/interfaces/bindings/native_struct.mojom @@ -0,0 +1,26 @@ +// Copyright 2017 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. + +[JavaPackage="org.chromium.mojo.native_types"] +module mojo.native; + +struct SerializedHandle { + handle the_handle; + + enum Type { + MOJO_HANDLE, + PLATFORM_FILE, + WIN_HANDLE, + MACH_PORT, + FUCHSIA_HANDLE, + }; + + Type type; +}; + +[CustomSerializer] +struct NativeStruct { + array<uint8> data; + array<SerializedHandle>? handles; +}; diff --git a/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn b/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn index fdda16dc4b5..10d8e60ba35 100644 --- a/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn +++ b/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn @@ -73,6 +73,10 @@ mojom("test_interfaces") { use_once_callback = false support_lazy_serialization = true + + # Validation tests require precise message content matching, so we avoid + # scrambling message IDs for test interfaces. + scramble_message_ids = false } component("test_export_component") { @@ -212,6 +216,10 @@ mojom("test_associated_interfaces") { # TODO(crbug.com/714018): Convert the implementation to use OnceCallback. use_once_callback = false + + # Validation tests require precise message content matching, so we avoid + # scrambling message IDs for test interfaces. + scramble_message_ids = false } mojom("versioning_test_service_interfaces") { diff --git a/chromium/mojo/public/interfaces/bindings/tests/test_native_types.mojom b/chromium/mojo/public/interfaces/bindings/tests/test_native_types.mojom index 3df43182a37..caa6a71c569 100644 --- a/chromium/mojo/public/interfaces/bindings/tests/test_native_types.mojom +++ b/chromium/mojo/public/interfaces/bindings/tests/test_native_types.mojom @@ -36,3 +36,15 @@ interface RectService { GetLargestRect() => (TypemappedRect largest); PassSharedRect(SharedTypemappedRect r) => (SharedTypemappedRect passed); }; + +[Native] +struct TestNativeStructMojom; + +[Native] +struct TestNativeStructWithAttachmentsMojom; + +interface NativeTypeTester { + PassNativeStruct(TestNativeStructMojom s) => (TestNativeStructMojom passed); + PassNativeStructWithAttachments(TestNativeStructWithAttachmentsMojom s) + => (TestNativeStructWithAttachmentsMojom s); +}; diff --git a/chromium/mojo/public/js/new_bindings/connector.js b/chromium/mojo/public/js/new_bindings/connector.js index 5acba5f804d..2cc2e5545ee 100644 --- a/chromium/mojo/public/js/new_bindings/connector.js +++ b/chromium/mojo/public/js/new_bindings/connector.js @@ -103,6 +103,10 @@ var receiverResult = this.incomingReceiver_ && this.incomingReceiver_.accept(message); + // Dispatching the message may have closed the connector. + if (this.handle_ == null) + return; + // Handle invalid incoming message. if (!internal.isTestingMode() && !receiverResult) { // TODO(yzshen): Consider notifying the embedder. diff --git a/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni index 6fe236dcf45..a6c270b206f 100644 --- a/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni +++ b/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni @@ -4,10 +4,10 @@ _typemap_imports = [ "//ash/public/interfaces/typemaps.gni", - "//cc/ipc/typemaps.gni", "//chrome/common/extensions/typemaps.gni", "//chrome/common/importer/typemaps.gni", "//chrome/common/media_router/mojo/typemaps.gni", + "//chrome/common/printing/typemaps.gni", "//chrome/typemaps.gni", "//components/arc/common/typemaps.gni", "//components/metrics/public/cpp/typemaps.gni", @@ -28,14 +28,17 @@ _typemap_imports = [ "//mojo/common/typemaps.gni", "//mojo/public/cpp/bindings/tests/chromium_typemaps.gni", "//net/interfaces/typemaps.gni", + "//sandbox/mac/mojom/typemaps.gni", "//services/device/public/interfaces/typemaps.gni", "//services/identity/public/cpp/typemaps.gni", + "//services/network/public/cpp/typemaps.gni", "//services/preferences/public/cpp/typemaps.gni", + "//services/proxy_resolver/public/cpp/typemaps.gni", "//services/resource_coordinator/public/cpp/typemaps.gni", "//services/service_manager/public/cpp/typemaps.gni", - "//services/ui/gpu/interfaces/typemaps.gni", "//services/ui/public/interfaces/cursor/typemaps.gni", "//services/ui/public/interfaces/ime/typemaps.gni", + "//services/viz/privileged/cpp/typemaps.gni", "//services/viz/privileged/interfaces/compositing/typemaps.gni", "//services/viz/public/cpp/compositing/typemaps.gni", "//skia/public/interfaces/typemaps.gni", diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl index f5acd37de69..4221832264a 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl @@ -69,6 +69,6 @@ class {{export_attribute}} {{interface.name}}InterceptorForTesting : public {{in virtual {{interface.name}}* GetForwardingInterface() = 0; {%- for method in interface.methods %} - void {{method.name}}({{interface_macros.declare_request_params("", method, use_once_callback)}}); + void {{method.name}}({{interface_macros.declare_request_params("", method, use_once_callback)}}) override; {%- endfor %} }; diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl index 4f799bd1d38..209384ad778 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl @@ -253,6 +253,9 @@ class {{class_name}}_{{method.name}}_ProxyToResponder { bool {{class_name}}_{{method.name}}_ForwardToCallback::Accept( mojo::Message* message) { +#if BUILDFLAG(MOJO_TRACE_ENABLED) + TRACE_EVENT1("mojom", "{{method.name}}", "message", message->name()); +#endif mojo::internal::MessageDispatchContext dispatch_context(message); {%- if method|method_supports_lazy_serialization %} if (!message->is_serialized()) { @@ -299,6 +302,9 @@ void {{class_name}}_{{method.name}}_ProxyToResponder::Run( response_params_description, "kFlags", "message")}} {%- endif %} +#if BUILDFLAG(MOJO_TRACE_ENABLED) + TRACE_EVENT1("mojom", "{{method.name}}", "message", message.name()); +#endif message.set_request_id(request_id_); ignore_result(responder_->Accept(&message)); // TODO(darin): Accept() returning false indicates a malformed message, and @@ -311,6 +317,9 @@ void {{class_name}}_{{method.name}}_ProxyToResponder::Run( {%- if method.sync %} bool {{class_name}}_{{method.name}}_HandleSyncResponse::Accept( mojo::Message* message) { +#if BUILDFLAG(MOJO_TRACE_ENABLED) + TRACE_EVENT1("mojom", "{{method.name}}", "message", message->name()); +#endif {%- if method|method_supports_lazy_serialization %} if (!message->is_serialized()) { auto context = @@ -364,6 +373,9 @@ bool {{class_name}}StubDispatch::Accept( switch (message->header()->name) { {%- for method in interface.methods %} case internal::k{{class_name}}_{{method.name}}_Name: { +#if BUILDFLAG(MOJO_TRACE_ENABLED) + TRACE_EVENT1("mojom", "{{method.name}}", "message", message->name()); +#endif {%- if method.response_parameters == None %} mojo::internal::MessageDispatchContext context(message); {%- if method|method_supports_lazy_serialization %} @@ -413,6 +425,9 @@ bool {{class_name}}StubDispatch::AcceptWithResponder( switch (message->header()->name) { {%- for method in interface.methods %} case internal::k{{class_name}}_{{method.name}}_Name: { +#if BUILDFLAG(MOJO_TRACE_ENABLED) + TRACE_EVENT1("mojom", "{{method.name}}", "message", message->name()); +#endif {%- if method.response_parameters != None %} mojo::internal::MessageDispatchContext context(message); {%- if method|method_supports_lazy_serialization %} @@ -478,6 +493,9 @@ bool {{class_name}}RequestValidator::Accept(mojo::Message* message) { switch (message->header()->name) { {%- for method in interface.methods %} case internal::k{{class_name}}_{{method.name}}_Name: { +#if BUILDFLAG(MOJO_TRACE_ENABLED) + TRACE_EVENT1("mojom", "{{method.name}}", "message", message->name()); +#endif {%- if method.response_parameters != None %} if (!mojo::internal::ValidateMessageIsRequestExpectingResponse( message, &validation_context)) { @@ -524,6 +542,9 @@ bool {{class_name}}ResponseValidator::Accept(mojo::Message* message) { switch (message->header()->name) { {%- for method in interface.methods if method.response_parameters != None %} case internal::k{{class_name}}_{{method.name}}_Name: { +#if BUILDFLAG(MOJO_TRACE_ENABLED) + TRACE_EVENT1("mojom", "{{method.name}}", "message", message->name()); +#endif if (!mojo::internal::ValidateMessagePayload< internal::{{class_name}}_{{method.name}}_ResponseParams_Data>( message, &validation_context)) { diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl index 3033a997e06..21e50258438 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl @@ -15,13 +15,16 @@ #include "mojo/public/cpp/bindings/lib/bindings_internal.h" #include "mojo/public/cpp/bindings/lib/map_data_internal.h" #include "mojo/public/cpp/bindings/lib/native_enum_data.h" -#include "mojo/public/cpp/bindings/lib/native_struct_data.h" #include "mojo/public/cpp/bindings/lib/buffer.h" {%- for import in imports %} #include "{{import.path}}-shared-internal.h" {%- endfor %} +{%- if allow_native_structs %} +#include "mojo/public/interfaces/bindings/native_struct.mojom-shared-internal.h" +{%- endif %} + {%- if export_header %} #include "{{export_header}}" {%- endif %} @@ -40,7 +43,7 @@ namespace internal { {#--- Internal forward declarations #} {%- for struct in structs %} {%- if struct|is_native_only_kind %} -using {{struct.name}}_Data = mojo::internal::NativeStruct_Data; +using {{struct.name}}_Data = mojo::native::internal::NativeStruct_Data; {%- else %} class {{struct.name}}_Data; {%- endif %} diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl index 148dc7aeb51..58ced630ee4 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl @@ -50,13 +50,16 @@ namespace {{namespace}} { #include "mojo/public/cpp/bindings/lib/serialization.h" #include "mojo/public/cpp/bindings/map_data_view.h" #include "mojo/public/cpp/bindings/native_enum.h" -#include "mojo/public/cpp/bindings/native_struct_data_view.h" #include "mojo/public/cpp/bindings/string_data_view.h" #include "{{module.path}}-shared-internal.h" {%- for import in imports %} #include "{{import.path}}-shared.h" {%- endfor %} +{% if allow_native_structs %} +#include "mojo/public/cpp/bindings/lib/native_struct_serialization.h" +{%- endif %} + {%- if export_header %} #include "{{export_header}}" {%- endif %} @@ -66,7 +69,7 @@ namespace {{namespace}} { {#--- Struct Forward Declarations -#} {%- for struct in structs %} {%- if struct|is_native_only_kind %} -using {{struct.name}}DataView = mojo::NativeStructDataView; +using {{struct.name}}DataView = mojo::native::NativeStructDataView; {%- else %} class {{struct.name}}DataView; {%- endif %} diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl index 6460ebac408..1700115445a 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl @@ -42,6 +42,11 @@ namespace {{variant}} { #include "base/callback.h" #include "base/macros.h" #include "base/optional.h" + +#include "mojo/public/cpp/bindings/mojo_features.h" +#if BUILDFLAG(MOJO_TRACE_ENABLED) +#include "base/trace_event/trace_event.h" +#endif #include "mojo/public/cpp/bindings/associated_interface_ptr.h" #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h" #include "mojo/public/cpp/bindings/associated_interface_request.h" @@ -52,7 +57,6 @@ namespace {{variant}} { #include "mojo/public/cpp/bindings/lib/control_message_handler.h" #include "mojo/public/cpp/bindings/lib/control_message_proxy.h" #include "mojo/public/cpp/bindings/lib/serialization.h" -#include "mojo/public/cpp/bindings/native_struct.h" #include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h" #include "mojo/public/cpp/bindings/struct_ptr.h" #include "mojo/public/cpp/bindings/struct_traits.h" @@ -78,6 +82,10 @@ namespace {{variant}} { #include "third_party/WebKit/Source/platform/wtf/text/WTFString.h" {%- endif %} +{% if allow_native_structs %} +#include "mojo/public/cpp/bindings/lib/native_struct_serialization.h" +{%- endif %} + {%- for header in extra_public_headers %} #include "{{header}}" {%- endfor %} @@ -131,8 +139,8 @@ using {{interface.name}}AssociatedRequest = {#--- Struct Forward Declarations -#} {% for struct in structs %} {%- if struct|is_native_only_kind %} -using {{struct.name}} = mojo::NativeStruct; -using {{struct.name}}Ptr = mojo::NativeStructPtr; +using {{struct.name}} = mojo::native::NativeStruct; +using {{struct.name}}Ptr = mojo::native::NativeStructPtr; {%- else %} class {{struct.name}}; {%- if struct|should_inline %} diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl index 61799a8f26c..5571e8449f9 100644 --- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl @@ -2,6 +2,8 @@ {%- set data_view = struct|get_qualified_name_for_kind ~ "DataView" %} {%- set data_type = struct|get_qualified_name_for_kind(internal=True) %} +{%- if not struct|use_custom_serializer %} + namespace internal { template <typename MaybeConstUserType> @@ -35,3 +37,5 @@ struct Serializer<{{data_view}}, MaybeConstUserType> { }; } // namespace internal + +{%- endif %} diff --git a/chromium/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl b/chromium/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl index 4e5e29adb3a..0e9b89315c2 100644 --- a/chromium/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl +++ b/chromium/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl @@ -52,7 +52,7 @@ err = messageValidator.validateEnum({{offset}}, {{field|validate_enum_params}}); // validate {{name}} err = messageValidator.validateUnion({{offset}}, {{field|validate_union_params}}); {{_check_err()}} -{%- else %} +{%- else -%} {{_validate_field(field, offset, name)}} {%- endif %} {%- endmacro %} diff --git a/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py index 08514cb7b5c..c60e36d593a 100644 --- a/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py +++ b/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py @@ -134,6 +134,10 @@ def IsNativeOnlyKind(kind): kind.native_only +def UseCustomSerializer(kind): + return mojom.IsStructKind(kind) and kind.custom_serializer + + def AllEnumValues(enum): """Return all enum values associated with an enum. @@ -286,6 +290,7 @@ class Generator(generator.Generator): return { "all_enums": all_enums, + "allow_native_structs": self.allow_native_structs, "enums": self.module.enums, "export_attribute": self.export_attribute, "export_header": self.export_header, @@ -359,6 +364,7 @@ class Generator(generator.Generator): "struct_constructors": self._GetStructConstructors, "under_to_camel": generator.ToCamel, "unmapped_type_for_serializer": self._GetUnmappedTypeForSerializer, + "use_custom_serializer": UseCustomSerializer, "wtf_hash_fn_name_for_enum": GetWtfHashFnNameForEnum, } return cpp_filters @@ -457,6 +463,8 @@ class Generator(generator.Generator): if mojom.IsNullableKind(kind): return False elif mojom.IsStructKind(kind): + if kind.native_only: + return False if (self._IsTypemappedKind(kind) and not self.typemap[self._GetFullMojomNameForKind(kind)]["hashable"]): return False diff --git a/chromium/mojo/public/tools/bindings/mojom.gni b/chromium/mojo/public/tools/bindings/mojom.gni index 5018a7b0932..9b5ed6adc1e 100644 --- a/chromium/mojo/public/tools/bindings/mojom.gni +++ b/chromium/mojo/public/tools/bindings/mojom.gni @@ -2,6 +2,17 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/jumbo.gni") + +# TODO(rockot): Maybe we can factor these dependencies out of //mojo. They're +# used to conditionally enable message ID scrambling in a way which is +# consistent across toolchains and which is affected by branded vs non-branded +# Chrome builds. Ideally we could create some generic knobs here that could be +# flipped elsewhere though. +import("//build/config/chrome_build.gni") +import("//build/config/nacl/config.gni") +import("//components/nacl/features.gni") + declare_args() { # Indicates whether typemapping should be supported in this build # configuration. This may be disabled when building external projects which @@ -14,6 +25,23 @@ declare_args() { enable_mojom_typemapping = true } +# NOTE: We would like to avoid scrambling message IDs where it doesn't add +# value, so we limit the behavior to desktop builds for now. There is some +# redundancy in the conditions here, but it is tolerated for clarity: +# We're explicit about Mac, Windows, and Linux desktop support, but it's +# also necessary to ensure that bindings in alternate toolchains (e.g. +# NaCl IRT) are always consistent with the default toolchain; for that +# reason we always enable scrambling within NaCl toolchains when possible, +# as well as within the default toolchain when NaCl is enabled. +# +# Finally, because we *cannot* enable scrambling on Chrome OS (it would break +# ARC) we have to explicitly opt out there even when NaCl is enabled (and +# consequently also when building for NaCl toolchains.) For this reason we +# check |target_os| explicitly, as it's consistent across all toolchains. +enable_scrambled_message_ids = + is_mac || is_win || (is_linux && !is_chromeos) || + ((enable_nacl || is_nacl || is_nacl_nonsfi) && target_os != "chromeos") + mojom_generator_root = "//mojo/public/tools/bindings" mojom_generator_script = "$mojom_generator_root/mojom_bindings_generator.py" mojom_generator_sources = [ @@ -36,6 +64,30 @@ mojom_generator_sources = [ "$mojom_generator_script", ] +if (enable_scrambled_message_ids) { + declare_args() { + # The path to a file whose contents can be used as the basis for a message + # ID scrambling salt. + mojom_message_id_salt_path = "//chrome/VERSION" + + # The path to a file whose contents will be concatenated to the contents of + # the file at |mojom_message_id_salt_path| to form a complete salt for + # message ID scrambling. May be the empty string, in which case the contents + # of the above file alone are used as the complete salt. + if (is_chrome_branded) { + mojom_message_id_salt_suffix_path = + "//mojo/internal/chrome-message-id-salt-suffix" + } else { + mojom_message_id_salt_suffix_path = "" + } + } + + mojom_generator_sources += [ mojom_message_id_salt_path ] + if (mojom_message_id_salt_suffix_path != "") { + mojom_generator_sources += [ mojom_message_id_salt_suffix_path ] + } +} + generate_export_header_script = "$mojom_generator_root/generate_export_header.py" @@ -174,6 +226,20 @@ if (enable_mojom_typemapping) { # deserialization, and validation logic at the expensive of increased # code size. Defaults to |false|. # +# disable_variants (optional) +# If |true|, no variant sources will be generated for the target. Defaults +# to |false|. +# +# allow_native_structs (optional) +# If set to |true| (the default), mojoms in this target may apply the +# [Native] attribute to struct declarations, causing that mojom struct to +# be serialized and deserialized using a legacy IPC::ParamTraits +# specialization. +# +# scramble_message_ids (optional) +# If set to |true| (the default), generated mojom interfaces will use +# scrambled ordinal identifiers in encoded messages. +# # component_output_prefix (optional) # The prefix to use for the output_name of any component library emitted # for generated C++ bindings. If this is omitted, C++ bindings targets are @@ -313,6 +379,29 @@ template("mojom") { rebase_path("$root_gen_dir/mojo/public/tools/bindings", root_build_dir), ] + if (!defined(invoker.scramble_message_ids) || invoker.scramble_message_ids) { + # Scramble message IDs if enabled, unless the target has explicitly opted + # out. + if (enable_scrambled_message_ids) { + assert(mojom_message_id_salt_path != "") + common_generator_args += [ + "--scrambled_message_id_salt_path", + rebase_path(mojom_message_id_salt_path, root_build_dir), + ] + + if (mojom_message_id_salt_suffix_path != "") { + common_generator_args += [ + "--scrambled_message_id_salt_path", + rebase_path(mojom_message_id_salt_suffix_path, root_build_dir), + ] + } + } + } + + if (!defined(invoker.allow_native_structs) || invoker.allow_native_structs) { + common_generator_args += [ "--allow_native_structs" ] + } + if (defined(invoker.import_dirs)) { foreach(import_dir, invoker.import_dirs) { common_generator_args += [ @@ -424,7 +513,7 @@ template("mojom") { } shared_cpp_sources_target_name = "${target_name}_shared_cpp_sources" - source_set(shared_cpp_sources_target_name) { + jumbo_source_set(shared_cpp_sources_target_name) { if (defined(invoker.testonly)) { testonly = invoker.testonly } @@ -476,7 +565,14 @@ template("mojom") { } # Generate code for variants. - foreach(bindings_configuration, _bindings_configurations) { + if (!defined(invoker.disable_variants) || !invoker.disable_variants) { + enabled_configurations = _bindings_configurations + } else { + first_config = _bindings_configurations[0] + assert(!defined(first_config.variant)) + enabled_configurations = [ first_config ] + } + foreach(bindings_configuration, enabled_configurations) { cpp_only = false if (defined(invoker.cpp_only)) { cpp_only = invoker.cpp_only @@ -734,7 +830,7 @@ template("mojom") { output_target_type = "source_set" } - target(output_target_type, "${target_name}${variant_suffix}") { + target("jumbo_" + output_target_type, "${target_name}${variant_suffix}") { if (defined(bindings_configuration.for_blink) && bindings_configuration.for_blink && defined(invoker.visibility_blink)) { diff --git a/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py b/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py index cc8101613ea..a1d535c1824 100755 --- a/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py +++ b/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py @@ -113,13 +113,13 @@ def ScrambleMethodOrdinals(interfaces, salt): i = i + 1 if i == 1000000: raise Exception("Could not generate %d method ordinals for %s" % - (len(interface.methods), interface.name)) + (len(interface.methods), interface.mojom_name)) # Generate a scrambled method.ordinal value. The algorithm doesn't have # to be very strong, cryptographically. It just needs to be non-trivial # to guess the results without the secret salt, in order to make it # harder for a compromised process to send fake Mojo messages. sha256 = hashlib.sha256(salt) - sha256.update(interface.name) + sha256.update(interface.mojom_name) sha256.update(str(i)) # Take the first 4 bytes as a little-endian uint32. ordinal = struct.unpack('<L', sha256.digest()[:4])[0] @@ -131,10 +131,15 @@ def ScrambleMethodOrdinals(interfaces, salt): method.ordinal = ordinal method.ordinal_comment = ( 'The %s value is based on sha256(salt + "%s%d").' % - (ordinal, interface.name, i)) + (ordinal, interface.mojom_name, i)) break +def ReadFileContents(filename): + with open(filename, 'rb') as f: + return f.read() + + class MojomProcessor(object): """Parses mojom files and creates ASTs for them. @@ -193,8 +198,10 @@ class MojomProcessor(object): module = translate.OrderedModule(tree, module_path, imports) - if args.scrambled_message_id_salt: - ScrambleMethodOrdinals(module.interfaces, args.scrambled_message_id_salt) + if args.scrambled_message_id_salt_paths: + salt = ''.join( + map(ReadFileContents, args.scrambled_message_id_salt_paths)) + ScrambleMethodOrdinals(module.interfaces, salt) if self._should_generate(rel_filename.path): AddComputedData(module) @@ -208,7 +215,8 @@ class MojomProcessor(object): export_attribute=args.export_attribute, export_header=args.export_header, generate_non_variant_code=args.generate_non_variant_code, - support_lazy_serialization=args.support_lazy_serialization) + support_lazy_serialization=args.support_lazy_serialization, + allow_native_structs=args.allow_native_structs) filtered_args = [] if hasattr(generator_module, 'GENERATOR_PREFIX'): prefix = '--' + generator_module.GENERATOR_PREFIX + '_' @@ -361,12 +369,21 @@ def main(): "--depfile_target", help="The target name to use in the depfile.") generate_parser.add_argument( - "--scrambled_message_id_salt", - help="If non-empty, the salt for generating scrambled message IDs.") + "--scrambled_message_id_salt_path", + dest="scrambled_message_id_salt_paths", + help="If non-empty, the path to a file whose contents should be used as" + "a salt for generating scrambled message IDs. If this switch is specified" + "more than once, the contents of all salt files are concatenated to form" + "the salt value.", default=[], action="append") generate_parser.add_argument( "--support_lazy_serialization", help="If set, generated bindings will serialize lazily when possible.", action="store_true") + generate_parser.add_argument( + "--allow_native_structs", + help="Allows the [Native] attribute to be specified on structs within " + "the mojom file. Must not be specified on internal bindings mojom or " + "other dependencies thereof.", action="store_true") generate_parser.set_defaults(func=_Generate) precompile_parser = subparsers.add_parser("precompile", diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py index 4d81a13dbd9..f59c33db21c 100644 --- a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py @@ -157,7 +157,7 @@ class Generator(object): bytecode_path=None, for_blink=False, use_once_callback=False, js_bindings_mode="new", export_attribute=None, export_header=None, generate_non_variant_code=False, - support_lazy_serialization=False): + support_lazy_serialization=False, allow_native_structs=False): self.module = module self.output_dir = output_dir self.typemap = typemap or {} @@ -170,6 +170,7 @@ class Generator(object): self.export_header = export_header self.generate_non_variant_code = generate_non_variant_code self.support_lazy_serialization = support_lazy_serialization + self.allow_native_structs = allow_native_structs def Write(self, contents, filename): if self.output_dir is None: diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/module.py index 8208f7b5dd5..ebe5601b0a3 100644 --- a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/module.py +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/module.py @@ -316,6 +316,8 @@ class Struct(ReferenceKind): name: {str} The stylized name. native_only: {bool} Does the struct have a body (i.e. any fields) or is it purely a native struct. + custom_serializer: {bool} Should we generate a serializer for the struct or + will one be provided by non-generated code. fields: {List[StructField]} The members of the struct. enums: {List[Enum]} The enums defined in the struct scope. constants: {List[Constant]} The constants defined in the struct scope. @@ -326,6 +328,7 @@ class Struct(ReferenceKind): ReferenceKind.AddSharedProperty('mojom_name') ReferenceKind.AddSharedProperty('name') ReferenceKind.AddSharedProperty('native_only') + ReferenceKind.AddSharedProperty('custom_serializer') ReferenceKind.AddSharedProperty('fields') ReferenceKind.AddSharedProperty('enums') ReferenceKind.AddSharedProperty('constants') @@ -339,6 +342,7 @@ class Struct(ReferenceKind): ReferenceKind.__init__(self, spec, False, module) self.mojom_name = mojom_name self.native_only = False + self.custom_serializer = False self.fields = [] self.enums = [] self.constants = [] diff --git a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/translate.py b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/translate.py index f1d8f4264ec..4153e7456cf 100644 --- a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/translate.py +++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/translate.py @@ -273,6 +273,9 @@ def _Struct(module, parsed_struct): raise Exception("Native-only struct declarations must include a " + "Native attribute.") + if struct.attributes and struct.attributes.get('CustomSerializer', False): + struct.custom_serializer = True + return struct def _Union(module, parsed_union): |