summaryrefslogtreecommitdiff
path: root/chromium/mojo
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-20 15:06:40 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-22 11:48:58 +0000
commitdaa093eea7c773db06799a13bd7e4e2e2a9f8f14 (patch)
tree96cc5e7b9194c1b29eab927730bfa419e7111c25 /chromium/mojo
parentbe59a35641616a4cf23c4a13fa0632624b021c1b (diff)
downloadqtwebengine-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')
-rw-r--r--chromium/mojo/OWNERS3
-rw-r--r--chromium/mojo/common/BUILD.gn1
-rw-r--r--chromium/mojo/common/file_info.mojom8
-rw-r--r--chromium/mojo/common/file_info.typemap12
-rw-r--r--chromium/mojo/common/typemaps.gni1
-rw-r--r--chromium/mojo/common/values_struct_traits.h2
-rw-r--r--chromium/mojo/edk/embedder/platform_channel_pair_fuchsia.cc14
-rw-r--r--chromium/mojo/edk/embedder/platform_handle.cc14
-rw-r--r--chromium/mojo/edk/embedder/platform_handle.h18
-rw-r--r--chromium/mojo/edk/embedder/platform_handle_utils_fuchsia.cc10
-rw-r--r--chromium/mojo/edk/system/channel.cc2
-rw-r--r--chromium/mojo/edk/system/channel.h8
-rw-r--r--chromium/mojo/edk/system/channel_fuchsia.cc106
-rw-r--r--chromium/mojo/edk/system/core.cc4
-rw-r--r--chromium/mojo/edk/system/core_test_base.cc2
-rw-r--r--chromium/mojo/edk/system/data_pipe_consumer_dispatcher.cc6
-rw-r--r--chromium/mojo/edk/system/data_pipe_producer_dispatcher.cc6
-rw-r--r--chromium/mojo/edk/system/handle_table_unittest.cc29
-rw-r--r--chromium/mojo/edk/system/message_pipe_dispatcher.cc7
-rw-r--r--chromium/mojo/edk/system/message_unittest.cc29
-rw-r--r--chromium/mojo/edk/system/node_channel.h6
-rw-r--r--chromium/mojo/edk/system/node_controller.cc3
-rw-r--r--chromium/mojo/edk/system/node_controller.h6
-rw-r--r--chromium/mojo/edk/system/platform_wrapper_unittest.cc2
-rw-r--r--chromium/mojo/edk/system/ports/event.h24
-rw-r--r--chromium/mojo/edk/system/ports/node.cc49
-rw-r--r--chromium/mojo/edk/system/ports/node.h36
-rw-r--r--chromium/mojo/edk/system/ports/port.h104
-rw-r--r--chromium/mojo/edk/system/ports/ports_unittest.cc6
-rw-r--r--chromium/mojo/edk/system/shared_buffer_dispatcher.h2
-rw-r--r--chromium/mojo/edk/system/user_message_impl.cc4
-rw-r--r--chromium/mojo/edk/system/watcher_dispatcher.cc20
-rw-r--r--chromium/mojo/edk/system/watcher_dispatcher.h3
-rw-r--r--chromium/mojo/public/c/system/data_pipe.h5
-rw-r--r--chromium/mojo/public/c/system/platform_handle.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/BUILD.gn24
-rw-r--r--chromium/mojo/public/cpp/bindings/associated_binding.h7
-rw-r--r--chromium/mojo/public/cpp/bindings/binding.h5
-rw-r--r--chromium/mojo/public/cpp/bindings/binding_set.h16
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/binding_state.h5
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/bindings_internal.h12
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc7
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc19
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/multiplex_router.h4
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/native_struct.cc34
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/native_struct_data.cc22
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/native_struct_data.h61
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.cc113
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/native_struct_serialization.h92
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/serialization.h1
-rw-r--r--chromium/mojo/public/cpp/bindings/native_struct.h51
-rw-r--r--chromium/mojo/public/cpp/bindings/native_struct_data_view.h36
-rw-r--r--chromium/mojo/public/cpp/bindings/tests/BUILD.gn1
-rw-r--r--chromium/mojo/public/cpp/bindings/tests/test_native_types_chromium.typemap8
-rw-r--r--chromium/mojo/public/cpp/bindings/thread_safe_interface_ptr.h2
-rw-r--r--chromium/mojo/public/cpp/system/BUILD.gn4
-rw-r--r--chromium/mojo/public/cpp/system/file_data_pipe_producer.cc215
-rw-r--r--chromium/mojo/public/cpp/system/file_data_pipe_producer.h76
-rw-r--r--chromium/mojo/public/cpp/system/message.cc13
-rw-r--r--chromium/mojo/public/cpp/system/platform_handle.cc2
-rw-r--r--chromium/mojo/public/cpp/system/simple_watcher.cc2
-rw-r--r--chromium/mojo/public/cpp/system/simple_watcher.h6
-rw-r--r--chromium/mojo/public/cpp/system/string_data_pipe_producer.cc131
-rw-r--r--chromium/mojo/public/cpp/system/string_data_pipe_producer.h73
-rw-r--r--chromium/mojo/public/cpp/system/tests/BUILD.gn2
-rw-r--r--chromium/mojo/public/cpp/system/wait_set.cc2
-rw-r--r--chromium/mojo/public/cpp/test_support/BUILD.gn2
-rw-r--r--chromium/mojo/public/cpp/test_support/waiter.cc19
-rw-r--r--chromium/mojo/public/cpp/test_support/waiter.h99
-rw-r--r--chromium/mojo/public/interfaces/bindings/BUILD.gn3
-rw-r--r--chromium/mojo/public/interfaces/bindings/native_struct.mojom26
-rw-r--r--chromium/mojo/public/interfaces/bindings/tests/BUILD.gn8
-rw-r--r--chromium/mojo/public/interfaces/bindings/tests/test_native_types.mojom12
-rw-r--r--chromium/mojo/public/js/new_bindings/connector.js4
-rw-r--r--chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni7
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl2
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl21
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared-internal.h.tmpl7
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/module-shared.h.tmpl7
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl14
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl4
-rw-r--r--chromium/mojo/public/tools/bindings/generators/js_templates/validation_macros.tmpl2
-rw-r--r--chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py8
-rw-r--r--chromium/mojo/public/tools/bindings/mojom.gni102
-rwxr-xr-xchromium/mojo/public/tools/bindings/mojom_bindings_generator.py33
-rw-r--r--chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py3
-rw-r--r--chromium/mojo/public/tools/bindings/pylib/mojom/generate/module.py4
-rw-r--r--chromium/mojo/public/tools/bindings/pylib/mojom/generate/translate.py3
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(), &params, 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):