summaryrefslogtreecommitdiff
path: root/chromium/mojo
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-08-30 10:22:43 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-08-30 12:36:28 +0000
commit271a6c3487a14599023a9106329505597638d793 (patch)
treee040d58ffc86c1480b79ca8528020ca9ec919bf8 /chromium/mojo
parent7b2ffa587235a47d4094787d72f38102089f402a (diff)
downloadqtwebengine-chromium-271a6c3487a14599023a9106329505597638d793.tar.gz
BASELINE: Update Chromium to 77.0.3865.59
Change-Id: I1e89a5f3b009a9519a6705102ad65c92fe736f21 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/mojo')
-rw-r--r--chromium/mojo/core/BUILD.gn10
-rw-r--r--chromium/mojo/core/README.md309
-rw-r--r--chromium/mojo/core/broker_host.cc19
-rw-r--r--chromium/mojo/core/channel.cc87
-rw-r--r--chromium/mojo/core/channel.h30
-rw-r--r--chromium/mojo/core/channel_mac.cc11
-rw-r--r--chromium/mojo/core/channel_mac_fuzzer.cc11
-rw-r--r--chromium/mojo/core/channel_posix.cc235
-rw-r--r--chromium/mojo/core/channel_unittest.cc90
-rw-r--r--chromium/mojo/core/core.cc12
-rw-r--r--chromium/mojo/core/core.h12
-rw-r--r--chromium/mojo/core/data_pipe_unittest.cc45
-rw-r--r--chromium/mojo/core/doc/layering.pngbin0 -> 40210 bytes
-rw-r--r--chromium/mojo/core/embedder/BUILD.gn5
-rw-r--r--chromium/mojo/core/embedder/default_mach_broker.cc45
-rw-r--r--chromium/mojo/core/embedder/default_mach_broker.h53
-rw-r--r--chromium/mojo/core/embedder/embedder.cc7
-rw-r--r--chromium/mojo/core/embedder/embedder.h13
-rw-r--r--chromium/mojo/core/invitation_unittest.cc15
-rw-r--r--chromium/mojo/core/mach_port_relay.cc200
-rw-r--r--chromium/mojo/core/mach_port_relay.h90
-rw-r--r--chromium/mojo/core/message_pipe_dispatcher.cc34
-rw-r--r--chromium/mojo/core/message_pipe_dispatcher.h1
-rw-r--r--chromium/mojo/core/multiprocess_message_pipe_unittest.cc4
-rw-r--r--chromium/mojo/core/node_channel.cc19
-rw-r--r--chromium/mojo/core/node_channel.h4
-rw-r--r--chromium/mojo/core/node_channel_fuzzer.cc2
-rw-r--r--chromium/mojo/core/node_controller.cc52
-rw-r--r--chromium/mojo/core/node_controller.h22
-rw-r--r--chromium/mojo/core/platform_handle_in_transit.cc18
-rw-r--r--chromium/mojo/core/platform_handle_in_transit.h21
-rw-r--r--chromium/mojo/core/ports/event.cc80
-rw-r--r--chromium/mojo/core/ports/event.h50
-rw-r--r--chromium/mojo/core/ports/node.cc242
-rw-r--r--chromium/mojo/core/ports/node.h29
-rw-r--r--chromium/mojo/core/ports/port.cc3
-rw-r--r--chromium/mojo/core/ports/port.h18
-rw-r--r--chromium/mojo/core/ports/ports_unittest.cc92
-rw-r--r--chromium/mojo/core/quota_unittest.cc102
-rw-r--r--chromium/mojo/core/trap_unittest.cc4
-rw-r--r--chromium/mojo/public/c/system/quota.h5
-rw-r--r--chromium/mojo/public/cpp/base/BUILD.gn5
-rw-r--r--chromium/mojo/public/cpp/base/generic_pending_receiver.typemap15
-rw-r--r--chromium/mojo/public/cpp/base/generic_pending_receiver_mojom_traits.cc22
-rw-r--r--chromium/mojo/public/cpp/base/generic_pending_receiver_mojom_traits.h37
-rw-r--r--chromium/mojo/public/cpp/base/message_loop_type.typemap15
-rw-r--r--chromium/mojo/public/cpp/base/message_loop_type_mojom_traits.cc76
-rw-r--r--chromium/mojo/public/cpp/base/message_loop_type_mojom_traits.h26
-rw-r--r--chromium/mojo/public/cpp/base/read_only_buffer.typemap6
-rw-r--r--chromium/mojo/public/cpp/base/read_only_buffer_mojom_traits.h6
-rw-r--r--chromium/mojo/public/cpp/base/typemaps.gni2
-rw-r--r--chromium/mojo/public/cpp/bindings/BUILD.gn11
-rw-r--r--chromium/mojo/public/cpp/bindings/array_traits_stl.h26
-rw-r--r--chromium/mojo/public/cpp/bindings/associated_remote.h31
-rw-r--r--chromium/mojo/public/cpp/bindings/binding.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/binding_set.h4
-rw-r--r--chromium/mojo/public/cpp/bindings/connection_group.cc93
-rw-r--r--chromium/mojo/public/cpp/bindings/connection_group.h110
-rw-r--r--chromium/mojo/public/cpp/bindings/connector.h11
-rw-r--r--chromium/mojo/public/cpp/bindings/generic_pending_receiver.cc39
-rw-r--r--chromium/mojo/public/cpp/bindings/generic_pending_receiver.h72
-rw-r--r--chromium/mojo/public/cpp/bindings/interface_endpoint_client.h79
-rw-r--r--chromium/mojo/public/cpp/bindings/interface_ptr.h2
-rw-r--r--chromium/mojo/public/cpp/bindings/interface_ptr_info.h39
-rw-r--r--chromium/mojo/public/cpp/bindings/interface_ptr_set.h4
-rw-r--r--chromium/mojo/public/cpp/bindings/interface_request.h54
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/binding_state.cc11
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/binding_state.h10
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/connector.cc9
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/control_message_handler.cc16
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/control_message_handler.h8
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/control_message_proxy.cc39
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/control_message_proxy.h13
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc154
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.cc9
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.h21
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/interface_serialization.h6
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/message.cc38
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc14
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/multiplex_router.h6
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/pending_receiver_state.cc29
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/pending_receiver_state.h37
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/pending_remote_state.cc35
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/pending_remote_state.h39
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc12
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/serialization_context.cc9
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/serialization_context.h15
-rw-r--r--chromium/mojo/public/cpp/bindings/lib/sync_handle_registry.cc11
-rw-r--r--chromium/mojo/public/cpp/bindings/message.h26
-rw-r--r--chromium/mojo/public/cpp/bindings/pending_receiver.h33
-rw-r--r--chromium/mojo/public/cpp/bindings/pending_remote.h24
-rw-r--r--chromium/mojo/public/cpp/bindings/receiver.h9
-rw-r--r--chromium/mojo/public/cpp/bindings/receiver_set.h21
-rw-r--r--chromium/mojo/public/cpp/bindings/remote.h58
-rw-r--r--chromium/mojo/public/cpp/bindings/remote_set.h162
-rw-r--r--chromium/mojo/public/cpp/bindings/strong_associated_binding.h10
-rw-r--r--chromium/mojo/public/cpp/bindings/strong_binding.h5
-rw-r--r--chromium/mojo/public/cpp/bindings/struct_ptr.h89
-rw-r--r--chromium/mojo/public/cpp/bindings/tests/BUILD.gn17
-rw-r--r--chromium/mojo/public/cpp/bindings/unique_associated_receiver_set.h39
-rw-r--r--chromium/mojo/public/cpp/platform/BUILD.gn6
-rw-r--r--chromium/mojo/public/cpp/platform/features.cc19
-rw-r--r--chromium/mojo/public/cpp/platform/features.h23
-rw-r--r--chromium/mojo/public/cpp/platform/named_platform_channel_mac.cc11
-rw-r--r--chromium/mojo/public/cpp/platform/named_platform_channel_posix.cc23
-rw-r--r--chromium/mojo/public/cpp/platform/platform_channel.cc106
-rw-r--r--chromium/mojo/public/cpp/platform/platform_channel.h12
-rw-r--r--chromium/mojo/public/cpp/system/BUILD.gn14
-rw-r--r--chromium/mojo/public/cpp/system/README.md4
-rw-r--r--chromium/mojo/public/cpp/system/data_pipe_drainer.cc3
-rw-r--r--chromium/mojo/public/cpp/system/data_pipe_drainer.h2
-rw-r--r--chromium/mojo/public/cpp/system/data_pipe_producer.cc208
-rw-r--r--chromium/mojo/public/cpp/system/data_pipe_producer.h110
-rw-r--r--chromium/mojo/public/cpp/system/file_data_pipe_producer.cc292
-rw-r--r--chromium/mojo/public/cpp/system/file_data_pipe_producer.h114
-rw-r--r--chromium/mojo/public/cpp/system/file_data_source.cc87
-rw-r--r--chromium/mojo/public/cpp/system/file_data_source.h43
-rw-r--r--chromium/mojo/public/cpp/system/filtered_data_source.cc46
-rw-r--r--chromium/mojo/public/cpp/system/filtered_data_source.h64
-rw-r--r--chromium/mojo/public/cpp/system/simple_watcher.cc3
-rw-r--r--chromium/mojo/public/cpp/system/simple_watcher.h2
-rw-r--r--chromium/mojo/public/cpp/system/string_data_pipe_producer.cc138
-rw-r--r--chromium/mojo/public/cpp/system/string_data_pipe_producer.h90
-rw-r--r--chromium/mojo/public/cpp/system/string_data_source.cc52
-rw-r--r--chromium/mojo/public/cpp/system/string_data_source.h49
-rw-r--r--chromium/mojo/public/cpp/system/tests/BUILD.gn4
-rw-r--r--chromium/mojo/public/interfaces/bindings/interface_control_messages.mojom24
-rw-r--r--chromium/mojo/public/interfaces/bindings/tests/BUILD.gn1
-rw-r--r--chromium/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom6
-rw-r--r--chromium/mojo/public/java/system/BUILD.gn5
-rw-r--r--chromium/mojo/public/java/system/base_run_loop.cc17
-rw-r--r--chromium/mojo/public/java/system/core_impl.cc2
-rw-r--r--chromium/mojo/public/java/system/javatests/AndroidManifest.xml2
-rw-r--r--chromium/mojo/public/java/system/javatests/mojo_test_rule.cc6
-rw-r--r--chromium/mojo/public/java/system/javatests/validation_test_util.cc2
-rw-r--r--chromium/mojo/public/java/system/watcher_impl.cc2
-rw-r--r--chromium/mojo/public/js/interface_support.js149
-rw-r--r--chromium/mojo/public/js/test/BUILD.gn15
-rw-r--r--chromium/mojo/public/mojom/base/BUILD.gn9
-rw-r--r--chromium/mojo/public/mojom/base/generic_pending_receiver.mojom16
-rw-r--r--chromium/mojo/public/mojom/base/message_loop_type.mojom21
-rw-r--r--chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni14
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl10
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl39
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl4
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl27
-rw-r--r--chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl15
-rw-r--r--chromium/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl162
-rw-r--r--chromium/mojo/public/tools/bindings/generators/js_templates/lite/test/BUILD.gn16
-rw-r--r--chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py5
-rw-r--r--chromium/mojo/public/tools/bindings/generators/mojom_java_generator.py2
-rw-r--r--chromium/mojo/public/tools/bindings/generators/mojom_js_generator.py46
-rw-r--r--chromium/mojo/public/tools/bindings/mojom.gni9
-rwxr-xr-xchromium/mojo/public/tools/bindings/mojom_bindings_generator.py6
-rw-r--r--chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py5
155 files changed, 3950 insertions, 2134 deletions
diff --git a/chromium/mojo/core/BUILD.gn b/chromium/mojo/core/BUILD.gn
index 515972a9cf5..2d46dda4f9a 100644
--- a/chromium/mojo/core/BUILD.gn
+++ b/chromium/mojo/core/BUILD.gn
@@ -119,7 +119,7 @@ template("core_impl_source_set") {
public_deps += [ "//third_party/fuchsia-sdk/sdk:fdio" ]
}
- if (is_posix) {
+ if (is_posix && !is_mac) {
if (!is_nacl || is_nacl_nonsfi) {
sources += [
"broker_posix.cc",
@@ -128,12 +128,8 @@ template("core_impl_source_set") {
}
}
- if (is_mac && !is_ios) {
- sources += [
- "channel_mac.cc",
- "mach_port_relay.cc",
- "mach_port_relay.h",
- ]
+ if (is_mac) {
+ sources += [ "channel_mac.cc" ]
}
if (!is_nacl || is_nacl_nonsfi) {
diff --git a/chromium/mojo/core/README.md b/chromium/mojo/core/README.md
new file mode 100644
index 00000000000..050f5e52fb1
--- /dev/null
+++ b/chromium/mojo/core/README.md
@@ -0,0 +1,309 @@
+# Mojo Core Overview
+
+[TOC]
+
+## Overview
+
+Mojo Core implements an IPC mechanism based on Message routing over a network
+of "Nodes". A Node in typical usage corresponds to a system process.
+"Messages" are exchanged between pairs of "Ports", where a pair of Ports
+represent a "MessagePipe" from the outside. A MessagePipe provides
+reliable in-order delivery of Messages.
+Messages can be used to transport Ports and platform handles (file descriptors,
+Mach ports, Windows handles, etc.) between Nodes.
+Communication between Nodes is done through platform IPC channels, such as
+AF_UNIX sockets, pipes or Fuchsia channels. A new Node has to be invited into
+the network by giving it an IPC channel to an existing Node in the network,
+or else provided with a way to establish one, such as e.g. the name/path to a
+listening pipe or an AF_UNIX socket.
+
+Mojo Core also provides a shared memory buffer primitive and assists in the
+creation and transport of shared memory buffers as required by the underlying
+operating system and process permissions.
+
+A single Node in the network is termed the "Broker".
+The Broker has some special responsibilities in the network, notably the Broker
+is responsible for:
+ - Introducing a pair of Nodes in the network to one another to establish a
+ direct IPC link between them.
+ - Copying handles between Nodes, where they cannot themselves do so. This is
+ e.g. the case for sandboxed processes on Windows.
+ - Creating shared memory objects for processes that can't themselves do so.
+
+Mojo Core exposes two API sets:
+ 1. The [C system API](../public/c/system/README.md).
+ 1. The [embedder API](embedder/README.md).
+
+This document is to describe how these APIs are implemented by Mojo Core.
+
+## Layering
+
+This image provides an overview of how the Mojo Core implementation is layered:
+
+![Mojo Core Layering](doc/layering.png)
+
+The C system API is a stable, versioned API, exposed through a singleton
+structure containing C function thunks. This allows multiple clients in the same
+application to use a single embedder-provided instance of Mojo, and allows these
+clients to be versioned and distributed independently of Mojo.
+Using C thunks also makes it easier to provide compatibility with other
+programming languages than C and C++.
+
+When clients invoke on the Mojo public API, they go through the dispatch
+functions implemented in [dispatcher.cc](dispatcher.cc), which in turn forwards
+the call to a global instance of [mojo::core::Core](core.h).
+Core further dispatches the calls to the implementation instance, which is
+either a [mojo::core::Dispatcher](dispatcher.h), or a
+[mojo::core::UserMessageImpl](user_message_impl.h).
+In the case of a Dispatcher, the incoming MojoHandle is looked up in the
+[mojo::core::HandleTable](handle_table.h), which returns the Dispatcher
+corresponding to the MojoHandle.
+
+The public API exposes the following concepts as MojoHandles:
+ 1. [DataPipeConsumer](data_pipe_consumer_dispatcher.h).
+ 1. [DataPipeProducer](data_pipe_producer_dispatcher.h).
+ 1. [Invitation](invitation_dispatcher.h).
+ 1. [MessagePipe](message_pipe_dispatcher.h).
+ 1. [PlatformHandle](platform_handle_dispatcher.h).
+ 1. [SharedBuffer](shared_buffer_dispatcher.h).
+ 1. [Watcher](watcher_dispatcher.h) - this is know as "Trap" in the public API.
+
+These are implemented as subclasses of [mojo::core::Dispatcher](dispatcher.h).
+The Dispatcher class implements the union of all possible operations on a
+MojoHandle, and the various subclasses implement the subset appropriate to their
+type.
+
+Additionally the public API exposes Messages as MojoMessageHandles, which are
+simply an instance of a [mojo::core::UserMessageImpl](user_message_impl.h).
+
+## Threading model
+
+Mojo Core is multi-threaded, so any API can be used from any thread in a
+process. Receiving Messages from other Nodes is done on the "IO Thread", which
+is an [embedder-supplied task runner](embedder/README.md#ipc-initialization).
+Sending Messages to other Nodes is typically done on the sending thread.
+However, if the native IPC channel's buffer is full, the outgoing Message will
+be queued and subsequently sent on the "IO Thread".
+
+## Event Dispatching
+
+During the processing of an API call and during activity in the NodeController,
+various entities may change states, which can lead to the generation of
+[TrapEvents](../public/c/system/README.md#Signals-Traps) to the user.
+The [mojo::core::RequestContext](request_context.h) takes care of aggregating
+Watchers that need dispatching and issuing outstanding TrapEvents as the last
+RequestContext in a thread goes out of scope.
+
+This avoids calling out to user code from deep within Core, and the resulting
+reentrancy that might ensue.
+
+## Messaging implementation
+
+Mojo Core is implemented on top of "[Ports](ports)" and is an embedder of Ports.
+
+Ports provides the base abstractions of addressing,
+[mojo::core::ports::Node](ports/node.h) and
+[mojo::core::ports::Port](ports/port.h) as well as the messaging and event
+handling for maintaining and transporting Port pairs across Nodes.
+
+All routing and IPC is however delegated to the embedder, Mojo Core, via
+the [mojo::core::NodeController](node_controller.h) which owns an instance of
+Node, and implements its delegate interface.
+
+### Naming and Addressing
+
+Nodes are named by a large (128 bit) random number. Ports are likewise named
+by a large (128 bit) random number.
+Messages are directed at a Port, and so are addressed by a (Node:Port) pair.
+
+Each Port has precisely one "conjugate" Port at any point in time. When a
+Message is sent through a Port, its conjugate Port is the implicit destination,
+and this is a symmetrical relationship. The address of the conjugate Port can
+change as it is moved between nodes.
+In practice a Port is renamed each time it's moved between Nodes, and so changes
+in both components of the (Node:Port) address pair.
+
+Note that since each Port has a single conjugate Port at any time, en-route
+Messages are addressed only with the destination Port address, as the source
+is implicit.
+
+### Routing and Topology
+
+A process network initially starts with only the Broker process Node.
+New Nodes must be introduced to the broker by some means. This can be done by
+inheriting an IPC handle into a newly created process, or by providing them
+the name of a listening IPC channel they can connect to.
+
+Each Node thus starts with only a direct IPC connection to a single other Node
+in the network. The first time a Node tries to forward a Message to a Node it
+doesn't have a direct IPC channel with, it will send a message to the broker to
+request an introduction to the new peer Node.
+
+If the broker knows of the peer Node, it will construct a new native IPC
+channel, then hand one end of it to the requesting Node and one end to the new
+peer Node. This will result in a direct Node-to-Node link between the two, and
+so the topology of a process network will trend towards a fully connected graph.
+
+### Messages
+
+A UserMessageImpl is the unit of transport in Mojo Core.
+This is a collection of
+ 1. Handles,
+ 1. Ports,
+ 1. User data.
+
+Mojo Core takes care of transferring and serializing and deserializing Handles
+and Ports.
+The user data on the other hand has to be serialized and deserialized by the
+user. Mojo Core optimizes this by allowing the user data to be serialized only
+at need, e.g. when a Message is routed to another Node.
+
+### Port
+
+A Node maintains a set of Ports local to that Node.
+
+Logically, each Port has a conjugate Port where all its Messages are destined.
+However, when a Port is transferred to a different Node, the newly created Port
+on the destination Node will have the transferred Port as its next-hop "Proxy"
+Port it sends Messages to. The Proxy Port is responsible for delivering
+in-progress Messages across to the new destination Port, and may buffer Messages
+to that end. Once a Proxy Port has delivered all in-progress Messages, it
+is dissolved and Messages start flowing through the next Peer Port in turn,
+which may be the conjugate Port or another Proxy Port.
+
+Each Port maintains state relating to its:
+ - Current Peer Port, which may be a Proxy Port, but in the stable state will
+ be its conjugate Port.
+ - Its current state of messaging, which changes as Ports move across Nodes.
+ - Its outgoing Message state, notably Message serial numbers.
+ - Its incoming Message queue.
+
+The unit of messaging at this level is the
+[mojo::core::ports::Event](ports/event.h), which has several sub-types relating
+to the business of maintaining and transporting Ports and keeping their
+Peer Port address up to date.
+
+The UserMessageEvent subclass is the event type that carries all user messaging.
+A UserMessageEvent owns a
+[mojo::core::ports::UserMessage](ports/user_message.h), which is the interface
+to the embedder's Message type. Mojo Core implements this in
+[mojoe::core::UserMessageImpl](user_message_impl.h). Note that at the Ports
+level, this is simply opaque user data. It's the Mojo Core embedder that is
+aware of the handles and data attached to a UserMessageImpl.
+
+Note that if a Port is transferred across multiple Nodes, it may end up with a
+multi-leg Peer relationship. As result, and because different Messages for the
+same Port may take different routes through the process network, out of order
+Message delivery is possible. The incoming
+[mojo::core::ports::MessageQueue](ports/message_queue.h) takes care of
+re-ordering incoming Messages.
+
+The Node does all Message handling and delivery for its local Ports, but
+delegates all routing to its delegate through the
+[mojo::core::ports::NodeDelegate](ports/node_delegate.h) interface.
+Mojo Core implements this in [mojo::core::NodeController](node_controller.h).
+
+### Node to Node IPC
+
+The business of handling Node to Node IPC is primarily handled in
+[mojo::core::NodeChannel](node_channel.h) as well as
+[mojo::core::Channel](channel.h) and its OS-specific subclasses by exchanging
+[mojo::core::Channel::Message](channel.h)s.
+
+Note that a Channel::Message always goes from a source Node to a destination
+Node through a Channel (strictly speaking one on each side). As the Channels on
+either side (or the OS-provided IPC mechanism) conspire to copy the handles
+across, the processes involved in the handle transfer are always implicit.
+This means that a low-privilege or sandboxed process can only send its own
+handles in a Message, and it's not possible to abuse this to acquire another
+process's handles.
+
+A NodeChannel wraps a Channel that communicates to and from another given Node.
+It implements all messaging to another specific Node, both relating to general
+messaging (see NodeChannel::OnEventMessage), as well as messaging relating to
+invitations and Port management.
+Since the NodeChannel is associated with a single given Node, the peer Node name
+is an implicit given in any incoming Message from the Channel.
+
+The Channel takes care of maintaining and servicing a queue of Messages outgoing
+to the peer node, as well as reading and parsing the next incoming Message from
+the IPC channel.
+Depending on the platform and the Node topology, it may also take care of moving
+outgoing and incoming handles between the processes hosting the Nodes on either
+side of the Channel.
+
+Note that on Windows, the Broker always takes care of handle copying, as the
+Broker will typically be the only process with sufficient privilege to copy
+handles. This means that any Message carrying handles is routed through the
+Broker on Windows.
+
+### Packet Framing
+
+An in-transit Message on an IPC channel will be serialized as a
+[mojo::core::Channel::Message](channel.h).
+
+For user Messages, this will contain:
+ 1. A [mojo::core::Channel::Message::Header](channel.h) containing:
+ - The length of the full Message
+ - The length of the header.
+ - The Message type.
+ - The number of handles.
+ 2. The Platform handles.
+ 3. The serialized [mojo::core::ports::Event](ports/event.h). Specifically for
+ a UserMessageEvent:
+ - [mojo::core::ports::SerializedHeader](ports/event.cc).
+ - [mojo::core::ports::UserMessageEventData](ports/event.cc).
+ - Ports; num_ports times core::Ports::PortDescriptor.
+ - The serialized user data.
+
+## Buffering
+
+Message buffering in Mojo Core primarily occurs at two levels:
+ - In the incoming Message queue of a receiving Port.
+ - In the outgoing queue for an IPC Channel to a peer Node.
+
+There is also transient buffering of Messages to a new Peer Node while
+introductions are in-flight.
+Finally, while a Port is in transport to different node, it buffers inbound data
+until the destination Node accepts the new Peer, at which time any buffered data
+is forwarded to the new Port in the destination Node.
+
+Mojo Core does implement quotas on Port receiving queue Message number and byte
+size. If the receive length quota is exceeded on a Port, it signals an
+over-quota TrapEvent on the receiving Port. This doesn't however limit buffering
+as the caller needs to handle the TrapEvent in some way - most likely by simply
+closing the Port.
+
+Since Mojo Core does not limit buffering, the producers and consumers in a
+process network must be balanced.
+If a producer runs wild, the producer's process may buffer an arbirarly large
+number of Messages (and bytes) in the outgoing Message queue on the IPC channel
+to the consumer's Node.
+Alternatively the consumer's process may buffer an arbitrarily large
+number of Messages (and bytes) in the incoming Message queue on the consumer's
+Port.
+
+## Security
+
+Mojo can be viewed as a Capability system, where a Port is a Capability.
+If a Node can name a Port, that Port can be considered a granted Capability
+to that Node. Many Ports will grant other Ports upon request, and so the
+transitive closure of those Ports can be considered in the set of granted
+Capabilities to a Node.
+
+Native handles can also be viewed as Capabilities, and so any native handle
+reachable from the set of Ports granted to a Node can also be considered in
+the Node's set of granted Capabilities.
+
+There's however a significant difference between Ports and native handles, in
+that native handles are kernel-mediated capabilities. This means there's no way
+for a process that doesn't hold a handle to operate on it.
+
+Mojo Ports, in contrast, are a pure user-mode construct and any Node can send
+any Message to any Port of any other Node so long as it has knowledge of the
+Port and Node names. If it doesn't already have an IPC channel to that node,
+it can either send the Message through the Broker, or request an invitation to
+the destination Node from the Broker and then send the Message directly.
+
+It is therefore important not to leak Port names into Nodes that shouldn't be
+granted the corresponding Capability.
diff --git a/chromium/mojo/core/broker_host.cc b/chromium/mojo/core/broker_host.cc
index 5e6b2250e69..a555bcc3ca9 100644
--- a/chromium/mojo/core/broker_host.cc
+++ b/chromium/mojo/core/broker_host.cc
@@ -108,29 +108,32 @@ void BrokerHost::OnBufferRequest(uint32_t num_bytes) {
base::subtle::PlatformSharedMemoryRegion region =
base::subtle::PlatformSharedMemoryRegion::CreateWritable(num_bytes);
- std::vector<PlatformHandleInTransit> handles(2);
+ std::vector<PlatformHandleInTransit> handles;
+ handles.reserve(2);
if (region.IsValid()) {
PlatformHandle h[2];
ExtractPlatformHandlesFromSharedMemoryRegionHandle(
region.PassPlatformHandle(), &h[0], &h[1]);
- handles[0] = PlatformHandleInTransit(std::move(h[0]));
- handles[1] = PlatformHandleInTransit(std::move(h[1]));
+ handles.emplace_back(std::move(h[0]));
#if !defined(OS_POSIX) || defined(OS_ANDROID) || \
(defined(OS_MACOSX) && !defined(OS_IOS))
// Non-POSIX systems, as well as Android, and non-iOS Mac, only use a single
// handle to represent a writable region.
- DCHECK(!handles[1].handle().is_valid());
- handles.resize(1);
+ DCHECK(!h[1].is_valid());
#else
- DCHECK(handles[1].handle().is_valid());
+ DCHECK(h[1].is_valid());
+ handles.emplace_back(std::move(h[1]));
#endif
}
BufferResponseData* response;
Channel::MessagePtr message = CreateBrokerMessage(
BrokerMessageType::BUFFER_RESPONSE, handles.size(), 0, &response);
- if (!handles.empty()) {
- base::UnguessableToken guid = region.GetGUID();
+ if (handles.empty()) {
+ response->guid_high = 0;
+ response->guid_low = 0;
+ } else {
+ const base::UnguessableToken& guid = region.GetGUID();
response->guid_high = guid.GetHighForSerialization();
response->guid_low = guid.GetLowForSerialization();
PrepareHandlesForClient(&handles);
diff --git a/chromium/mojo/core/channel.cc b/chromium/mojo/core/channel.cc
index 7daaaa13d22..6aa38d22c86 100644
--- a/chromium/mojo/core/channel.cc
+++ b/chromium/mojo/core/channel.cc
@@ -19,7 +19,6 @@
#include "build/build_config.h"
#include "mojo/core/configuration.h"
#include "mojo/core/core.h"
-#include "mojo/public/cpp/platform/features.h"
#if defined(OS_MACOSX) && !defined(OS_IOS)
#include "base/mac/mach_logging.h"
@@ -154,12 +153,7 @@ Channel::Message::Message(size_t capacity,
mach_ports_header_->num_ports = 0;
// Initialize all handles to invalid values.
for (size_t i = 0; i < max_handles_; ++i) {
- if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) {
- mach_ports_header_->entries[i].mach_entry.type = {0};
- } else {
- mach_ports_header_->entries[i].posix_entry = {
- 0, static_cast<uint32_t>(MACH_PORT_NULL)};
- }
+ mach_ports_header_->entries[i] = {0};
}
#endif
}
@@ -247,6 +241,11 @@ Channel::MessagePtr Channel::Message::Deserialize(
sizeof(MachPortsEntry);
#else
const uint32_t max_handles = 0;
+ // No extra header expected. Fail if this is detected.
+ if (extra_header_size > 0) {
+ DLOG(ERROR) << "Decoding invalid message: unexpected extra_header_size > 0";
+ return nullptr;
+ }
#endif // defined(OS_WIN)
const uint16_t num_handles =
@@ -377,19 +376,6 @@ bool Channel::Message::has_handles() const {
: header()->num_handles) > 0;
}
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-bool Channel::Message::has_mach_ports() const {
- if (!has_handles())
- return false;
-
- for (const auto& handle : handle_vector_) {
- if (handle.is_mach_port_name() || handle.handle().is_mach_port())
- return true;
- }
- return false;
-}
-#endif
-
bool Channel::Message::is_legacy_message() const {
return legacy_header()->message_type == MessageType::NORMAL_LEGACY;
}
@@ -444,56 +430,20 @@ void Channel::Message::SetHandles(
#endif // defined(OS_WIN)
#if defined(OS_MACOSX) && !defined(OS_IOS)
- size_t mach_port_index = 0;
- const bool use_channel_mac =
- base::FeatureList::IsEnabled(features::kMojoChannelMac);
if (mach_ports_header_) {
for (size_t i = 0; i < max_handles_; ++i) {
- if (use_channel_mac) {
- mach_ports_header_->entries[i].mach_entry.type = {0};
- } else {
- mach_ports_header_->entries[i].posix_entry = {
- 0, static_cast<uint32_t>(MACH_PORT_NULL)};
- }
+ mach_ports_header_->entries[i] = {0};
}
for (size_t i = 0; i < handle_vector_.size(); i++) {
- if (use_channel_mac) {
- mach_ports_header_->entries[i].mach_entry.type =
- static_cast<uint8_t>(handle_vector_[i].handle().type());
- } else {
- if (!handle_vector_[i].is_mach_port_name() &&
- !handle_vector_[i].handle().is_mach_port()) {
- DCHECK(handle_vector_[i].handle().is_valid_fd());
- continue;
- }
-
- mach_port_t port = handle_vector_[i].is_mach_port_name()
- ? handle_vector_[i].mach_port_name()
- : handle_vector_[i].handle().GetMachPort().get();
- mach_ports_header_->entries[mach_port_index].posix_entry.index = i;
- mach_ports_header_->entries[mach_port_index].posix_entry.mach_port =
- port;
- mach_port_index++;
- }
+ mach_ports_header_->entries[i].type =
+ static_cast<uint8_t>(handle_vector_[i].handle().type());
}
- mach_ports_header_->num_ports =
- use_channel_mac ? handle_vector_.size()
- : static_cast<uint16_t>(mach_port_index);
+ mach_ports_header_->num_ports = handle_vector_.size();
}
#endif
}
std::vector<PlatformHandleInTransit> Channel::Message::TakeHandles() {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- if (mach_ports_header_ &&
- !base::FeatureList::IsEnabled(features::kMojoChannelMac)) {
- for (size_t i = 0; i < max_handles_; ++i) {
- mach_ports_header_->entries[i].posix_entry = {
- 0, static_cast<uint32_t>(MACH_PORT_NULL)};
- }
- mach_ports_header_->num_ports = 0;
- }
-#endif
return std::move(handle_vector_);
}
@@ -503,23 +453,6 @@ Channel::Message::TakeHandlesForTransport() {
// Not necessary on Windows.
NOTREACHED();
return std::vector<PlatformHandleInTransit>();
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
- if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) {
- return std::move(handle_vector_);
- } else {
- std::vector<PlatformHandleInTransit> non_mach_handles;
- for (auto& handle : handle_vector_) {
- if (handle.is_mach_port_name() || handle.handle().is_mach_port()) {
- // Ownership is effectively transferred to the receiving process
- // out-of-band via MachPortRelay.
- handle.CompleteTransit();
- } else {
- non_mach_handles.emplace_back(std::move(handle));
- }
- }
- handle_vector_.clear();
- return non_mach_handles;
- }
#else
return std::move(handle_vector_);
#endif
diff --git a/chromium/mojo/core/channel.h b/chromium/mojo/core/channel.h
index e06ce1af2b9..bf8e02820a8 100644
--- a/chromium/mojo/core/channel.h
+++ b/chromium/mojo/core/channel.h
@@ -66,7 +66,7 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel
// TODO(https://crbug.com/695645): remove legacy support when Arc++ has
// updated to Mojo with normal versioned messages.
NORMAL_LEGACY = 0,
-#if defined(OS_MACOSX)
+#if defined(OS_IOS)
// A control message containing handles to echo back.
HANDLES_SENT,
// A control message containing handles that can now be closed.
@@ -111,27 +111,12 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel
};
#if defined(OS_MACOSX) && !defined(OS_IOS)
- union MachPortsEntry {
- // Used with ChannelPosix.
- struct {
- // Index of Mach port in the original vector of
- // PlatformHandleInTransits.
- uint16_t index;
-
- // Mach port name.
- uint32_t mach_port;
- } posix_entry;
-
- // Used with ChannelMac.
- struct {
- // The PlatformHandle::Type.
- uint8_t type;
- } mach_entry;
- static_assert(sizeof(mach_port_t) <= sizeof(uint32_t),
- "mach_port_t must be no larger than uint32_t");
+ struct MachPortsEntry {
+ // The PlatformHandle::Type.
+ uint8_t type;
};
- static_assert(sizeof(MachPortsEntry) == 6,
- "sizeof(MachPortsEntry) must be 6 bytes");
+ static_assert(sizeof(MachPortsEntry) == 1,
+ "sizeof(MachPortsEntry) must be 1 byte");
// Structure of the extra header field when present on OSX.
struct MachPortsExtraHeader {
@@ -205,9 +190,6 @@ class MOJO_SYSTEM_IMPL_EXPORT Channel
size_t num_handles() const;
bool has_handles() const;
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- bool has_mach_ports() const;
-#endif
bool is_legacy_message() const;
LegacyHeader* legacy_header() const;
diff --git a/chromium/mojo/core/channel_mac.cc b/chromium/mojo/core/channel_mac.cc
index 8820afe0a0c..582b056d2d4 100644
--- a/chromium/mojo/core/channel_mac.cc
+++ b/chromium/mojo/core/channel_mac.cc
@@ -133,8 +133,8 @@ class ChannelMac : public Channel,
}
for (uint16_t i = 0; i < mach_ports_header->num_ports; ++i) {
- auto type = static_cast<PlatformHandle::Type>(
- mach_ports_header->entries[i].mach_entry.type);
+ auto type =
+ static_cast<PlatformHandle::Type>(mach_ports_header->entries[i].type);
if (type == PlatformHandle::Type::kNone) {
return false;
} else if (type == PlatformHandle::Type::kFd &&
@@ -353,8 +353,8 @@ class ChannelMac : public Channel,
sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t) +
(message->num_handles() * sizeof(mach_msg_port_descriptor_t));
const size_t expected_message_size =
- round_msg(mach_header_size + message->data_num_bytes() +
- sizeof(mach_msg_audit_trailer_t));
+ round_msg(mach_header_size + sizeof(uint64_t) +
+ message->data_num_bytes() + sizeof(mach_msg_audit_trailer_t));
const bool transfer_message_ool =
expected_message_size >= send_buffer_.size();
@@ -703,9 +703,8 @@ class ChannelMac : public Channel,
} // namespace
-// TODO(crbug.com/932175): This will be renamed Channel::Create.
MOJO_SYSTEM_IMPL_EXPORT
-scoped_refptr<Channel> ChannelMacCreate(
+scoped_refptr<Channel> Channel::Create(
Channel::Delegate* delegate,
ConnectionParams connection_params,
Channel::HandlePolicy handle_policy,
diff --git a/chromium/mojo/core/channel_mac_fuzzer.cc b/chromium/mojo/core/channel_mac_fuzzer.cc
index e45e6bbe5c2..87674baec92 100644
--- a/chromium/mojo/core/channel_mac_fuzzer.cc
+++ b/chromium/mojo/core/channel_mac_fuzzer.cc
@@ -6,13 +6,11 @@
#include "base/logging.h"
#include "base/mac/mach_logging.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
-#include "base/test/scoped_feature_list.h"
+#include "base/task/single_thread_task_executor.h"
#include "mojo/core/channel.h"
#include "mojo/core/entrypoints.h"
#include "mojo/core/test/data/channel_mac/channel_mac.pb.h"
-#include "mojo/public/cpp/platform/features.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "testing/libfuzzer/fuzzers/mach/mach_message_converter.h"
#include "testing/libfuzzer/proto/lpm_interface.h"
@@ -22,20 +20,17 @@ namespace {
class ChannelMacFuzzer {
public:
ChannelMacFuzzer() {
- feature_list_.InitAndEnableFeature(mojo::features::kMojoChannelMac);
-
mojo::core::InitializeCore();
logging::SetMinLogLevel(logging::LOG_FATAL);
}
scoped_refptr<base::TaskRunner> io_task_runner() {
- return message_loop_.task_runner();
+ return io_task_executor_.task_runner();
}
private:
- base::test::ScopedFeatureList feature_list_;
- base::MessageLoopForIO message_loop_;
+ base::SingleThreadTaskExecutor io_task_executor_{base::MessagePump::Type::IO};
};
class FakeChannelDelegate : public mojo::core::Channel::Delegate {
diff --git a/chromium/mojo/core/channel_posix.cc b/chromium/mojo/core/channel_posix.cc
index eed78a3c7f4..24818bdf0f4 100644
--- a/chromium/mojo/core/channel_posix.cc
+++ b/chromium/mojo/core/channel_posix.cc
@@ -22,17 +22,12 @@
#include "base/task_runner.h"
#include "build/build_config.h"
#include "mojo/core/core.h"
-#include "mojo/public/cpp/platform/features.h"
#include "mojo/public/cpp/platform/socket_utils_posix.h"
#if !defined(OS_NACL)
#include <sys/uio.h>
#endif
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-#include "mojo/core/mach_port_relay.h"
-#endif
-
namespace mojo {
namespace core {
@@ -97,9 +92,6 @@ class MessageView {
};
class ChannelPosix : public Channel,
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- public MachPortRelay::Observer,
-#endif
public base::MessageLoopCurrent::DestructionObserver,
public base::MessagePumpForIO::FdWatcher {
public:
@@ -119,15 +111,6 @@ class ChannelPosix : public Channel,
}
void Start() override {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- auto* relay = Core::Get()->GetMachPortRelay();
- if (relay) {
- // We should only have a relay if we know the remote process handle,
- // because that means we're in the broker process.
- relay->AddObserver(this);
- }
-#endif
-
if (io_task_runner_->RunsTasksInCurrentSequence()) {
StartOnIOThread();
} else {
@@ -143,30 +126,6 @@ class ChannelPosix : public Channel,
}
void Write(MessagePtr message) override {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- // If this message has Mach ports and we have a MachPortRelay, use the relay
- // to rewrite the ports as receive rights from which the send right can be
- // read. See |MachPortRelay::SendPortsToProcess()|.
- //
- // Note that if we don't have a relay, the receiving process must, and they
- // must also have the ability to extract a send right from the ports that
- // are already attached.
- MachPortRelay* relay = Core::Get()->GetMachPortRelay();
- if (relay && remote_process().is_valid() && message->has_mach_ports()) {
- if (relay->port_provider()->TaskForPid(remote_process().get()) ==
- MACH_PORT_NULL) {
- // We also need to have a task port for the remote process before we can
- // send it any other ports. If we don't have one yet, queue the message
- // until OnProcessReady() is invoked.
- base::AutoLock lock(task_port_wait_lock_);
- pending_outgoing_with_mach_ports_.emplace_back(std::move(message));
- return;
- }
-
- relay->SendPortsToProcess(message.get(), remote_process().get());
- }
-#endif
-
bool write_error = false;
{
base::AutoLock lock(write_lock_);
@@ -202,82 +161,6 @@ class ChannelPosix : public Channel,
bool* deferred) override {
if (num_handles > std::numeric_limits<uint16_t>::max())
return false;
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- // On OSX, we can have mach ports which are located in the extra header
- // section.
- using MachPortsEntry = Channel::Message::MachPortsEntry;
- using MachPortsExtraHeader = Channel::Message::MachPortsExtraHeader;
- if (extra_header_size <
- sizeof(MachPortsExtraHeader) + num_handles * sizeof(MachPortsEntry)) {
- return false;
- }
- const MachPortsExtraHeader* mach_ports_header =
- reinterpret_cast<const MachPortsExtraHeader*>(extra_header);
- size_t num_mach_ports = mach_ports_header->num_ports;
- if (num_mach_ports > num_handles)
- return false;
- if (incoming_fds_.size() + num_mach_ports < num_handles)
- return true;
-
- std::vector<PlatformHandleInTransit> handles_in_transit(num_handles);
- const MachPortsEntry* mach_ports = mach_ports_header->entries;
-
- // If we know the remote process handle, we assume all incoming Mach ports
- // are send right references owned by the remote process. Otherwise they're
- // receive ports we can use to read a send right.
- const bool extract_send_rights = remote_process().is_valid();
- for (size_t i = 0, mach_port_index = 0; i < num_handles; ++i) {
- if (mach_port_index < num_mach_ports &&
- mach_ports[mach_port_index].posix_entry.index == i) {
- mach_port_t port_name = static_cast<mach_port_t>(
- mach_ports[mach_port_index].posix_entry.mach_port);
- if (extract_send_rights) {
- handles_in_transit[i] =
- PlatformHandleInTransit::CreateForMachPortName(port_name);
- } else {
- handles_in_transit[i] = PlatformHandleInTransit(
- PlatformHandle(MachPortRelay::ReceiveSendRight(
- base::mac::ScopedMachReceiveRight(port_name))));
- }
- mach_port_index++;
- } else {
- if (incoming_fds_.empty())
- return false;
- handles_in_transit[i] = PlatformHandleInTransit(
- PlatformHandle(std::move(incoming_fds_.front())));
- incoming_fds_.pop_front();
- }
- }
- if (extract_send_rights && num_mach_ports) {
- MachPortRelay* relay = Core::Get()->GetMachPortRelay();
- DCHECK(relay);
- // Extracting send rights requires that we have a task port for the
- // remote process, which we may not yet have.
- if (relay->port_provider()->TaskForPid(remote_process().get()) !=
- MACH_PORT_NULL) {
- // We do have a task port, so extract the send rights immediately.
- for (auto& handle : handles_in_transit) {
- if (handle.is_mach_port_name()) {
- handle = PlatformHandleInTransit(PlatformHandle(relay->ExtractPort(
- handle.mach_port_name(), remote_process().get())));
- }
- }
- } else {
- // No task port, we have to defer this message.
- *deferred = true;
- base::AutoLock lock(task_port_wait_lock_);
- std::vector<uint8_t> data(payload_size);
- memcpy(data.data(), payload, payload_size);
- pending_incoming_with_mach_ports_.emplace_back(
- std::move(data), std::move(handles_in_transit));
- return true;
- }
- }
-
- handles->resize(handles_in_transit.size());
- for (size_t i = 0; i < handles->size(); ++i)
- handles->at(i) = handles_in_transit[i].TakeHandle();
-#else
if (incoming_fds_.size() < num_handles)
return true;
@@ -286,7 +169,6 @@ class ChannelPosix : public Channel,
handles->at(i) = PlatformHandle(std::move(incoming_fds_.front()));
incoming_fds_.pop_front();
}
-#endif
return true;
}
@@ -352,74 +234,14 @@ class ChannelPosix : public Channel,
socket_.reset();
ignore_result(server_.TakePlatformHandle());
}
-#if defined(OS_MACOSX)
+#if defined(OS_IOS)
fds_to_close_.clear();
#endif
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- auto* relay = Core::Get()->GetMachPortRelay();
- if (relay)
- relay->RemoveObserver(this);
-#endif
-
// May destroy the |this| if it was the last reference.
self_ = nullptr;
}
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- // MachPortRelay::Observer:
- void OnProcessReady(base::ProcessHandle process) override {
- if (process != remote_process().get())
- return;
-
- io_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(
- &ChannelPosix::FlushPendingMessagesWithMachPortsOnIOThread, this));
- }
-
- void FlushPendingMessagesWithMachPortsOnIOThread() {
- // We have a task port for the remote process. Now we can send or accept
- // any pending messages with Mach ports.
- std::vector<RawIncomingMessage> incoming;
- std::vector<MessagePtr> outgoing;
- {
- base::AutoLock lock(task_port_wait_lock_);
- if (reject_incoming_messages_with_mach_ports_)
- return;
- std::swap(pending_incoming_with_mach_ports_, incoming);
- std::swap(pending_outgoing_with_mach_ports_, outgoing);
- }
-
- DCHECK(remote_process().is_valid());
- base::ProcessHandle process = remote_process().get();
- MachPortRelay* relay = Core::Get()->GetMachPortRelay();
- DCHECK(relay);
- for (auto& message : incoming) {
- Channel::Delegate* d = delegate();
- if (!d)
- break;
- std::vector<PlatformHandle> handles(message.handles.size());
- for (size_t i = 0; i < message.handles.size(); ++i) {
- if (message.handles[i].is_mach_port_name()) {
- handles[i] = PlatformHandle(
- relay->ExtractPort(message.handles[i].mach_port_name(), process));
- } else {
- DCHECK(!message.handles[i].owning_process().is_valid());
- handles[i] = message.handles[i].TakeHandle();
- }
- }
- d->OnChannelMessage(message.data.data(), message.data.size(),
- std::move(handles));
- }
-
- for (auto& message : outgoing) {
- relay->SendPortsToProcess(message.get(), process);
- Write(std::move(message));
- }
- }
-#endif
-
// base::MessageLoopCurrent::DestructionObserver:
void WillDestroyCurrentMessageLoop() override {
DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
@@ -535,8 +357,8 @@ class ChannelPosix : public Channel,
// TODO: Handle lots of handles.
result = SendmsgWithHandles(socket_.get(), &iov, 1, fds);
if (result >= 0) {
-#if defined(OS_MACOSX)
- // There is a bug on OSX which makes it dangerous to close
+#if defined(OS_IOS)
+ // There is a bug in XNU which makes it dangerous to close
// a file descriptor while it is in transit. So instead we
// store the file descriptor in a set and send a message to
// the recipient, which is queued AFTER the message that
@@ -555,7 +377,7 @@ class ChannelPosix : public Channel,
for (auto& fd : fds)
fds_to_close_.emplace_back(std::move(fd));
}
-#endif // defined(OS_MACOSX)
+#endif // defined(OS_IOS)
handles_written += num_handles_to_send;
DCHECK_LE(handles_written, num_handles);
message_view.set_num_handles_sent(handles_written);
@@ -575,8 +397,8 @@ class ChannelPosix : public Channel,
if (result < 0) {
if (errno != EAGAIN &&
errno != EWOULDBLOCK
-#if defined(OS_MACOSX)
- // On OS X if sendmsg() is trying to send fds between processes and
+#if defined(OS_IOS)
+ // On iOS if sendmsg() is trying to send fds between processes and
// there isn't enough room in the output buffer to send the fd
// structure over atomically then EMSGSIZE is returned.
//
@@ -591,7 +413,7 @@ class ChannelPosix : public Channel,
// passing the FD over atomically.
&& errno != EMSGSIZE
#endif
- ) {
+ ) {
return false;
}
message_view.SetHandles(std::move(handles));
@@ -634,7 +456,7 @@ class ChannelPosix : public Channel,
return true;
}
-#if defined(OS_MACOSX)
+#if defined(OS_IOS)
bool OnControlMessage(Message::MessageType message_type,
const void* payload,
size_t payload_size,
@@ -700,7 +522,7 @@ class ChannelPosix : public Channel,
fds_to_close_.erase(start, it);
return true;
}
-#endif // defined(OS_MACOSX)
+#endif // defined(OS_IOS)
void OnWriteError(Error error) {
DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
@@ -746,57 +568,22 @@ class ChannelPosix : public Channel,
bool leak_handle_ = false;
-#if defined(OS_MACOSX)
+#if defined(OS_IOS)
base::Lock fds_to_close_lock_;
std::vector<base::ScopedFD> fds_to_close_;
-#if !defined(OS_IOS)
- // Guards access to the send/receive queues below. These are messages that
- // can't be fully accepted from or dispatched to the Channel user yet because
- // we're still waiting on a task port for the remote process.
- struct RawIncomingMessage {
- RawIncomingMessage(std::vector<uint8_t> data,
- std::vector<PlatformHandleInTransit> handles)
- : data(std::move(data)), handles(std::move(handles)) {}
- RawIncomingMessage(RawIncomingMessage&&) = default;
- ~RawIncomingMessage() = default;
-
- std::vector<uint8_t> data;
- std::vector<PlatformHandleInTransit> handles;
- };
-
- base::Lock task_port_wait_lock_;
- bool reject_incoming_messages_with_mach_ports_ = false;
- std::vector<MessagePtr> pending_outgoing_with_mach_ports_;
- std::vector<RawIncomingMessage> pending_incoming_with_mach_ports_;
-#endif // !defined(OS_IOS)
-#endif // defined(OS_MACOSX)
+#endif // defined(OS_IOS)
DISALLOW_COPY_AND_ASSIGN(ChannelPosix);
};
} // namespace
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-// Forward declare from channel_mac.cc.
-scoped_refptr<Channel> ChannelMacCreate(
- Channel::Delegate* delegate,
- ConnectionParams connection_params,
- Channel::HandlePolicy handle_policy,
- scoped_refptr<base::TaskRunner> io_task_runner);
-#endif
-
// static
scoped_refptr<Channel> Channel::Create(
Delegate* delegate,
ConnectionParams connection_params,
HandlePolicy handle_policy,
scoped_refptr<base::TaskRunner> io_task_runner) {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) {
- return ChannelMacCreate(delegate, std::move(connection_params),
- handle_policy, io_task_runner);
- }
-#endif
return new ChannelPosix(delegate, std::move(connection_params), handle_policy,
io_task_runner);
}
diff --git a/chromium/mojo/core/channel_unittest.cc b/chromium/mojo/core/channel_unittest.cc
index 14585e348ea..623ec6cd7be 100644
--- a/chromium/mojo/core/channel_unittest.cc
+++ b/chromium/mojo/core/channel_unittest.cc
@@ -11,8 +11,11 @@
#include "base/message_loop/message_loop.h"
#include "base/optional.h"
#include "base/process/process_handle.h"
+#include "base/process/process_metrics.h"
#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
#include "base/threading/thread.h"
+#include "build/build_config.h"
#include "mojo/core/platform_handle_utils.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -364,6 +367,28 @@ TEST(ChannelTest, DeserializeMessage_BadExtraHeaderSize) {
base::kNullProcessHandle));
}
+#if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(OS_FUCHSIA)
+TEST(ChannelTest, DeserializeMessage_NonZeroExtraHeaderSize) {
+ // Verifies that a message payload is rejected when the extra header chunk
+ // size anything but zero on Linux, even if it's aligned.
+ constexpr uint16_t kTotalHeaderSize =
+ sizeof(Channel::Message::Header) + kChannelMessageAlignment;
+ constexpr uint32_t kEmptyPayloadSize = 8;
+ constexpr uint32_t kMessageSize = kTotalHeaderSize + kEmptyPayloadSize;
+ char message[kMessageSize];
+ memset(message, 0, kMessageSize);
+
+ Channel::Message::Header* header =
+ reinterpret_cast<Channel::Message::Header*>(&message[0]);
+ header->num_bytes = kMessageSize;
+ header->num_header_bytes = kTotalHeaderSize;
+ header->message_type = Channel::Message::MessageType::NORMAL;
+ header->num_handles = 0;
+ EXPECT_EQ(nullptr, Channel::Message::Deserialize(&message[0], kMessageSize,
+ base::kNullProcessHandle));
+}
+#endif
+
class CountingChannelDelegate : public Channel::Delegate {
public:
explicit CountingChannelDelegate(base::OnceClosure on_final_message)
@@ -485,6 +510,71 @@ TEST(ChannelTest, PeerStressTest) {
EXPECT_EQ(0u, delegate_b.error_count_);
}
+class SingleMessageWaiterDelegate : public Channel::Delegate {
+ public:
+ SingleMessageWaiterDelegate() {}
+
+ void OnChannelMessage(const void* payload,
+ size_t payload_size,
+ std::vector<PlatformHandle> handles) override {
+ message_received_ = true;
+ run_loop_->Quit();
+ }
+
+ void OnChannelError(Channel::Error error) override {
+ channel_error_ = true;
+ run_loop_->Quit();
+ }
+
+ void Reset(base::RunLoop* loop) {
+ run_loop_ = loop;
+ message_received_ = false;
+ channel_error_ = false;
+ }
+
+ bool message_received() { return message_received_; }
+ bool channel_error() { return channel_error_; }
+
+ private:
+ bool message_received_ = false;
+ bool channel_error_ = false;
+ base::RunLoop* run_loop_;
+ DISALLOW_COPY_AND_ASSIGN(SingleMessageWaiterDelegate);
+};
+
+TEST(ChannelTest, MessageSizeTest) {
+ base::MessageLoop message_loop(base::MessageLoop::TYPE_IO);
+ PlatformChannel platform_channel;
+
+ SingleMessageWaiterDelegate receiver_delegate;
+ scoped_refptr<Channel> receiver = Channel::Create(
+ &receiver_delegate,
+ ConnectionParams(platform_channel.TakeLocalEndpoint()),
+ Channel::HandlePolicy::kAcceptHandles, message_loop.task_runner());
+ receiver->Start();
+
+ MockChannelDelegate sender_delegate;
+ scoped_refptr<Channel> sender = Channel::Create(
+ &sender_delegate, ConnectionParams(platform_channel.TakeRemoteEndpoint()),
+ Channel::HandlePolicy::kAcceptHandles, message_loop.task_runner());
+ sender->Start();
+
+ for (uint32_t i = 0; i < base::GetPageSize() * 4; ++i) {
+ SCOPED_TRACE(base::StringPrintf("message size %d", i));
+
+ auto message = std::make_unique<Channel::Message>(i, 0);
+ memset(message->mutable_payload(), 0xAB, i);
+ sender->Write(std::move(message));
+
+ base::RunLoop loop;
+ receiver_delegate.Reset(&loop);
+ loop.Run();
+
+ EXPECT_TRUE(receiver_delegate.message_received());
+ EXPECT_FALSE(receiver_delegate.channel_error());
+ }
+}
+
} // namespace
} // namespace core
} // namespace mojo
diff --git a/chromium/mojo/core/core.cc b/chromium/mojo/core/core.cc
index 32ecea3eae5..bfd727a3992 100644
--- a/chromium/mojo/core/core.cc
+++ b/chromium/mojo/core/core.cc
@@ -213,18 +213,6 @@ void Core::ConnectIsolated(ConnectionParams connection_params,
connection_name);
}
-void Core::SetMachPortProvider(base::PortProvider* port_provider) {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- GetNodeController()->CreateMachPortRelay(port_provider);
-#endif
-}
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-MachPortRelay* Core::GetMachPortRelay() {
- return GetNodeController()->GetMachPortRelay();
-}
-#endif
-
MojoHandle Core::AddDispatcher(scoped_refptr<Dispatcher> dispatcher) {
base::AutoLock lock(handles_->GetLock());
return handles_->AddDispatcher(dispatcher);
diff --git a/chromium/mojo/core/core.h b/chromium/mojo/core/core.h
index 2840bc5e680..b3f557b27de 100644
--- a/chromium/mojo/core/core.h
+++ b/chromium/mojo/core/core.h
@@ -30,14 +30,9 @@
#include "mojo/public/c/system/trap.h"
#include "mojo/public/c/system/types.h"
-namespace base {
-class PortProvider;
-}
-
namespace mojo {
namespace core {
-class MachPortRelay;
class PlatformSharedMemoryMapping;
// |Core| is an object that implements the Mojo system calls. All public methods
@@ -112,13 +107,6 @@ class MOJO_SYSTEM_IMPL_EXPORT Core {
const ports::PortRef& port,
base::StringPiece connection_name);
- // Sets the mach port provider for this process.
- void SetMachPortProvider(base::PortProvider* port_provider);
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- MachPortRelay* GetMachPortRelay();
-#endif
-
MojoHandle AddDispatcher(scoped_refptr<Dispatcher> dispatcher);
// Adds new dispatchers for non-message-pipe handles received in a message.
diff --git a/chromium/mojo/core/data_pipe_unittest.cc b/chromium/mojo/core/data_pipe_unittest.cc
index 0ce3f1ed985..a46750795a4 100644
--- a/chromium/mojo/core/data_pipe_unittest.cc
+++ b/chromium/mojo/core/data_pipe_unittest.cc
@@ -10,9 +10,9 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
+#include "base/test/scoped_task_environment.h"
#include "build/build_config.h"
#include "mojo/core/embedder/embedder.h"
#include "mojo/core/test/mojo_test_base.h"
@@ -42,6 +42,9 @@ const size_t kMultiprocessCapacity = 37;
const char kMultiprocessTestData[] = "hello i'm a string that is 36 bytes";
const int kMultiprocessMaxIter = 5;
+// Capacity that will cause data pipe creation to fail.
+constexpr size_t kOversizedCapacity = std::numeric_limits<uint32_t>::max();
+
// TODO(rockot): There are many uses of ASSERT where EXPECT would be more
// appropriate. Fix this.
@@ -1727,6 +1730,17 @@ bool ReadAllData(MojoHandle consumer,
return num_bytes == 0;
}
+TEST_F(DataPipeTest, CreateOversized) {
+ const MojoCreateDataPipeOptions options = {
+ kSizeOfOptions, // |struct_size|.
+ MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|.
+ 1, // |element_num_bytes|.
+ kOversizedCapacity, // |capacity_num_bytes|.
+ };
+
+ ASSERT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED, Create(&options));
+}
+
#if !defined(OS_IOS)
TEST_F(DataPipeTest, Multiprocess) {
@@ -1972,7 +1986,7 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(DataPipeStatusChangeInTransitClient,
EXPECT_EQ(MOJO_RESULT_OK,
WaitForSignals(consumers[0], MOJO_HANDLE_SIGNAL_PEER_CLOSED));
- base::MessageLoop message_loop;
+ base::test::ScopedTaskEnvironment scoped_task_environment;
// Wait on producer 1 and consumer 1 using SimpleWatchers.
{
@@ -2040,6 +2054,33 @@ TEST_F(DataPipeTest, StatusChangeInTransit) {
});
}
+DEFINE_TEST_CLIENT_TEST_WITH_PIPE(CreateOversizedChild, DataPipeTest, h) {
+ const MojoCreateDataPipeOptions options = {
+ kSizeOfOptions, // |struct_size|.
+ MOJO_CREATE_DATA_PIPE_FLAG_NONE, // |flags|.
+ 1, // |element_num_bytes|.
+ kOversizedCapacity // |capacity_num_bytes|.
+ };
+
+ MojoHandle p, c;
+ ASSERT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
+ MojoCreateDataPipe(&options, &p, &c));
+ WriteMessage(h, "success");
+
+ // Wait for a quit message.
+ EXPECT_EQ("quit", ReadMessage(h));
+}
+
+TEST_F(DataPipeTest, CreateOversizedInChild) {
+ RunTestClient("CreateOversizedChild", [&](MojoHandle child) {
+ // Wait for the child to finish the test.
+ std::string expected_message = ReadMessage(child);
+ EXPECT_EQ("success", expected_message);
+
+ WriteMessage(child, "quit");
+ });
+}
+
#endif // !defined(OS_IOS)
} // namespace
diff --git a/chromium/mojo/core/doc/layering.png b/chromium/mojo/core/doc/layering.png
new file mode 100644
index 00000000000..72c6d0bb0cd
--- /dev/null
+++ b/chromium/mojo/core/doc/layering.png
Binary files differ
diff --git a/chromium/mojo/core/embedder/BUILD.gn b/chromium/mojo/core/embedder/BUILD.gn
index 774afe42938..47f1c390166 100644
--- a/chromium/mojo/core/embedder/BUILD.gn
+++ b/chromium/mojo/core/embedder/BUILD.gn
@@ -16,11 +16,6 @@ component("embedder") {
"scoped_ipc_support.cc",
]
- if (is_mac && !is_ios) {
- public += [ "default_mach_broker.h" ]
- sources += [ "default_mach_broker.cc" ]
- }
-
defines = [ "IS_MOJO_CORE_EMBEDDER_IMPL" ]
public_deps = [
diff --git a/chromium/mojo/core/embedder/default_mach_broker.cc b/chromium/mojo/core/embedder/default_mach_broker.cc
deleted file mode 100644
index 436917a7536..00000000000
--- a/chromium/mojo/core/embedder/default_mach_broker.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/core/embedder/default_mach_broker.h"
-
-#include "base/logging.h"
-
-namespace mojo {
-namespace core {
-
-namespace {
-const char kBootstrapPortName[] = "mojo_default_mach_broker";
-}
-
-// static
-void DefaultMachBroker::SendTaskPortToParent() {
- bool result =
- base::MachPortBroker::ChildSendTaskPortToParent(kBootstrapPortName);
- DCHECK(result);
-}
-
-// static
-DefaultMachBroker* DefaultMachBroker::Get() {
- static DefaultMachBroker* broker = new DefaultMachBroker;
- return broker;
-}
-
-DefaultMachBroker::DefaultMachBroker() : broker_(kBootstrapPortName) {
- bool result = broker_.Init();
- DCHECK(result);
-}
-
-DefaultMachBroker::~DefaultMachBroker() {}
-
-void DefaultMachBroker::ExpectPid(base::ProcessHandle pid) {
- broker_.AddPlaceholderForPid(pid);
-}
-
-void DefaultMachBroker::RemovePid(base::ProcessHandle pid) {
- broker_.InvalidatePid(pid);
-}
-
-} // namespace core
-} // namespace mojo
diff --git a/chromium/mojo/core/embedder/default_mach_broker.h b/chromium/mojo/core/embedder/default_mach_broker.h
deleted file mode 100644
index 2229ec12a44..00000000000
--- a/chromium/mojo/core/embedder/default_mach_broker.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_CORE_EMBEDDER_DEFAULT_MACH_BROKER_H_
-#define MOJO_CORE_EMBEDDER_DEFAULT_MACH_BROKER_H_
-
-#include "base/component_export.h"
-#include "base/mac/mach_port_broker.h"
-#include "base/macros.h"
-
-namespace mojo {
-namespace core {
-
-// A singleton Mojo embedders can use to manage task port brokering among
-// connected processes.
-class COMPONENT_EXPORT(MOJO_CORE_EMBEDDER) DefaultMachBroker {
- public:
- // Sends the task port of the current process to the parent over Mach IPC.
- // For use in child processes.
- static void SendTaskPortToParent();
-
- // Returns the global |DefaultMachBroker|.
- static DefaultMachBroker* Get();
-
- // Registers |pid| with a MACH_PORT_NULL task port in the port provider. A
- // child's pid must be registered before the broker will accept a task port
- // from that child.
- //
- // Callers MUST have the lock acquired (see |GetLock()) while calling this.
- void ExpectPid(base::ProcessHandle pid);
-
- // Removes |pid| from the port provider.
- //
- // Callers MUST have the lock acquired (see |GetLock()) while calling this.
- void RemovePid(base::ProcessHandle pid);
-
- base::Lock& GetLock() { return broker_.GetLock(); }
- base::PortProvider* port_provider() { return &broker_; }
-
- private:
- DefaultMachBroker();
- ~DefaultMachBroker();
-
- base::MachPortBroker broker_;
-
- DISALLOW_COPY_AND_ASSIGN(DefaultMachBroker);
-};
-
-} // namespace core
-} // namespace mojo
-
-#endif // MOJO_CORE_EMBEDDER_DEFAULT_MACH_BROKER_H_
diff --git a/chromium/mojo/core/embedder/embedder.cc b/chromium/mojo/core/embedder/embedder.cc
index 4044de083ee..a25d501386b 100644
--- a/chromium/mojo/core/embedder/embedder.cc
+++ b/chromium/mojo/core/embedder/embedder.cc
@@ -39,12 +39,5 @@ scoped_refptr<base::TaskRunner> GetIOTaskRunner() {
return Core::Get()->GetNodeController()->io_task_runner();
}
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-void SetMachPortProvider(base::PortProvider* port_provider) {
- DCHECK(port_provider);
- Core::Get()->SetMachPortProvider(port_provider);
-}
-#endif
-
} // namespace core
} // namespace mojo
diff --git a/chromium/mojo/core/embedder/embedder.h b/chromium/mojo/core/embedder/embedder.h
index feb7ca1be4b..2b7d7dbfbae 100644
--- a/chromium/mojo/core/embedder/embedder.h
+++ b/chromium/mojo/core/embedder/embedder.h
@@ -18,10 +18,6 @@
#include "build/build_config.h"
#include "mojo/core/embedder/configuration.h"
-namespace base {
-class PortProvider;
-}
-
namespace mojo {
namespace core {
@@ -50,15 +46,6 @@ void SetDefaultProcessErrorCallback(const ProcessErrorCallback& callback);
COMPONENT_EXPORT(MOJO_CORE_EMBEDDER)
scoped_refptr<base::TaskRunner> GetIOTaskRunner();
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-// Set the |base::PortProvider| for this process. Can be called on any thread,
-// but must be set in the root process before any Mach ports can be transferred.
-//
-// If called at all, this must be called while a ScopedIPCSupport exists.
-COMPONENT_EXPORT(MOJO_CORE_EMBEDDER)
-void SetMachPortProvider(base::PortProvider* port_provider);
-#endif
-
} // namespace core
} // namespace mojo
diff --git a/chromium/mojo/core/invitation_unittest.cc b/chromium/mojo/core/invitation_unittest.cc
index dae047ad6c9..674a4fe803c 100644
--- a/chromium/mojo/core/invitation_unittest.cc
+++ b/chromium/mojo/core/invitation_unittest.cc
@@ -22,7 +22,6 @@
#include "build/build_config.h"
#include "mojo/core/test/mojo_test_base.h"
#include "mojo/public/c/system/invitation.h"
-#include "mojo/public/cpp/platform/features.h"
#include "mojo/public/cpp/platform/named_platform_channel.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/system/platform_handle.h"
@@ -80,18 +79,8 @@ void PrepareToPassRemoteEndpoint(PlatformChannel* channel,
#if defined(OS_FUCHSIA)
channel->PrepareToPassRemoteEndpoint(&options->handles_to_transfer, &value);
#elif defined(OS_MACOSX)
- PlatformChannel::HandlePassingInfo info;
- if (base::FeatureList::IsEnabled(features::kMojoChannelMac))
- info = options->mach_ports_for_rendezvous;
- else
- info = options->fds_to_remap;
-
- channel->PrepareToPassRemoteEndpoint(&info, &value);
-
- if (base::FeatureList::IsEnabled(features::kMojoChannelMac))
- options->mach_ports_for_rendezvous = info;
- else
- options->fds_to_remap = info;
+ channel->PrepareToPassRemoteEndpoint(&options->mach_ports_for_rendezvous,
+ &value);
#elif defined(OS_POSIX)
channel->PrepareToPassRemoteEndpoint(&options->fds_to_remap, &value);
#elif defined(OS_WIN)
diff --git a/chromium/mojo/core/mach_port_relay.cc b/chromium/mojo/core/mach_port_relay.cc
deleted file mode 100644
index 7d7a42510e4..00000000000
--- a/chromium/mojo/core/mach_port_relay.cc
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/core/mach_port_relay.h"
-
-#include <mach/mach.h>
-
-#include <utility>
-
-#include "base/logging.h"
-#include "base/mac/mach_port_util.h"
-#include "base/mac/scoped_mach_port.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/process/process.h"
-
-namespace mojo {
-namespace core {
-
-namespace {
-
-// Errors that can occur in the broker (privileged parent) process.
-// These match tools/metrics/histograms.xml.
-// This enum is append-only.
-enum class BrokerUMAError : int {
- SUCCESS = 0,
- // Couldn't get a task port for the process with a given pid.
- ERROR_TASK_FOR_PID = 1,
- // Couldn't make a port with receive rights in the destination process.
- ERROR_MAKE_RECEIVE_PORT = 2,
- // Couldn't change the attributes of a Mach port.
- ERROR_SET_ATTRIBUTES = 3,
- // Couldn't extract a right from the destination.
- ERROR_EXTRACT_DEST_RIGHT = 4,
- // Couldn't send a Mach port in a call to mach_msg().
- ERROR_SEND_MACH_PORT = 5,
- // Couldn't extract a right from the source.
- ERROR_EXTRACT_SOURCE_RIGHT = 6,
- ERROR_MAX
-};
-
-// Errors that can occur in a child process.
-// These match tools/metrics/histograms.xml.
-// This enum is append-only.
-enum class ChildUMAError : int {
- SUCCESS = 0,
- // An error occurred while trying to receive a Mach port with mach_msg().
- ERROR_RECEIVE_MACH_MESSAGE = 1,
- ERROR_MAX
-};
-
-void ReportBrokerError(BrokerUMAError error) {
- UMA_HISTOGRAM_ENUMERATION("Mojo.MachPortRelay.BrokerError",
- static_cast<int>(error),
- static_cast<int>(BrokerUMAError::ERROR_MAX));
-}
-
-void ReportChildError(ChildUMAError error) {
- UMA_HISTOGRAM_ENUMERATION("Mojo.MachPortRelay.ChildError",
- static_cast<int>(error),
- static_cast<int>(ChildUMAError::ERROR_MAX));
-}
-
-} // namespace
-
-// static
-base::mac::ScopedMachSendRight MachPortRelay::ReceiveSendRight(
- base::mac::ScopedMachReceiveRight port) {
- // MACH_PORT_NULL doesn't need translation.
- if (!port.is_valid())
- return base::mac::ScopedMachSendRight();
-
- // Take ownership of the receive right. We only need it to read this single
- // send right, then it can be closed.
- base::mac::ScopedMachSendRight received_port(
- base::ReceiveMachPort(port.get()));
- if (!received_port.is_valid()) {
- ReportChildError(ChildUMAError::ERROR_RECEIVE_MACH_MESSAGE);
- DLOG(ERROR) << "Error receiving mach port";
- return base::mac::ScopedMachSendRight();
- }
-
- ReportChildError(ChildUMAError::SUCCESS);
- return received_port;
-}
-
-MachPortRelay::MachPortRelay(base::PortProvider* port_provider)
- : port_provider_(port_provider) {
- DCHECK(port_provider);
- port_provider_->AddObserver(this);
-}
-
-MachPortRelay::~MachPortRelay() {
- port_provider_->RemoveObserver(this);
-}
-
-void MachPortRelay::SendPortsToProcess(Channel::Message* message,
- base::ProcessHandle process) {
- DCHECK(message);
- mach_port_t task_port = port_provider_->TaskForPid(process);
-
- std::vector<PlatformHandleInTransit> handles = message->TakeHandles();
- // Message should have handles, otherwise there's no point in calling this
- // function.
- DCHECK(!handles.empty());
- for (auto& handle : handles) {
- if (!handle.handle().is_valid_mach_port())
- continue;
-
- if (task_port == MACH_PORT_NULL) {
- // Callers check the port provider for the task port before calling this
- // function, in order to queue pending messages. Therefore, if this fails,
- // it should be considered a genuine, bona fide, electrified, six-car
- // error.
- ReportBrokerError(BrokerUMAError::ERROR_TASK_FOR_PID);
- handle = PlatformHandleInTransit(
- PlatformHandle(base::mac::ScopedMachSendRight()));
- continue;
- }
-
- mach_port_name_t intermediate_port;
- base::MachCreateError error_code;
- intermediate_port = base::CreateIntermediateMachPort(
- task_port, handle.TakeHandle().TakeMachPort(), &error_code);
- if (intermediate_port == MACH_PORT_NULL) {
- BrokerUMAError uma_error;
- switch (error_code) {
- case base::MachCreateError::ERROR_MAKE_RECEIVE_PORT:
- uma_error = BrokerUMAError::ERROR_MAKE_RECEIVE_PORT;
- break;
- case base::MachCreateError::ERROR_SET_ATTRIBUTES:
- uma_error = BrokerUMAError::ERROR_SET_ATTRIBUTES;
- break;
- case base::MachCreateError::ERROR_EXTRACT_DEST_RIGHT:
- uma_error = BrokerUMAError::ERROR_EXTRACT_DEST_RIGHT;
- break;
- case base::MachCreateError::ERROR_SEND_MACH_PORT:
- uma_error = BrokerUMAError::ERROR_SEND_MACH_PORT;
- break;
- }
- ReportBrokerError(uma_error);
- handle = PlatformHandleInTransit(
- PlatformHandle(base::mac::ScopedMachSendRight()));
- continue;
- }
-
- handle = PlatformHandleInTransit::CreateForMachPortName(intermediate_port);
- ReportBrokerError(BrokerUMAError::SUCCESS);
- }
- message->SetHandles(std::move(handles));
-}
-
-base::mac::ScopedMachSendRight MachPortRelay::ExtractPort(
- mach_port_t port_name,
- base::ProcessHandle process) {
- // No extraction necessary for MACH_PORT_NULL.
- if (port_name == MACH_PORT_NULL)
- return base::mac::ScopedMachSendRight();
-
- mach_port_t task_port = port_provider_->TaskForPid(process);
- if (task_port == MACH_PORT_NULL) {
- ReportBrokerError(BrokerUMAError::ERROR_TASK_FOR_PID);
- return base::mac::ScopedMachSendRight();
- }
-
- mach_port_t extracted_right = MACH_PORT_NULL;
- mach_msg_type_name_t extracted_right_type;
- kern_return_t kr =
- mach_port_extract_right(task_port, port_name, MACH_MSG_TYPE_MOVE_SEND,
- &extracted_right, &extracted_right_type);
- if (kr != KERN_SUCCESS) {
- ReportBrokerError(BrokerUMAError::ERROR_EXTRACT_SOURCE_RIGHT);
- return base::mac::ScopedMachSendRight();
- }
-
- ReportBrokerError(BrokerUMAError::SUCCESS);
- DCHECK_EQ(static_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND),
- extracted_right_type);
- return base::mac::ScopedMachSendRight(extracted_right);
-}
-
-void MachPortRelay::AddObserver(Observer* observer) {
- base::AutoLock locker(observers_lock_);
- bool inserted = observers_.insert(observer).second;
- DCHECK(inserted);
-}
-
-void MachPortRelay::RemoveObserver(Observer* observer) {
- base::AutoLock locker(observers_lock_);
- observers_.erase(observer);
-}
-
-void MachPortRelay::OnReceivedTaskPort(base::ProcessHandle process) {
- base::AutoLock locker(observers_lock_);
- for (auto* observer : observers_)
- observer->OnProcessReady(process);
-}
-
-} // namespace core
-} // namespace mojo
diff --git a/chromium/mojo/core/mach_port_relay.h b/chromium/mojo/core/mach_port_relay.h
deleted file mode 100644
index 4cb6de4bd64..00000000000
--- a/chromium/mojo/core/mach_port_relay.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_CORE_MACH_PORT_RELAY_H_
-#define MOJO_CORE_MACH_PORT_RELAY_H_
-
-#include <set>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/process/port_provider_mac.h"
-#include "base/synchronization/lock.h"
-#include "mojo/core/channel.h"
-
-namespace mojo {
-namespace core {
-
-// The MachPortRelay is used by a privileged process, usually the root process,
-// to manipulate Mach ports in a child process. Ports can be added to and
-// extracted from a child process that has registered itself with the
-// |base::PortProvider| used by this class.
-class MachPortRelay : public base::PortProvider::Observer {
- public:
- class Observer {
- public:
- // Called by the MachPortRelay to notify observers that a new process is
- // ready for Mach ports to be sent/received. There are no guarantees about
- // the thread this is called on, including the presence of a MessageLoop.
- // Implementations must not call AddObserver() or RemoveObserver() during
- // this function, as doing so will deadlock.
- virtual void OnProcessReady(base::ProcessHandle process) = 0;
- };
-
- // Used by a child process to receive Mach ports from a sender (privileged)
- // process. The Mach port in |port| is interpreted as an intermediate Mach
- // port. It replaces each Mach port with the final Mach port received from the
- // intermediate port. This method takes ownership of the intermediate Mach
- // port and gives ownership of the final Mach port to the caller.
- //
- // On failure, returns a null send right.
- //
- // See SendPortsToProcess() for the definition of intermediate and final Mach
- // ports.
- static base::mac::ScopedMachSendRight ReceiveSendRight(
- base::mac::ScopedMachReceiveRight port);
-
- explicit MachPortRelay(base::PortProvider* port_provider);
- ~MachPortRelay() override;
-
- // Sends the Mach ports attached to |message| to |process|.
- // For each Mach port attached to |message|, a new Mach port, the intermediate
- // port, is created in |process|. The message's Mach port is then sent over
- // this intermediate port and the message is modified to refer to the name of
- // the intermediate port. The Mach port received over the intermediate port in
- // the child is referred to as the final Mach port.
- //
- // All ports in |message|'s set of handles are reset by this call, and all
- // port names in the message's header are replaced with the new receive right
- // ports.
- void SendPortsToProcess(Channel::Message* message,
- base::ProcessHandle process);
-
- // Given the name of a Mach send right within |process|, extracts an owned
- // send right ref and returns it. May return a null port on failure.
- base::mac::ScopedMachSendRight ExtractPort(mach_port_t port_name,
- base::ProcessHandle process);
-
- // Observer interface.
- void AddObserver(Observer* observer);
- void RemoveObserver(Observer* observer);
-
- base::PortProvider* port_provider() const { return port_provider_; }
-
- private:
- // base::PortProvider::Observer implementation.
- void OnReceivedTaskPort(base::ProcessHandle process) override;
-
- base::PortProvider* const port_provider_;
-
- base::Lock observers_lock_;
- std::set<Observer*> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(MachPortRelay);
-};
-
-} // namespace core
-} // namespace mojo
-
-#endif // MOJO_CORE_MACH_PORT_RELAY_H_
diff --git a/chromium/mojo/core/message_pipe_dispatcher.cc b/chromium/mojo/core/message_pipe_dispatcher.cc
index 00fc12e2aa0..482a685c0eb 100644
--- a/chromium/mojo/core/message_pipe_dispatcher.cc
+++ b/chromium/mojo/core/message_pipe_dispatcher.cc
@@ -158,6 +158,10 @@ MojoResult MessagePipeDispatcher::WriteMessage(
return MOJO_RESULT_UNKNOWN;
}
+ // We may need to update anyone watching our signals in case we just exceeded
+ // the unread message count quota.
+ base::AutoLock lock(signal_lock_);
+ watchers_.NotifyState(GetHandleSignalsStateNoLock());
return MOJO_RESULT_OK;
}
@@ -194,6 +198,8 @@ MojoResult MessagePipeDispatcher::ReadMessage(
}
MojoResult MessagePipeDispatcher::SetQuota(MojoQuotaType type, uint64_t limit) {
+ base::AutoLock lock(signal_lock_);
+
switch (type) {
case MOJO_QUOTA_TYPE_RECEIVE_QUEUE_LENGTH:
if (limit == MOJO_QUOTA_LIMIT_NONE)
@@ -209,6 +215,23 @@ MojoResult MessagePipeDispatcher::SetQuota(MojoQuotaType type, uint64_t limit) {
receive_queue_memory_size_limit_ = limit;
break;
+ case MOJO_QUOTA_TYPE_UNREAD_MESSAGE_COUNT:
+ if (limit == MOJO_QUOTA_LIMIT_NONE) {
+ unread_message_count_limit_.reset();
+ node_controller_->node()->SetAcknowledgeRequestInterval(port_, 0);
+ } else {
+ unread_message_count_limit_ = limit;
+ // Setting the acknowledge request interval for the port to half the
+ // unread quota limit, means the ack roundtrip has half the window to
+ // catch up with sent messages. In other words, if the producer is
+ // producing messages at a steady rate of limit/2 packets per message
+ // round trip or lower, the quota limit won't be exceeded. This is
+ // assuming the consumer is consuming messages at the same rate.
+ node_controller_->node()->SetAcknowledgeRequestInterval(
+ port_, (limit + 1) / 2);
+ }
+ break;
+
default:
return MOJO_RESULT_INVALID_ARGUMENT;
}
@@ -219,6 +242,8 @@ MojoResult MessagePipeDispatcher::SetQuota(MojoQuotaType type, uint64_t limit) {
MojoResult MessagePipeDispatcher::QueryQuota(MojoQuotaType type,
uint64_t* limit,
uint64_t* usage) {
+ base::AutoLock lock(signal_lock_);
+
ports::PortStatus port_status;
if (node_controller_->node()->GetStatus(port_, &port_status) != ports::OK) {
CHECK(in_transit_ || port_transferred_ || port_closed_);
@@ -236,6 +261,11 @@ MojoResult MessagePipeDispatcher::QueryQuota(MojoQuotaType type,
*usage = port_status.queued_num_bytes;
break;
+ case MOJO_QUOTA_TYPE_UNREAD_MESSAGE_COUNT:
+ *limit = unread_message_count_limit_.value_or(MOJO_QUOTA_LIMIT_NONE);
+ *usage = port_status.unacknowledged_message_count;
+ break;
+
default:
return MOJO_RESULT_INVALID_ARGUMENT;
}
@@ -384,6 +414,10 @@ HandleSignalsState MessagePipeDispatcher::GetHandleSignalsStateNoLock() const {
} else if (receive_queue_memory_size_limit_ &&
port_status.queued_num_bytes > *receive_queue_memory_size_limit_) {
rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED;
+ } else if (unread_message_count_limit_ &&
+ port_status.unacknowledged_message_count >
+ *unread_message_count_limit_) {
+ rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED;
}
rv.satisfiable_signals |=
MOJO_HANDLE_SIGNAL_PEER_CLOSED | MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED;
diff --git a/chromium/mojo/core/message_pipe_dispatcher.h b/chromium/mojo/core/message_pipe_dispatcher.h
index 4fef7080997..231cb02162c 100644
--- a/chromium/mojo/core/message_pipe_dispatcher.h
+++ b/chromium/mojo/core/message_pipe_dispatcher.h
@@ -106,6 +106,7 @@ class MessagePipeDispatcher : public Dispatcher {
WatcherSet watchers_;
base::Optional<uint64_t> receive_queue_length_limit_;
base::Optional<uint64_t> receive_queue_memory_size_limit_;
+ base::Optional<uint64_t> unread_message_count_limit_;
DISALLOW_COPY_AND_ASSIGN(MessagePipeDispatcher);
};
diff --git a/chromium/mojo/core/multiprocess_message_pipe_unittest.cc b/chromium/mojo/core/multiprocess_message_pipe_unittest.cc
index ea06608fc21..60332c0716d 100644
--- a/chromium/mojo/core/multiprocess_message_pipe_unittest.cc
+++ b/chromium/mojo/core/multiprocess_message_pipe_unittest.cc
@@ -18,10 +18,10 @@
#include "base/files/scoped_file.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/strings/string_split.h"
+#include "base/test/scoped_task_environment.h"
#include "build/build_config.h"
#include "mojo/core/handle_signals_state.h"
#include "mojo/core/test/mojo_test_base.h"
@@ -1274,7 +1274,7 @@ DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MessagePipeStatusChangeInTransitClient,
EXPECT_EQ(MOJO_RESULT_OK,
WaitForSignals(handles[0], MOJO_HANDLE_SIGNAL_PEER_CLOSED));
- base::MessageLoop message_loop;
+ base::test::ScopedTaskEnvironment scoped_task_environment;
// Wait on handle 1 using a SimpleWatcher.
{
diff --git a/chromium/mojo/core/node_channel.cc b/chromium/mojo/core/node_channel.cc
index cabbe8809e6..c227a72f690 100644
--- a/chromium/mojo/core/node_channel.cc
+++ b/chromium/mojo/core/node_channel.cc
@@ -33,11 +33,11 @@ enum class MessageType : uint32_t {
REQUEST_PORT_MERGE,
REQUEST_INTRODUCTION,
INTRODUCE,
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN)
RELAY_EVENT_MESSAGE,
#endif
BROADCAST_EVENT,
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN)
EVENT_MESSAGE_FROM_RELAY,
#endif
ACCEPT_PEER,
@@ -110,7 +110,7 @@ struct IntroductionData {
ports::NodeName name;
};
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN)
// This struct is followed by the full payload of a message to be relayed.
struct RelayEventMessageData {
ports::NodeName destination;
@@ -373,7 +373,7 @@ void NodeChannel::Broadcast(Channel::MessagePtr message) {
WriteChannelMessage(std::move(broadcast_message));
}
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN)
void NodeChannel::RelayEventMessage(const ports::NodeName& destination,
Channel::MessagePtr message) {
#if defined(OS_WIN)
@@ -437,7 +437,7 @@ void NodeChannel::EventMessageFromRelay(const ports::NodeName& source,
relayed_message->SetHandles(message->TakeHandles());
WriteChannelMessage(std::move(relayed_message));
}
-#endif // defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#endif // defined(OS_WIN)
NodeChannel::NodeChannel(Delegate* delegate,
ConnectionParams connection_params,
@@ -606,7 +606,7 @@ void NodeChannel::OnChannelMessage(const void* payload,
break;
}
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN)
case MessageType::RELAY_EVENT_MESSAGE: {
base::ProcessHandle from_process;
{
@@ -630,9 +630,6 @@ void NodeChannel::OnChannelMessage(const void* payload,
DLOG(ERROR) << "Dropping invalid relay message.";
break;
}
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- message->SetHandles(std::move(handles));
-#endif
delegate_->OnRelayEventMessage(remote_node_name_, from_process,
data->destination, std::move(message));
return;
@@ -656,7 +653,7 @@ void NodeChannel::OnChannelMessage(const void* payload,
return;
}
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN)
case MessageType::EVENT_MESSAGE_FROM_RELAY:
const EventMessageFromRelayData* data;
if (GetMessagePayload(payload, payload_size, &data)) {
@@ -676,7 +673,7 @@ void NodeChannel::OnChannelMessage(const void* payload,
}
break;
-#endif // defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#endif // defined(OS_WIN)
case MessageType::ACCEPT_PEER: {
const AcceptPeerData* data;
diff --git a/chromium/mojo/core/node_channel.h b/chromium/mojo/core/node_channel.h
index 55486007743..4297307847d 100644
--- a/chromium/mojo/core/node_channel.h
+++ b/chromium/mojo/core/node_channel.h
@@ -59,7 +59,7 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
PlatformHandle channel_handle) = 0;
virtual void OnBroadcast(const ports::NodeName& from_node,
Channel::MessagePtr message) = 0;
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN)
virtual void OnRelayEventMessage(const ports::NodeName& from_node,
base::ProcessHandle from_process,
const ports::NodeName& destination,
@@ -133,7 +133,7 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
void SendChannelMessage(Channel::MessagePtr message);
void Broadcast(Channel::MessagePtr message);
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN)
// Relay the message to the specified node via this channel. This is used to
// pass windows handles between two processes that do not have permission to
// duplicate handles into the other's address space. The relay process is
diff --git a/chromium/mojo/core/node_channel_fuzzer.cc b/chromium/mojo/core/node_channel_fuzzer.cc
index 295f7a9e53e..4cce8445512 100644
--- a/chromium/mojo/core/node_channel_fuzzer.cc
+++ b/chromium/mojo/core/node_channel_fuzzer.cc
@@ -57,7 +57,7 @@ class FakeNodeChannelDelegate : public NodeChannel::Delegate {
mojo::PlatformHandle channel_handle) override {}
void OnBroadcast(const ports::NodeName& from_node,
Channel::MessagePtr message) override {}
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN)
void OnRelayEventMessage(const ports::NodeName& from_node,
base::ProcessHandle from_process,
const ports::NodeName& destination,
diff --git a/chromium/mojo/core/node_controller.cc b/chromium/mojo/core/node_controller.cc
index 5a796e95b52..e919ccd0b75 100644
--- a/chromium/mojo/core/node_controller.cc
+++ b/chromium/mojo/core/node_controller.cc
@@ -32,10 +32,6 @@
#include <windows.h>
#endif
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-#include "mojo/core/mach_port_relay.h"
-#endif
-
#if !defined(OS_NACL)
#include "crypto/random.h"
#endif
@@ -158,14 +154,6 @@ NodeController::NodeController(Core* core)
DVLOG(1) << "Initializing node " << name_;
}
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-void NodeController::CreateMachPortRelay(base::PortProvider* port_provider) {
- base::AutoLock lock(mach_port_relay_lock_);
- DCHECK(!mach_port_relay_);
- mach_port_relay_.reset(new MachPortRelay(port_provider));
-}
-#endif
-
void NodeController::SetIOTaskRunner(
scoped_refptr<base::TaskRunner> task_runner) {
io_task_runner_ = task_runner;
@@ -612,28 +600,6 @@ void NodeController::SendPeerEvent(const ports::NodeName& name,
return;
}
}
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
- if (event_message->has_mach_ports()) {
- // Messages containing Mach ports are always routed through the broker, even
- // if the broker process is the intended recipient.
- bool use_broker = false;
- if (!GetConfiguration().is_broker_process) {
- base::AutoLock lock(inviter_lock_);
- use_broker = (bootstrap_inviter_channel_ ||
- inviter_name_ != ports::kInvalidNodeName);
- }
-
- if (use_broker) {
- scoped_refptr<NodeChannel> broker = GetBrokerChannel();
- if (broker) {
- broker->RelayEventMessage(name, std::move(event_message));
- } else {
- base::AutoLock lock(broker_lock_);
- pending_relay_messages_[name].emplace(std::move(event_message));
- }
- return;
- }
- }
#endif // defined(OS_WIN)
if (peer) {
@@ -969,7 +935,7 @@ void NodeController::OnAcceptBrokerClient(const ports::NodeName& from_node,
pending_broker_clients.pop();
}
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN)
// Have the broker relay any messages we have waiting.
for (auto& entry : pending_relay_messages) {
const ports::NodeName& destination = entry.first;
@@ -1128,7 +1094,7 @@ void NodeController::OnBroadcast(const ports::NodeName& from_node,
}
}
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN)
void NodeController::OnRelayEventMessage(const ports::NodeName& from_node,
base::ProcessHandle from_process,
const ports::NodeName& destination,
@@ -1221,20 +1187,6 @@ void NodeController::OnChannelError(const ports::NodeName& from_node,
}
}
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-MachPortRelay* NodeController::GetMachPortRelay() {
- {
- base::AutoLock lock(inviter_lock_);
- // Return null if we're not the root.
- if (bootstrap_inviter_channel_ || inviter_name_ != ports::kInvalidNodeName)
- return nullptr;
- }
-
- base::AutoLock lock(mach_port_relay_lock_);
- return mach_port_relay_.get();
-}
-#endif
-
void NodeController::CancelPendingPortMerges() {
std::vector<ports::PortRef> ports_to_close;
diff --git a/chromium/mojo/core/node_controller.h b/chromium/mojo/core/node_controller.h
index 0b44a6a2c4a..b0338f78696 100644
--- a/chromium/mojo/core/node_controller.h
+++ b/chromium/mojo/core/node_controller.h
@@ -31,16 +31,11 @@
#include "mojo/core/system_impl_export.h"
#include "mojo/public/cpp/platform/platform_handle.h"
-namespace base {
-class PortProvider;
-}
-
namespace mojo {
namespace core {
class Broker;
class Core;
-class MachPortRelay;
// The owner of ports::Node which facilitates core EDK implementation. All
// public interface methods are safe to call from any thread.
@@ -66,11 +61,6 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
return io_task_runner_;
}
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- // Create the relay used to transfer mach ports between processes.
- void CreateMachPortRelay(base::PortProvider* port_provider);
-#endif
-
// Called exactly once, shortly after construction, and before any other
// methods are called on this object.
void SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner);
@@ -217,7 +207,7 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
PlatformHandle channel_handle) override;
void OnBroadcast(const ports::NodeName& from_node,
Channel::MessagePtr message) override;
-#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+#if defined(OS_WIN)
void OnRelayEventMessage(const ports::NodeName& from_node,
base::ProcessHandle from_process,
const ports::NodeName& destination,
@@ -233,10 +223,6 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
void OnChannelError(const ports::NodeName& from_node,
NodeChannel* channel) override;
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- MachPortRelay* GetMachPortRelay();
-#endif
-
// Cancels all pending port merges. These are merges which are supposed to
// be requested from the inviter ASAP, and they may be cancelled if the
// connection to the inviter is broken or never established.
@@ -335,12 +321,6 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
std::unique_ptr<Broker> broker_;
#endif
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- base::Lock mach_port_relay_lock_;
- // Relay for transferring mach ports to/from broker clients.
- std::unique_ptr<MachPortRelay> mach_port_relay_;
-#endif
-
DISALLOW_COPY_AND_ASSIGN(NodeController);
};
diff --git a/chromium/mojo/core/platform_handle_in_transit.cc b/chromium/mojo/core/platform_handle_in_transit.cc
index 9ee60d86c3d..4e75480a1bf 100644
--- a/chromium/mojo/core/platform_handle_in_transit.cc
+++ b/chromium/mojo/core/platform_handle_in_transit.cc
@@ -89,9 +89,6 @@ PlatformHandleInTransit& PlatformHandleInTransit::operator=(
remote_handle_ = INVALID_HANDLE_VALUE;
std::swap(remote_handle_, other.remote_handle_);
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
- mach_port_name_ = MACH_PORT_NULL;
- std::swap(mach_port_name_, other.mach_port_name_);
#endif
handle_ = std::move(other.handle_);
owning_process_ = std::move(other.owning_process_);
@@ -152,20 +149,5 @@ PlatformHandle PlatformHandleInTransit::TakeIncomingRemoteHandle(
}
#endif
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-// static
-PlatformHandleInTransit PlatformHandleInTransit::CreateForMachPortName(
- mach_port_t name) {
- if (name == MACH_PORT_NULL) {
- return PlatformHandleInTransit(
- PlatformHandle(base::mac::ScopedMachSendRight()));
- }
-
- PlatformHandleInTransit handle;
- handle.mach_port_name_ = name;
- return handle;
-}
-#endif
-
} // namespace core
} // namespace mojo
diff --git a/chromium/mojo/core/platform_handle_in_transit.h b/chromium/mojo/core/platform_handle_in_transit.h
index ebe49e262e4..b69d3b6788c 100644
--- a/chromium/mojo/core/platform_handle_in_transit.h
+++ b/chromium/mojo/core/platform_handle_in_transit.h
@@ -10,10 +10,6 @@
#include "mojo/core/scoped_process_handle.h"
#include "mojo/public/cpp/platform/platform_handle.h"
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-#include <mach/mach.h>
-#endif
-
#if defined(OS_WIN)
#include <windows.h>
#endif
@@ -89,19 +85,6 @@ class PlatformHandleInTransit {
base::ProcessHandle owning_process);
#endif
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- // Creates a special wrapper holding an unowned Mach port name. This may refer
- // to a send or receive right in a remote task (process), and is used for
- // cases where message must retain such an object as one of its attached
- // handles. We're OK for now with leaking in any scenario where a lack of
- // strict ownership could cause leakage. See https://crbug.com/855930 for more
- // details.
- static PlatformHandleInTransit CreateForMachPortName(mach_port_t name);
-
- bool is_mach_port_name() const { return mach_port_name_ != MACH_PORT_NULL; }
- mach_port_t mach_port_name() const { return mach_port_name_; }
-#endif
-
private:
#if defined(OS_WIN)
// We don't use a ScopedHandle (or, by extension, PlatformHandle) here because
@@ -114,10 +97,6 @@ class PlatformHandleInTransit {
PlatformHandle handle_;
ScopedProcessHandle owning_process_;
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- mach_port_t mach_port_name_ = MACH_PORT_NULL;
-#endif
-
DISALLOW_COPY_AND_ASSIGN(PlatformHandleInTransit);
};
diff --git a/chromium/mojo/core/ports/event.cc b/chromium/mojo/core/ports/event.cc
index f3cf74edbdd..a9bec670cb4 100644
--- a/chromium/mojo/core/ports/event.cc
+++ b/chromium/mojo/core/ports/event.cc
@@ -52,6 +52,14 @@ struct MergePortEventData {
Event::PortDescriptor new_port_descriptor;
};
+struct UserMessageReadAckRequestEventData {
+ uint64_t sequence_num_to_acknowledge;
+};
+
+struct UserMessageReadAckEventData {
+ uint64_t sequence_num_acknowledged;
+};
+
#pragma pack(pop)
static_assert(sizeof(Event::PortDescriptor) % kPortsMessageAlignment == 0,
@@ -75,6 +83,14 @@ static_assert(sizeof(ObserveClosureEventData) % kPortsMessageAlignment == 0,
static_assert(sizeof(MergePortEventData) % kPortsMessageAlignment == 0,
"Invalid MergePortEventData size.");
+static_assert(sizeof(UserMessageReadAckRequestEventData) %
+ kPortsMessageAlignment ==
+ 0,
+ "Invalid UserMessageReadAckRequestEventData size.");
+
+static_assert(sizeof(UserMessageReadAckEventData) % kPortsMessageAlignment == 0,
+ "Invalid UserMessageReadAckEventData size.");
+
} // namespace
Event::PortDescriptor::PortDescriptor() {
@@ -378,6 +394,70 @@ void MergePortEvent::SerializeData(void* buffer) const {
data->new_port_descriptor = new_port_descriptor_;
}
+UserMessageReadAckRequestEvent::UserMessageReadAckRequestEvent(
+ const PortName& port_name,
+ uint64_t sequence_num_to_acknowledge)
+ : Event(Type::kUserMessageReadAckRequest, port_name),
+ sequence_num_to_acknowledge_(sequence_num_to_acknowledge) {
+ DCHECK(sequence_num_to_acknowledge);
+}
+
+UserMessageReadAckRequestEvent::~UserMessageReadAckRequestEvent() = default;
+
+// static
+ScopedEvent UserMessageReadAckRequestEvent::Deserialize(
+ const PortName& port_name,
+ const void* buffer,
+ size_t num_bytes) {
+ if (num_bytes < sizeof(UserMessageReadAckRequestEventData))
+ return nullptr;
+
+ const auto* data =
+ static_cast<const UserMessageReadAckRequestEventData*>(buffer);
+ return std::make_unique<UserMessageReadAckRequestEvent>(
+ port_name, data->sequence_num_to_acknowledge);
+}
+
+size_t UserMessageReadAckRequestEvent::GetSerializedDataSize() const {
+ return sizeof(UserMessageReadAckRequestEventData);
+}
+
+void UserMessageReadAckRequestEvent::SerializeData(void* buffer) const {
+ auto* data = static_cast<UserMessageReadAckRequestEventData*>(buffer);
+ data->sequence_num_to_acknowledge = sequence_num_to_acknowledge_;
+}
+
+UserMessageReadAckEvent::UserMessageReadAckEvent(
+ const PortName& port_name,
+ uint64_t sequence_num_acknowledged)
+ : Event(Type::kUserMessageReadAck, port_name),
+ sequence_num_acknowledged_(sequence_num_acknowledged) {
+ DCHECK(sequence_num_acknowledged);
+}
+
+UserMessageReadAckEvent::~UserMessageReadAckEvent() = default;
+
+// static
+ScopedEvent UserMessageReadAckEvent::Deserialize(const PortName& port_name,
+ const void* buffer,
+ size_t num_bytes) {
+ if (num_bytes < sizeof(UserMessageReadAckEventData))
+ return nullptr;
+
+ const auto* data = static_cast<const UserMessageReadAckEventData*>(buffer);
+ return std::make_unique<UserMessageReadAckEvent>(
+ port_name, data->sequence_num_acknowledged);
+}
+
+size_t UserMessageReadAckEvent::GetSerializedDataSize() const {
+ return sizeof(UserMessageReadAckEventData);
+}
+
+void UserMessageReadAckEvent::SerializeData(void* buffer) const {
+ auto* data = static_cast<UserMessageReadAckEventData*>(buffer);
+ data->sequence_num_acknowledged = sequence_num_acknowledged_;
+}
+
} // namespace ports
} // namespace core
} // namespace mojo
diff --git a/chromium/mojo/core/ports/event.h b/chromium/mojo/core/ports/event.h
index c9a7d6a733a..55c081e3e81 100644
--- a/chromium/mojo/core/ports/event.h
+++ b/chromium/mojo/core/ports/event.h
@@ -56,6 +56,13 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) Event {
// Used to request the merging of two routes via two sacrificial receiving
// ports, one from each route.
kMergePort,
+
+ // Used to request that the conjugate port acknowledges read messages by
+ // sending back a UserMessageReadAck.
+ kUserMessageReadAckRequest,
+
+ // Used to acknowledge read messages to the conjugate.
+ kUserMessageReadAck,
};
#pragma pack(push, 1)
@@ -277,6 +284,49 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) MergePortEvent : public Event {
DISALLOW_COPY_AND_ASSIGN(MergePortEvent);
};
+class COMPONENT_EXPORT(MOJO_CORE_PORTS) UserMessageReadAckRequestEvent
+ : public Event {
+ public:
+ UserMessageReadAckRequestEvent(const PortName& port_name,
+ uint64_t sequence_num_to_acknowledge);
+ ~UserMessageReadAckRequestEvent() override;
+
+ uint64_t sequence_num_to_acknowledge() const {
+ return sequence_num_to_acknowledge_;
+ }
+
+ static ScopedEvent Deserialize(const PortName& port_name,
+ const void* buffer,
+ size_t num_bytes);
+
+ private:
+ size_t GetSerializedDataSize() const override;
+ void SerializeData(void* buffer) const override;
+
+ uint64_t sequence_num_to_acknowledge_;
+};
+
+class COMPONENT_EXPORT(MOJO_CORE_PORTS) UserMessageReadAckEvent : public Event {
+ public:
+ UserMessageReadAckEvent(const PortName& port_name,
+ uint64_t sequence_num_acknowledged);
+ ~UserMessageReadAckEvent() override;
+
+ uint64_t sequence_num_acknowledged() const {
+ return sequence_num_acknowledged_;
+ }
+
+ static ScopedEvent Deserialize(const PortName& port_name,
+ const void* buffer,
+ size_t num_bytes);
+
+ private:
+ size_t GetSerializedDataSize() const override;
+ void SerializeData(void* buffer) const override;
+
+ uint64_t sequence_num_acknowledged_;
+};
+
} // namespace ports
} // namespace core
} // namespace mojo
diff --git a/chromium/mojo/core/ports/node.cc b/chromium/mojo/core/ports/node.cc
index 3f24c97defb..c895dee816d 100644
--- a/chromium/mojo/core/ports/node.cc
+++ b/chromium/mojo/core/ports/node.cc
@@ -313,6 +313,10 @@ int Node::GetStatus(const PortRef& port_ref, PortStatus* port_status) {
port_status->queued_message_count =
port->message_queue.queued_message_count();
port_status->queued_num_bytes = port->message_queue.queued_num_bytes();
+ port_status->unacknowledged_message_count =
+ port->next_sequence_num_to_send - port->last_sequence_num_acknowledged -
+ 1;
+
return OK;
}
@@ -323,6 +327,8 @@ int Node::GetMessage(const PortRef& port_ref,
DVLOG(4) << "GetMessage for " << port_ref.name() << "@" << name_;
+ NodeName peer_node_name;
+ ScopedEvent ack_event;
{
SinglePortLocker locker(&port_ref);
auto* port = locker.port();
@@ -338,8 +344,17 @@ int Node::GetMessage(const PortRef& port_ref,
return ERROR_PORT_PEER_CLOSED;
port->message_queue.GetNextMessage(message, filter);
+ if (*message &&
+ (*message)->sequence_num() == port->sequence_num_to_acknowledge) {
+ peer_node_name = port->peer_node_name;
+ ack_event = std::make_unique<UserMessageReadAckEvent>(
+ port->peer_port_name, port->sequence_num_to_acknowledge);
+ }
}
+ if (ack_event)
+ delegate_->ForwardEvent(peer_node_name, std::move(ack_event));
+
// Allow referenced ports to trigger PortStatusChanged calls.
if (*message) {
for (size_t i = 0; i < (*message)->num_ports(); ++i) {
@@ -381,6 +396,35 @@ int Node::SendUserMessage(const PortRef& port_ref,
return rv;
}
+int Node::SetAcknowledgeRequestInterval(
+ const PortRef& port_ref,
+ uint64_t sequence_num_acknowledge_interval) {
+ NodeName peer_node_name;
+ PortName peer_port_name;
+ uint64_t sequence_num_to_request_ack = 0;
+ {
+ SinglePortLocker locker(&port_ref);
+ auto* port = locker.port();
+ if (port->state != Port::kReceiving)
+ return ERROR_PORT_STATE_UNEXPECTED;
+
+ port->sequence_num_acknowledge_interval = sequence_num_acknowledge_interval;
+ if (!sequence_num_acknowledge_interval)
+ return OK;
+
+ peer_node_name = port->peer_node_name;
+ peer_port_name = port->peer_port_name;
+
+ sequence_num_to_request_ack = port->last_sequence_num_acknowledged +
+ sequence_num_acknowledge_interval;
+ }
+
+ delegate_->ForwardEvent(peer_node_name,
+ std::make_unique<UserMessageReadAckRequestEvent>(
+ peer_port_name, sequence_num_to_request_ack));
+ return OK;
+}
+
int Node::AcceptEvent(ScopedEvent event) {
switch (event->type()) {
case Event::Type::kUserMessage:
@@ -395,6 +439,11 @@ int Node::AcceptEvent(ScopedEvent event) {
return OnObserveClosure(Event::Cast<ObserveClosureEvent>(&event));
case Event::Type::kMergePort:
return OnMergePort(Event::Cast<MergePortEvent>(&event));
+ case Event::Type::kUserMessageReadAckRequest:
+ return OnUserMessageReadAckRequest(
+ Event::Cast<UserMessageReadAckRequestEvent>(&event));
+ case Event::Type::kUserMessageReadAck:
+ return OnUserMessageReadAck(Event::Cast<UserMessageReadAckEvent>(&event));
}
return OOPS(ERROR_NOT_IMPLEMENTED);
}
@@ -593,7 +642,7 @@ int Node::OnObserveProxy(std::unique_ptr<ObserveProxyEvent> event) {
<< event->proxy_target_port_name() << "@"
<< event->proxy_target_node_name();
- bool update_status = false;
+ bool peer_changed = false;
ScopedEvent event_to_forward;
NodeName event_target_node;
{
@@ -613,7 +662,7 @@ int Node::OnObserveProxy(std::unique_ptr<ObserveProxyEvent> event) {
event_target_node = event->proxy_node_name();
event_to_forward = std::make_unique<ObserveProxyAckEvent>(
event->proxy_port_name(), port->next_sequence_num_to_send - 1);
- update_status = true;
+ peer_changed = true;
DVLOG(2) << "Forwarding ObserveProxyAck from " << event->port_name()
<< "@" << name_ << " to " << event->proxy_port_name() << "@"
<< event_target_node;
@@ -648,8 +697,14 @@ int Node::OnObserveProxy(std::unique_ptr<ObserveProxyEvent> event) {
if (event_to_forward)
delegate_->ForwardEvent(event_target_node, std::move(event_to_forward));
- if (update_status)
+ if (peer_changed) {
+ // Re-send ack and/or ack requests, as the previous peer proxy may not have
+ // forwarded the previous request before it died.
+ MaybeResendAck(port_ref);
+ MaybeResendAckRequest(port_ref);
+
delegate_->PortStatusChanged(port_ref);
+ }
return OK;
}
@@ -732,6 +787,11 @@ int Node::OnObserveClosure(std::unique_ptr<ObserveClosureEvent> event) {
// may be semantically confusing since the forwarding port is not actually
// closed. Consider replacing this with a new event type.
event->set_last_sequence_num(port->next_sequence_num_to_send - 1);
+
+ // Treat the closure as an acknowledge that all sent messages have been
+ // read from the other end.
+ port->last_sequence_num_acknowledged =
+ port->next_sequence_num_to_send - 1;
} else {
// We haven't yet reached the receiving peer of the closed port, so we'll
// forward the message along as-is.
@@ -799,6 +859,114 @@ int Node::OnMergePort(std::unique_ptr<MergePortEvent> event) {
false /* allow_close_on_bad_state */);
}
+int Node::OnUserMessageReadAckRequest(
+ std::unique_ptr<UserMessageReadAckRequestEvent> event) {
+ PortRef port_ref;
+ GetPort(event->port_name(), &port_ref);
+
+ DVLOG(1) << "AckRequest " << port_ref.name() << "@" << name_ << " sequence "
+ << event->sequence_num_to_acknowledge();
+
+ if (!port_ref.is_valid())
+ return ERROR_PORT_UNKNOWN;
+
+ NodeName peer_node_name;
+ std::unique_ptr<Event> event_to_send;
+ {
+ SinglePortLocker locker(&port_ref);
+ auto* port = locker.port();
+
+ peer_node_name = port->peer_node_name;
+ if (port->state == Port::kProxying) {
+ // Proxies simply forward the ack request to their peer.
+ event->set_port_name(port->peer_port_name);
+ event_to_send = std::move(event);
+ } else {
+ uint64_t current_sequence_num =
+ port->message_queue.next_sequence_num() - 1;
+ // Either this is requesting an ack for a sequence number already read, or
+ // else for a sequence number that is yet to be read.
+ if (current_sequence_num >= event->sequence_num_to_acknowledge()) {
+ // If the current sequence number to read already exceeds the ack
+ // request, send an ack immediately.
+ event_to_send = std::make_unique<UserMessageReadAckEvent>(
+ port->peer_port_name, current_sequence_num);
+
+ // This might be a late or duplicate acknowledge request, that's
+ // requesting acknowledge for an already read message. There may already
+ // have been a request for future reads, so take care not to back up
+ // the requested acknowledge counter.
+ if (current_sequence_num > port->sequence_num_to_acknowledge)
+ port->sequence_num_to_acknowledge = current_sequence_num;
+ } else {
+ // This is request to ack a sequence number that hasn't been read yet.
+ // The state of the port can either be that it already has a
+ // future-requested ack, or not. Because ack requests aren't guaranteed
+ // to arrive in order, store the earlier of the current queued request
+ // and the new one, if one was already requested.
+ bool has_queued_ack_request =
+ port->sequence_num_to_acknowledge > current_sequence_num;
+ if (!has_queued_ack_request ||
+ port->sequence_num_to_acknowledge >
+ event->sequence_num_to_acknowledge()) {
+ port->sequence_num_to_acknowledge =
+ event->sequence_num_to_acknowledge();
+ }
+ return OK;
+ }
+ }
+ }
+
+ delegate_->ForwardEvent(peer_node_name, std::move(event_to_send));
+
+ return OK;
+}
+
+int Node::OnUserMessageReadAck(std::unique_ptr<UserMessageReadAckEvent> event) {
+ PortRef port_ref;
+ GetPort(event->port_name(), &port_ref);
+
+ DVLOG(1) << "Acknowledge " << port_ref.name() << "@" << name_ << " sequence "
+ << event->sequence_num_acknowledged();
+
+ NodeName peer_node_name;
+ ScopedEvent ack_request_event;
+ if (port_ref.is_valid()) {
+ SinglePortLocker locker(&port_ref);
+ auto* port = locker.port();
+
+ if (event->sequence_num_acknowledged() >= port->next_sequence_num_to_send) {
+ // TODO(http://crbug.com/980952): This is a malformed event.
+ // This could return a new error "ERROR_MALFORMED_EVENT" which the
+ // delegate could use as a signal to drop the peer node.
+ return OK;
+ }
+
+ // Keep the largest acknowledge seen.
+ if (event->sequence_num_acknowledged() <=
+ port->last_sequence_num_acknowledged) {
+ // The acknowledge was late or a duplicate, it's safe to ignore it.
+ return OK;
+ }
+
+ port->last_sequence_num_acknowledged = event->sequence_num_acknowledged();
+ // Send another ack request if the interval is non-zero and the peer has
+ // not been closed.
+ if (port->sequence_num_acknowledge_interval && !port->peer_closed) {
+ peer_node_name = port->peer_node_name;
+ ack_request_event = std::make_unique<UserMessageReadAckRequestEvent>(
+ port->peer_port_name, port->last_sequence_num_acknowledged +
+ port->sequence_num_acknowledge_interval);
+ }
+ }
+ if (ack_request_event)
+ delegate_->ForwardEvent(peer_node_name, std::move(ack_request_event));
+
+ delegate_->PortStatusChanged(port_ref);
+
+ return OK;
+}
+
int Node::AddPortWithName(const PortName& port_name, scoped_refptr<Port> port) {
PortLocker::AssertNoPortsLockedOnCurrentThread();
base::AutoLock lock(ports_lock_);
@@ -1207,6 +1375,9 @@ int Node::BeginProxying(const PortRef& port_ref) {
if (rv != OK)
return rv;
+ // Forward any pending acknowledge request.
+ MaybeForwardAckRequest(port_ref);
+
bool try_remove_proxy_immediately;
ScopedEvent closure_event;
NodeName closure_target_node;
@@ -1484,6 +1655,71 @@ void Node::SwapPortPeers(const PortName& port0_name,
std::swap(port0->peer_port_name, port1->peer_port_name);
}
+void Node::MaybeResendAckRequest(const PortRef& port_ref) {
+ NodeName peer_node_name;
+ ScopedEvent ack_request_event;
+ {
+ SinglePortLocker locker(&port_ref);
+ auto* port = locker.port();
+ if (port->state != Port::kReceiving)
+ return;
+
+ if (!port->sequence_num_acknowledge_interval)
+ return;
+
+ peer_node_name = port->peer_node_name;
+ ack_request_event = std::make_unique<UserMessageReadAckRequestEvent>(
+ port->peer_port_name, port->last_sequence_num_acknowledged +
+ port->sequence_num_acknowledge_interval);
+ }
+
+ delegate_->ForwardEvent(peer_node_name, std::move(ack_request_event));
+}
+
+void Node::MaybeForwardAckRequest(const PortRef& port_ref) {
+ NodeName peer_node_name;
+ ScopedEvent ack_request_event;
+ {
+ SinglePortLocker locker(&port_ref);
+ auto* port = locker.port();
+ if (port->state != Port::kProxying)
+ return;
+
+ if (!port->sequence_num_to_acknowledge)
+ return;
+
+ peer_node_name = port->peer_node_name;
+ ack_request_event = std::make_unique<UserMessageReadAckRequestEvent>(
+ port->peer_port_name, port->sequence_num_to_acknowledge);
+
+ port->sequence_num_to_acknowledge = 0;
+ }
+
+ delegate_->ForwardEvent(peer_node_name, std::move(ack_request_event));
+}
+
+void Node::MaybeResendAck(const PortRef& port_ref) {
+ NodeName peer_node_name;
+ ScopedEvent ack_event;
+ {
+ SinglePortLocker locker(&port_ref);
+ auto* port = locker.port();
+ if (port->state != Port::kReceiving)
+ return;
+
+ uint64_t last_sequence_num_read =
+ port->message_queue.next_sequence_num() - 1;
+ if (!port->sequence_num_to_acknowledge || !last_sequence_num_read)
+ return;
+
+ peer_node_name = port->peer_node_name;
+ ack_event = std::make_unique<UserMessageReadAckEvent>(
+ port->peer_port_name, last_sequence_num_read);
+ }
+
+ delegate_->ForwardEvent(peer_node_name, std::move(ack_event));
+}
+
Node::DelegateHolder::DelegateHolder(Node* node, NodeDelegate* delegate)
: node_(node), delegate_(delegate) {
DCHECK(node_);
diff --git a/chromium/mojo/core/ports/node.h b/chromium/mojo/core/ports/node.h
index 9c771eb2342..e806e1d918c 100644
--- a/chromium/mojo/core/ports/node.h
+++ b/chromium/mojo/core/ports/node.h
@@ -44,6 +44,7 @@ struct PortStatus {
bool peer_remote;
size_t queued_message_count;
size_t queued_num_bytes;
+ size_t unacknowledged_message_count;
};
class MessageFilter;
@@ -140,6 +141,16 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node {
int SendUserMessage(const PortRef& port_ref,
std::unique_ptr<UserMessageEvent> message);
+ // Makes the port send acknowledge requests to its conjugate to acknowledge
+ // at least every |sequence_number_acknowledge_interval| messages as they're
+ // read from the conjugate. The number of unacknowledged messages is exposed
+ // in the |unacknowledged_message_count| field of PortStatus. This allows
+ // bounding the number of unread and/or in-transit messages from this port
+ // to its conjugate between zero and |unacknowledged_message_count|.
+ int SetAcknowledgeRequestInterval(
+ const PortRef& port_ref,
+ uint64_t sequence_number_acknowledge_interval);
+
// Corresponding to NodeDelegate::ForwardEvent.
int AcceptEvent(ScopedEvent event);
@@ -200,6 +211,9 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node {
int OnObserveProxyAck(std::unique_ptr<ObserveProxyAckEvent> event);
int OnObserveClosure(std::unique_ptr<ObserveClosureEvent> event);
int OnMergePort(std::unique_ptr<MergePortEvent> event);
+ int OnUserMessageReadAckRequest(
+ std::unique_ptr<UserMessageReadAckRequestEvent> event);
+ int OnUserMessageReadAck(std::unique_ptr<UserMessageReadAckEvent> event);
int AddPortWithName(const PortName& port_name, scoped_refptr<Port> port);
void ErasePort(const PortName& port_name);
@@ -249,6 +263,21 @@ class COMPONENT_EXPORT(MOJO_CORE_PORTS) Node {
const PortName& port1_name,
Port* port1);
+ // Sends an acknowledge request to the peer if the port has a non-zero
+ // |sequence_num_acknowledge_interval|. This needs to be done when the port's
+ // peer changes, as the previous peer proxy may not have forwarded any prior
+ // acknowledge request before deleting itself.
+ void MaybeResendAckRequest(const PortRef& port_ref);
+
+ // Forwards a stored acknowledge request to the peer if the proxy has a
+ // non-zero |sequence_num_acknowledge_interval|.
+ void MaybeForwardAckRequest(const PortRef& port_ref);
+
+ // Sends an acknowledge of the most recently read sequence number to the peer
+ // if any messages have been read, and the port has a non-zero
+ // |sequence_num_to_acknowledge|.
+ void MaybeResendAck(const PortRef& port_ref);
+
const NodeName name_;
const DelegateHolder delegate_;
diff --git a/chromium/mojo/core/ports/port.cc b/chromium/mojo/core/ports/port.cc
index 71869790218..c3ead1ecadf 100644
--- a/chromium/mojo/core/ports/port.cc
+++ b/chromium/mojo/core/ports/port.cc
@@ -12,7 +12,10 @@ Port::Port(uint64_t next_sequence_num_to_send,
uint64_t next_sequence_num_to_receive)
: state(kUninitialized),
next_sequence_num_to_send(next_sequence_num_to_send),
+ last_sequence_num_acknowledged(next_sequence_num_to_send - 1),
+ sequence_num_acknowledge_interval(0),
last_sequence_num_to_receive(0),
+ sequence_num_to_acknowledge(0),
message_queue(next_sequence_num_to_receive),
remove_proxy_on_last_message(false),
peer_closed(false) {}
diff --git a/chromium/mojo/core/ports/port.h b/chromium/mojo/core/ports/port.h
index d1a825e2c62..cc36568183a 100644
--- a/chromium/mojo/core/ports/port.h
+++ b/chromium/mojo/core/ports/port.h
@@ -110,12 +110,30 @@ class Port : public base::RefCountedThreadSafe<Port> {
// originating from this port.
uint64_t next_sequence_num_to_send;
+ // The largest acknowledged user message event sequence number.
+ uint64_t last_sequence_num_acknowledged;
+
+ // The interval for which acknowledge requests will be sent. A value of N will
+ // cause an acknowledge request for |last_sequence_num_acknowledged| + N when
+ // initially set and on received acknowledge. This means that the lower bound
+ // for unread or in-transit messages is |next_sequence_num_to_send| -
+ // |last_sequence_num_acknowledged| + |sequence_number_acknowledge_interval|.
+ // If zero, no acknowledge requests are sent.
+ uint64_t sequence_num_acknowledge_interval;
+
// 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 sequence number of the message for which this Port should send an
+ // acknowledge message. In the buffering state, holds the acknowledge request
+ // value that is forwarded to the peer on transition to proxying.
+ // This is zero in any port that's never received an acknowledge request, and
+ // in proxies that have forwarded a stored acknowledge.
+ uint64_t sequence_num_to_acknowledge;
+
// 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
diff --git a/chromium/mojo/core/ports/ports_unittest.cc b/chromium/mojo/core/ports/ports_unittest.cc
index e3a2a085723..40c278b3a8e 100644
--- a/chromium/mojo/core/ports/ports_unittest.cc
+++ b/chromium/mojo/core/ports/ports_unittest.cc
@@ -139,6 +139,15 @@ class TestNode : public NodeDelegate {
return node_.SendUserMessage(port, NewUserMessageEvent(s, 0));
}
+ int SendMultipleMessages(const PortRef& port, size_t num_messages) {
+ for (size_t i = 0; i < num_messages; ++i) {
+ int result = SendStringMessage(port, "");
+ if (result != OK)
+ return result;
+ }
+ return OK;
+ }
+
int SendStringMessageWithPort(const PortRef& port,
const std::string& s,
const PortName& sent_port_name) {
@@ -167,6 +176,15 @@ class TestNode : public NodeDelegate {
return node_.GetMessage(port, message, nullptr) == OK && *message;
}
+ bool ReadMultipleMessages(const PortRef& port, size_t num_messages) {
+ for (size_t i = 0; i < num_messages; ++i) {
+ ScopedMessage message;
+ if (!ReadMessage(port, &message))
+ return false;
+ }
+ return true;
+ }
+
bool GetSavedMessage(ScopedMessage* message) {
base::AutoLock lock(lock_);
if (saved_messages_.empty()) {
@@ -240,6 +258,14 @@ class TestNode : public NodeDelegate {
}
}
+ uint64_t GetUnacknowledgedMessageCount(const PortRef& port_ref) {
+ PortStatus status;
+ if (node_.GetStatus(port_ref, &status) != OK)
+ return 0;
+
+ return status.unacknowledged_message_count;
+ }
+
private:
void ProcessEvents() {
for (;;) {
@@ -1638,6 +1664,72 @@ TEST_F(PortsTest, RetransmitUserMessageEvents) {
EXPECT_EQ(OK, node0.node().ClosePort(b));
}
+TEST_F(PortsTest, SetAcknowledgeRequestInterval) {
+ TestNode node0(0);
+ AddNode(&node0);
+
+ PortRef a0, a1;
+ EXPECT_EQ(OK, node0.node().CreatePortPair(&a0, &a1));
+ EXPECT_EQ(0u, node0.GetUnacknowledgedMessageCount(a0));
+
+ // Send a batch of messages.
+ EXPECT_EQ(OK, node0.SendMultipleMessages(a0, 15));
+ EXPECT_EQ(15u, node0.GetUnacknowledgedMessageCount(a0));
+ EXPECT_TRUE(node0.ReadMultipleMessages(a1, 5));
+ WaitForIdle();
+ EXPECT_EQ(15u, node0.GetUnacknowledgedMessageCount(a0));
+
+ // Set to acknowledge every read message, and validate that already-read
+ // messages are acknowledged.
+ EXPECT_EQ(OK, node0.node().SetAcknowledgeRequestInterval(a0, 1));
+ WaitForIdle();
+ EXPECT_EQ(10u, node0.GetUnacknowledgedMessageCount(a0));
+
+ // Read a third of the messages from the other end.
+ EXPECT_TRUE(node0.ReadMultipleMessages(a1, 5));
+ WaitForIdle();
+
+ EXPECT_EQ(5u, node0.GetUnacknowledgedMessageCount(a0));
+
+ TestNode node1(1);
+ AddNode(&node1);
+
+ // Transfer a1 across to node1.
+ PortRef x0, x1;
+ CreatePortPair(&node0, &x0, &node1, &x1);
+ EXPECT_EQ(OK, node0.SendStringMessageWithPort(x0, "foo", a1));
+ WaitForIdle();
+
+ ScopedMessage message;
+ ASSERT_TRUE(node1.ReadMessage(x1, &message));
+ ASSERT_EQ(1u, message->num_ports());
+ ASSERT_EQ(OK, node1.node().GetPort(message->ports()[0], &a1));
+
+ // Read the last third of the messages from the transferred node, and
+ // validate that the unacknowledge message count updates correctly.
+ EXPECT_TRUE(node1.ReadMultipleMessages(a1, 5));
+ WaitForIdle();
+ EXPECT_EQ(0u, node0.GetUnacknowledgedMessageCount(a0));
+
+ // Turn the acknowledges down and validate that they don't go on indefinitely.
+ EXPECT_EQ(OK, node0.node().SetAcknowledgeRequestInterval(a0, 0));
+ EXPECT_EQ(OK, node0.SendMultipleMessages(a0, 10));
+ WaitForIdle();
+ EXPECT_TRUE(node1.ReadMultipleMessages(a1, 10));
+ WaitForIdle();
+ EXPECT_NE(0u, node0.GetUnacknowledgedMessageCount(a0));
+
+ // Close the far port and validate that the closure updates the unacknowledged
+ // count.
+ EXPECT_EQ(OK, node1.node().ClosePort(a1));
+ WaitForIdle();
+ EXPECT_EQ(0u, node0.GetUnacknowledgedMessageCount(a0));
+
+ EXPECT_EQ(OK, node0.node().ClosePort(a0));
+ EXPECT_EQ(OK, node0.node().ClosePort(x0));
+ EXPECT_EQ(OK, node1.node().ClosePort(x1));
+}
+
} // namespace test
} // namespace ports
} // namespace core
diff --git a/chromium/mojo/core/quota_unittest.cc b/chromium/mojo/core/quota_unittest.cc
index bc26baf151a..e1d1a6ebd9e 100644
--- a/chromium/mojo/core/quota_unittest.cc
+++ b/chromium/mojo/core/quota_unittest.cc
@@ -256,6 +256,108 @@ TEST_F(QuotaTest, ReceiveQueueMemorySizeLimitExceeded) {
MojoClose(b);
}
+TEST_F(QuotaTest, BasicUnreadMessageCount) {
+ MojoHandle a, b;
+ CreateMessagePipe(&a, &b);
+
+ uint64_t limit = 0;
+ uint64_t usage = 0;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoQueryQuota(a, MOJO_QUOTA_TYPE_UNREAD_MESSAGE_COUNT, nullptr,
+ &limit, &usage));
+ EXPECT_EQ(MOJO_QUOTA_LIMIT_NONE, limit);
+ EXPECT_EQ(0u, usage);
+
+ const uint64_t kTestLimit = 42;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSetQuota(a, MOJO_QUOTA_TYPE_UNREAD_MESSAGE_COUNT, kTestLimit,
+ nullptr));
+
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoQueryQuota(a, MOJO_QUOTA_TYPE_UNREAD_MESSAGE_COUNT, nullptr,
+ &limit, &usage));
+ EXPECT_EQ(kTestLimit, limit);
+ EXPECT_EQ(0u, usage);
+
+ const std::string kTestMessage = "doot";
+ WriteMessage(a, kTestMessage);
+
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoQueryQuota(a, MOJO_QUOTA_TYPE_UNREAD_MESSAGE_COUNT, nullptr,
+ &limit, &usage));
+ EXPECT_EQ(kTestLimit, limit);
+ EXPECT_EQ(usage, 1u);
+
+ MojoClose(a);
+ MojoClose(b);
+}
+
+TEST_F(QuotaTest, UnreadMessageCountLimitExceeded) {
+ MojoHandle a, b;
+ CreateMessagePipe(&a, &b);
+
+ const uint64_t kMaxUnreadMessageCount = 4;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoSetQuota(a, MOJO_QUOTA_TYPE_UNREAD_MESSAGE_COUNT,
+ kMaxUnreadMessageCount, nullptr));
+
+ MojoHandleSignalsState signals;
+ EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(a, &signals));
+ EXPECT_FALSE(signals.satisfied_signals & MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
+
+ const std::string kTestMessage = "msg";
+ WriteMessage(a, kTestMessage);
+
+ uint64_t limit = 0;
+ uint64_t usage = 0;
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoQueryQuota(a, MOJO_QUOTA_TYPE_UNREAD_MESSAGE_COUNT, nullptr,
+ &limit, &usage));
+ EXPECT_EQ(kMaxUnreadMessageCount, limit);
+ EXPECT_EQ(1u, usage);
+
+ EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(a, &signals));
+ EXPECT_FALSE(signals.satisfied_signals & MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
+
+ // Push the endpoint over quota and ensure that it signals accordingly.
+ WriteMessage(a, kTestMessage);
+ WriteMessage(a, kTestMessage);
+ WriteMessage(a, kTestMessage);
+ WriteMessage(a, kTestMessage);
+ WaitForSignals(a, MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
+
+ EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(a, &signals));
+ EXPECT_TRUE(signals.satisfied_signals & MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
+
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoQueryQuota(a, MOJO_QUOTA_TYPE_UNREAD_MESSAGE_COUNT, nullptr,
+ &limit, &usage));
+ EXPECT_EQ(kMaxUnreadMessageCount, limit);
+ EXPECT_EQ(5u, usage);
+
+ // Read the messages and wait for QUOTA_EXCEEDED on the other end to go back
+ // low. There's some hysteresis in the signaling, so it's not sufficient to
+ // read a single packet, but reading below the quota size should work.
+ EXPECT_EQ(kTestMessage, ReadMessage(b));
+ EXPECT_EQ(kTestMessage, ReadMessage(b));
+ EXPECT_EQ(kTestMessage, ReadMessage(b));
+ EXPECT_EQ(kTestMessage, ReadMessage(b));
+ WaitForSignals(a, MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED,
+ MOJO_TRIGGER_CONDITION_SIGNALS_UNSATISFIED);
+
+ EXPECT_EQ(MOJO_RESULT_OK, MojoQueryHandleSignalsState(a, &signals));
+ EXPECT_FALSE(signals.satisfied_signals & MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
+
+ EXPECT_EQ(MOJO_RESULT_OK,
+ MojoQueryQuota(a, MOJO_QUOTA_TYPE_UNREAD_MESSAGE_COUNT, nullptr,
+ &limit, &usage));
+ EXPECT_EQ(kMaxUnreadMessageCount, limit);
+ EXPECT_LE(1u, usage);
+
+ MojoClose(a);
+ MojoClose(b);
+}
+
TEST_F(QuotaTest, TrapQuotaExceeded) {
// Simple sanity check to verify that QUOTA_EXCEEDED signals can be trapped
// like any other signals.
diff --git a/chromium/mojo/core/trap_unittest.cc b/chromium/mojo/core/trap_unittest.cc
index 309e5476ffd..b7ae4f3b02c 100644
--- a/chromium/mojo/core/trap_unittest.cc
+++ b/chromium/mojo/core/trap_unittest.cc
@@ -1486,6 +1486,10 @@ TEST_F(TrapTest, TriggersRemoveEachOtherWithinEventHandlers) {
[](MojoHandle b) { WriteMessage(b, kTestMessageToA); }, b));
runner.Start();
+ // To enforce that the two traps run concurrently, wait until the WriteMessage
+ // above has made a readable before firing the readable trap on b.
+ wait_for_a_to_notify.Wait();
+
WriteMessage(a, kTestMessageToB);
wait_for_a_to_cancel.Wait();
diff --git a/chromium/mojo/public/c/system/quota.h b/chromium/mojo/public/c/system/quota.h
index 721c0e1bfdc..e817578e6d0 100644
--- a/chromium/mojo/public/c/system/quota.h
+++ b/chromium/mojo/public/c/system/quota.h
@@ -61,6 +61,11 @@ typedef uint32_t MojoQuotaType;
// signal on that endpoint. May only be set on message pipe handles.
#define MOJO_QUOTA_TYPE_RECEIVE_QUEUE_MEMORY_SIZE ((MojoQuotaType)1)
+// Limits the number of sent, unread messages which can be queued on a message
+// pipe endpoint before raising a |MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED| signal on
+// that endpoint. May only be set on message pipe handles.
+#define MOJO_QUOTA_TYPE_UNREAD_MESSAGE_COUNT ((MojoQuotaType)2)
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/chromium/mojo/public/cpp/base/BUILD.gn b/chromium/mojo/public/cpp/base/BUILD.gn
index 934bb510161..5341d72fb00 100644
--- a/chromium/mojo/public/cpp/base/BUILD.gn
+++ b/chromium/mojo/public/cpp/base/BUILD.gn
@@ -38,6 +38,10 @@ component("shared_typemap_traits") {
"file_mojom_traits.h",
"file_path_mojom_traits.cc",
"file_path_mojom_traits.h",
+ "generic_pending_receiver_mojom_traits.cc",
+ "generic_pending_receiver_mojom_traits.h",
+ "read_only_buffer_mojom_traits.cc",
+ "read_only_buffer_mojom_traits.h",
"shared_memory_mojom_traits.cc",
"shared_memory_mojom_traits.h",
"time_mojom_traits.cc",
@@ -88,7 +92,6 @@ source_set("tests") {
"//base/test:test_support",
"//mojo/public/cpp/test_support:test_utils",
"//mojo/public/mojom/base",
- "//mojo/public/mojom/base:read_only_buffer",
"//testing/gtest",
]
}
diff --git a/chromium/mojo/public/cpp/base/generic_pending_receiver.typemap b/chromium/mojo/public/cpp/base/generic_pending_receiver.typemap
new file mode 100644
index 00000000000..bb60f1569de
--- /dev/null
+++ b/chromium/mojo/public/cpp/base/generic_pending_receiver.typemap
@@ -0,0 +1,15 @@
+# Copyright 2019 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/public/mojom/base/generic_pending_receiver.mojom"
+public_headers = [ "//mojo/public/cpp/bindings/generic_pending_receiver.h" ]
+traits_headers =
+ [ "//mojo/public/cpp/base/generic_pending_receiver_mojom_traits.h" ]
+public_deps = [
+ "//mojo/public/cpp/bindings",
+]
+deps = [
+ "//mojo/public/cpp/base:shared_typemap_traits",
+]
+type_mappings = [ "mojo_base.mojom.GenericPendingReceiver=::mojo::GenericPendingReceiver[move_only]" ]
diff --git a/chromium/mojo/public/cpp/base/generic_pending_receiver_mojom_traits.cc b/chromium/mojo/public/cpp/base/generic_pending_receiver_mojom_traits.cc
new file mode 100644
index 00000000000..fb6137dfec6
--- /dev/null
+++ b/chromium/mojo/public/cpp/base/generic_pending_receiver_mojom_traits.cc
@@ -0,0 +1,22 @@
+// Copyright 2019 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/base/generic_pending_receiver_mojom_traits.h"
+
+namespace mojo {
+
+// static
+bool StructTraits<mojo_base::mojom::GenericPendingReceiverDataView,
+ GenericPendingReceiver>::
+ Read(mojo_base::mojom::GenericPendingReceiverDataView data,
+ GenericPendingReceiver* out) {
+ base::StringPiece interface_name;
+ if (!data.ReadInterfaceName(&interface_name))
+ return false;
+ *out = GenericPendingReceiver(interface_name.as_string(),
+ data.TakeReceivingPipe());
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/mojo/public/cpp/base/generic_pending_receiver_mojom_traits.h b/chromium/mojo/public/cpp/base/generic_pending_receiver_mojom_traits.h
new file mode 100644
index 00000000000..ad6e284d208
--- /dev/null
+++ b/chromium/mojo/public/cpp/base/generic_pending_receiver_mojom_traits.h
@@ -0,0 +1,37 @@
+// Copyright 2019 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_BASE_GENERIC_PENDING_RECEIVER_MOJOM_TRAITS_H_
+#define MOJO_PUBLIC_CPP_BASE_GENERIC_PENDING_RECEIVER_MOJOM_TRAITS_H_
+
+#include "base/component_export.h"
+#include "base/strings/string_piece.h"
+#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "mojo/public/mojom/base/generic_pending_receiver.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct COMPONENT_EXPORT(MOJO_BASE_SHARED_TRAITS)
+ StructTraits<mojo_base::mojom::GenericPendingReceiverDataView,
+ GenericPendingReceiver> {
+ static base::StringPiece interface_name(
+ const GenericPendingReceiver& receiver) {
+ DCHECK(receiver.interface_name().has_value());
+ return receiver.interface_name().value();
+ }
+
+ static mojo::ScopedMessagePipeHandle receiving_pipe(
+ GenericPendingReceiver& receiver) {
+ return receiver.PassPipe();
+ }
+
+ static bool Read(mojo_base::mojom::GenericPendingReceiverDataView data,
+ GenericPendingReceiver* out);
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BASE_GENERIC_PENDING_RECEIVER_MOJOM_TRAITS_H_
diff --git a/chromium/mojo/public/cpp/base/message_loop_type.typemap b/chromium/mojo/public/cpp/base/message_loop_type.typemap
new file mode 100644
index 00000000000..44d9fa57fba
--- /dev/null
+++ b/chromium/mojo/public/cpp/base/message_loop_type.typemap
@@ -0,0 +1,15 @@
+# Copyright 2019 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/public/mojom/base/message_loop_type.mojom"
+public_headers = [ "//base/message_loop/message_loop.h" ]
+traits_headers = [ "//mojo/public/cpp/base/message_loop_type_mojom_traits.h" ]
+sources = [
+ "//mojo/public/cpp/base/message_loop_type_mojom_traits.cc",
+ "//mojo/public/cpp/base/message_loop_type_mojom_traits.h",
+]
+public_deps = [
+ "//base",
+]
+type_mappings = [ "mojo_base.mojom.MessageLoopType=base::MessageLoop::Type" ]
diff --git a/chromium/mojo/public/cpp/base/message_loop_type_mojom_traits.cc b/chromium/mojo/public/cpp/base/message_loop_type_mojom_traits.cc
new file mode 100644
index 00000000000..2daaa609181
--- /dev/null
+++ b/chromium/mojo/public/cpp/base/message_loop_type_mojom_traits.cc
@@ -0,0 +1,76 @@
+// Copyright 2019 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/base/message_loop_type_mojom_traits.h"
+#include "build/build_config.h"
+
+namespace mojo {
+
+// static
+mojo_base::mojom::MessageLoopType
+EnumTraits<mojo_base::mojom::MessageLoopType, base::MessageLoop::Type>::ToMojom(
+ base::MessageLoop::Type input) {
+ switch (input) {
+ case base::MessageLoop::TYPE_DEFAULT:
+ return mojo_base::mojom::MessageLoopType::kDefault;
+ case base::MessageLoop::TYPE_UI:
+ return mojo_base::mojom::MessageLoopType::kUi;
+ case base::MessageLoop::TYPE_CUSTOM:
+ return mojo_base::mojom::MessageLoopType::kCustom;
+ case base::MessageLoop::TYPE_IO:
+ return mojo_base::mojom::MessageLoopType::kIo;
+#if defined(OS_ANDROID)
+ case base::MessageLoop::TYPE_JAVA:
+ return mojo_base::mojom::MessageLoopType::kJava;
+#endif
+#if defined(OS_MACOSX)
+ case base::MessageLoop::Type::NS_RUNLOOP:
+ return mojo_base::mojom::MessageLoopType::kNsRunloop;
+#endif
+#if defined(OS_WIN)
+ case base::MessageLoop::Type::UI_WITH_WM_QUIT_SUPPORT:
+ return mojo_base::mojom::MessageLoopType::kUiWithWmQuitSupport;
+#endif
+ }
+ NOTREACHED();
+ return mojo_base::mojom::MessageLoopType::kDefault;
+}
+
+// static
+bool EnumTraits<mojo_base::mojom::MessageLoopType, base::MessageLoop::Type>::
+ FromMojom(mojo_base::mojom::MessageLoopType input,
+ base::MessageLoop::Type* output) {
+ switch (input) {
+ case mojo_base::mojom::MessageLoopType::kDefault:
+ *output = base::MessageLoop::TYPE_DEFAULT;
+ return true;
+ case mojo_base::mojom::MessageLoopType::kUi:
+ *output = base::MessageLoop::TYPE_UI;
+ return true;
+ case mojo_base::mojom::MessageLoopType::kCustom:
+ *output = base::MessageLoop::TYPE_CUSTOM;
+ return true;
+ case mojo_base::mojom::MessageLoopType::kIo:
+ *output = base::MessageLoop::TYPE_IO;
+ return true;
+#if defined(OS_ANDROID)
+ case mojo_base::mojom::MessageLoopType::kJava:
+ *output = base::MessageLoop::TYPE_JAVA;
+ return true;
+#endif
+#if defined(OS_MACOSX)
+ case mojo_base::mojom::MessageLoopType::kNsRunloop:
+ *output = base::MessageLoop::Type::NS_RUNLOOP;
+ return true;
+#endif
+#if defined(OS_WIN)
+ case mojo_base::mojom::MessageLoopType::kUiWithWmQuitSupport:
+ *output = base::MessageLoop::Type::UI_WITH_WM_QUIT_SUPPORT;
+ return true;
+#endif
+ }
+ return false;
+}
+
+} // namespace mojo
diff --git a/chromium/mojo/public/cpp/base/message_loop_type_mojom_traits.h b/chromium/mojo/public/cpp/base/message_loop_type_mojom_traits.h
new file mode 100644
index 00000000000..44860d0a465
--- /dev/null
+++ b/chromium/mojo/public/cpp/base/message_loop_type_mojom_traits.h
@@ -0,0 +1,26 @@
+// Copyright 2019 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_BASE_MESSAGE_LOOP_TYPE_MOJOM_TRAITS_H_
+#define MOJO_PUBLIC_CPP_BASE_MESSAGE_LOOP_TYPE_MOJOM_TRAITS_H_
+
+#include "base/component_export.h"
+#include "base/message_loop/message_loop.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "mojo/public/mojom/base/message_loop_type.mojom.h"
+
+namespace mojo {
+
+template <>
+struct COMPONENT_EXPORT(MOJO_BASE_MOJOM)
+ EnumTraits<mojo_base::mojom::MessageLoopType, base::MessageLoop::Type> {
+ static mojo_base::mojom::MessageLoopType ToMojom(
+ base::MessageLoop::Type input);
+ static bool FromMojom(mojo_base::mojom::MessageLoopType input,
+ base::MessageLoop::Type* output);
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BASE_MESSAGE_LOOP_TYPE_MOJOM_TRAITS_H_
diff --git a/chromium/mojo/public/cpp/base/read_only_buffer.typemap b/chromium/mojo/public/cpp/base/read_only_buffer.typemap
index b772b729b67..08c764fe91a 100644
--- a/chromium/mojo/public/cpp/base/read_only_buffer.typemap
+++ b/chromium/mojo/public/cpp/base/read_only_buffer.typemap
@@ -5,9 +5,9 @@
mojom = "//mojo/public/mojom/base/read_only_buffer.mojom"
public_headers = [ "//base/containers/span.h" ]
traits_headers = [ "//mojo/public/cpp/base/read_only_buffer_mojom_traits.h" ]
-sources = [
- "//mojo/public/cpp/base/read_only_buffer_mojom_traits.cc",
- "//mojo/public/cpp/base/read_only_buffer_mojom_traits.h",
+public_deps = [
+ "//base",
+ "//mojo/public/cpp/base:shared_typemap_traits",
]
type_mappings = [ "mojo_base.mojom.ReadOnlyBuffer=base::span<const uint8_t>[copyable_pass_by_value,force_serialize]" ]
diff --git a/chromium/mojo/public/cpp/base/read_only_buffer_mojom_traits.h b/chromium/mojo/public/cpp/base/read_only_buffer_mojom_traits.h
index ad96e91e078..09e06cf35cf 100644
--- a/chromium/mojo/public/cpp/base/read_only_buffer_mojom_traits.h
+++ b/chromium/mojo/public/cpp/base/read_only_buffer_mojom_traits.h
@@ -5,14 +5,16 @@
#ifndef MOJO_PUBLIC_CPP_BASE_READ_ONLY_BUFFER_MOJOM_TRAITS_H_
#define MOJO_PUBLIC_CPP_BASE_READ_ONLY_BUFFER_MOJOM_TRAITS_H_
+#include "base/component_export.h"
#include "base/containers/span.h"
#include "mojo/public/mojom/base/read_only_buffer.mojom-shared.h"
namespace mojo {
template <>
-struct StructTraits<mojo_base::mojom::ReadOnlyBufferDataView,
- base::span<const uint8_t>> {
+struct COMPONENT_EXPORT(MOJO_BASE_SHARED_TRAITS)
+ StructTraits<mojo_base::mojom::ReadOnlyBufferDataView,
+ base::span<const uint8_t>> {
static base::span<const uint8_t> buffer(base::span<const uint8_t> input) {
return input;
}
diff --git a/chromium/mojo/public/cpp/base/typemaps.gni b/chromium/mojo/public/cpp/base/typemaps.gni
index 874e8c90e95..8d806254d13 100644
--- a/chromium/mojo/public/cpp/base/typemaps.gni
+++ b/chromium/mojo/public/cpp/base/typemaps.gni
@@ -10,9 +10,11 @@ typemaps = [
"//mojo/public/cpp/base/file_info.typemap",
"//mojo/public/cpp/base/file_path.typemap",
"//mojo/public/cpp/base/file.typemap",
+ "//mojo/public/cpp/base/generic_pending_receiver.typemap",
"//mojo/public/cpp/base/read_only_buffer.typemap",
"//mojo/public/cpp/base/memory_allocator_dump_cross_process_uid.typemap",
"//mojo/public/cpp/base/memory_pressure_level.typemap",
+ "//mojo/public/cpp/base/message_loop_type.typemap",
"//mojo/public/cpp/base/process_id.typemap",
"//mojo/public/cpp/base/ref_counted_memory.typemap",
"//mojo/public/cpp/base/shared_memory.typemap",
diff --git a/chromium/mojo/public/cpp/bindings/BUILD.gn b/chromium/mojo/public/cpp/bindings/BUILD.gn
index 7ba10d41f16..5667582bfd8 100644
--- a/chromium/mojo/public/cpp/bindings/BUILD.gn
+++ b/chromium/mojo/public/cpp/bindings/BUILD.gn
@@ -36,6 +36,8 @@ component("bindings_base") {
"associated_group.h",
"associated_group_controller.h",
"clone_traits.h",
+ "connection_group.cc",
+ "connection_group.h",
"disconnect_reason.h",
"enum_traits.h",
"equals_traits.h",
@@ -62,6 +64,10 @@ component("bindings_base") {
"lib/message_header_validator.cc",
"lib/message_internal.cc",
"lib/message_internal.h",
+ "lib/pending_receiver_state.cc",
+ "lib/pending_receiver_state.h",
+ "lib/pending_remote_state.cc",
+ "lib/pending_remote_state.h",
"lib/scoped_interface_endpoint_handle.cc",
"lib/serialization.h",
"lib/serialization_context.cc",
@@ -127,6 +133,8 @@ component("bindings") {
"connection_error_callback.h",
"connector.h",
"filter_chain.h",
+ "generic_pending_receiver.cc",
+ "generic_pending_receiver.h",
"interface_endpoint_client.h",
"interface_endpoint_controller.h",
"interface_ptr.h",
@@ -176,6 +184,7 @@ component("bindings") {
"receiver.h",
"receiver_set.h",
"remote.h",
+ "remote_set.h",
"self_owned_receiver.h",
"sequence_local_sync_event_watcher.h",
"shared_associated_remote.h",
@@ -188,6 +197,7 @@ component("bindings") {
"sync_handle_registry.h",
"sync_handle_watcher.h",
"thread_safe_interface_ptr.h",
+ "unique_associated_receiver_set.h",
"unique_ptr_impl_ref_traits.h",
"unique_receiver_set.h",
]
@@ -210,6 +220,7 @@ component("bindings") {
":bindings_base",
":struct_traits",
"//base",
+ "//base/util/type_safety",
"//ipc:message_support",
"//ipc:param_traits",
"//mojo/public/cpp/system",
diff --git a/chromium/mojo/public/cpp/bindings/array_traits_stl.h b/chromium/mojo/public/cpp/bindings/array_traits_stl.h
index 61688ed43bb..d579e5c2cdb 100644
--- a/chromium/mojo/public/cpp/bindings/array_traits_stl.h
+++ b/chromium/mojo/public/cpp/bindings/array_traits_stl.h
@@ -5,6 +5,7 @@
#ifndef MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STL_H_
#define MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STL_H_
+#include <array>
#include <map>
#include <set>
#include <vector>
@@ -145,6 +146,31 @@ struct ArrayTraits<MapValuesArrayView<K, V>> {
static const V& GetValue(ConstIterator& iterator) { return iterator->second; }
};
+// This ArrayTraits specialization is used for conversion between
+// std::array<T, N> and array<T, N>.
+template <typename T, size_t N>
+struct ArrayTraits<std::array<T, N>> {
+ using Element = T;
+
+ static bool IsNull(const std::array<T, N>& input) { return false; }
+
+ static size_t GetSize(const std::array<T, N>& input) { return N; }
+
+ static const T& GetAt(const std::array<T, N>& input, size_t index) {
+ return input[index];
+ }
+ static T& GetAt(std::array<T, N>& input, size_t index) {
+ return input[index];
+ }
+
+ // std::array is fixed size but this is called during deserialization.
+ static bool Resize(std::array<T, N>& input, size_t size) {
+ if (size != N)
+ return false;
+ return true;
+ }
+};
+
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_ARRAY_TRAITS_STL_H_
diff --git a/chromium/mojo/public/cpp/bindings/associated_remote.h b/chromium/mojo/public/cpp/bindings/associated_remote.h
index 8ff75188c06..1feadc1611d 100644
--- a/chromium/mojo/public/cpp/bindings/associated_remote.h
+++ b/chromium/mojo/public/cpp/bindings/associated_remote.h
@@ -16,6 +16,7 @@
#include "base/sequenced_task_runner.h"
#include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
#include "mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h"
+#include "mojo/public/cpp/bindings/lib/multiplex_router.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
@@ -172,6 +173,36 @@ class AssociatedRemote {
return PendingAssociatedReceiver<Interface>(std::move(receiver_handle));
}
+ // Like BindNewEndpointAndPassReceiver() above, but it creates a dedicated
+ // message pipe. The returned receiver can be bound directly to an
+ // implementation, without being first passed through a message pipe endpoint.
+ //
+ // For testing, where the returned request is bound to e.g. a mock and there
+ // are no other interfaces involved.
+ PendingAssociatedReceiver<Interface>
+ BindNewEndpointAndPassDedicatedReceiverForTesting() WARN_UNUSED_RESULT {
+ MessagePipe pipe;
+ scoped_refptr<internal::MultiplexRouter> router0 =
+ new internal::MultiplexRouter(
+ std::move(pipe.handle0), internal::MultiplexRouter::MULTI_INTERFACE,
+ false, base::SequencedTaskRunnerHandle::Get());
+ scoped_refptr<internal::MultiplexRouter> router1 =
+ new internal::MultiplexRouter(
+ std::move(pipe.handle1), internal::MultiplexRouter::MULTI_INTERFACE,
+ true, base::SequencedTaskRunnerHandle::Get());
+
+ ScopedInterfaceEndpointHandle remote_handle;
+ ScopedInterfaceEndpointHandle receiver_handle;
+ ScopedInterfaceEndpointHandle::CreatePairPendingAssociation(
+ &remote_handle, &receiver_handle);
+ InterfaceId id = router1->AssociateInterface(std::move(remote_handle));
+ remote_handle = router0->CreateLocalEndpointHandle(id);
+
+ Bind(PendingAssociatedRemote<Interface>(std::move(remote_handle), 0),
+ nullptr);
+ return PendingAssociatedReceiver<Interface>(std::move(receiver_handle));
+ }
+
// Binds this AssociatedRemote by consuming |pending_remote|, which must be
// valid. The AssociatedRemote will schedule any response callbacks or
// disconnection notifications on the default SequencedTaskRunner (i.e.
diff --git a/chromium/mojo/public/cpp/bindings/binding.h b/chromium/mojo/public/cpp/bindings/binding.h
index 1cd1677bd0b..d342c57208e 100644
--- a/chromium/mojo/public/cpp/bindings/binding.h
+++ b/chromium/mojo/public/cpp/bindings/binding.h
@@ -97,7 +97,7 @@ class Binding {
// binding it to the previously specified implementation.
void Bind(InterfaceRequest<Interface> request,
scoped_refptr<base::SequencedTaskRunner> runner = nullptr) {
- internal_state_.Bind(request.PassMessagePipe(), std::move(runner));
+ internal_state_.Bind(request.internal_state(), std::move(runner));
}
// Adds a message filter to be notified of each incoming message before
diff --git a/chromium/mojo/public/cpp/bindings/binding_set.h b/chromium/mojo/public/cpp/bindings/binding_set.h
index 33872fa97a4..c31405d9be7 100644
--- a/chromium/mojo/public/cpp/bindings/binding_set.h
+++ b/chromium/mojo/public/cpp/bindings/binding_set.h
@@ -70,7 +70,7 @@ class BindingSetBase {
using RequestType = typename Traits::RequestType;
using ImplPointerType = typename Traits::ImplPointerType;
- BindingSetBase() : weak_ptr_factory_(this) {}
+ BindingSetBase() {}
void set_connection_error_handler(base::RepeatingClosure error_handler) {
error_handler_ = std::move(error_handler);
@@ -309,7 +309,7 @@ class BindingSetBase {
bool is_flushing_ = false;
const Context* dispatch_context_ = nullptr;
BindingId dispatch_binding_;
- base::WeakPtrFactory<BindingSetBase> weak_ptr_factory_;
+ base::WeakPtrFactory<BindingSetBase> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(BindingSetBase);
};
diff --git a/chromium/mojo/public/cpp/bindings/connection_group.cc b/chromium/mojo/public/cpp/bindings/connection_group.cc
new file mode 100644
index 00000000000..7dd255deed6
--- /dev/null
+++ b/chromium/mojo/public/cpp/bindings/connection_group.cc
@@ -0,0 +1,93 @@
+// Copyright 2019 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/connection_group.h"
+
+#include "base/bind.h"
+
+namespace mojo {
+
+ConnectionGroup::Ref::Ref() = default;
+
+ConnectionGroup::Ref::Ref(const Ref& other) {
+ *this = other;
+}
+
+ConnectionGroup::Ref::Ref(Ref&& other) noexcept {
+ *this = std::move(other);
+}
+
+ConnectionGroup::Ref::~Ref() {
+ reset();
+}
+
+ConnectionGroup::Ref& ConnectionGroup::Ref::operator=(const Ref& other) {
+ reset();
+ type_ = Type::kStrong;
+ group_ = other.group_;
+ group_->AddGroupRef();
+ return *this;
+}
+
+ConnectionGroup::Ref& ConnectionGroup::Ref::operator=(Ref&& other) noexcept {
+ reset();
+ type_ = other.type_;
+ group_.swap(other.group_);
+ return *this;
+}
+
+void ConnectionGroup::Ref::reset() {
+ if (type_ == Type::kStrong && group_)
+ group_->ReleaseGroupRef();
+ type_ = Type::kWeak;
+ group_.reset();
+}
+
+ConnectionGroup::Ref ConnectionGroup::Ref::WeakCopy() const {
+ DCHECK(group_->notification_task_runner_->RunsTasksInCurrentSequence());
+ return Ref(group_);
+}
+
+bool ConnectionGroup::Ref::HasZeroRefs() const {
+ DCHECK(group_->notification_task_runner_->RunsTasksInCurrentSequence());
+ return group_->num_refs_ == 0;
+}
+
+ConnectionGroup::Ref::Ref(scoped_refptr<ConnectionGroup> group)
+ : group_(std::move(group)) {}
+
+// static
+ConnectionGroup::Ref ConnectionGroup::Create(
+ base::RepeatingClosure callback,
+ scoped_refptr<base::TaskRunner> task_runner) {
+ return Ref(base::WrapRefCounted(
+ new ConnectionGroup(std::move(callback), std::move(task_runner))));
+}
+
+ConnectionGroup::ConnectionGroup(base::RepeatingClosure callback,
+ scoped_refptr<base::TaskRunner> task_runner)
+ : notification_callback_(std::move(callback)),
+ notification_task_runner_(std::move(task_runner)) {}
+
+ConnectionGroup::~ConnectionGroup() {
+ // Just a sanity check. This ref-count should always be adjusted before the
+ // internal RefCountedThreadSafe ref-count, so we should never hit the
+ // destructor with a non-zero |num_refs_|.
+ DCHECK_EQ(num_refs_, 0u);
+}
+
+void ConnectionGroup::AddGroupRef() {
+ ++num_refs_;
+}
+
+void ConnectionGroup::ReleaseGroupRef() {
+ DCHECK_GT(num_refs_, 0u);
+ --num_refs_;
+ if (num_refs_ == 0 && notification_task_runner_) {
+ notification_task_runner_->PostTask(FROM_HERE,
+ base::BindOnce(notification_callback_));
+ }
+}
+
+} // namespace mojo
diff --git a/chromium/mojo/public/cpp/bindings/connection_group.h b/chromium/mojo/public/cpp/bindings/connection_group.h
new file mode 100644
index 00000000000..ba97769f02d
--- /dev/null
+++ b/chromium/mojo/public/cpp/bindings/connection_group.h
@@ -0,0 +1,110 @@
+// Copyright 2019 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_CONNECTION_GROUP_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_CONNECTION_GROUP_H_
+
+#include <atomic>
+
+#include "base/callback.h"
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/task_runner.h"
+
+namespace mojo {
+
+// A ConnectionGroup is used to loosely track groups of related interface
+// receivers. Any Receiver or PendingReceiver can reference a single
+// ConnectionGroup by holding onto a corresponding Ref.
+//
+// Belonging to a connection group is a viral property: if a Receiver belongs to
+// a connection group, any PendingReceivers arriving in inbound messages
+// automatically inherit a Ref to the same group. Likewise if a PendingReceiver
+// belongs to a group, any Receiver which consumes and binds that
+// PendingReceiver inherits its group membership.
+class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) ConnectionGroup
+ : public base::RefCountedThreadSafe<ConnectionGroup> {
+ public:
+ // A single opaque reference to a ConnectionGroup. May be freely moved and
+ // copied.
+ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) Ref {
+ public:
+ Ref();
+ Ref(const Ref&);
+ Ref(Ref&&) noexcept;
+ ~Ref();
+
+ Ref& operator=(const Ref&);
+ Ref& operator=(Ref&&) noexcept;
+
+ explicit operator bool() const { return group_ != nullptr; }
+ void reset();
+
+ // Returns a real reference to the underlying ConnectionGroup. Should only
+ // be used in testing.
+ scoped_refptr<ConnectionGroup> GetGroupForTesting() { return group_; }
+
+ // Returns a weak copy of this Ref. Does not increase ref-count.
+ Ref WeakCopy() const;
+
+ // Indicates whether the underlying ConnectionGroup has zero strong
+ // references. Must ONLY be called from the sequence which owns the
+ // primordial weak Ref, since that sequence may increase the ref count at
+ // any time and otherwise this accessor would be unreliable.
+ bool HasZeroRefs() const;
+
+ private:
+ friend class ConnectionGroup;
+
+ enum class Type {
+ // A weak Ref does not influence the ref-count of its referenced group.
+ // Weak references always produce strong references when copied.
+ kWeak,
+
+ // A strong Ref influences the ref-count of its reference group.
+ kStrong,
+ };
+
+ explicit Ref(scoped_refptr<ConnectionGroup> group);
+
+ Type type_ = Type::kWeak;
+ scoped_refptr<ConnectionGroup> group_;
+ };
+
+ // Constructs a new ConnectionGroup and returns an initial Ref to it. This
+ // initial reference does *not* increase the group's ref-count. All other
+ // copies of Ref increase the ref-count. Any time the ref-count is decremented
+ // to zero, |callback| is invoked on |task_runner|. If |task_runner| is null
+ // (useless except perhaps in tests), |callback| is ignored.
+ static Ref Create(base::RepeatingClosure callback,
+ scoped_refptr<base::TaskRunner> task_runner);
+
+ unsigned int GetNumRefsForTesting() const { return num_refs_; }
+
+ private:
+ friend class base::RefCountedThreadSafe<ConnectionGroup>;
+ friend class Ref;
+
+ ConnectionGroup(base::RepeatingClosure callback,
+ scoped_refptr<base::TaskRunner> task_runner);
+ virtual ~ConnectionGroup();
+
+ void AddGroupRef();
+ void ReleaseGroupRef();
+
+ const base::RepeatingClosure notification_callback_;
+ const scoped_refptr<base::TaskRunner> notification_task_runner_;
+
+ // We maintain our own ref count because we need to trigger behavior on
+ // release, and doing that in conjunction with the RefCountedThreadSafe's own
+ // lifetime-controlling ref count is not safely possible.
+ std::atomic<unsigned int> num_refs_{0};
+
+ DISALLOW_COPY_AND_ASSIGN(ConnectionGroup);
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_CONNECTION_GROUP_H_
diff --git a/chromium/mojo/public/cpp/bindings/connector.h b/chromium/mojo/public/cpp/bindings/connector.h
index b05b747b1a2..c2cf962e87d 100644
--- a/chromium/mojo/public/cpp/bindings/connector.h
+++ b/chromium/mojo/public/cpp/bindings/connector.h
@@ -18,6 +18,7 @@
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
+#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/message.h"
#include "mojo/public/cpp/bindings/sequence_local_sync_event_watcher.h"
#include "mojo/public/cpp/bindings/sync_handle_watcher.h"
@@ -154,6 +155,11 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) Connector : public MessageReceiver {
return message_pipe_.is_valid();
}
+ // Adds this object to a ConnectionGroup identified by |ref|. All receiving
+ // pipe endpoints decoded from inbound messages on this MultiplexRouter will
+ // be added to the same group.
+ void SetConnectionGroup(ConnectionGroup::Ref ref);
+
// Waits for the next message on the pipe, blocking until one arrives,
// |deadline| elapses, or an error happens. Returns |true| if a message has
// been delivered, |false| otherwise.
@@ -320,12 +326,15 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) Connector : public MessageReceiver {
std::unique_ptr<MessageReceiver> message_dumper_;
#endif
+ // A reference to the ConnectionGroup to which this Connector belongs, if any.
+ ConnectionGroup::Ref connection_group_;
+
// Create a single weak ptr and use it everywhere, to avoid the malloc/free
// cost of creating a new weak ptr whenever it is needed.
// NOTE: This weak pointer is invalidated when the message pipe is closed or
// transferred (i.e., when |connected_| is set to false).
base::WeakPtr<Connector> weak_self_;
- base::WeakPtrFactory<Connector> weak_factory_;
+ base::WeakPtrFactory<Connector> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(Connector);
};
diff --git a/chromium/mojo/public/cpp/bindings/generic_pending_receiver.cc b/chromium/mojo/public/cpp/bindings/generic_pending_receiver.cc
new file mode 100644
index 00000000000..1fb70944d17
--- /dev/null
+++ b/chromium/mojo/public/cpp/bindings/generic_pending_receiver.cc
@@ -0,0 +1,39 @@
+// Copyright 2019 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/generic_pending_receiver.h"
+
+namespace mojo {
+
+GenericPendingReceiver::GenericPendingReceiver() = default;
+
+GenericPendingReceiver::GenericPendingReceiver(
+ base::StringPiece interface_name,
+ mojo::ScopedMessagePipeHandle receiving_pipe)
+ : interface_name_(interface_name.as_string()),
+ pipe_(std::move(receiving_pipe)) {}
+
+GenericPendingReceiver::GenericPendingReceiver(GenericPendingReceiver&&) =
+ default;
+
+GenericPendingReceiver::~GenericPendingReceiver() = default;
+
+GenericPendingReceiver& GenericPendingReceiver::operator=(
+ GenericPendingReceiver&&) = default;
+
+mojo::ScopedMessagePipeHandle GenericPendingReceiver::PassPipe() {
+ DCHECK(is_valid());
+ interface_name_.reset();
+ return std::move(pipe_);
+}
+
+mojo::ScopedMessagePipeHandle GenericPendingReceiver::PassPipeIfNameIs(
+ const char* interface_name) {
+ DCHECK(is_valid());
+ if (interface_name_ == interface_name)
+ return PassPipe();
+ return mojo::ScopedMessagePipeHandle();
+}
+
+} // namespace mojo
diff --git a/chromium/mojo/public/cpp/bindings/generic_pending_receiver.h b/chromium/mojo/public/cpp/bindings/generic_pending_receiver.h
new file mode 100644
index 00000000000..8a0a71abeef
--- /dev/null
+++ b/chromium/mojo/public/cpp/bindings/generic_pending_receiver.h
@@ -0,0 +1,72 @@
+// Copyright 2019 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_GENERIC_PENDING_RECEIVER_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_GENERIC_PENDING_RECEIVER_H_
+
+#include <string>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "base/strings/string_piece.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace mojo {
+
+// GenericPendingReceiver encapsulates a pairing of a receiving pipe endpoint
+// with the name of the mojom interface assumed by the corresponding remote
+// endpoint.
+//
+// This is used by mojom C++ bindings to represent
+// |mojo_base.mojom.GenericPendingReceiver|, and it serves as a semi-safe
+// wrapper for transporting arbitrary interface receivers in a generic object.
+class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) GenericPendingReceiver {
+ public:
+ GenericPendingReceiver();
+ GenericPendingReceiver(base::StringPiece interface_name,
+ mojo::ScopedMessagePipeHandle receiving_pipe);
+
+ template <typename Interface>
+ GenericPendingReceiver(mojo::PendingReceiver<Interface> receiver)
+ : GenericPendingReceiver(Interface::Name_, receiver.PassPipe()) {}
+
+ GenericPendingReceiver(GenericPendingReceiver&&);
+ ~GenericPendingReceiver();
+
+ GenericPendingReceiver& operator=(GenericPendingReceiver&&);
+
+ bool is_valid() const { return pipe_.is_valid(); }
+ explicit operator bool() const { return is_valid(); }
+
+ const base::Optional<std::string>& interface_name() const {
+ return interface_name_;
+ }
+
+ mojo::MessagePipeHandle pipe() const { return pipe_.get(); }
+
+ // Takes ownership of the receiving pipe, invalidating this
+ // GenericPendingReceiver.
+ mojo::ScopedMessagePipeHandle PassPipe();
+
+ // Takes ownership of the pipe, strongly typed as an |Interface| receiver, if
+ // and only if that interface's name matches the stored interface name.
+ template <typename Interface>
+ mojo::PendingReceiver<Interface> As() {
+ return mojo::PendingReceiver<Interface>(PassPipeIfNameIs(Interface::Name_));
+ }
+
+ private:
+ mojo::ScopedMessagePipeHandle PassPipeIfNameIs(const char* interface_name);
+
+ base::Optional<std::string> interface_name_;
+ mojo::ScopedMessagePipeHandle pipe_;
+
+ DISALLOW_COPY_AND_ASSIGN(GenericPendingReceiver);
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_GENERIC_PENDING_RECEIVER_H_
diff --git a/chromium/mojo/public/cpp/bindings/interface_endpoint_client.h b/chromium/mojo/public/cpp/bindings/interface_endpoint_client.h
index 48ba96437e6..363f97f9a10 100644
--- a/chromium/mojo/public/cpp/bindings/interface_endpoint_client.h
+++ b/chromium/mojo/public/cpp/bindings/interface_endpoint_client.h
@@ -22,7 +22,10 @@
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
#include "mojo/public/cpp/bindings/connection_error_callback.h"
+#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/disconnect_reason.h"
#include "mojo/public/cpp/bindings/filter_chain.h"
#include "mojo/public/cpp/bindings/lib/control_message_handler.h"
@@ -94,6 +97,12 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) InterfaceEndpointClient
void CloseWithReason(uint32_t custom_reason, const std::string& description);
+ // Used by ControlMessageProxy to send messages through this endpoint.
+ void SendControlMessage(Message* message);
+ void SendControlMessageWithResponder(
+ Message* message,
+ std::unique_ptr<MessageReceiver> responder);
+
// MessageReceiverWithResponder implementation:
// They must only be called when the handle is not in pending association
// state.
@@ -102,6 +111,12 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) InterfaceEndpointClient
bool AcceptWithResponder(Message* message,
std::unique_ptr<MessageReceiver> responder) override;
+ // Implementations used by both SendControlMessage* and Accept* above.
+ bool SendMessage(Message* message, bool is_control_message);
+ bool SendMessageWithResponder(Message* message,
+ bool is_control_message,
+ std::unique_ptr<MessageReceiver> responder);
+
// The following methods are called by the router. They must be called
// outside of the router's lock.
@@ -117,6 +132,36 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) InterfaceEndpointClient
void FlushForTesting();
void FlushAsyncForTesting(base::OnceClosure callback);
+ // Sets a callback to handle idle notifications. This callback will be invoked
+ // any time the peer endpoint sends a NotifyIdle control message AND
+ // |num_unacked_messages_| is zero.
+ //
+ // Configures the peer endpoint to ack incoming messages send NotifyIdle
+ // notifications only once it's been idle continuously for at least a duration
+ // of |timeout|.
+ void SetIdleHandler(base::TimeDelta timeout, base::RepeatingClosure handler);
+
+ unsigned int GetNumUnackedMessagesForTesting() const {
+ return num_unacked_messages_;
+ }
+
+ // Sets a callback to invoke whenever this endpoint receives an
+ // EnableIdleTracking message from its peer. The callback is invoked with a
+ // new ConnectionGroup Ref that is expected to be adopted by whatever owns
+ // this endpoint.
+ using IdleTrackingEnabledCallback =
+ base::OnceCallback<void(ConnectionGroup::Ref connection_group)>;
+ void SetIdleTrackingEnabledCallback(IdleTrackingEnabledCallback callback);
+
+ // Called by the ControlMessageHandler when receiving corresponding control
+ // messages.
+ bool AcceptEnableIdleTracking(base::TimeDelta timeout);
+ bool AcceptMessageAck();
+ bool AcceptNotifyIdle();
+
+ void MaybeStartIdleTimer();
+ void MaybeSendNotifyIdle();
+
const char* interface_name() const { return interface_name_; }
#if DCHECK_IS_ON()
@@ -172,12 +217,40 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) InterfaceEndpointClient
const bool expect_sync_requests_ = false;
+ // The callback to invoke when our peer endpoint sends us NotifyIdle and we
+ // have no outstanding unacked messages. If null, no callback has been set and
+ // we do not expect to receive NotifyIdle or MessageAck messages from the
+ // peer.
+ base::RepeatingClosure idle_handler_;
+
+ // A callback to invoke if and when this endpoint receives an
+ // EnableIdleTracking control message.
+ IdleTrackingEnabledCallback idle_tracking_enabled_callback_;
+
+ // The timeout to wait for continuous idling before notiftying our peer that
+ // we're idle.
+ base::Optional<base::TimeDelta> idle_timeout_;
+
+ // The current idle timer, valid only while we're idle. If this fires, we send
+ // a NotifyIdle to our peer.
+ base::Optional<base::OneShotTimer> notify_idle_timer_;
+
+ // A ref to a ConnectionGroup used to track the idle state of this endpoint,
+ // if any. Only non-null if an EnableIdleTracking message has been received.
+ // This is a weak ref to the group.
+ ConnectionGroup::Ref idle_tracking_connection_group_;
+
+ // Indicates the number of unacked messages that have been sent so far. Only
+ // non-zero when |idle_handler_| has been set and some number of unacked
+ // messages remain in-flight.
+ unsigned int num_unacked_messages_ = 0;
+
ScopedInterfaceEndpointHandle handle_;
std::unique_ptr<AssociatedGroup> associated_group_;
InterfaceEndpointController* controller_ = nullptr;
MessageReceiverWithResponderStatus* const incoming_receiver_ = nullptr;
- HandleIncomingMessageThunk thunk_;
+ HandleIncomingMessageThunk thunk_{this};
FilterChain filters_;
AsyncResponderMap async_responders_;
@@ -191,7 +264,7 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) InterfaceEndpointClient
scoped_refptr<base::SequencedTaskRunner> task_runner_;
- internal::ControlMessageProxy control_message_proxy_;
+ internal::ControlMessageProxy control_message_proxy_{this};
internal::ControlMessageHandler control_message_handler_;
const char* interface_name_;
@@ -204,7 +277,7 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) InterfaceEndpointClient
SEQUENCE_CHECKER(sequence_checker_);
- base::WeakPtrFactory<InterfaceEndpointClient> weak_ptr_factory_;
+ base::WeakPtrFactory<InterfaceEndpointClient> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(InterfaceEndpointClient);
};
diff --git a/chromium/mojo/public/cpp/bindings/interface_ptr.h b/chromium/mojo/public/cpp/bindings/interface_ptr.h
index f6fc4394391..af383ed1cd2 100644
--- a/chromium/mojo/public/cpp/bindings/interface_ptr.h
+++ b/chromium/mojo/public/cpp/bindings/interface_ptr.h
@@ -91,7 +91,7 @@ class InterfacePtr {
scoped_refptr<base::SequencedTaskRunner> runner = nullptr) {
reset();
if (info.is_valid())
- internal_state_.Bind(std::move(info), std::move(runner));
+ internal_state_.Bind(info.internal_state(), std::move(runner));
}
// Returns whether or not this InterfacePtr is bound to a message pipe.
diff --git a/chromium/mojo/public/cpp/bindings/interface_ptr_info.h b/chromium/mojo/public/cpp/bindings/interface_ptr_info.h
index 70030434178..a6e189ace27 100644
--- a/chromium/mojo/public/cpp/bindings/interface_ptr_info.h
+++ b/chromium/mojo/public/cpp/bindings/interface_ptr_info.h
@@ -10,6 +10,7 @@
#include <utility>
#include "base/macros.h"
+#include "mojo/public/cpp/bindings/lib/pending_remote_state.h"
#include "mojo/public/cpp/system/message_pipe.h"
namespace mojo {
@@ -19,46 +20,36 @@ namespace mojo {
template <typename Interface>
class InterfacePtrInfo {
public:
- InterfacePtrInfo() : version_(0u) {}
+ InterfacePtrInfo() = default;
InterfacePtrInfo(std::nullptr_t) : InterfacePtrInfo() {}
InterfacePtrInfo(ScopedMessagePipeHandle handle, uint32_t version)
- : handle_(std::move(handle)), version_(version) {}
+ : state_(std::move(handle), version) {}
- InterfacePtrInfo(InterfacePtrInfo&& other)
- : handle_(std::move(other.handle_)), version_(other.version_) {
- other.version_ = 0u;
- }
+ InterfacePtrInfo(InterfacePtrInfo&& other) = default;
~InterfacePtrInfo() {}
- InterfacePtrInfo& operator=(InterfacePtrInfo&& other) {
- if (this != &other) {
- handle_ = std::move(other.handle_);
- version_ = other.version_;
- other.version_ = 0u;
- }
-
- return *this;
- }
+ InterfacePtrInfo& operator=(InterfacePtrInfo&& other) = default;
- bool is_valid() const { return handle_.is_valid(); }
+ bool is_valid() const { return state_.pipe.is_valid(); }
- ScopedMessagePipeHandle PassHandle() { return std::move(handle_); }
- const ScopedMessagePipeHandle& handle() const { return handle_; }
+ ScopedMessagePipeHandle PassHandle() { return std::move(state_.pipe); }
+ const ScopedMessagePipeHandle& handle() const { return state_.pipe; }
void set_handle(ScopedMessagePipeHandle handle) {
- handle_ = std::move(handle);
+ state_.pipe = std::move(handle);
}
- uint32_t version() const { return version_; }
- void set_version(uint32_t version) { version_ = version; }
+ uint32_t version() const { return state_.version; }
+ void set_version(uint32_t version) { state_.version = version; }
// Allow InterfacePtrInfo<> to be used in boolean expressions.
- explicit operator bool() const { return handle_.is_valid(); }
+ explicit operator bool() const { return state_.pipe.is_valid(); }
+
+ internal::PendingRemoteState* internal_state() { return &state_; }
private:
- ScopedMessagePipeHandle handle_;
- uint32_t version_;
+ internal::PendingRemoteState state_;
DISALLOW_COPY_AND_ASSIGN(InterfacePtrInfo);
};
diff --git a/chromium/mojo/public/cpp/bindings/interface_ptr_set.h b/chromium/mojo/public/cpp/bindings/interface_ptr_set.h
index 8130785bdae..faf91adbe2e 100644
--- a/chromium/mojo/public/cpp/bindings/interface_ptr_set.h
+++ b/chromium/mojo/public/cpp/bindings/interface_ptr_set.h
@@ -21,8 +21,8 @@ using InterfacePtrSetElementId = size_t;
namespace internal {
-// TODO(blundell): This class should be rewritten to be structured
-// similarly to BindingSet if possible, with PtrSet owning its
+// TODO(https://crbug.com/965668): This class should be rewritten to be
+// structured similarly to BindingSet if possible, with PtrSet owning its
// Elements and those Elements calling back into PtrSet on connection
// error.
template <typename Interface, template <typename> class Ptr>
diff --git a/chromium/mojo/public/cpp/bindings/interface_request.h b/chromium/mojo/public/cpp/bindings/interface_request.h
index 03372bc9755..44174347126 100644
--- a/chromium/mojo/public/cpp/bindings/interface_request.h
+++ b/chromium/mojo/public/cpp/bindings/interface_request.h
@@ -12,8 +12,12 @@
#include "base/macros.h"
#include "base/optional.h"
#include "base/sequenced_task_runner.h"
+#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/disconnect_reason.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/pending_receiver_state.h"
+#include "mojo/public/cpp/bindings/lib/serialization_context.h"
#include "mojo/public/cpp/bindings/pipe_control_message_proxy.h"
#include "mojo/public/cpp/system/message_pipe.h"
@@ -34,31 +38,27 @@ class InterfaceRequest {
InterfaceRequest(std::nullptr_t) {}
explicit InterfaceRequest(ScopedMessagePipeHandle handle)
- : handle_(std::move(handle)) {}
+ : state_(std::move(handle)) {}
// Takes the message pipe from another InterfaceRequest.
- InterfaceRequest(InterfaceRequest&& other) {
- handle_ = std::move(other.handle_);
- }
- InterfaceRequest& operator=(InterfaceRequest&& other) {
- handle_ = std::move(other.handle_);
- return *this;
- }
+ InterfaceRequest(InterfaceRequest&& other) = default;
+
+ InterfaceRequest& operator=(InterfaceRequest&& other) = default;
// Assigning to nullptr resets the InterfaceRequest to an empty state,
// closing the message pipe currently bound to it (if any).
InterfaceRequest& operator=(std::nullptr_t) {
- handle_.reset();
+ state_.reset();
return *this;
}
// Indicates whether the request currently contains a valid message pipe.
- bool is_pending() const { return handle_.is_valid(); }
+ bool is_pending() const { return state_.pipe.is_valid(); }
- explicit operator bool() const { return handle_.is_valid(); }
+ explicit operator bool() const { return is_pending(); }
// Removes the message pipe from the request and returns it.
- ScopedMessagePipeHandle PassMessagePipe() { return std::move(handle_); }
+ ScopedMessagePipeHandle PassMessagePipe() { return std::move(state_.pipe); }
bool Equals(const InterfaceRequest& other) const {
if (this == &other)
@@ -70,21 +70,41 @@ class InterfaceRequest {
}
void ResetWithReason(uint32_t custom_reason, const std::string& description) {
- if (!handle_.is_valid())
+ if (!is_pending())
return;
Message message =
PipeControlMessageProxy::ConstructPeerEndpointClosedMessage(
kMasterInterfaceId, DisconnectReason(custom_reason, description));
- MojoResult result = WriteMessageNew(
- handle_.get(), message.TakeMojoMessage(), MOJO_WRITE_MESSAGE_FLAG_NONE);
+ MojoResult result =
+ WriteMessageNew(state_.pipe.get(), message.TakeMojoMessage(),
+ MOJO_WRITE_MESSAGE_FLAG_NONE);
DCHECK_EQ(MOJO_RESULT_OK, result);
- handle_.reset();
+ state_.reset();
+ }
+
+ // Assigns this InterfaceRequest to the ConnectionGroup referenced by |ref|.
+ // Any Receiver which binds this InterfaceRequest will inherit the Ref.
+ void set_connection_group(ConnectionGroup::Ref ref) {
+ state_.connection_group = std::move(ref);
}
+ const ConnectionGroup::Ref& connection_group() const {
+ return state_.connection_group;
+ }
+
+ // Passes ownership of this InterfaceRequest's ConnectionGroup Ref, removing
+ // it from its group.
+ ConnectionGroup::Ref PassConnectionGroupRef() {
+ return std::move(state_.connection_group);
+ }
+
+ // For internal Mojo use only.
+ internal::PendingReceiverState* internal_state() { return &state_; }
+
private:
- ScopedMessagePipeHandle handle_;
+ internal::PendingReceiverState state_;
DISALLOW_COPY_AND_ASSIGN(InterfaceRequest);
};
diff --git a/chromium/mojo/public/cpp/bindings/lib/binding_state.cc b/chromium/mojo/public/cpp/bindings/lib/binding_state.cc
index 87560a19c32..b82a2c4ff66 100644
--- a/chromium/mojo/public/cpp/bindings/lib/binding_state.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/binding_state.cc
@@ -13,7 +13,7 @@
namespace mojo {
namespace internal {
-BindingStateBase::BindingStateBase() : weak_ptr_factory_(this) {}
+BindingStateBase::BindingStateBase() = default;
BindingStateBase::~BindingStateBase() = default;
@@ -90,7 +90,7 @@ scoped_refptr<internal::MultiplexRouter> BindingStateBase::RouterForTesting() {
}
void BindingStateBase::BindInternal(
- ScopedMessagePipeHandle handle,
+ PendingReceiverState* receiver_state,
scoped_refptr<base::SequencedTaskRunner> runner,
const char* interface_name,
std::unique_ptr<MessageReceiver> request_validator,
@@ -110,14 +110,17 @@ void BindingStateBase::BindInternal(
: (has_sync_methods
? MultiplexRouter::SINGLE_INTERFACE_WITH_SYNC_METHODS
: MultiplexRouter::SINGLE_INTERFACE);
- router_ =
- new MultiplexRouter(std::move(handle), config, false, sequenced_runner);
+ router_ = new MultiplexRouter(std::move(receiver_state->pipe), config, false,
+ sequenced_runner);
router_->SetMasterInterfaceName(interface_name);
+ router_->SetConnectionGroup(std::move(receiver_state->connection_group));
endpoint_client_.reset(new InterfaceEndpointClient(
router_->CreateLocalEndpointHandle(kMasterInterfaceId), stub,
std::move(request_validator), has_sync_methods,
std::move(sequenced_runner), interface_version, interface_name));
+ endpoint_client_->SetIdleTrackingEnabledCallback(
+ base::BindOnce(&MultiplexRouter::SetConnectionGroup, router_));
#if BUILDFLAG(MOJO_RANDOM_DELAYS_ENABLED)
MakeBindingRandomlyPaused(base::SequencedTaskRunnerHandle::Get(),
diff --git a/chromium/mojo/public/cpp/bindings/lib/binding_state.h b/chromium/mojo/public/cpp/bindings/lib/binding_state.h
index cc2ac0c3166..ced07dd4f73 100644
--- a/chromium/mojo/public/cpp/bindings/lib/binding_state.h
+++ b/chromium/mojo/public/cpp/bindings/lib/binding_state.h
@@ -18,6 +18,7 @@
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
#include "mojo/public/cpp/bindings/connection_error_callback.h"
+#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/filter_chain.h"
#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
#include "mojo/public/cpp/bindings/interface_id.h"
@@ -25,6 +26,7 @@
#include "mojo/public/cpp/bindings/interface_ptr_info.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/bindings/lib/multiplex_router.h"
+#include "mojo/public/cpp/bindings/lib/pending_receiver_state.h"
#include "mojo/public/cpp/bindings/message_header_validator.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
#include "mojo/public/cpp/system/core.h"
@@ -83,7 +85,7 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) BindingStateBase {
scoped_refptr<internal::MultiplexRouter> RouterForTesting();
protected:
- void BindInternal(ScopedMessagePipeHandle handle,
+ void BindInternal(PendingReceiverState* receiver_state,
scoped_refptr<base::SequencedTaskRunner> runner,
const char* interface_name,
std::unique_ptr<MessageReceiver> request_validator,
@@ -95,7 +97,7 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) BindingStateBase {
scoped_refptr<internal::MultiplexRouter> router_;
std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
- base::WeakPtrFactory<BindingStateBase> weak_ptr_factory_;
+ base::WeakPtrFactory<BindingStateBase> weak_ptr_factory_{this};
};
template <typename Interface, typename ImplRefTraits>
@@ -109,10 +111,10 @@ class BindingState : public BindingStateBase {
~BindingState() { Close(); }
- void Bind(ScopedMessagePipeHandle handle,
+ void Bind(PendingReceiverState* receiver_state,
scoped_refptr<base::SequencedTaskRunner> runner) {
BindingStateBase::BindInternal(
- std::move(handle), runner, Interface::Name_,
+ std::move(receiver_state), runner, Interface::Name_,
std::make_unique<typename Interface::RequestValidator_>(),
Interface::PassesAssociatedKinds_, Interface::HasSyncMethods_, &stub_,
Interface::Version_);
diff --git a/chromium/mojo/public/cpp/bindings/lib/connector.cc b/chromium/mojo/public/cpp/bindings/lib/connector.cc
index 01c5c3b21b6..d0739ddbf1f 100644
--- a/chromium/mojo/public/cpp/bindings/lib/connector.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/connector.cc
@@ -145,8 +145,7 @@ Connector::Connector(ScopedMessagePipeHandle message_pipe,
force_immediate_dispatch_(!EnableTaskPerMessage()),
outgoing_serialization_mode_(g_default_outgoing_serialization_mode),
incoming_serialization_mode_(g_default_incoming_serialization_mode),
- nesting_observer_(RunLoopNestingObserver::GetForThread()),
- weak_factory_(this) {
+ nesting_observer_(RunLoopNestingObserver::GetForThread()) {
if (config == MULTI_THREADED_SEND)
lock_.emplace();
@@ -209,6 +208,10 @@ void Connector::RaiseError() {
HandleError(true, true);
}
+void Connector::SetConnectionGroup(ConnectionGroup::Ref ref) {
+ connection_group_ = std::move(ref);
+}
+
bool Connector::WaitForIncomingMessage(MojoDeadline deadline) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -505,6 +508,8 @@ bool Connector::DispatchMessage(Message message) {
TRACE_EVENT0("mojom", heap_profiler_tag_);
#endif
+ if (connection_group_)
+ message.set_receiver_connection_group(&connection_group_);
bool receiver_result =
incoming_receiver_ && incoming_receiver_->Accept(&message);
if (!weak_self)
diff --git a/chromium/mojo/public/cpp/bindings/lib/control_message_handler.cc b/chromium/mojo/public/cpp/bindings/lib/control_message_handler.cc
index b87c11c874b..254f452835c 100644
--- a/chromium/mojo/public/cpp/bindings/lib/control_message_handler.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/control_message_handler.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/macros.h"
+#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
#include "mojo/public/cpp/bindings/lib/serialization.h"
#include "mojo/public/cpp/bindings/lib/validation_util.h"
#include "mojo/public/cpp/bindings/message.h"
@@ -61,9 +62,9 @@ bool ControlMessageHandler::IsControlMessage(const Message* message) {
message->header()->name == interface_control::kRunOrClosePipeMessageId;
}
-ControlMessageHandler::ControlMessageHandler(uint32_t interface_version)
- : interface_version_(interface_version) {
-}
+ControlMessageHandler::ControlMessageHandler(InterfaceEndpointClient* owner,
+ uint32_t interface_version)
+ : owner_(owner), interface_version_(interface_version) {}
ControlMessageHandler::~ControlMessageHandler() {
}
@@ -138,7 +139,14 @@ bool ControlMessageHandler::RunOrClosePipe(Message* message) {
auto& input = *params_ptr->input;
if (input.is_require_version())
return interface_version_ >= input.get_require_version()->version;
-
+ if (input.is_enable_idle_tracking()) {
+ return owner_->AcceptEnableIdleTracking(base::TimeDelta::FromMicroseconds(
+ input.get_enable_idle_tracking()->timeout_in_microseconds));
+ }
+ if (input.is_message_ack())
+ return owner_->AcceptMessageAck();
+ if (input.is_notify_idle())
+ return owner_->AcceptNotifyIdle();
return false;
}
diff --git a/chromium/mojo/public/cpp/bindings/lib/control_message_handler.h b/chromium/mojo/public/cpp/bindings/lib/control_message_handler.h
index 3594134c97e..cab631a72de 100644
--- a/chromium/mojo/public/cpp/bindings/lib/control_message_handler.h
+++ b/chromium/mojo/public/cpp/bindings/lib/control_message_handler.h
@@ -7,13 +7,15 @@
#include <stdint.h>
-#include "base/compiler_specific.h"
#include "base/component_export.h"
#include "base/macros.h"
#include "mojo/public/cpp/bindings/lib/serialization_context.h"
#include "mojo/public/cpp/bindings/message.h"
namespace mojo {
+
+class InterfaceEndpointClient;
+
namespace internal {
// Handlers for request messages defined in interface_control_messages.mojom.
@@ -22,7 +24,8 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) ControlMessageHandler
public:
static bool IsControlMessage(const Message* message);
- explicit ControlMessageHandler(uint32_t interface_version);
+ ControlMessageHandler(InterfaceEndpointClient* owner,
+ uint32_t interface_version);
~ControlMessageHandler() override;
// Call the following methods only if IsControlMessage() returned true.
@@ -36,6 +39,7 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) ControlMessageHandler
std::unique_ptr<MessageReceiverWithStatus> responder);
bool RunOrClosePipe(Message* message);
+ InterfaceEndpointClient* const owner_;
uint32_t interface_version_;
SerializationContext context_;
diff --git a/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.cc b/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.cc
index c48261a6625..ed0e85f94fd 100644
--- a/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.cc
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "mojo/public/cpp/bindings/interface_endpoint_client.h"
#include "mojo/public/cpp/bindings/lib/serialization.h"
#include "mojo/public/cpp/bindings/lib/validation_util.h"
#include "mojo/public/cpp/bindings/message.h"
@@ -72,7 +73,7 @@ bool RunResponseForwardToCallback::Accept(Message* message) {
return true;
}
-void SendRunMessage(MessageReceiverWithResponder* receiver,
+void SendRunMessage(InterfaceEndpointClient* endpoint,
interface_control::RunInputPtr input_ptr,
RunCallback callback) {
auto params_ptr = interface_control::RunMessageParams::New();
@@ -86,7 +87,7 @@ void SendRunMessage(MessageReceiverWithResponder* receiver,
params_ptr, message.payload_buffer(), &params, &context);
std::unique_ptr<MessageReceiver> responder =
std::make_unique<RunResponseForwardToCallback>(std::move(callback));
- ignore_result(receiver->AcceptWithResponder(&message, std::move(responder)));
+ endpoint->SendControlMessageWithResponder(&message, std::move(responder));
}
Message ConstructRunOrClosePipeMessage(
@@ -105,11 +106,11 @@ Message ConstructRunOrClosePipeMessage(
}
void SendRunOrClosePipeMessage(
- MessageReceiverWithResponder* receiver,
+ InterfaceEndpointClient* endpoint,
interface_control::RunOrClosePipeInputPtr input_ptr) {
Message message(ConstructRunOrClosePipeMessage(std::move(input_ptr)));
message.set_heap_profiler_tag(kMessageTag);
- ignore_result(receiver->Accept(&message));
+ endpoint->SendControlMessage(&message);
}
void RunVersionCallback(
@@ -128,9 +129,8 @@ void RunClosure(base::OnceClosure callback,
} // namespace
-ControlMessageProxy::ControlMessageProxy(MessageReceiverWithResponder* receiver)
- : receiver_(receiver) {
-}
+ControlMessageProxy::ControlMessageProxy(InterfaceEndpointClient* owner)
+ : owner_(owner) {}
ControlMessageProxy::~ControlMessageProxy() {
// If this is destroyed in the middle of a flush, make sure the callback is
@@ -143,7 +143,7 @@ void ControlMessageProxy::QueryVersion(
const base::Callback<void(uint32_t)>& callback) {
auto input_ptr = interface_control::RunInput::New();
input_ptr->set_query_version(interface_control::QueryVersion::New());
- SendRunMessage(receiver_, std::move(input_ptr),
+ SendRunMessage(owner_, std::move(input_ptr),
base::BindOnce(&RunVersionCallback, callback));
}
@@ -152,7 +152,7 @@ void ControlMessageProxy::RequireVersion(uint32_t version) {
require_version->version = version;
auto input_ptr = interface_control::RunOrClosePipeInput::New();
input_ptr->set_require_version(std::move(require_version));
- SendRunOrClosePipeMessage(receiver_, std::move(input_ptr));
+ SendRunOrClosePipeMessage(owner_, std::move(input_ptr));
}
void ControlMessageProxy::FlushForTesting() {
@@ -173,7 +173,7 @@ void ControlMessageProxy::FlushAsyncForTesting(base::OnceClosure callback) {
DCHECK(!pending_flush_callback_);
pending_flush_callback_ = std::move(callback);
SendRunMessage(
- receiver_, std::move(input_ptr),
+ owner_, std::move(input_ptr),
base::BindOnce(
&RunClosure,
base::BindOnce(&ControlMessageProxy::RunFlushForTestingClosure,
@@ -185,6 +185,25 @@ void ControlMessageProxy::RunFlushForTestingClosure() {
std::move(pending_flush_callback_).Run();
}
+void ControlMessageProxy::EnableIdleTracking(base::TimeDelta timeout) {
+ auto input = interface_control::RunOrClosePipeInput::New();
+ input->set_enable_idle_tracking(
+ interface_control::EnableIdleTracking::New(timeout.InMicroseconds()));
+ SendRunOrClosePipeMessage(owner_, std::move(input));
+}
+
+void ControlMessageProxy::SendMessageAck() {
+ auto input = interface_control::RunOrClosePipeInput::New();
+ input->set_message_ack(interface_control::MessageAck::New());
+ SendRunOrClosePipeMessage(owner_, std::move(input));
+}
+
+void ControlMessageProxy::NotifyIdle() {
+ auto input = interface_control::RunOrClosePipeInput::New();
+ input->set_notify_idle(interface_control::NotifyIdle::New());
+ SendRunOrClosePipeMessage(owner_, std::move(input));
+}
+
void ControlMessageProxy::OnConnectionError() {
encountered_error_ = true;
if (!pending_flush_callback_.is_null())
diff --git a/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.h b/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.h
index 99f52cd4e65..533f5181157 100644
--- a/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.h
+++ b/chromium/mojo/public/cpp/bindings/lib/control_message_proxy.h
@@ -14,15 +14,15 @@
namespace mojo {
-class MessageReceiverWithResponder;
+class InterfaceEndpointClient;
namespace internal {
// Proxy for request messages defined in interface_control_messages.mojom.
class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) ControlMessageProxy {
public:
- // Doesn't take ownership of |receiver|. It must outlive this object.
- explicit ControlMessageProxy(MessageReceiverWithResponder* receiver);
+ // Doesn't take ownership of |owner|. It must outlive this object.
+ explicit ControlMessageProxy(InterfaceEndpointClient* owner);
~ControlMessageProxy();
void QueryVersion(const base::Callback<void(uint32_t)>& callback);
@@ -30,13 +30,18 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) ControlMessageProxy {
void FlushForTesting();
void FlushAsyncForTesting(base::OnceClosure callback);
+
+ void EnableIdleTracking(base::TimeDelta timeout);
+ void SendMessageAck();
+ void NotifyIdle();
+
void OnConnectionError();
private:
void RunFlushForTestingClosure();
// Not owned.
- MessageReceiverWithResponder* receiver_;
+ InterfaceEndpointClient* const owner_;
bool encountered_error_ = false;
base::OnceClosure pending_flush_callback_;
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 51e4171ff67..d210a668b56 100644
--- a/chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
@@ -67,6 +67,12 @@ class ResponderThunk : public MessageReceiverWithStatus {
}
}
+ // Allows this thunk to be attached to a ConnectionGroup as a means of keeping
+ // the group from idling while the response is pending.
+ void set_connection_group(ConnectionGroup::Ref connection_group) {
+ connection_group_ = std::move(connection_group);
+ }
+
// MessageReceiver implementation:
bool PrefersSerializedMessages() override {
return endpoint_client_ && endpoint_client_->PrefersSerializedMessages();
@@ -105,6 +111,7 @@ class ResponderThunk : public MessageReceiverWithStatus {
base::WeakPtr<InterfaceEndpointClient> endpoint_client_;
bool accept_was_invoked_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ ConnectionGroup::Ref connection_group_;
DISALLOW_COPY_AND_ASSIGN(ResponderThunk);
};
@@ -146,13 +153,10 @@ InterfaceEndpointClient::InterfaceEndpointClient(
: expect_sync_requests_(expect_sync_requests),
handle_(std::move(handle)),
incoming_receiver_(receiver),
- thunk_(this),
filters_(&thunk_),
task_runner_(std::move(runner)),
- control_message_proxy_(this),
- control_message_handler_(interface_version),
- interface_name_(interface_name),
- weak_ptr_factory_(this) {
+ control_message_handler_(this, interface_version),
+ interface_name_(interface_name) {
DCHECK(handle_.is_valid());
// TODO(yzshen): the way to use validator (or message filter in general)
@@ -223,7 +227,30 @@ bool InterfaceEndpointClient::PrefersSerializedMessages() {
return controller && controller->PrefersSerializedMessages();
}
+void InterfaceEndpointClient::SendControlMessage(Message* message) {
+ SendMessage(message, true /* is_control_message */);
+}
+
+void InterfaceEndpointClient::SendControlMessageWithResponder(
+ Message* message,
+ std::unique_ptr<MessageReceiver> responder) {
+ SendMessageWithResponder(message, true /* is_control_message */,
+ std::move(responder));
+}
+
bool InterfaceEndpointClient::Accept(Message* message) {
+ return SendMessage(message, false /* is_control_message */);
+}
+
+bool InterfaceEndpointClient::AcceptWithResponder(
+ Message* message,
+ std::unique_ptr<MessageReceiver> responder) {
+ return SendMessageWithResponder(message, false /* is_control_message */,
+ std::move(responder));
+}
+
+bool InterfaceEndpointClient::SendMessage(Message* message,
+ bool is_control_message) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!message->has_flag(Message::kFlagExpectsResponse));
DCHECK(!handle_.pending_association());
@@ -247,11 +274,18 @@ bool InterfaceEndpointClient::Accept(Message* message) {
#endif
message->set_heap_profiler_tag(interface_name_);
- return controller_->SendMessage(message);
+ if (!controller_->SendMessage(message))
+ return false;
+
+ if (!is_control_message && idle_handler_)
+ ++num_unacked_messages_;
+
+ return true;
}
-bool InterfaceEndpointClient::AcceptWithResponder(
+bool InterfaceEndpointClient::SendMessageWithResponder(
Message* message,
+ bool is_control_message,
std::unique_ptr<MessageReceiver> responder) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(message->has_flag(Message::kFlagExpectsResponse));
@@ -283,6 +317,9 @@ bool InterfaceEndpointClient::AcceptWithResponder(
if (!controller_->SendMessage(message))
return false;
+ if (!is_control_message && idle_handler_)
+ ++num_unacked_messages_;
+
if (!is_sync) {
async_responders_[request_id] = std::move(responder);
return true;
@@ -299,7 +336,7 @@ bool InterfaceEndpointClient::AcceptWithResponder(
controller_->SyncWatch(&response_received);
// Make sure that this instance hasn't been destroyed.
if (weak_self) {
- DCHECK(base::ContainsKey(sync_responses_, request_id));
+ DCHECK(base::Contains(sync_responses_, request_id));
auto iter = sync_responses_.find(request_id);
DCHECK_EQ(&response_received, iter->second->response_received);
if (response_received) {
@@ -365,6 +402,81 @@ void InterfaceEndpointClient::FlushAsyncForTesting(base::OnceClosure callback) {
control_message_proxy_.FlushAsyncForTesting(std::move(callback));
}
+void InterfaceEndpointClient::SetIdleHandler(base::TimeDelta timeout,
+ base::RepeatingClosure handler) {
+ // We allow for idle handler replacement and changing the timeout duration.
+ control_message_proxy_.EnableIdleTracking(timeout);
+ idle_handler_ = std::move(handler);
+}
+
+void InterfaceEndpointClient::SetIdleTrackingEnabledCallback(
+ IdleTrackingEnabledCallback callback) {
+ idle_tracking_enabled_callback_ = std::move(callback);
+}
+
+bool InterfaceEndpointClient::AcceptEnableIdleTracking(
+ base::TimeDelta timeout) {
+ // If this is the first time EnableIdleTracking was received, set up the
+ // ConnectionGroup and give a ref to our owner.
+ if (idle_tracking_enabled_callback_) {
+ idle_tracking_connection_group_ = ConnectionGroup::Create(
+ base::BindRepeating(&InterfaceEndpointClient::MaybeStartIdleTimer,
+ weak_ptr_factory_.GetWeakPtr()),
+ task_runner_);
+ std::move(idle_tracking_enabled_callback_)
+ .Run(idle_tracking_connection_group_.WeakCopy());
+ }
+
+ idle_timeout_ = timeout;
+ return true;
+}
+
+bool InterfaceEndpointClient::AcceptMessageAck() {
+ if (!idle_handler_ || num_unacked_messages_ == 0)
+ return false;
+
+ --num_unacked_messages_;
+ return true;
+}
+
+bool InterfaceEndpointClient::AcceptNotifyIdle() {
+ if (!idle_handler_)
+ return false;
+
+ // We have outstanding unacked messages, so quietly ignore this NotifyIdle.
+ if (num_unacked_messages_ > 0)
+ return true;
+
+ // With no outstanding unacked messages, a NotifyIdle received implies that
+ // the peer really is idle. We can invoke our idle handler.
+ idle_handler_.Run();
+ return true;
+}
+
+void InterfaceEndpointClient::MaybeStartIdleTimer() {
+ // Something has happened to interrupt the current idle state, if any. We
+ // either restart the idle timer (if idle again) or clear it so it doesn't
+ // fire.
+ if (idle_tracking_connection_group_ &&
+ idle_tracking_connection_group_.HasZeroRefs()) {
+ DCHECK(idle_timeout_);
+ notify_idle_timer_.emplace();
+ notify_idle_timer_->Start(
+ FROM_HERE, *idle_timeout_,
+ base::BindOnce(&InterfaceEndpointClient::MaybeSendNotifyIdle,
+ base::Unretained(this)));
+ } else {
+ notify_idle_timer_.reset();
+ }
+}
+
+void InterfaceEndpointClient::MaybeSendNotifyIdle() {
+ if (idle_tracking_connection_group_ &&
+ idle_tracking_connection_group_.HasZeroRefs()) {
+ control_message_proxy_.NotifyIdle();
+ }
+}
+
void InterfaceEndpointClient::InitControllerIfNecessary() {
if (controller_ || handle_.pending_association())
return;
@@ -401,16 +513,21 @@ bool InterfaceEndpointClient::HandleValidatedMessage(Message* message) {
return false;
}
+ auto weak_self = weak_ptr_factory_.GetWeakPtr();
+ bool accepted_interface_message = false;
+ bool has_response = false;
if (message->has_flag(Message::kFlagExpectsResponse)) {
- std::unique_ptr<MessageReceiverWithStatus> responder =
- std::make_unique<ResponderThunk>(weak_ptr_factory_.GetWeakPtr(),
- task_runner_);
+ has_response = true;
+ auto responder = std::make_unique<ResponderThunk>(
+ weak_ptr_factory_.GetWeakPtr(), task_runner_);
if (mojo::internal::ControlMessageHandler::IsControlMessage(message)) {
return control_message_handler_.AcceptWithResponder(message,
std::move(responder));
} else {
- return incoming_receiver_->AcceptWithResponder(message,
- std::move(responder));
+ if (idle_tracking_connection_group_)
+ responder->set_connection_group(idle_tracking_connection_group_);
+ accepted_interface_message = incoming_receiver_->AcceptWithResponder(
+ message, std::move(responder));
}
} else if (message->has_flag(Message::kFlagIsResponse)) {
uint64_t request_id = message->request_id();
@@ -434,8 +551,17 @@ bool InterfaceEndpointClient::HandleValidatedMessage(Message* message) {
if (mojo::internal::ControlMessageHandler::IsControlMessage(message))
return control_message_handler_.Accept(message);
- return incoming_receiver_->Accept(message);
+ accepted_interface_message = incoming_receiver_->Accept(message);
}
+
+ if (weak_self && accepted_interface_message &&
+ idle_tracking_connection_group_) {
+ control_message_proxy_.SendMessageAck();
+ if (!has_response)
+ MaybeStartIdleTimer();
+ }
+
+ return accepted_interface_message;
}
} // namespace mojo
diff --git a/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.cc b/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.cc
index 7d49fa3e544..6d31bab0c9d 100644
--- a/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.cc
@@ -44,17 +44,16 @@ void InterfacePtrStateBase::Swap(InterfacePtrStateBase* other) {
}
void InterfacePtrStateBase::Bind(
- ScopedMessagePipeHandle handle,
- uint32_t version,
+ PendingRemoteState* remote_state,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
DCHECK(!router_);
DCHECK(!endpoint_client_);
DCHECK(!handle_.is_valid());
DCHECK_EQ(0u, version_);
- DCHECK(handle.is_valid());
+ DCHECK(remote_state->pipe.is_valid());
- handle_ = std::move(handle);
- version_ = version;
+ handle_ = std::move(remote_state->pipe);
+ version_ = remote_state->version;
runner_ =
GetTaskRunnerToUseFromUserProvidedTaskRunner(std::move(task_runner));
}
diff --git a/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.h b/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.h
index fa1e469b71d..8cd7886262b 100644
--- a/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.h
+++ b/chromium/mojo/public/cpp/bindings/lib/interface_ptr_state.h
@@ -21,6 +21,7 @@
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
+#include "base/time/time.h"
#include "mojo/public/cpp/bindings/associated_group.h"
#include "mojo/public/cpp/bindings/connection_error_callback.h"
#include "mojo/public/cpp/bindings/filter_chain.h"
@@ -28,6 +29,7 @@
#include "mojo/public/cpp/bindings/interface_id.h"
#include "mojo/public/cpp/bindings/interface_ptr_info.h"
#include "mojo/public/cpp/bindings/lib/multiplex_router.h"
+#include "mojo/public/cpp/bindings/lib/pending_remote_state.h"
#include "mojo/public/cpp/bindings/message_header_validator.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
@@ -75,8 +77,7 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) InterfacePtrStateBase {
void QueryVersion(base::OnceCallback<void(uint32_t)> callback);
void RequireVersion(uint32_t version);
void Swap(InterfacePtrStateBase* other);
- void Bind(ScopedMessagePipeHandle handle,
- uint32_t version,
+ void Bind(PendingRemoteState* remote_state,
scoped_refptr<base::SequencedTaskRunner> task_runner);
ScopedMessagePipeHandle PassMessagePipe() {
@@ -166,11 +167,10 @@ class InterfacePtrState : public InterfacePtrStateBase {
InterfacePtrStateBase::Swap(other);
}
- void Bind(InterfacePtrInfo<Interface> info,
+ void Bind(PendingRemoteState* remote_state,
scoped_refptr<base::SequencedTaskRunner> runner) {
DCHECK(!proxy_);
- InterfacePtrStateBase::Bind(info.PassHandle(), info.version(),
- std::move(runner));
+ InterfacePtrStateBase::Bind(remote_state, std::move(runner));
}
// After this method is called, the object is in an invalid state and
@@ -196,6 +196,17 @@ class InterfacePtrState : public InterfacePtrStateBase {
std::move(error_handler));
}
+ void set_idle_handler(base::TimeDelta timeout,
+ base::RepeatingClosure handler) {
+ ConfigureProxyIfNecessary();
+ DCHECK(endpoint_client());
+ endpoint_client()->SetIdleHandler(timeout, std::move(handler));
+ }
+
+ unsigned int GetNumUnackedMessagesForTesting() const {
+ return endpoint_client()->GetNumUnackedMessagesForTesting();
+ }
+
AssociatedGroup* associated_group() {
ConfigureProxyIfNecessary();
return endpoint_client()->associated_group();
diff --git a/chromium/mojo/public/cpp/bindings/lib/interface_serialization.h b/chromium/mojo/public/cpp/bindings/lib/interface_serialization.h
index 88e2f0118b6..858152bf522 100644
--- a/chromium/mojo/public/cpp/bindings/lib/interface_serialization.h
+++ b/chromium/mojo/public/cpp/bindings/lib/interface_serialization.h
@@ -202,8 +202,7 @@ struct Serializer<InterfaceRequestDataView<Base>, InterfaceRequest<T>> {
static bool Deserialize(Handle_Data* input,
InterfaceRequest<T>* output,
SerializationContext* context) {
- *output =
- InterfaceRequest<T>(context->TakeHandleAs<MessagePipeHandle>(*input));
+ context->TakeHandleAsReceiver(*input, output->internal_state());
return true;
}
};
@@ -221,8 +220,7 @@ struct Serializer<InterfaceRequestDataView<Base>, PendingReceiver<T>> {
static bool Deserialize(Handle_Data* input,
PendingReceiver<T>* output,
SerializationContext* context) {
- *output =
- PendingReceiver<T>(context->TakeHandleAs<MessagePipeHandle>(*input));
+ context->TakeHandleAsReceiver(*input, output->internal_state());
return true;
}
};
diff --git a/chromium/mojo/public/cpp/bindings/lib/message.cc b/chromium/mojo/public/cpp/bindings/lib/message.cc
index 29b4d3cc385..46b4d8b745a 100644
--- a/chromium/mojo/public/cpp/bindings/lib/message.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/message.cc
@@ -218,10 +218,11 @@ Message::Message(Message&& other)
associated_endpoint_handles_(
std::move(other.associated_endpoint_handles_)),
transferable_(other.transferable_),
- serialized_(other.serialized_) {
+ serialized_(other.serialized_),
+ heap_profiler_tag_(other.heap_profiler_tag_),
+ receiver_connection_group_(other.receiver_connection_group_) {
other.transferable_ = false;
other.serialized_ = false;
- heap_profiler_tag_ = other.heap_profiler_tag_;
#if defined(ENABLE_IPC_FUZZER)
interface_name_ = other.interface_name_;
method_name_ = other.method_name_;
@@ -243,6 +244,35 @@ Message::Message(uint32_t name,
serialized_ = true;
}
+Message::Message(base::span<const uint8_t> payload,
+ base::span<ScopedHandle> handles) {
+ MojoResult rv = mojo::CreateMessage(&handle_);
+ DCHECK_EQ(MOJO_RESULT_OK, rv);
+ DCHECK(handle_.is_valid());
+
+ void* buffer;
+ uint32_t buffer_size;
+ DCHECK(base::IsValueInRangeForNumericType<uint32_t>(payload.size()));
+ DCHECK(base::IsValueInRangeForNumericType<uint32_t>(handles.size()));
+ MojoAppendMessageDataOptions options;
+ options.struct_size = sizeof(options);
+ options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE;
+ rv = MojoAppendMessageData(
+ handle_->value(), static_cast<uint32_t>(payload.size()),
+ reinterpret_cast<MojoHandle*>(handles.data()),
+ static_cast<uint32_t>(handles.size()), &options, &buffer, &buffer_size);
+ DCHECK_EQ(MOJO_RESULT_OK, rv);
+ // Handle ownership has been taken by MojoAppendMessageData.
+ for (auto& handle : handles)
+ ignore_result(handle.release());
+
+ payload_buffer_ = internal::Buffer(buffer, payload.size(), payload.size());
+ std::copy(payload.begin(), payload.end(),
+ static_cast<uint8_t*>(payload_buffer_.data()));
+ transferable_ = true;
+ serialized_ = true;
+}
+
// static
Message Message::CreateFromMessageHandle(ScopedMessageHandle* message_handle) {
DCHECK(message_handle);
@@ -303,7 +333,8 @@ Message& Message::operator=(Message&& other) {
other.transferable_ = false;
serialized_ = other.serialized_;
other.serialized_ = false;
- other.heap_profiler_tag_ = heap_profiler_tag_;
+ heap_profiler_tag_ = other.heap_profiler_tag_;
+ receiver_connection_group_ = other.receiver_connection_group_;
#if defined(ENABLE_IPC_FUZZER)
interface_name_ = other.interface_name_;
method_name_ = other.method_name_;
@@ -319,6 +350,7 @@ void Message::Reset() {
transferable_ = false;
serialized_ = false;
heap_profiler_tag_ = nullptr;
+ receiver_connection_group_ = nullptr;
}
const uint8_t* Message::payload() const {
diff --git a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc
index 3fc58449c54..9da1f0aa620 100644
--- a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.cc
@@ -372,6 +372,10 @@ void MultiplexRouter::SetMasterInterfaceName(const char* name) {
connector_.SetWatcherHeapProfilerTag(name);
}
+void MultiplexRouter::SetConnectionGroup(ConnectionGroup::Ref ref) {
+ connector_.SetConnectionGroup(std::move(ref));
+}
+
InterfaceId MultiplexRouter::AssociateInterface(
ScopedInterfaceEndpointHandle handle_to_send) {
if (!handle_to_send.pending_association())
@@ -386,7 +390,7 @@ InterfaceId MultiplexRouter::AssociateInterface(
id = next_interface_id_value_++;
if (set_interface_id_namespace_bit_)
id |= kInterfaceIdNamespaceMask;
- } while (base::ContainsKey(endpoints_, id));
+ } while (base::Contains(endpoints_, id));
InterfaceEndpoint* endpoint = new InterfaceEndpoint(this, id);
endpoints_[id] = endpoint;
@@ -438,7 +442,7 @@ void MultiplexRouter::CloseEndpointHandle(
return;
MayAutoLock locker(&lock_);
- DCHECK(base::ContainsKey(endpoints_, id));
+ DCHECK(base::Contains(endpoints_, id));
InterfaceEndpoint* endpoint = endpoints_[id].get();
DCHECK(!endpoint->client());
DCHECK(!endpoint->closed());
@@ -462,7 +466,7 @@ InterfaceEndpointController* MultiplexRouter::AttachEndpointClient(
DCHECK(client);
MayAutoLock locker(&lock_);
- DCHECK(base::ContainsKey(endpoints_, id));
+ DCHECK(base::Contains(endpoints_, id));
InterfaceEndpoint* endpoint = endpoints_[id].get();
endpoint->AttachClient(client, std::move(runner));
@@ -481,7 +485,7 @@ void MultiplexRouter::DetachEndpointClient(
DCHECK(IsValidInterfaceId(id));
MayAutoLock locker(&lock_);
- DCHECK(base::ContainsKey(endpoints_, id));
+ DCHECK(base::Contains(endpoints_, id));
InterfaceEndpoint* endpoint = endpoints_[id].get();
endpoint->DetachClient();
@@ -549,7 +553,7 @@ bool MultiplexRouter::HasAssociatedEndpoints() const {
if (endpoints_.size() == 0)
return false;
- return !base::ContainsKey(endpoints_, kMasterInterfaceId);
+ return !base::Contains(endpoints_, kMasterInterfaceId);
}
void MultiplexRouter::EnableBatchDispatch() {
diff --git a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h
index cca9e1808e9..7152453f37c 100644
--- a/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h
+++ b/chromium/mojo/public/cpp/bindings/lib/multiplex_router.h
@@ -24,6 +24,7 @@
#include "base/sequenced_task_runner.h"
#include "base/synchronization/lock.h"
#include "mojo/public/cpp/bindings/associated_group_controller.h"
+#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/connector.h"
#include "mojo/public/cpp/bindings/filter_chain.h"
#include "mojo/public/cpp/bindings/interface_id.h"
@@ -87,6 +88,11 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) MultiplexRouter
// |name| must be a string literal.
void SetMasterInterfaceName(const char* name);
+ // Adds this object to a ConnectionGroup identified by |ref|. All receiving
+ // pipe endpoints decoded from inbound messages on this MultiplexRouter will
+ // be added to the same group.
+ void SetConnectionGroup(ConnectionGroup::Ref ref);
+
// ---------------------------------------------------------------------------
// The following public methods are safe to call from any sequence.
diff --git a/chromium/mojo/public/cpp/bindings/lib/pending_receiver_state.cc b/chromium/mojo/public/cpp/bindings/lib/pending_receiver_state.cc
new file mode 100644
index 00000000000..c30d0764bf4
--- /dev/null
+++ b/chromium/mojo/public/cpp/bindings/lib/pending_receiver_state.cc
@@ -0,0 +1,29 @@
+// Copyright 2019 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/pending_receiver_state.h"
+
+namespace mojo {
+namespace internal {
+
+PendingReceiverState::PendingReceiverState() = default;
+
+PendingReceiverState::PendingReceiverState(ScopedMessagePipeHandle pipe)
+ : pipe(std::move(pipe)) {}
+
+PendingReceiverState::PendingReceiverState(PendingReceiverState&&) noexcept =
+ default;
+
+PendingReceiverState::~PendingReceiverState() = default;
+
+PendingReceiverState& PendingReceiverState::operator=(
+ PendingReceiverState&&) noexcept = default;
+
+void PendingReceiverState::reset() {
+ pipe.reset();
+ connection_group.reset();
+}
+
+} // namespace internal
+} // namespace mojo
diff --git a/chromium/mojo/public/cpp/bindings/lib/pending_receiver_state.h b/chromium/mojo/public/cpp/bindings/lib/pending_receiver_state.h
new file mode 100644
index 00000000000..3bc34a94a61
--- /dev/null
+++ b/chromium/mojo/public/cpp/bindings/lib/pending_receiver_state.h
@@ -0,0 +1,37 @@
+// Copyright 2019 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_PENDING_RECEIVER_STATE_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_PENDING_RECEIVER_STATE_H_
+
+#include "base/component_export.h"
+#include "mojo/public/cpp/bindings/connection_group.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace mojo {
+namespace internal {
+
+// Generic state owned by every templated InterfaceRequest or PendingReceiver
+// instance.
+struct COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) PendingReceiverState {
+ public:
+ PendingReceiverState();
+ explicit PendingReceiverState(ScopedMessagePipeHandle pipe);
+ PendingReceiverState(const PendingReceiverState&) = delete;
+ PendingReceiverState(PendingReceiverState&&) noexcept;
+ ~PendingReceiverState();
+
+ PendingReceiverState& operator=(const PendingReceiverState&) = delete;
+ PendingReceiverState& operator=(PendingReceiverState&&) noexcept;
+
+ void reset();
+
+ ScopedMessagePipeHandle pipe;
+ ConnectionGroup::Ref connection_group;
+};
+
+} // namespace internal
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_PENDING_RECEIVER_STATE_H_
diff --git a/chromium/mojo/public/cpp/bindings/lib/pending_remote_state.cc b/chromium/mojo/public/cpp/bindings/lib/pending_remote_state.cc
new file mode 100644
index 00000000000..cf99e42ecf8
--- /dev/null
+++ b/chromium/mojo/public/cpp/bindings/lib/pending_remote_state.cc
@@ -0,0 +1,35 @@
+// Copyright 2019 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/pending_remote_state.h"
+
+namespace mojo {
+namespace internal {
+
+PendingRemoteState::PendingRemoteState() = default;
+
+PendingRemoteState::PendingRemoteState(ScopedMessagePipeHandle pipe,
+ uint32_t version)
+ : pipe(std::move(pipe)), version(version) {}
+
+PendingRemoteState::PendingRemoteState(PendingRemoteState&&) noexcept = default;
+
+PendingRemoteState::~PendingRemoteState() = default;
+
+PendingRemoteState& PendingRemoteState::operator=(
+ PendingRemoteState&& other) noexcept {
+ reset();
+ pipe = std::move(other.pipe);
+ version = other.version;
+ other.version = 0;
+ return *this;
+}
+
+void PendingRemoteState::reset() {
+ pipe.reset();
+ version = 0;
+}
+
+} // namespace internal
+} // namespace mojo
diff --git a/chromium/mojo/public/cpp/bindings/lib/pending_remote_state.h b/chromium/mojo/public/cpp/bindings/lib/pending_remote_state.h
new file mode 100644
index 00000000000..ad22f2243f4
--- /dev/null
+++ b/chromium/mojo/public/cpp/bindings/lib/pending_remote_state.h
@@ -0,0 +1,39 @@
+// Copyright 2019 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_PENDING_REMOTE_STATE_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_LIB_PENDING_REMOTE_STATE_H_
+
+#include <stdint.h>
+
+#include "base/component_export.h"
+#include "mojo/public/cpp/bindings/connection_group.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace mojo {
+namespace internal {
+
+// Generic state owned by every templated InterfacePtrInfo or PendingRemote
+// instance.
+struct COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) PendingRemoteState {
+ public:
+ PendingRemoteState();
+ PendingRemoteState(ScopedMessagePipeHandle pipe, uint32_t version);
+ PendingRemoteState(const PendingRemoteState&) = delete;
+ PendingRemoteState(PendingRemoteState&&) noexcept;
+ ~PendingRemoteState();
+
+ PendingRemoteState& operator=(const PendingRemoteState&) = delete;
+ PendingRemoteState& operator=(PendingRemoteState&&) noexcept;
+
+ void reset();
+
+ ScopedMessagePipeHandle pipe;
+ uint32_t version = 0;
+};
+
+} // namespace internal
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_PENDING_REMOTE_STATE_H_
diff --git a/chromium/mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc b/chromium/mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc
index 6543802d2e1..c443c65cf55 100644
--- a/chromium/mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/sequence_local_sync_event_watcher.cc
@@ -18,6 +18,7 @@
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/sequence_local_storage_slot.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "mojo/public/cpp/bindings/sync_event_watcher.h"
namespace mojo {
@@ -60,8 +61,7 @@ class SequenceLocalSyncEventWatcher::SequenceLocalState {
base::WaitableEvent::InitialState::NOT_SIGNALED),
event_watcher_(&event_,
base::BindRepeating(&SequenceLocalState::OnEventSignaled,
- base::Unretained(this))),
- weak_ptr_factory_(this) {
+ base::Unretained(this))) {
// We always allow this event handler to be awoken during any sync event on
// the sequence. Individual watchers still must opt into having such
// wake-ups propagated to them.
@@ -105,7 +105,11 @@ class SequenceLocalSyncEventWatcher::SequenceLocalState {
if (registered_watchers_.empty()) {
// If no more watchers are registered, clear our sequence-local storage.
// Deletes |this|.
- GetStorageSlot().reset();
+ // Check if the current task runner is valid before doing this to avoid
+ // races at shutdown when other objects use SequenceLocalStorageSlot and
+ // indirectly call to here.
+ if (base::SequencedTaskRunnerHandle::IsSet())
+ GetStorageSlot().reset();
}
}
@@ -190,7 +194,7 @@ class SequenceLocalSyncEventWatcher::SequenceLocalState {
base::Lock ready_watchers_lock_;
base::flat_set<const SequenceLocalSyncEventWatcher*> ready_watchers_;
- base::WeakPtrFactory<SequenceLocalState> weak_ptr_factory_;
+ base::WeakPtrFactory<SequenceLocalState> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(SequenceLocalState);
};
diff --git a/chromium/mojo/public/cpp/bindings/lib/serialization_context.cc b/chromium/mojo/public/cpp/bindings/lib/serialization_context.cc
index 267b54154bf..a804cfe3976 100644
--- a/chromium/mojo/public/cpp/bindings/lib/serialization_context.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/serialization_context.cc
@@ -59,6 +59,7 @@ void SerializationContext::AddAssociatedInterfaceInfo(
}
void SerializationContext::TakeHandlesFromMessage(Message* message) {
+ receiver_connection_group_ = message->receiver_connection_group();
handles_.swap(*message->mutable_handles());
associated_endpoint_handles_.swap(
*message->mutable_associated_endpoint_handles());
@@ -72,6 +73,14 @@ mojo::ScopedHandle SerializationContext::TakeHandle(
return std::move(handles_[encoded_handle.value]);
}
+void SerializationContext::TakeHandleAsReceiver(
+ const Handle_Data& encoded_handle,
+ PendingReceiverState* receiver_state) {
+ receiver_state->pipe = TakeHandleAs<MessagePipeHandle>(encoded_handle);
+ if (receiver_connection_group_)
+ receiver_state->connection_group = *receiver_connection_group_;
+}
+
mojo::ScopedInterfaceEndpointHandle
SerializationContext::TakeAssociatedEndpointHandle(
const AssociatedEndpointHandle_Data& encoded_handle) {
diff --git a/chromium/mojo/public/cpp/bindings/lib/serialization_context.h b/chromium/mojo/public/cpp/bindings/lib/serialization_context.h
index 0e3c0788dce..d8fecc4f5b4 100644
--- a/chromium/mojo/public/cpp/bindings/lib/serialization_context.h
+++ b/chromium/mojo/public/cpp/bindings/lib/serialization_context.h
@@ -13,7 +13,9 @@
#include "base/component_export.h"
#include "base/containers/stack_container.h"
#include "base/macros.h"
+#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/pending_receiver_state.h"
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
#include "mojo/public/cpp/system/handle.h"
@@ -51,6 +53,10 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) SerializationContext {
uint32_t version,
AssociatedInterface_Data* out_data);
+ const ConnectionGroup::Ref* receiver_connection_group() const {
+ return receiver_connection_group_;
+ }
+
const std::vector<mojo::ScopedHandle>* handles() { return &handles_; }
std::vector<mojo::ScopedHandle>* mutable_handles() { return &handles_; }
@@ -77,10 +83,19 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) SerializationContext {
return ScopedHandleBase<T>::From(TakeHandle(encoded_handle));
}
+ // Takes a handle from the list of serialized handle data and stuffs it into
+ // the internal data of an InterfaceRequest or PendingReceiver.
+ void TakeHandleAsReceiver(const Handle_Data& encoded_handle,
+ PendingReceiverState* receiver_state);
+
mojo::ScopedInterfaceEndpointHandle TakeAssociatedEndpointHandle(
const AssociatedEndpointHandle_Data& encoded_handle);
private:
+ // The ConnectionGroup to which deserialized PendingReceivers should be added,
+ // if any.
+ const ConnectionGroup::Ref* receiver_connection_group_ = nullptr;
+
// Handles owned by this object. Used during serialization to hold onto
// handles accumulated during pre-serialization, and used during
// deserialization to hold onto handles extracted from a message.
diff --git a/chromium/mojo/public/cpp/bindings/lib/sync_handle_registry.cc b/chromium/mojo/public/cpp/bindings/lib/sync_handle_registry.cc
index 3278a76a676..b91d5f9c29c 100644
--- a/chromium/mojo/public/cpp/bindings/lib/sync_handle_registry.cc
+++ b/chromium/mojo/public/cpp/bindings/lib/sync_handle_registry.cc
@@ -36,7 +36,7 @@ bool SyncHandleRegistry::RegisterHandle(const Handle& handle,
const HandleCallback& callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (base::ContainsKey(handles_, handle))
+ if (base::Contains(handles_, handle))
return false;
MojoResult result = wait_set_.AddHandle(handle, handle_signals);
@@ -49,7 +49,7 @@ bool SyncHandleRegistry::RegisterHandle(const Handle& handle,
void SyncHandleRegistry::UnregisterHandle(const Handle& handle) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!base::ContainsKey(handles_, handle))
+ if (!base::Contains(handles_, handle))
return;
MojoResult result = wait_set_.RemoveHandle(handle);
@@ -85,17 +85,14 @@ void SyncHandleRegistry::UnregisterEvent(base::WaitableEvent* event,
// Not safe to remove any elements from |callbacks| here since an outer
// stack frame is currently iterating over it in Wait().
for (auto& cb : callbacks) {
- if (cb.Equals(callback))
+ if (cb == callback)
cb.Reset();
else if (cb)
has_valid_callbacks = true;
}
remove_invalid_event_callbacks_after_dispatch_ = true;
} else {
- callbacks.erase(std::remove_if(callbacks.begin(), callbacks.end(),
- [&callback](const base::Closure& cb) {
- return cb.Equals(callback);
- }),
+ callbacks.erase(std::remove(callbacks.begin(), callbacks.end(), callback),
callbacks.end());
if (callbacks.empty())
events_.erase(it);
diff --git a/chromium/mojo/public/cpp/bindings/message.h b/chromium/mojo/public/cpp/bindings/message.h
index 4ff8a6b5e63..1d359526357 100644
--- a/chromium/mojo/public/cpp/bindings/message.h
+++ b/chromium/mojo/public/cpp/bindings/message.h
@@ -16,8 +16,10 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/component_export.h"
+#include "base/containers/span.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
+#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/lib/buffer.h"
#include "mojo/public/cpp/bindings/lib/message_internal.h"
#include "mojo/public/cpp/bindings/lib/unserialized_message_context.h"
@@ -68,6 +70,14 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) Message {
size_t payload_interface_id_count,
std::vector<ScopedHandle>* handles);
+ // Constructs a new serialized Message object from a fully populated message
+ // payload (including a well-formed message header) and an optional set of
+ // handle attachments. This Message may not be extended with additional
+ // payload or handles once constructed, but its payload remains mutable as
+ // long as the Message is not moved and neither |Reset()| nor
+ // |TakeMojoMessage()| is called.
+ Message(base::span<const uint8_t> payload, base::span<ScopedHandle> handles);
+
// Constructs a new serialized Message object from an existing
// ScopedMessageHandle; e.g., one read from a message pipe.
//
@@ -178,6 +188,17 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) Message {
return &associated_endpoint_handles_;
}
+ // Sets the ConnectionGroup to which this Message's local receiver belongs, if
+ // any. This is called immediately after a Message is read from a message pipe
+ // but before it's deserialized. If non-null, |ref| must point to a Ref that
+ // outlives this Message object.
+ void set_receiver_connection_group(const ConnectionGroup::Ref* ref) {
+ receiver_connection_group_ = ref;
+ }
+ const ConnectionGroup::Ref* receiver_connection_group() const {
+ return receiver_connection_group_;
+ }
+
// Takes ownership of any handles within |*context| and attaches them to this
// Message.
void AttachHandlesFromSerializationContext(
@@ -268,6 +289,11 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) Message {
const char* method_name_ = nullptr;
#endif
+ // A reference to the ConnectionGroup to which the receiver of this Message
+ // belongs, if any. Only set if this Message was just read off of a message
+ // pipe and is about to be deserialized.
+ const ConnectionGroup::Ref* receiver_connection_group_ = nullptr;
+
DISALLOW_COPY_AND_ASSIGN(Message);
};
diff --git a/chromium/mojo/public/cpp/bindings/pending_receiver.h b/chromium/mojo/public/cpp/bindings/pending_receiver.h
index 9d02333fe50..bffc6e90170 100644
--- a/chromium/mojo/public/cpp/bindings/pending_receiver.h
+++ b/chromium/mojo/public/cpp/bindings/pending_receiver.h
@@ -8,7 +8,11 @@
#include <utility>
#include "base/macros.h"
+#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/lib/bindings_internal.h"
+#include "mojo/public/cpp/bindings/lib/pending_receiver_state.h"
+#include "mojo/public/cpp/bindings/lib/serialization_context.h"
#include "mojo/public/cpp/system/message_pipe.h"
namespace mojo {
@@ -49,7 +53,7 @@ class PendingReceiver {
// Constructs a valid PendingReceiver from a valid raw message pipe handle.
explicit PendingReceiver(ScopedMessagePipeHandle pipe)
- : pipe_(std::move(pipe)) {}
+ : state_(std::move(pipe)) {}
~PendingReceiver() = default;
@@ -64,14 +68,14 @@ class PendingReceiver {
// Indicates whether the PendingReceiver is valid, meaning it can ne used to
// bind a Receiver that wants to begin dispatching method calls made by the
// entangled Remote.
- bool is_valid() const { return pipe_.is_valid(); }
+ bool is_valid() const { return state_.pipe.is_valid(); }
explicit operator bool() const { return is_valid(); }
// Resets this PendingReceiver to an invalid state. If it was entangled with a
// Remote or PendingRemote, that object remains in a valid state and will
// eventually detect that its receiver is gone. Any calls it makes will
// effectively be dropped.
- void reset() { pipe_.reset(); }
+ void reset() { state_.reset(); }
// Like above but provides a reason for the disconnection.
void ResetWithReason(uint32_t reason, const std::string& description) {
@@ -83,11 +87,30 @@ class PendingReceiver {
// call, the PendingReceiver is no longer in a valid state and can no longer
// be used to bind a Receiver.
ScopedMessagePipeHandle PassPipe() WARN_UNUSED_RESULT {
- return std::move(pipe_);
+ return std::move(state_.pipe);
}
+ // Assigns this PendingReceiver to the ConnectionGroup referenced by |ref|.
+ // Any Receiver which binds this PendingReceiver will inherit the Ref.
+ void set_connection_group(ConnectionGroup::Ref ref) {
+ state_.connection_group = std::move(ref);
+ }
+
+ const ConnectionGroup::Ref& connection_group() const {
+ return state_.connection_group;
+ }
+
+ // Passes ownership of this PendingReceiver's ConnectionGroup Ref, removing it
+ // from its group.
+ ConnectionGroup::Ref PassConnectionGroupRef() {
+ return std::move(state_.connection_group);
+ }
+
+ // For internal Mojo use only.
+ internal::PendingReceiverState* internal_state() { return &state_; }
+
private:
- ScopedMessagePipeHandle pipe_;
+ internal::PendingReceiverState state_;
DISALLOW_COPY_AND_ASSIGN(PendingReceiver);
};
diff --git a/chromium/mojo/public/cpp/bindings/pending_remote.h b/chromium/mojo/public/cpp/bindings/pending_remote.h
index 4141633489b..e2788ce7c55 100644
--- a/chromium/mojo/public/cpp/bindings/pending_remote.h
+++ b/chromium/mojo/public/cpp/bindings/pending_remote.h
@@ -12,6 +12,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "mojo/public/cpp/bindings/interface_ptr_info.h"
+#include "mojo/public/cpp/bindings/lib/pending_remote_state.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/system/message_pipe.h"
@@ -56,7 +57,7 @@ class PendingRemote {
// Constructs a valid PendingRemote over a valid raw message pipe handle and
// expected interface version number.
PendingRemote(ScopedMessagePipeHandle pipe, uint32_t version)
- : pipe_(std::move(pipe)), version_(version) {}
+ : state_(std::move(pipe), version) {}
~PendingRemote() = default;
@@ -65,7 +66,7 @@ class PendingRemote {
// Indicates whether the PendingRemote is valid, meaning it can be used to
// bind a Remote that wants to begin issuing method calls to be dispatched by
// the entangled Receiver.
- bool is_valid() const { return pipe_.is_valid(); }
+ bool is_valid() const { return state_.pipe.is_valid(); }
explicit operator bool() const { return is_valid(); }
// Temporary helper for transitioning away from old bindings types. This is
@@ -77,23 +78,20 @@ class PendingRemote {
// Resets this PendingRemote to an invalid state. If it was entangled with a
// Receiver or PendingReceiver, that object remains in a valid state and will
// eventually detect that its remote caller is gone.
- void reset() {
- pipe_.reset();
- version_ = 0;
- }
+ void reset() { state_.reset(); }
// Takes ownership of this PendingRemote's message pipe handle. After this
// call, the PendingRemote is no longer in a valid state and can no longer be
// used to bind a Remote.
ScopedMessagePipeHandle PassPipe() WARN_UNUSED_RESULT {
- version_ = 0;
- return std::move(pipe_);
+ state_.version = 0;
+ return std::move(state_.pipe);
}
// The version of the interface this Remote is assuming when making method
// calls. For the most common case of unversioned mojom interfaces, this is
// always zero.
- uint32_t version() const { return version_; }
+ uint32_t version() const { return state_.version; }
// Creates a new message pipe, retaining one end in the PendingRemote (making
// it valid) and returning the other end as its entangled PendingReceiver. May
@@ -102,13 +100,15 @@ class PendingRemote {
WARN_UNUSED_RESULT {
DCHECK(!is_valid()) << "PendingRemote already has a receiver";
MessagePipe pipe;
- pipe_ = std::move(pipe.handle0);
+ state_.pipe = std::move(pipe.handle0);
return PendingReceiver<Interface>(std::move(pipe.handle1));
}
+ // For internal Mojo use only.
+ internal::PendingRemoteState* internal_state() { return &state_; }
+
private:
- ScopedMessagePipeHandle pipe_;
- uint32_t version_ = 0;
+ internal::PendingRemoteState state_;
DISALLOW_COPY_AND_ASSIGN(PendingRemote);
};
diff --git a/chromium/mojo/public/cpp/bindings/receiver.h b/chromium/mojo/public/cpp/bindings/receiver.h
index d30c5d15b54..0bac69338bc 100644
--- a/chromium/mojo/public/cpp/bindings/receiver.h
+++ b/chromium/mojo/public/cpp/bindings/receiver.h
@@ -14,6 +14,7 @@
#include "base/memory/scoped_refptr.h"
#include "base/sequenced_task_runner.h"
#include "mojo/public/cpp/bindings/connection_error_callback.h"
+#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "mojo/public/cpp/bindings/lib/binding_state.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
@@ -154,10 +155,12 @@ class Receiver {
// Receiver.
void Bind(PendingReceiver<Interface> pending_receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
- if (pending_receiver)
- internal_state_.Bind(pending_receiver.PassPipe(), std::move(task_runner));
- else
+ if (pending_receiver) {
+ internal_state_.Bind(pending_receiver.internal_state(),
+ std::move(task_runner));
+ } else {
reset();
+ }
}
// Unbinds this Receiver, preventing any further |impl| method calls or
diff --git a/chromium/mojo/public/cpp/bindings/receiver_set.h b/chromium/mojo/public/cpp/bindings/receiver_set.h
index 5019554903c..cf740d2695a 100644
--- a/chromium/mojo/public/cpp/bindings/receiver_set.h
+++ b/chromium/mojo/public/cpp/bindings/receiver_set.h
@@ -94,7 +94,7 @@ class ReceiverSetBase {
using Context = typename ContextTraits::Type;
using PreDispatchCallback = base::RepeatingCallback<void(const Context&)>;
- ReceiverSetBase() : weak_ptr_factory_(this) {}
+ ReceiverSetBase() = default;
// Sets a callback to be invoked any time a receiver in the set is
// disconnected. The callback is invoked *after* the receiver in question
@@ -230,6 +230,13 @@ class ReceiverSetBase {
current_receiver());
}
+ void FlushForTesting() {
+ for (const auto& it : receivers_) {
+ if (it.second)
+ it.second->FlushForTesting();
+ }
+ }
+
private:
friend class Entry;
@@ -252,6 +259,8 @@ class ReceiverSetBase {
base::BindOnce(&Entry::OnDisconnect, base::Unretained(this)));
}
+ void FlushForTesting() { receiver_.FlushForTesting(); }
+
private:
class DispatchFilter : public MessageReceiver {
public:
@@ -329,7 +338,7 @@ class ReceiverSetBase {
std::map<ReceiverId, std::unique_ptr<Entry>> receivers_;
const Context* current_context_ = nullptr;
ReceiverId current_receiver_;
- base::WeakPtrFactory<ReceiverSetBase> weak_ptr_factory_;
+ base::WeakPtrFactory<ReceiverSetBase> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(ReceiverSetBase);
};
@@ -338,14 +347,6 @@ class ReceiverSetBase {
template <typename Interface, typename ContextType = void>
using ReceiverSet = ReceiverSetBase<Receiver<Interface>, ContextType>;
-// Helper for a set of Receivers where each bound Receiver is tied to an owned
-// implementation. The |Add()| method takes a std::unique_ptr<Interface> for
-// each bound implementation.
-template <typename Interface, typename ContextType = void>
-using OwnedReceiverSet =
- ReceiverSetBase<Receiver<Interface, UniquePtrImplRefTraits<Interface>>,
- ContextType>;
-
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_RECEIVER_SET_H_
diff --git a/chromium/mojo/public/cpp/bindings/remote.h b/chromium/mojo/public/cpp/bindings/remote.h
index f709d03352c..60744438cbf 100644
--- a/chromium/mojo/public/cpp/bindings/remote.h
+++ b/chromium/mojo/public/cpp/bindings/remote.h
@@ -14,6 +14,7 @@
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequenced_task_runner.h"
+#include "base/time/time.h"
#include "mojo/public/cpp/bindings/interface_ptr_info.h"
#include "mojo/public/cpp/bindings/lib/interface_ptr_state.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
@@ -151,6 +152,54 @@ class Remote {
std::move(handler));
}
+ // A convenient helper that resets this Remote on disconnect. Note that this
+ // replaces any previously set disconnection handler.
+ void reset_on_disconnect() {
+ if (!is_connected()) {
+ reset();
+ return;
+ }
+ set_disconnect_handler(
+ base::BindOnce(&Remote::reset, base::Unretained(this)));
+ }
+
+ // Sets a Closure to be invoked if the receiving endpoint reports itself as
+ // idle and there are no in-flight messages it has yet to acknowledge, and
+ // this state occurs continuously for a duration of at least |timeout|. The
+ // first time this is called, it must be called BEFORE sending any interface
+ // messages to the receiver. It may be called any number of times after that
+ // to reconfigure the idle timeout period or assign a new idle handler.
+ //
+ // Once called, the interface connection incurs some permanent additional
+ // per-message overhead to help track idle state across the interface
+ // boundary.
+ //
+ // Whenever this callback is invoked, the following conditions are guaranteed
+ // to hold:
+ //
+ // - There are no messages sent on this Remote that have not already been
+ // dispatched by the receiver.
+ // - The receiver has explicitly notified us that it considers itself to be
+ // "idle."
+ // - The receiver has not dispatched any additional messages since sending
+ // this idle notification
+ // - The Remote does not have any outstanding reply callbacks that haven't
+ // been called yet
+ // - All of the above has been true continuously for a duration of at least
+ // |timeout|.
+ //
+ void set_idle_handler(base::TimeDelta timeout,
+ base::RepeatingClosure handler) {
+ internal_state_.set_idle_handler(timeout, std::move(handler));
+ }
+
+ // A convenient helper for common idle timeout behavior. This is equivalent to
+ // calling |set_idle_handler| with a handler that only resets this Remote.
+ void reset_on_idle_timeout(base::TimeDelta timeout) {
+ set_idle_handler(
+ timeout, base::BindRepeating(&Remote::reset, base::Unretained(this)));
+ }
+
// Resets this Remote to an unbound state. To reset the Remote and recover an
// PendingRemote that can be bound again later, use |Unbind()| instead.
void reset() {
@@ -213,8 +262,7 @@ class Remote {
return;
}
- internal_state_.Bind(InterfacePtrInfo<Interface>(pending_remote.PassPipe(),
- pending_remote.version()),
+ internal_state_.Bind(pending_remote.internal_state(),
std::move(task_runner));
// Force the internal state to configure its proxy. Unlike InterfacePtr we
@@ -270,6 +318,12 @@ class Remote {
internal_state_.FlushAsyncForTesting(std::move(callback));
}
+ // Returns the number of unacknowledged messages sent by this Remote. Only
+ // non-zero when |set_idle_handler()| has been called.
+ unsigned int GetNumUnackedMessagesForTesting() const {
+ return internal_state_.GetNumUnackedMessagesForTesting();
+ }
+
// DO NOT USE. Exposed only for internal use and for testing.
internal::InterfacePtrState<Interface>* internal_state() {
return &internal_state_;
diff --git a/chromium/mojo/public/cpp/bindings/remote_set.h b/chromium/mojo/public/cpp/bindings/remote_set.h
new file mode 100644
index 00000000000..82a00999c23
--- /dev/null
+++ b/chromium/mojo/public/cpp/bindings/remote_set.h
@@ -0,0 +1,162 @@
+// Copyright 2019 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_REMOTE_SET_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_REMOTE_SET_H_
+
+#include <iterator>
+#include <set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "base/util/type_safety/id_type.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+namespace mojo {
+
+namespace internal {
+struct RemoteSetElementIdTypeTag {};
+} // namespace internal
+
+using RemoteSetElementId = util::IdTypeU32<internal::RemoteSetElementIdTypeTag>;
+
+// Shared implementation of a set of remotes, used by both RemoteSet and
+// AssociatedRemoteSet aliases (see below).
+//
+// A RemoteSet or AssociatedRemoteSet is a collection of remote interface
+// endpoints whose lifetime is conveniently managed by the set, i.e., remotes
+// are removed from the set automatically when losing a connection).
+template <typename Interface,
+ template <typename>
+ class RemoteType,
+ template <typename>
+ class PendingRemoteType>
+class RemoteSetImpl {
+ public:
+ using Storage = std::map<RemoteSetElementId, RemoteType<Interface>>;
+
+ // An iterator definition to support range-for iteration over RemoteSet
+ // objects. An iterator can be dereferenced to get at the Remote, and |id()|
+ // can be called to get the element's ID (for e.g. later removal).
+ struct Iterator {
+ using self_type = Iterator;
+ using value_type = RemoteType<Interface>;
+ using reference = const value_type&;
+ using pointer = const value_type*;
+ using iterator_category = std::bidirectional_iterator_tag;
+ using difference_type = std::ptrdiff_t;
+
+ explicit Iterator(typename Storage::const_iterator it) : it_(it) {}
+
+ self_type& operator++() {
+ ++it_;
+ return *this;
+ }
+ self_type operator++(int) {
+ self_type result(*this);
+ ++(*this);
+ return result;
+ }
+ self_type& operator--() {
+ --it_;
+ return *this;
+ }
+ self_type operator--(int) {
+ self_type result(*this);
+ --(*this);
+ return result;
+ }
+
+ RemoteSetElementId id() const { return it_.first; }
+
+ reference operator*() const { return it_->second; }
+ pointer operator->() const { return &it_->second; }
+ bool operator==(const self_type& rhs) { return it_ == rhs.it_; }
+ bool operator!=(const self_type& rhs) { return it_ != rhs.it_; }
+
+ private:
+ typename Storage::const_iterator it_;
+ };
+
+ RemoteSetImpl() = default;
+ ~RemoteSetImpl() = default;
+
+ // Adds a new remote to this set and returns a unique ID that can be used to
+ // identify the remote later.
+ RemoteSetElementId Add(RemoteType<Interface> remote) {
+ auto id = GenerateNextElementId();
+ remote.set_disconnect_handler(base::BindOnce(&RemoteSetImpl::OnDisconnect,
+ base::Unretained(this), id));
+ auto result = storage_.emplace(id, std::move(remote));
+ DCHECK(result.second);
+ return id;
+ }
+
+ // Same as above but for the equivalent pending remote type, for convenience.
+ RemoteSetElementId Add(PendingRemoteType<Interface> remote) {
+ return Add(RemoteType<Interface>(std::move(remote)));
+ }
+
+ // Removes a remote from the set given |id|, if present.
+ void Remove(RemoteSetElementId id) { storage_.erase(id); }
+
+ // Indicates whether a remote with the given ID is present in the set.
+ bool Contains(RemoteSetElementId id) { return base::Contains(storage_, id); }
+
+ // Sets a callback to invoke any time a remote in the set is disconnected.
+ // Note that the remote in question is already removed from the set by the
+ // time the callback is run for its disconnection.
+ using DisconnectHandler = base::RepeatingCallback<void(RemoteSetElementId)>;
+ void set_disconnect_handler(DisconnectHandler handler) {
+ disconnect_handler_ = std::move(handler);
+ }
+
+ void Clear() { storage_.clear(); }
+
+ bool empty() const { return storage_.empty(); }
+ Iterator begin() { return Iterator(storage_.begin()); }
+ Iterator begin() const { return Iterator(storage_.begin()); }
+ Iterator end() { return Iterator(storage_.end()); }
+ Iterator end() const { return Iterator(storage_.end()); }
+
+ void FlushForTesting() {
+ for (auto& it : storage_) {
+ it.second.FlushForTesting();
+ }
+ }
+
+ private:
+ RemoteSetElementId GenerateNextElementId() {
+ return RemoteSetElementId::FromUnsafeValue(next_element_id_++);
+ }
+
+ void OnDisconnect(RemoteSetElementId id) {
+ Remove(id);
+ if (disconnect_handler_)
+ disconnect_handler_.Run(id);
+ }
+
+ uint32_t next_element_id_ = 1;
+ Storage storage_;
+ DisconnectHandler disconnect_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteSetImpl);
+};
+
+template <typename Interface>
+using RemoteSet = RemoteSetImpl<Interface, Remote, PendingRemote>;
+
+template <typename Interface>
+using AssociatedRemoteSet =
+ RemoteSetImpl<Interface, AssociatedRemote, PendingAssociatedRemote>;
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_REMOTE_SET_H_
diff --git a/chromium/mojo/public/cpp/bindings/strong_associated_binding.h b/chromium/mojo/public/cpp/bindings/strong_associated_binding.h
index dceb21f025e..f017956f334 100644
--- a/chromium/mojo/public/cpp/bindings/strong_associated_binding.h
+++ b/chromium/mojo/public/cpp/bindings/strong_associated_binding.h
@@ -43,9 +43,6 @@ using StrongAssociatedBindingPtr =
template <typename Interface>
class StrongAssociatedBinding {
public:
- using ImplPointerType =
- typename AssociatedBinding<Interface>::ImplPointerType;
-
// Create a new StrongAssociatedBinding instance. The instance owns itself,
// cleaning up only in the event of a pipe connection error. Returns a WeakPtr
// to the new StrongAssociatedBinding instance.
@@ -87,8 +84,11 @@ class StrongAssociatedBinding {
void FlushForTesting() { binding_.FlushForTesting(); }
// Allows test code to swap the interface implementation.
- ImplPointerType SwapImplForTesting(ImplPointerType new_impl) {
- return binding_.SwapImplForTesting(new_impl);
+ std::unique_ptr<Interface> SwapImplForTesting(
+ std::unique_ptr<Interface> new_impl) {
+ binding_.SwapImplForTesting(new_impl.get());
+ impl_.swap(new_impl);
+ return new_impl;
}
private:
diff --git a/chromium/mojo/public/cpp/bindings/strong_binding.h b/chromium/mojo/public/cpp/bindings/strong_binding.h
index 441ce9baf22..a0fe6214772 100644
--- a/chromium/mojo/public/cpp/bindings/strong_binding.h
+++ b/chromium/mojo/public/cpp/bindings/strong_binding.h
@@ -104,8 +104,7 @@ class StrongBinding {
InterfaceRequest<Interface> request,
scoped_refptr<base::SequencedTaskRunner> task_runner)
: impl_(std::move(impl)),
- binding_(impl_.get(), std::move(request), std::move(task_runner)),
- weak_factory_(this) {
+ binding_(impl_.get(), std::move(request), std::move(task_runner)) {
binding_.set_connection_error_with_reason_handler(
base::Bind(&StrongBinding::OnConnectionError, base::Unretained(this)));
}
@@ -127,7 +126,7 @@ class StrongBinding {
base::OnceClosure connection_error_handler_;
ConnectionErrorWithReasonCallback connection_error_with_reason_handler_;
Binding<Interface> binding_;
- base::WeakPtrFactory<StrongBinding> weak_factory_;
+ base::WeakPtrFactory<StrongBinding> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(StrongBinding);
};
diff --git a/chromium/mojo/public/cpp/bindings/struct_ptr.h b/chromium/mojo/public/cpp/bindings/struct_ptr.h
index 4dcddd15f55..50533e9a300 100644
--- a/chromium/mojo/public/cpp/bindings/struct_ptr.h
+++ b/chromium/mojo/public/cpp/bindings/struct_ptr.h
@@ -99,10 +99,6 @@ class StructPtr {
explicit operator bool() const { return !is_null(); }
- bool operator<(const StructPtr& other) const {
- return Hash(internal::kHashSeed) < other.Hash(internal::kHashSeed);
- }
-
private:
friend class internal::StructPtrWTFHelper<Struct>;
void Take(StructPtr* other) {
@@ -115,32 +111,23 @@ class StructPtr {
DISALLOW_COPY_AND_ASSIGN(StructPtr);
};
-template <typename T>
-bool operator==(const StructPtr<T>& lhs, const StructPtr<T>& rhs) {
- return lhs.Equals(rhs);
-}
-template <typename T>
-bool operator!=(const StructPtr<T>& lhs, const StructPtr<T>& rhs) {
- return !(lhs == rhs);
-}
-
// Designed to be used when Struct is small and copyable.
template <typename S>
class InlinedStructPtr {
public:
using Struct = S;
- InlinedStructPtr() : state_(NIL) {}
- InlinedStructPtr(std::nullptr_t) : state_(NIL) {}
+ InlinedStructPtr() = default;
+ InlinedStructPtr(std::nullptr_t) {}
- ~InlinedStructPtr() {}
+ ~InlinedStructPtr() = default;
InlinedStructPtr& operator=(std::nullptr_t) {
reset();
return *this;
}
- InlinedStructPtr(InlinedStructPtr&& other) : state_(NIL) { Take(&other); }
+ InlinedStructPtr(InlinedStructPtr&& other) { Take(&other); }
InlinedStructPtr& operator=(InlinedStructPtr&& other) {
Take(&other);
return *this;
@@ -198,10 +185,6 @@ class InlinedStructPtr {
explicit operator bool() const { return !is_null(); }
- bool operator<(const InlinedStructPtr& other) const {
- return Hash(internal::kHashSeed) < other.Hash(internal::kHashSeed);
- }
-
private:
friend class internal::InlinedStructPtrWTFHelper<Struct>;
void Take(InlinedStructPtr* other) {
@@ -210,28 +193,17 @@ class InlinedStructPtr {
}
enum State {
- VALID,
NIL,
+ VALID,
DELETED, // For use in WTF::HashMap only
};
mutable Struct value_;
- State state_;
+ State state_ = NIL;
DISALLOW_COPY_AND_ASSIGN(InlinedStructPtr);
};
-template <typename T>
-bool operator==(const InlinedStructPtr<T>& lhs,
- const InlinedStructPtr<T>& rhs) {
- return lhs.Equals(rhs);
-}
-template <typename T>
-bool operator!=(const InlinedStructPtr<T>& lhs,
- const InlinedStructPtr<T>& rhs) {
- return !(lhs == rhs);
-}
-
namespace internal {
template <typename Struct>
@@ -269,7 +241,56 @@ class InlinedStructPtrWTFHelper {
}
};
+// Convenience type trait so that we can get away with defining the comparison
+// operators only once.
+template <typename T>
+struct IsStructPtrImpl : std::false_type {};
+
+template <typename S>
+struct IsStructPtrImpl<StructPtr<S>> : std::true_type {};
+
+template <typename S>
+struct IsStructPtrImpl<InlinedStructPtr<S>> : std::true_type {};
+
} // namespace internal
+
+template <typename T>
+constexpr bool IsStructPtrV = internal::IsStructPtrImpl<std::decay_t<T>>::value;
+
+template <typename Ptr, std::enable_if_t<IsStructPtrV<Ptr>>* = nullptr>
+bool operator==(const Ptr& lhs, const Ptr& rhs) {
+ return lhs.Equals(rhs);
+}
+
+template <typename Ptr, std::enable_if_t<IsStructPtrV<Ptr>>* = nullptr>
+bool operator!=(const Ptr& lhs, const Ptr& rhs) {
+ return !(lhs == rhs);
+}
+
+// Perform a deep comparison if possible. Otherwise treat null pointers less
+// than valid pointers.
+template <typename Ptr, std::enable_if_t<IsStructPtrV<Ptr>>* = nullptr>
+bool operator<(const Ptr& lhs, const Ptr& rhs) {
+ if (!lhs || !rhs)
+ return bool{lhs} < bool{rhs};
+ return *lhs < *rhs;
+}
+
+template <typename Ptr, std::enable_if_t<IsStructPtrV<Ptr>>* = nullptr>
+bool operator<=(const Ptr& lhs, const Ptr& rhs) {
+ return !(rhs < lhs);
+}
+
+template <typename Ptr, std::enable_if_t<IsStructPtrV<Ptr>>* = nullptr>
+bool operator>(const Ptr& lhs, const Ptr& rhs) {
+ return rhs < lhs;
+}
+
+template <typename Ptr, std::enable_if_t<IsStructPtrV<Ptr>>* = nullptr>
+bool operator>=(const Ptr& lhs, const Ptr& rhs) {
+ return !(lhs < rhs);
+}
+
} // namespace mojo
namespace std {
diff --git a/chromium/mojo/public/cpp/bindings/tests/BUILD.gn b/chromium/mojo/public/cpp/bindings/tests/BUILD.gn
index 73c5ba421b9..709abe86c68 100644
--- a/chromium/mojo/public/cpp/bindings/tests/BUILD.gn
+++ b/chromium/mojo/public/cpp/bindings/tests/BUILD.gn
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//mojo/public/tools/bindings/mojom.gni")
+
source_set("tests") {
testonly = true
@@ -12,6 +14,7 @@ source_set("tests") {
"bindings_test_base.h",
"buffer_unittest.cc",
"callback_helpers_unittest.cc",
+ "connection_group_unittest.cc",
"connector_unittest.cc",
"constant_unittest.cc",
"container_test_util.cc",
@@ -20,10 +23,12 @@ source_set("tests") {
"equals_unittest.cc",
"handle_passing_unittest.cc",
"hash_unittest.cc",
+ "idle_tracking_unittest.cc",
"lazy_serialization_unittest.cc",
"map_unittest.cc",
"message_queue.cc",
"message_queue.h",
+ "message_unittest.cc",
"multiplex_router_unittest.cc",
"native_struct_unittest.cc",
"new_endpoint_types_unittest.cc",
@@ -50,6 +55,7 @@ source_set("tests") {
deps = [
":mojo_public_bindings_test_utils",
+ ":test_mojom",
"//base/test:test_support",
"//mojo/core/embedder",
"//mojo/public/cpp/bindings",
@@ -98,6 +104,7 @@ if (!is_ios) {
]
deps = [
+ "//base/test:test_support",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
"//mojo/public/interfaces/bindings/tests:test_export_blink_component",
@@ -123,6 +130,16 @@ source_set("struct_with_traits_impl") {
]
}
+mojom("test_mojom") {
+ testonly = true
+ sources = [
+ "connection_group_unittest.test-mojom",
+ "idle_tracking_unittest.test-mojom",
+ ]
+
+ support_lazy_serialization = true
+}
+
source_set("perftests") {
testonly = true
diff --git a/chromium/mojo/public/cpp/bindings/unique_associated_receiver_set.h b/chromium/mojo/public/cpp/bindings/unique_associated_receiver_set.h
new file mode 100644
index 00000000000..cabffa441f2
--- /dev/null
+++ b/chromium/mojo/public/cpp/bindings/unique_associated_receiver_set.h
@@ -0,0 +1,39 @@
+// Copyright 2019 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_UNIQUE_ASSOCIATED_RECEIVER_SET_H_
+#define MOJO_PUBLIC_CPP_BINDINGS_UNIQUE_ASSOCIATED_RECEIVER_SET_H_
+
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/unique_ptr_impl_ref_traits.h"
+
+namespace mojo {
+
+template <typename Interface, typename ImplRefTraits>
+struct ReceiverSetTraits<AssociatedReceiver<Interface, ImplRefTraits>> {
+ using InterfaceType = Interface;
+ using PendingType = PendingAssociatedReceiver<Interface>;
+ using ImplPointerType = typename ImplRefTraits::PointerType;
+};
+
+// This class manages a set of associated receiving endpoints where each
+// endpoint is bound to a unique implementation of the interface owned by this
+// object. That is to say, for every bound AssociatedReceiver<T> in the set,
+// there is a dedicated unique_ptr<T> owned by the set and receiving messages.
+//
+// Each owned implementation of T has its lifetime automatically managed by the
+// UniqueAssociatedReceiverSet, destroying an instance whenever its receiver is
+// disconnected because the remote endpoint intentionally hung up, crashed, or
+// sent malformed message.
+template <typename Interface,
+ typename ContextType = void,
+ typename Deleter = std::default_delete<Interface>>
+using UniqueAssociatedReceiverSet = ReceiverSetBase<
+ AssociatedReceiver<Interface, UniquePtrImplRefTraits<Interface, Deleter>>,
+ ContextType>;
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_BINDINGS_UNIQUE_ASSOCIATED_RECEIVER_SET_H_
diff --git a/chromium/mojo/public/cpp/platform/BUILD.gn b/chromium/mojo/public/cpp/platform/BUILD.gn
index 79c017608d8..8e1e014ede7 100644
--- a/chromium/mojo/public/cpp/platform/BUILD.gn
+++ b/chromium/mojo/public/cpp/platform/BUILD.gn
@@ -8,7 +8,6 @@ component("platform") {
output_name = "mojo_cpp_platform"
public = [
- "features.h",
"platform_channel.h",
"platform_channel_endpoint.h",
"platform_channel_server_endpoint.h",
@@ -16,7 +15,6 @@ component("platform") {
]
sources = [
- "features.cc",
"named_platform_channel_win.cc",
"platform_channel.cc",
"platform_channel_endpoint.cc",
@@ -24,7 +22,7 @@ component("platform") {
"platform_handle.cc",
]
- if (is_posix && (!is_nacl || is_nacl_nonsfi)) {
+ if (is_posix && !is_mac && (!is_nacl || is_nacl_nonsfi)) {
public += [ "socket_utils_posix.h" ]
sources += [ "socket_utils_posix.cc" ]
}
@@ -34,7 +32,7 @@ component("platform") {
"//mojo/public/c/system:headers",
]
- if (is_posix && !is_nacl) {
+ if (is_posix && !is_nacl && !is_mac) {
sources += [ "named_platform_channel_posix.cc" ]
}
diff --git a/chromium/mojo/public/cpp/platform/features.cc b/chromium/mojo/public/cpp/platform/features.cc
deleted file mode 100644
index 79bdd62c41f..00000000000
--- a/chromium/mojo/public/cpp/platform/features.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2019 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/platform/features.h"
-
-namespace mojo {
-namespace features {
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-// Enables the ChannelMac implementation, which uses Mach IPC as the underlying
-// transport mechanism for PlatformChannel. Otherwise, macOS defaults to using
-// ChannelPosix.
-const base::Feature kMojoChannelMac{"MojoChannelMac",
- base::FEATURE_DISABLED_BY_DEFAULT};
-#endif
-
-} // namespace features
-} // namespace mojo
diff --git a/chromium/mojo/public/cpp/platform/features.h b/chromium/mojo/public/cpp/platform/features.h
deleted file mode 100644
index 0ab2980e588..00000000000
--- a/chromium/mojo/public/cpp/platform/features.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2019 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_PLATFORM_FEATURES_H_
-#define MOJO_PUBLIC_CPP_PLATFORM_FEATURES_H_
-
-#include "base/component_export.h"
-#include "base/feature_list.h"
-#include "build/build_config.h"
-
-namespace mojo {
-namespace features {
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-COMPONENT_EXPORT(MOJO_CPP_PLATFORM)
-extern const base::Feature kMojoChannelMac;
-#endif
-
-} // namespace features
-} // namespace mojo
-
-#endif // MOJO_PUBLIC_CPP_PLATFORM_FEATURES_H_
diff --git a/chromium/mojo/public/cpp/platform/named_platform_channel_mac.cc b/chromium/mojo/public/cpp/platform/named_platform_channel_mac.cc
index 0a2df95360d..08d2d51f2bb 100644
--- a/chromium/mojo/public/cpp/platform/named_platform_channel_mac.cc
+++ b/chromium/mojo/public/cpp/platform/named_platform_channel_mac.cc
@@ -28,13 +28,8 @@ std::string GetBootstrapName(const std::string& name) {
} // namespace
-// TODO(crbug.com/932175): This namespace will go away and these methods
-// will be defined direclty on NamedPlatformChannel.
-namespace NamedPlatformChannelMac {
-
// static
-COMPONENT_EXPORT(MOJO_CPP_PLATFORM)
-PlatformChannelServerEndpoint CreateServerEndpoint(
+PlatformChannelServerEndpoint NamedPlatformChannel::CreateServerEndpoint(
const NamedPlatformChannel::Options& options,
NamedPlatformChannel::ServerName* server_name) {
const std::string bootstrap_name = GetBootstrapName(options.server_name);
@@ -64,8 +59,7 @@ PlatformChannelServerEndpoint CreateServerEndpoint(
}
// static
-COMPONENT_EXPORT(MOJO_CPP_PLATFORM)
-PlatformChannelEndpoint CreateClientEndpoint(
+PlatformChannelEndpoint NamedPlatformChannel::CreateClientEndpoint(
const NamedPlatformChannel::ServerName& server_name) {
base::mac::ScopedMachSendRight send_right;
kern_return_t kr = bootstrap_look_up(
@@ -79,5 +73,4 @@ PlatformChannelEndpoint CreateClientEndpoint(
return PlatformChannelEndpoint(PlatformHandle(std::move(send_right)));
}
-} // namespace NamedPlatformChannelMac
} // namespace mojo
diff --git a/chromium/mojo/public/cpp/platform/named_platform_channel_posix.cc b/chromium/mojo/public/cpp/platform/named_platform_channel_posix.cc
index d5f82d86430..9082ac4da59 100644
--- a/chromium/mojo/public/cpp/platform/named_platform_channel_posix.cc
+++ b/chromium/mojo/public/cpp/platform/named_platform_channel_posix.cc
@@ -15,8 +15,6 @@
#include "base/posix/eintr_wrapper.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
-#include "build/build_config.h"
-#include "mojo/public/cpp/platform/features.h"
namespace mojo {
@@ -79,26 +77,10 @@ PlatformHandle CreateUnixDomainSocket() {
} // namespace
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-// Temporarily forward declare named_platform_channel_mac.cc symbols.
-namespace NamedPlatformChannelMac {
-PlatformChannelServerEndpoint CreateServerEndpoint(
- const NamedPlatformChannel::Options& options,
- NamedPlatformChannel::ServerName* server_name);
-PlatformChannelEndpoint CreateClientEndpoint(
- const NamedPlatformChannel::ServerName& server_name);
-} // namespace NamedPlatformChannelMac
-#endif
-
// static
PlatformChannelServerEndpoint NamedPlatformChannel::CreateServerEndpoint(
const Options& options,
ServerName* server_name) {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) {
- return NamedPlatformChannelMac::CreateServerEndpoint(options, server_name);
- }
-#endif
ServerName name = options.server_name;
if (name.empty())
name = GenerateRandomServerName(options);
@@ -146,11 +128,6 @@ PlatformChannelServerEndpoint NamedPlatformChannel::CreateServerEndpoint(
// static
PlatformChannelEndpoint NamedPlatformChannel::CreateClientEndpoint(
const ServerName& server_name) {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) {
- return NamedPlatformChannelMac::CreateClientEndpoint(server_name);
- }
-#endif
DCHECK(!server_name.empty());
struct sockaddr_un unix_addr;
diff --git a/chromium/mojo/public/cpp/platform/platform_channel.cc b/chromium/mojo/public/cpp/platform/platform_channel.cc
index 8502ae35c95..3320bcce7eb 100644
--- a/chromium/mojo/public/cpp/platform/platform_channel.cc
+++ b/chromium/mojo/public/cpp/platform/platform_channel.cc
@@ -16,7 +16,6 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
-#include "mojo/public/cpp/platform/features.h"
#if defined(OS_WIN)
#include <windows.h>
@@ -102,12 +101,9 @@ void CreateChannel(PlatformHandle* local_endpoint,
DCHECK(local_endpoint->is_valid());
DCHECK(remote_endpoint->is_valid());
}
-#elif defined(OS_POSIX)
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-// TODO(crbug.com/932175): This will be renamed CreateChannel().
-void CreateMachChannel(PlatformHandle* local_endpoint,
- PlatformHandle* remote_endpoint) {
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+void CreateChannel(PlatformHandle* local_endpoint,
+ PlatformHandle* remote_endpoint) {
// Mach messaging is simplex; and in order to enable full-duplex
// communication, the Mojo channel implementation performs an internal
// handshake with its peer to establish two sets of Mach receive and send
@@ -124,7 +120,7 @@ void CreateMachChannel(PlatformHandle* local_endpoint,
*local_endpoint = PlatformHandle(std::move(send));
*remote_endpoint = PlatformHandle(std::move(receive));
}
-#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+#elif defined(OS_POSIX)
#if defined(OS_ANDROID)
// Leave room for any other descriptors defined in content for example.
@@ -145,11 +141,6 @@ bool IsTargetDescriptorUsed(const base::FileHandleMappingVector& mapping,
void CreateChannel(PlatformHandle* local_endpoint,
PlatformHandle* remote_endpoint) {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) {
- return CreateMachChannel(local_endpoint, remote_endpoint);
- }
-#endif
int fds[2];
#if defined(OS_NACL_SFI)
PCHECK(imc_socketpair(fds) == 0);
@@ -199,12 +190,8 @@ PlatformChannel::~PlatformChannel() = default;
PlatformChannel& PlatformChannel::operator=(PlatformChannel&& other) = default;
-void PlatformChannel::PrepareToPassRemoteEndpoint(HandlePassingInfo* info_input,
+void PlatformChannel::PrepareToPassRemoteEndpoint(HandlePassingInfo* info,
std::string* value) {
-#if !defined(OS_MACOSX) || defined(OS_IOS)
- auto* info = info_input;
- DCHECK(info);
-#endif
DCHECK(value);
DCHECK(remote_endpoint_.is_valid());
@@ -221,27 +208,19 @@ void PlatformChannel::PrepareToPassRemoteEndpoint(HandlePassingInfo* info_input,
int mapped_fd = kAndroidClientHandleDescriptor + info->size();
info->emplace_back(fd, mapped_fd);
*value = base::NumberToString(mapped_fd);
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ DCHECK(remote_endpoint_.platform_handle().is_mach_receive());
+ base::mac::ScopedMachReceiveRight receive_right =
+ remote_endpoint_.TakePlatformHandle().TakeMachReceiveRight();
+ base::MachPortsForRendezvous::key_type rendezvous_key = 0;
+ do {
+ rendezvous_key = static_cast<decltype(rendezvous_key)>(base::RandUint64());
+ } while (info->find(rendezvous_key) != info->end());
+ auto it = info->insert(std::make_pair(
+ rendezvous_key, base::MachRendezvousPort(std::move(receive_right))));
+ DCHECK(it.second) << "Failed to insert port for rendezvous.";
+ *value = base::NumberToString(rendezvous_key);
#elif defined(OS_POSIX)
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) {
- auto* info = static_cast<base::MachPortsForRendezvous*>(info_input);
- DCHECK(remote_endpoint_.platform_handle().is_mach_receive());
- base::mac::ScopedMachReceiveRight receive_right =
- remote_endpoint_.TakePlatformHandle().TakeMachReceiveRight();
- base::MachPortsForRendezvous::key_type rendezvous_key = 0;
- do {
- rendezvous_key =
- static_cast<decltype(rendezvous_key)>(base::RandUint64());
- } while (info->find(rendezvous_key) != info->end());
- auto it = info->insert(std::make_pair(
- rendezvous_key, base::MachRendezvousPort(std::move(receive_right))));
- DCHECK(it.second) << "Failed to insert port for rendezvous.";
- *value = base::NumberToString(rendezvous_key);
- return;
- }
-
- auto* info = static_cast<base::FileHandleMappingVector*>(info_input);
-#endif // defined(OS_MACOSX) && !defined(OS_IOS)
// Arbitrary sanity check to ensure the loop below terminates reasonably
// quickly.
CHECK_LT(info->size(), 1000u);
@@ -275,18 +254,8 @@ void PlatformChannel::PrepareToPassRemoteEndpoint(
#elif defined(OS_FUCHSIA)
PrepareToPassRemoteEndpoint(&options->handles_to_transfer, command_line);
#elif defined(OS_MACOSX) && !defined(OS_IOS)
- HandlePassingInfo info;
- if (base::FeatureList::IsEnabled(features::kMojoChannelMac))
- info = options->mach_ports_for_rendezvous;
- else
- info = options->fds_to_remap;
-
- PrepareToPassRemoteEndpoint(&info, command_line);
-
- if (base::FeatureList::IsEnabled(features::kMojoChannelMac))
- options->mach_ports_for_rendezvous = info;
- else
- options->fds_to_remap = info;
+ PrepareToPassRemoteEndpoint(&options->mach_ports_for_rendezvous,
+ command_line);
#elif defined(OS_POSIX)
PrepareToPassRemoteEndpoint(&options->fds_to_remap, command_line);
#else
@@ -333,27 +302,24 @@ PlatformChannelEndpoint PlatformChannel::RecoverPassedEndpointFromString(
}
return PlatformChannelEndpoint(PlatformHandle(
base::ScopedFD(base::GlobalDescriptors::GetInstance()->Get(key))));
-#elif defined(OS_POSIX)
-#if defined(OS_MACOSX) && !defined(OS_IOS)
- if (base::FeatureList::IsEnabled(features::kMojoChannelMac)) {
- auto* client = base::MachPortRendezvousClient::GetInstance();
- if (!client) {
- DLOG(ERROR) << "Mach rendezvous failed.";
- return PlatformChannelEndpoint();
- }
- uint32_t rendezvous_key = 0;
- if (value.empty() || !base::StringToUint(value, &rendezvous_key)) {
- DLOG(ERROR) << "Invalid PlatformChannel rendezvous key.";
- return PlatformChannelEndpoint();
- }
- auto receive = client->TakeReceiveRight(rendezvous_key);
- if (!receive.is_valid()) {
- DLOG(ERROR) << "Invalid PlatformChannel receive right.";
- return PlatformChannelEndpoint();
- }
- return PlatformChannelEndpoint(PlatformHandle(std::move(receive)));
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ auto* client = base::MachPortRendezvousClient::GetInstance();
+ if (!client) {
+ DLOG(ERROR) << "Mach rendezvous failed.";
+ return PlatformChannelEndpoint();
+ }
+ uint32_t rendezvous_key = 0;
+ if (value.empty() || !base::StringToUint(value, &rendezvous_key)) {
+ DLOG(ERROR) << "Invalid PlatformChannel rendezvous key.";
+ return PlatformChannelEndpoint();
}
-#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+ auto receive = client->TakeReceiveRight(rendezvous_key);
+ if (!receive.is_valid()) {
+ DLOG(ERROR) << "Invalid PlatformChannel receive right.";
+ return PlatformChannelEndpoint();
+ }
+ return PlatformChannelEndpoint(PlatformHandle(std::move(receive)));
+#elif defined(OS_POSIX)
int fd = -1;
if (value.empty() || !base::StringToInt(value, &fd) ||
fd < base::GlobalDescriptors::kBaseDescriptor) {
diff --git a/chromium/mojo/public/cpp/platform/platform_channel.h b/chromium/mojo/public/cpp/platform/platform_channel.h
index d31668a3286..74a060dfaf7 100644
--- a/chromium/mojo/public/cpp/platform/platform_channel.h
+++ b/chromium/mojo/public/cpp/platform/platform_channel.h
@@ -42,17 +42,7 @@ class COMPONENT_EXPORT(MOJO_CPP_PLATFORM) PlatformChannel {
#elif defined(OS_FUCHSIA)
using HandlePassingInfo = base::HandlesToTransferVector;
#elif defined(OS_MACOSX) && !defined(OS_IOS)
- // This type represents a union between MachPortsForRendezvous and
- // FileHandleMappingVector, so that the type to use can be determined at run-
- // time.
- // TODO(crbug.com/932175): This will become a typedef to
- // base::MachPortsForRendezvous in the future.
- class HandlePassingInfo : public base::MachPortsForRendezvous,
- public base::FileHandleMappingVector {
- public:
- using base::MachPortsForRendezvous::operator=;
- using base::FileHandleMappingVector::operator=;
- };
+ using HandlePassingInfo = base::MachPortsForRendezvous;
#elif defined(OS_POSIX)
using HandlePassingInfo = base::FileHandleMappingVector;
#else
diff --git a/chromium/mojo/public/cpp/system/BUILD.gn b/chromium/mojo/public/cpp/system/BUILD.gn
index 01b62788fbe..235c65d3288 100644
--- a/chromium/mojo/public/cpp/system/BUILD.gn
+++ b/chromium/mojo/public/cpp/system/BUILD.gn
@@ -30,10 +30,14 @@ component("system") {
"data_pipe.h",
"data_pipe_drainer.cc",
"data_pipe_drainer.h",
+ "data_pipe_producer.cc",
+ "data_pipe_producer.h",
"data_pipe_utils.cc",
"data_pipe_utils.h",
- "file_data_pipe_producer.cc",
- "file_data_pipe_producer.h",
+ "file_data_source.cc",
+ "file_data_source.h",
+ "filtered_data_source.cc",
+ "filtered_data_source.h",
"functions.h",
"handle.h",
"handle_signal_tracker.cc",
@@ -52,8 +56,8 @@ component("system") {
"scope_to_message_pipe.h",
"simple_watcher.cc",
"simple_watcher.h",
- "string_data_pipe_producer.cc",
- "string_data_pipe_producer.h",
+ "string_data_source.cc",
+ "string_data_source.h",
"system_export.h",
"trap.cc",
"trap.h",
@@ -67,7 +71,7 @@ component("system") {
# This file refers to a the base::File::File(path, flags)
# constructor which does not exist in nacl builds, and the code
# here is unused in nacl builds anyway.
- sources -= [ "file_data_pipe_producer.cc" ]
+ sources -= [ "file_data_source.cc" ]
}
public_deps = [
diff --git a/chromium/mojo/public/cpp/system/README.md b/chromium/mojo/public/cpp/system/README.md
index 60ef3f7a356..07bc7d3b9a2 100644
--- a/chromium/mojo/public/cpp/system/README.md
+++ b/chromium/mojo/public/cpp/system/README.md
@@ -145,10 +145,10 @@ memory:
``` cpp
mojo::ScopedSharedBufferMapping mapping = buffer->Map(64);
-static_cast<int*>(mapping.get()) = 42;
+static_cast<int*>(mapping.get())[0] = 42;
mojo::ScopedSharedBufferMapping another_mapping = buffer->MapAtOffset(64, 4);
-static_cast<int*>(mapping.get()) = 43;
+static_cast<int*>(mapping.get())[0] = 43;
```
When `mapping` and `another_mapping` are destroyed, they automatically unmap
diff --git a/chromium/mojo/public/cpp/system/data_pipe_drainer.cc b/chromium/mojo/public/cpp/system/data_pipe_drainer.cc
index 27b995a2a77..8b8d823fb75 100644
--- a/chromium/mojo/public/cpp/system/data_pipe_drainer.cc
+++ b/chromium/mojo/public/cpp/system/data_pipe_drainer.cc
@@ -18,8 +18,7 @@ DataPipeDrainer::DataPipeDrainer(Client* client,
source_(std::move(source)),
handle_watcher_(FROM_HERE,
SimpleWatcher::ArmingPolicy::AUTOMATIC,
- base::SequencedTaskRunnerHandle::Get()),
- weak_factory_(this) {
+ base::SequencedTaskRunnerHandle::Get()) {
DCHECK(client_);
handle_watcher_.Watch(
source_.get(), MOJO_HANDLE_SIGNAL_READABLE,
diff --git a/chromium/mojo/public/cpp/system/data_pipe_drainer.h b/chromium/mojo/public/cpp/system/data_pipe_drainer.h
index 209d93d705b..949c9d13dd2 100644
--- a/chromium/mojo/public/cpp/system/data_pipe_drainer.h
+++ b/chromium/mojo/public/cpp/system/data_pipe_drainer.h
@@ -37,7 +37,7 @@ class MOJO_CPP_SYSTEM_EXPORT DataPipeDrainer {
mojo::ScopedDataPipeConsumerHandle source_;
mojo::SimpleWatcher handle_watcher_;
- base::WeakPtrFactory<DataPipeDrainer> weak_factory_;
+ base::WeakPtrFactory<DataPipeDrainer> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(DataPipeDrainer);
};
diff --git a/chromium/mojo/public/cpp/system/data_pipe_producer.cc b/chromium/mojo/public/cpp/system/data_pipe_producer.cc
new file mode 100644
index 00000000000..228b58f4ddf
--- /dev/null
+++ b/chromium/mojo/public/cpp/system/data_pipe_producer.cc
@@ -0,0 +1,208 @@
+// 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/data_pipe_producer.h"
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/location.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/post_task.h"
+#include "base/thread_annotations.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 DataPipeProducer::SequenceState
+ : public base::RefCountedDeleteOnSequence<SequenceState> {
+ public:
+ using CompletionCallback =
+ base::OnceCallback<void(ScopedDataPipeProducerHandle producer,
+ MojoResult result)>;
+
+ SequenceState(ScopedDataPipeProducerHandle producer_handle,
+ scoped_refptr<base::SequencedTaskRunner> file_task_runner,
+ CompletionCallback callback,
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner)
+ : base::RefCountedDeleteOnSequence<SequenceState>(
+ 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 Start(std::unique_ptr<DataSource> data_source) {
+ owning_task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&SequenceState::StartOnSequence, this,
+ std::move(data_source)));
+ }
+
+ private:
+ friend class base::DeleteHelper<SequenceState>;
+ friend class base::RefCountedDeleteOnSequence<SequenceState>;
+
+ ~SequenceState() = default;
+
+ void StartOnSequence(std::unique_ptr<DataSource> data_source) {
+ data_source_ = std::move(data_source);
+ if (!data_source_->IsValid()) {
+ Finish(MOJO_RESULT_UNKNOWN);
+ return;
+ }
+ 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_ = std::make_unique<SimpleWatcher>(
+ FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC,
+ base::SequencedTaskRunnerHandle::Get());
+ watcher_->Watch(producer_handle_.get(), MOJO_HANDLE_SIGNAL_WRITABLE,
+ MOJO_WATCH_CONDITION_SATISFIED,
+ base::Bind(&SequenceState::OnHandleReady, this));
+ }
+ }
+
+ 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(result);
+ return;
+ }
+
+ TransferSomeBytes();
+ }
+
+ void TransferSomeBytes() {
+ while (true) {
+ // Lock as much of the pipe as we can.
+ void* pipe_buffer;
+ uint32_t size = kDefaultMaxReadSize;
+ int64_t max_data_size = data_source_->GetLength();
+ if (static_cast<int64_t>(size) > max_data_size)
+ size = static_cast<uint32_t>(max_data_size);
+
+ MojoResult mojo_result = producer_handle_->BeginWriteData(
+ &pipe_buffer, &size, MOJO_WRITE_DATA_FLAG_NONE);
+ if (mojo_result == MOJO_RESULT_SHOULD_WAIT)
+ return;
+ if (mojo_result != MOJO_RESULT_OK) {
+ Finish(mojo_result);
+ return;
+ }
+ base::span<char> read_buffer(static_cast<char*>(pipe_buffer), size);
+
+ DataSource::ReadResult result =
+ data_source_->Read(bytes_transferred_, read_buffer);
+ producer_handle_->EndWriteData(result.bytes_read);
+
+ if (result.result != MOJO_RESULT_OK) {
+ Finish(result.result);
+ return;
+ }
+
+ bytes_transferred_ += result.bytes_read;
+
+ if (result.bytes_read < read_buffer.size()) {
+ // DataSource::Read 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();
+ if (result != MOJO_RESULT_OK)
+ data_source_->Abort();
+ data_source_.reset();
+ callback_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback_),
+ std::move(producer_handle_), result));
+ }
+
+ const scoped_refptr<base::SequencedTaskRunner> callback_task_runner_;
+
+ // State which is effectively owned and used only on the file sequence.
+ ScopedDataPipeProducerHandle producer_handle_;
+ std::unique_ptr<DataPipeProducer::DataSource> data_source_;
+ size_t bytes_transferred_ = 0;
+ CompletionCallback callback_;
+ std::unique_ptr<SimpleWatcher> watcher_;
+
+ base::Lock lock_;
+ bool is_cancelled_ GUARDED_BY(lock_) = false;
+
+ DISALLOW_COPY_AND_ASSIGN(SequenceState);
+};
+
+DataPipeProducer::DataPipeProducer(ScopedDataPipeProducerHandle producer)
+ : producer_(std::move(producer)) {}
+
+DataPipeProducer::~DataPipeProducer() {
+ if (sequence_state_)
+ sequence_state_->Cancel();
+}
+
+void DataPipeProducer::Write(std::unique_ptr<DataSource> data_source,
+ CompletionCallback callback) {
+ InitializeNewRequest(std::move(callback));
+ sequence_state_->Start(std::move(data_source));
+}
+
+void DataPipeProducer::InitializeNewRequest(CompletionCallback callback) {
+ DCHECK(!sequence_state_);
+ // TODO(crbug.com/924416): Re-evaluate how TaskPriority is set here and in
+ // other file URL-loading-related code. Some callers require USER_VISIBLE
+ // (i.e., BEST_EFFORT is not enough).
+ auto file_task_runner = base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
+ sequence_state_ = new SequenceState(
+ std::move(producer_), file_task_runner,
+ base::BindOnce(&DataPipeProducer::OnWriteComplete,
+ weak_factory_.GetWeakPtr(), std::move(callback)),
+ base::SequencedTaskRunnerHandle::Get());
+}
+
+void DataPipeProducer::OnWriteComplete(CompletionCallback callback,
+ ScopedDataPipeProducerHandle producer,
+ MojoResult ready_result) {
+ producer_ = std::move(producer);
+ sequence_state_ = nullptr;
+ std::move(callback).Run(ready_result);
+}
+
+} // namespace mojo
diff --git a/chromium/mojo/public/cpp/system/data_pipe_producer.h b/chromium/mojo/public/cpp/system/data_pipe_producer.h
new file mode 100644
index 00000000000..b10f9ebb3c6
--- /dev/null
+++ b/chromium/mojo/public/cpp/system/data_pipe_producer.h
@@ -0,0 +1,110 @@
+// 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_DATA_PIPE_PRODUCER_H_
+#define MOJO_PUBLIC_CPP_SYSTEM_DATA_PIPE_PRODUCER_H_
+
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "base/containers/span.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 DataSource. This
+// takes care of waiting for pipe capacity as needed, and can notify callers
+// asynchronously when the operation is complete.
+//
+// Note that the DataPipeProducer 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 DataPipeProducer {
+ public:
+ using CompletionCallback = base::OnceCallback<void(MojoResult result)>;
+ // Interface definition of abstracted content reader that has minimum
+ // base::File equivalent interface to read content.
+ class DataSource {
+ public:
+ // Used as a return value for Read().
+ struct ReadResult {
+ // The number of bytes read. If returned |bytes_read| is less than
+ // requested size, it means EOF is reached.
+ size_t bytes_read = 0;
+
+ // MojoResult resulting from this call.
+ MojoResult result = MOJO_RESULT_OK;
+ };
+ virtual ~DataSource() {}
+
+ // Checks if this Reader instance owns a valid content to read.
+ virtual bool IsValid() const = 0;
+
+ // Returns maximum data size. Actual size may be smaller. This should return
+ // a positive value.
+ // TODO(crbug.com/983023): Return size_t.
+ virtual int64_t GetLength() const = 0;
+
+ // Similar to base::File::Read(), reads the given number of bytes (or until
+ // EOF is reached) starting with the given offset. Returns ReadResult to
+ // represent the number of bytes read and errors.
+ virtual ReadResult Read(int64_t offset, base::span<char> buffer) = 0;
+
+ // Notifies DataPipeProducer aborts read operations.
+ virtual void Abort() {}
+ };
+
+ // Constructs a new DataPipeProducer which will write data to |producer|.
+ explicit DataPipeProducer(ScopedDataPipeProducerHandle producer);
+ ~DataPipeProducer();
+
+ // Attempts to eventually write all of |data_source|'s contents to the pipe.
+ // Invokes |callback| asynchronously when done. Note that |callback| IS
+ // allowed to delete this DataPipeProducer.
+ //
+ // 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 open/reads fail for any reason) |result|
+ // will be one of the following:
+ //
+ // |MOJO_RESULT_ABORTED|
+ // |MOJO_RESULT_NOT_FOUND|
+ // |MOJO_RESULT_PERMISSION_DENIED|
+ // |MOJO_RESULT_RESOURCE_EXHAUSTED|
+ // |MOJO_RESULT_UNKNOWN|
+ //
+ // Note that if the DataPipeProducer 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(std::unique_ptr<DataSource> reader, CompletionCallback callback);
+
+ private:
+ class SequenceState;
+
+ void InitializeNewRequest(CompletionCallback callback);
+ void OnWriteComplete(CompletionCallback callback,
+ ScopedDataPipeProducerHandle producer,
+ MojoResult result);
+
+ ScopedDataPipeProducerHandle producer_;
+ scoped_refptr<SequenceState> sequence_state_;
+ base::WeakPtrFactory<DataPipeProducer> weak_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(DataPipeProducer);
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_SYSTEM_DATA_PIPE_PRODUCER_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
deleted file mode 100644
index 3c928db92ab..00000000000
--- a/chromium/mojo/public/cpp/system/file_data_pipe_producer.cc
+++ /dev/null
@@ -1,292 +0,0 @@
-// 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 <limits>
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/location.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/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;
-
-MojoResult FileErrorToMojoResult(base::File::Error error) {
- switch (error) {
- case base::File::FILE_OK:
- return MOJO_RESULT_OK;
- case base::File::FILE_ERROR_NOT_FOUND:
- return MOJO_RESULT_NOT_FOUND;
- case base::File::FILE_ERROR_SECURITY:
- case base::File::FILE_ERROR_ACCESS_DENIED:
- return MOJO_RESULT_PERMISSION_DENIED;
- case base::File::FILE_ERROR_TOO_MANY_OPENED:
- case base::File::FILE_ERROR_NO_MEMORY:
- return MOJO_RESULT_RESOURCE_EXHAUSTED;
- case base::File::FILE_ERROR_ABORT:
- return MOJO_RESULT_ABORTED;
- default:
- return MOJO_RESULT_UNKNOWN;
- }
-}
-
-} // 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,
- std::unique_ptr<Observer> observer)
- : base::RefCountedDeleteOnSequence<FileSequenceState>(
- std::move(file_task_runner)),
- callback_task_runner_(std::move(callback_task_runner)),
- producer_handle_(std::move(producer_handle)),
- callback_(std::move(callback)),
- observer_(std::move(observer)) {}
-
- void Cancel() {
- base::AutoLock lock(lock_);
- is_cancelled_ = true;
- }
-
- void StartFromFile(base::File file, size_t max_bytes) {
- owning_task_runner()->PostTask(
- FROM_HERE,
- base::BindOnce(&FileSequenceState::StartFromFileOnFileSequence, this,
- std::move(file), max_bytes));
- }
-
- void StartFromPath(const base::FilePath& path) {
- owning_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, size_t max_bytes) {
- if (file.error_details() != base::File::FILE_OK) {
- Finish(FileErrorToMojoResult(file.error_details()));
- return;
- }
- file_ = std::move(file);
- max_bytes_ = max_bytes;
- 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_ = std::make_unique<SimpleWatcher>(
- FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC,
- base::SequencedTaskRunnerHandle::Get());
- 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),
- std::numeric_limits<size_t>::max());
- }
-
- 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(result);
- 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(result);
- return;
- }
-
- // Attempt to read that many bytes from the file, directly into the data
- // pipe. Note that while |max_bytes_remaining| may be very large, the
- // length we attempt read is bounded by the much smaller
- // |kDefaultMaxReadSize| via |size|.
- DCHECK(base::IsValueInRangeForNumericType<int>(size));
- const size_t max_bytes_remaining = max_bytes_ - bytes_transferred_;
- int attempted_read_size = static_cast<int>(
- std::min(static_cast<size_t>(size), max_bytes_remaining));
- int read_size = file_.ReadAtCurrentPos(static_cast<char*>(pipe_buffer),
- attempted_read_size);
- base::File::Error read_error;
- if (read_size < 0) {
- read_error = base::File::GetLastFileError();
- DCHECK_NE(base::File::FILE_OK, read_error);
- if (observer_)
- observer_->OnBytesRead(pipe_buffer, 0u, read_error);
- } else {
- read_error = base::File::FILE_OK;
- if (observer_) {
- observer_->OnBytesRead(pipe_buffer, static_cast<size_t>(read_size),
- base::File::FILE_OK);
- }
- }
- producer_handle_->EndWriteData(
- read_size >= 0 ? static_cast<uint32_t>(read_size) : 0);
-
- if (read_size < 0) {
- Finish(FileErrorToMojoResult(read_error));
- return;
- }
-
- bytes_transferred_ += read_size;
- DCHECK_LE(bytes_transferred_, max_bytes_);
-
- 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;
- }
-
- if (bytes_transferred_ == max_bytes_) {
- // We've read as much as we were asked to read.
- Finish(MOJO_RESULT_OK);
- return;
- }
- }
- }
-
- void Finish(MojoResult result) {
- if (observer_) {
- if (result != MOJO_RESULT_OK)
- observer_->OnBytesRead(nullptr, 0u, base::File::FILE_ERROR_ABORT);
- observer_->OnDoneReading();
- observer_ = nullptr;
- }
- watcher_.reset();
- callback_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback_),
- std::move(producer_handle_), result));
- }
-
- 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_;
- size_t max_bytes_ = 0;
- size_t bytes_transferred_ = 0;
- CompletionCallback callback_;
- std::unique_ptr<SimpleWatcher> watcher_;
-
- // Guards |is_cancelled_|.
- base::Lock lock_;
- bool is_cancelled_ = false;
- std::unique_ptr<Observer> observer_;
-
- DISALLOW_COPY_AND_ASSIGN(FileSequenceState);
-};
-
-FileDataPipeProducer::FileDataPipeProducer(
- ScopedDataPipeProducerHandle producer,
- std::unique_ptr<Observer> observer)
- : producer_(std::move(producer)),
- observer_(std::move(observer)),
- weak_factory_(this) {}
-
-FileDataPipeProducer::~FileDataPipeProducer() {
- if (file_sequence_state_)
- file_sequence_state_->Cancel();
-}
-
-void FileDataPipeProducer::WriteFromFile(base::File file,
- CompletionCallback callback) {
- WriteFromFile(std::move(file), std::numeric_limits<size_t>::max(),
- std::move(callback));
-}
-
-void FileDataPipeProducer::WriteFromFile(base::File file,
- size_t max_bytes,
- CompletionCallback callback) {
- InitializeNewRequest(std::move(callback));
- file_sequence_state_->StartFromFile(std::move(file), max_bytes);
-}
-
-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_);
- // TODO(crbug.com/924416): Re-evaluate how TaskPriority is set here and in
- // other file URL-loading-related code. Some callers require USER_VISIBLE
- // (i.e., BEST_EFFORT is not enough).
- auto file_task_runner = base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
- file_sequence_state_ = new FileSequenceState(
- std::move(producer_), file_task_runner,
- base::BindOnce(&FileDataPipeProducer::OnWriteComplete,
- weak_factory_.GetWeakPtr(), std::move(callback)),
- base::SequencedTaskRunnerHandle::Get(), std::move(observer_));
-}
-
-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
deleted file mode 100644
index c3479f75bfe..00000000000
--- a/chromium/mojo/public/cpp/system/file_data_pipe_producer.h
+++ /dev/null
@@ -1,114 +0,0 @@
-// 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 <memory>
-
-#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)>;
-
- // Interface definition of an optional object that may be supplied to the
- // FileDataPipeProducer so that the data being read from the consumer can be
- // observed.
- class Observer {
- public:
- virtual ~Observer() {}
-
- // Called once per read attempt. |data| contains the read data (if any).
- // |num_bytes_read| is the number of read bytes, 0 indicates EOF. Both
- // parameters may only be used when |read_result| is base::File::FILE_OK.
- // Can be called on any sequence.
- virtual void OnBytesRead(const void* data,
- size_t num_bytes_read,
- base::File::Error read_result) = 0;
-
- // Called when the FileDataPipeProducer has finished reading all data. Will
- // be called even if there was an error opening the file or reading the
- // data. Can be called on any sequence.
- virtual void OnDoneReading() = 0;
- };
-
- // Constructs a new FileDataPipeProducer which will write data to |producer|.
- // Caller may supply an optional |observer| if observation of the read file
- // data is desired.
- FileDataPipeProducer(ScopedDataPipeProducerHandle producer,
- std::unique_ptr<Observer> observer);
- ~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 open/reads fail for any reason) |result|
- // will be one of the following:
- //
- // |MOJO_RESULT_ABORTED|
- // |MOJO_RESULT_NOT_FOUND|
- // |MOJO_RESULT_PERMISSION_DENIED|
- // |MOJO_RESULT_RESOURCE_EXHAUSTED|
- // |MOJO_RESULT_UNKNOWN|
- //
- // 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);
-
- // Like above, but writes at most |max_bytes| bytes from the file to the pipe.
- void WriteFromFile(base::File file,
- size_t max_bytes,
- 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_;
- std::unique_ptr<Observer> observer_;
- 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/file_data_source.cc b/chromium/mojo/public/cpp/system/file_data_source.cc
new file mode 100644
index 00000000000..642021e5530
--- /dev/null
+++ b/chromium/mojo/public/cpp/system/file_data_source.cc
@@ -0,0 +1,87 @@
+// Copyright 2019 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_source.h"
+
+#include <limits>
+
+#include "base/numerics/checked_math.h"
+
+namespace {
+
+int64_t CalculateBaseOffset(base::File* file) {
+ if (file->IsValid())
+ return file->Seek(base::File::FROM_CURRENT, 0);
+ return 0;
+}
+
+size_t CalculateMaxBytes(base::File* file,
+ int64_t base_offset,
+ base::Optional<int64_t> max_bytes) {
+ if (max_bytes)
+ return *max_bytes;
+ if (file->IsValid())
+ return file->GetLength() - base_offset;
+ return std::numeric_limits<size_t>::max();
+}
+
+} // namespace
+
+namespace mojo {
+
+// static
+MojoResult FileDataSource::ConvertFileErrorToMojoResult(
+ base::File::Error error) {
+ switch (error) {
+ case base::File::FILE_OK:
+ return MOJO_RESULT_OK;
+ case base::File::FILE_ERROR_NOT_FOUND:
+ return MOJO_RESULT_NOT_FOUND;
+ case base::File::FILE_ERROR_SECURITY:
+ case base::File::FILE_ERROR_ACCESS_DENIED:
+ return MOJO_RESULT_PERMISSION_DENIED;
+ case base::File::FILE_ERROR_TOO_MANY_OPENED:
+ case base::File::FILE_ERROR_NO_MEMORY:
+ return MOJO_RESULT_RESOURCE_EXHAUSTED;
+ case base::File::FILE_ERROR_ABORT:
+ return MOJO_RESULT_ABORTED;
+ default:
+ return MOJO_RESULT_UNKNOWN;
+ }
+}
+
+FileDataSource::FileDataSource(base::File file,
+ base::Optional<int64_t> max_bytes)
+ : file_(std::move(file)),
+ base_offset_(CalculateBaseOffset(&file_)),
+ max_bytes_(CalculateMaxBytes(&file_, base_offset_, max_bytes)) {}
+
+FileDataSource::~FileDataSource() = default;
+
+bool FileDataSource::IsValid() const {
+ return file_.IsValid();
+}
+
+int64_t FileDataSource::GetLength() const {
+ return max_bytes_ - base_offset_;
+}
+
+DataPipeProducer::DataSource::ReadResult FileDataSource::Read(
+ int64_t offset,
+ base::span<char> buffer) {
+ ReadResult result;
+ size_t readable_size = max_bytes_ - offset;
+ size_t read_size = std::min(readable_size, buffer.size());
+ DCHECK(base::IsValueInRangeForNumericType<int>(read_size));
+ int bytes_read = file_.Read(base_offset_ + offset, buffer.data(), read_size);
+ if (bytes_read < 0) {
+ result.bytes_read = 0;
+ result.result = ConvertFileErrorToMojoResult(file_.GetLastFileError());
+ } else {
+ result.bytes_read = bytes_read;
+ }
+ return result;
+}
+
+} // namespace mojo
diff --git a/chromium/mojo/public/cpp/system/file_data_source.h b/chromium/mojo/public/cpp/system/file_data_source.h
new file mode 100644
index 00000000000..a28755a0ae4
--- /dev/null
+++ b/chromium/mojo/public/cpp/system/file_data_source.h
@@ -0,0 +1,43 @@
+// Copyright 2019 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_SOURCE_H_
+#define MOJO_PUBLIC_CPP_SYSTEM_FILE_DATA_SOURCE_H_
+
+#include "base/containers/span.h"
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "mojo/public/cpp/system/data_pipe_producer.h"
+#include "mojo/public/cpp/system/system_export.h"
+
+namespace mojo {
+
+// A class to wrap base::File as DataPipeProducer::DataSource class. Reads at
+// most |max_bytes| bytes from the file.
+class MOJO_CPP_SYSTEM_EXPORT FileDataSource final
+ : public DataPipeProducer::DataSource {
+ public:
+ static MojoResult ConvertFileErrorToMojoResult(base::File::Error error);
+
+ FileDataSource(base::File file,
+ base::Optional<int64_t> max_bytes = base::nullopt);
+ ~FileDataSource() override;
+
+ private:
+ // DataPipeProducer::DataSource:
+ bool IsValid() const override;
+ int64_t GetLength() const override;
+ ReadResult Read(int64_t offset, base::span<char> buffer) override;
+
+ base::File file_;
+ const int64_t base_offset_;
+ const int64_t max_bytes_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileDataSource);
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_SYSTEM_FILE_DATA_SOURCE_H_
diff --git a/chromium/mojo/public/cpp/system/filtered_data_source.cc b/chromium/mojo/public/cpp/system/filtered_data_source.cc
new file mode 100644
index 00000000000..5916393bb2c
--- /dev/null
+++ b/chromium/mojo/public/cpp/system/filtered_data_source.cc
@@ -0,0 +1,46 @@
+// Copyright 2019 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/filtered_data_source.h"
+
+namespace mojo {
+
+FilteredDataSource::FilteredDataSource(
+ std::unique_ptr<DataPipeProducer::DataSource> source,
+ std::unique_ptr<Filter> filter)
+ : source_(std::move(source)), filter_(std::move(filter)) {
+ DCHECK(source_);
+}
+
+FilteredDataSource::~FilteredDataSource() {
+ if (filter_)
+ filter_->OnDone();
+}
+
+bool FilteredDataSource::IsValid() const {
+ return source_->IsValid();
+}
+
+int64_t FilteredDataSource::GetLength() const {
+ return source_->GetLength();
+}
+
+FilteredDataSource::ReadResult FilteredDataSource::Read(
+ int64_t offset,
+ base::span<char> buffer) {
+ ReadResult result = source_->Read(offset, buffer);
+ if (filter_)
+ filter_->OnRead(buffer, &result);
+ return result;
+}
+
+void FilteredDataSource::Abort() {
+ if (filter_) {
+ ReadResult result;
+ result.result = MOJO_RESULT_ABORTED;
+ filter_->OnRead(base::span<char>(), &result);
+ }
+}
+
+} // namespace mojo
diff --git a/chromium/mojo/public/cpp/system/filtered_data_source.h b/chromium/mojo/public/cpp/system/filtered_data_source.h
new file mode 100644
index 00000000000..69f58c989d5
--- /dev/null
+++ b/chromium/mojo/public/cpp/system/filtered_data_source.h
@@ -0,0 +1,64 @@
+// Copyright 2019 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_FILTERED_DATA_SOURCE_H_
+#define MOJO_PUBLIC_CPP_SYSTEM_FILTERED_DATA_SOURCE_H_
+
+#include <limits>
+#include <memory>
+
+#include "base/containers/span.h"
+#include "base/macros.h"
+#include "mojo/public/cpp/system/data_pipe_producer.h"
+#include "mojo/public/cpp/system/system_export.h"
+
+namespace mojo {
+
+// A class wraps any other DataPipeProducer::DataSource interface and provides
+// the Filter interface to monitor read manipulations.
+class MOJO_CPP_SYSTEM_EXPORT FilteredDataSource final
+ : public DataPipeProducer::DataSource {
+ public:
+ class Filter {
+ public:
+ virtual ~Filter() {}
+
+ // Called once after each |source|'s read attempt. Filter instance can use
+ // this interface both to monitor read payloads and to modify read results.
+ // |buffer| contains the read buffer. |result->bytes_read| is the actual
+ // bytes number that |source| read that should be less than buffer.size().
+ // 0 indicates EOF. Both parameters are only valid when |result->error| is
+ // MOJO_RESULT_OK.
+ // Filter can modify contents of |buffer| and |result|, but it could not
+ // expand |buffer|'s size. |result| should be updated to be aligned with
+ // modified result and size.
+ // Can be called on any sequence.
+ virtual void OnRead(base::span<char> buffer, ReadResult* result) = 0;
+
+ // Called when the DataPipeProducer has finished reading all data. Will be
+ // called even if there was an error opening the file or reading the data.
+ // Can be called on any sequence.
+ virtual void OnDone() = 0;
+ };
+
+ FilteredDataSource(std::unique_ptr<DataPipeProducer::DataSource> source,
+ std::unique_ptr<Filter> filter);
+ ~FilteredDataSource() override;
+
+ private:
+ // DataPipeProducer::DataSource:
+ bool IsValid() const override;
+ int64_t GetLength() const override;
+ ReadResult Read(int64_t offset, base::span<char> buffer) override;
+ void Abort() override;
+
+ std::unique_ptr<DataPipeProducer::DataSource> source_;
+ std::unique_ptr<Filter> filter_;
+
+ DISALLOW_COPY_AND_ASSIGN(FilteredDataSource);
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_SYSTEM_FILTERED_DATA_SOURCE_H_
diff --git a/chromium/mojo/public/cpp/system/simple_watcher.cc b/chromium/mojo/public/cpp/system/simple_watcher.cc
index 5905b02c247..c2ed7efd39a 100644
--- a/chromium/mojo/public/cpp/system/simple_watcher.cc
+++ b/chromium/mojo/public/cpp/system/simple_watcher.cc
@@ -142,8 +142,7 @@ SimpleWatcher::SimpleWatcher(const base::Location& from_here,
is_default_task_runner_(base::ThreadTaskRunnerHandle::IsSet() &&
task_runner_ ==
base::ThreadTaskRunnerHandle::Get()),
- heap_profiler_tag_(from_here.file_name()),
- weak_factory_(this) {
+ heap_profiler_tag_(from_here.file_name()) {
MojoResult rv = CreateTrap(&Context::CallNotify, &trap_handle_);
DCHECK_EQ(MOJO_RESULT_OK, rv);
DCHECK(task_runner_->RunsTasksInCurrentSequence());
diff --git a/chromium/mojo/public/cpp/system/simple_watcher.h b/chromium/mojo/public/cpp/system/simple_watcher.h
index cc916c88019..e34d7ddb210 100644
--- a/chromium/mojo/public/cpp/system/simple_watcher.h
+++ b/chromium/mojo/public/cpp/system/simple_watcher.h
@@ -233,7 +233,7 @@ class MOJO_CPP_SYSTEM_EXPORT SimpleWatcher {
// this watcher.
const char* heap_profiler_tag_ = nullptr;
- base::WeakPtrFactory<SimpleWatcher> weak_factory_;
+ base::WeakPtrFactory<SimpleWatcher> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(SimpleWatcher);
};
diff --git a/chromium/mojo/public/cpp/system/string_data_pipe_producer.cc b/chromium/mojo/public/cpp/system/string_data_pipe_producer.cc
deleted file mode 100644
index 81f7e7d5e29..00000000000
--- a/chromium/mojo/public/cpp/system/string_data_pipe_producer.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-// 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/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,
- base::SequencedTaskRunnerHandle::Get()),
- weak_factory_(this) {}
-
-StringDataPipeProducer::~StringDataPipeProducer() = default;
-
-void StringDataPipeProducer::Write(const base::StringPiece& data,
- AsyncWritingMode mode,
- 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.
- if (mode == AsyncWritingMode::STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION) {
- data_ = std::string(data.data() + size, data.size() - size);
- data_view_ = data_;
- } else {
- data_view_ = base::StringPiece(data.data() + size, data.size() - size);
- }
- 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
deleted file mode 100644
index 0e66f2bcfaa..00000000000
--- a/chromium/mojo/public/cpp/system/string_data_pipe_producer.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// 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();
-
- // Describes what happens to the data when an async writing situation occurs
- // (where the pipe cannot immediately accept all of the data).
- enum class AsyncWritingMode {
- // The |data| given to Write() may be invalidated before completion
- // |callback| is called. The pending |data| is copied and owned by this
- // class until all bytes are written.
- STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION,
- // The |data| given to Write() stays valid until the completion |callback|
- // is called.
- STRING_STAYS_VALID_UNTIL_COMPLETION
- };
-
- // Attempts to eventually write all of |data|. Invokes |callback|
- // asynchronously when done. Note that |callback| IS allowed to delete this
- // StringDataPipeProducer.
- //
- // If the data cannot be entirely written synchronously, then the |mode|
- // determines how this class holds the pending data.
- //
- // 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,
- AsyncWritingMode mode,
- 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/string_data_source.cc b/chromium/mojo/public/cpp/system/string_data_source.cc
new file mode 100644
index 00000000000..788195b4b3d
--- /dev/null
+++ b/chromium/mojo/public/cpp/system/string_data_source.cc
@@ -0,0 +1,52 @@
+// Copyright 2019 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_source.h"
+
+#include <algorithm>
+
+namespace mojo {
+
+StringDataSource::StringDataSource(base::StringPiece data,
+ AsyncWritingMode mode) {
+ switch (mode) {
+ case AsyncWritingMode::STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION:
+ data_ = std::string(data.data(), data.size());
+ data_view_ = base::span<const char>(data_.data(), data_.size());
+ break;
+ case AsyncWritingMode::STRING_STAYS_VALID_UNTIL_COMPLETION:
+ data_view_ = base::span<const char>(data.data(), data.size());
+ break;
+ }
+}
+
+StringDataSource::~StringDataSource() = default;
+
+bool StringDataSource::IsValid() const {
+ return true;
+}
+
+int64_t StringDataSource::GetLength() const {
+ return data_view_.size();
+}
+
+DataPipeProducer::DataSource::ReadResult StringDataSource::Read(
+ int64_t offset,
+ base::span<char> buffer) {
+ ReadResult result;
+ if (static_cast<size_t>(offset) <= data_view_.size()) {
+ size_t readable_size = data_view_.size() - offset;
+ size_t writable_size = buffer.size();
+ size_t copyable_size = std::min(readable_size, writable_size);
+ for (size_t copied_size = 0; copied_size < copyable_size; ++copied_size)
+ buffer[copied_size] = data_view_[offset + copied_size];
+ result.bytes_read = copyable_size;
+ } else {
+ NOTREACHED();
+ result.result = MOJO_RESULT_OUT_OF_RANGE;
+ }
+ return result;
+}
+
+} // namespace mojo
diff --git a/chromium/mojo/public/cpp/system/string_data_source.h b/chromium/mojo/public/cpp/system/string_data_source.h
new file mode 100644
index 00000000000..8c88109528b
--- /dev/null
+++ b/chromium/mojo/public/cpp/system/string_data_source.h
@@ -0,0 +1,49 @@
+// Copyright 2019 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_SOURCE_H_
+#define MOJO_PUBLIC_CPP_SYSTEM_STRING_DATA_SOURCE_H_
+
+#include <string>
+
+#include "base/containers/span.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "mojo/public/cpp/system/data_pipe_producer.h"
+#include "mojo/public/cpp/system/system_export.h"
+
+namespace mojo {
+
+// A class to wrap base::StringPiece as DataPipeProducer::DataSource class.
+class MOJO_CPP_SYSTEM_EXPORT StringDataSource final
+ : public DataPipeProducer::DataSource {
+ public:
+ enum class AsyncWritingMode {
+ // The |data| given to the constructor may be invalidated before completion
+ // |callback| is called. The pending |data| is copied and owned by this
+ // class until all bytes are written.
+ STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION,
+ // The |data| given to the constructor stays valid until this instance is
+ // moved to DataPipeProducer and the completion callback is called.
+ STRING_STAYS_VALID_UNTIL_COMPLETION
+ };
+
+ StringDataSource(base::StringPiece data, AsyncWritingMode mode);
+ ~StringDataSource() override;
+
+ private:
+ // DataPipeProducer::DataSource:
+ bool IsValid() const override;
+ int64_t GetLength() const override;
+ ReadResult Read(int64_t offset, base::span<char> buffer) override;
+
+ std::string data_;
+ base::span<const char> data_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(StringDataSource);
+};
+
+} // namespace mojo
+
+#endif // MOJO_PUBLIC_CPP_SYSTEM_STRING_DATA_SOURCE_H_
diff --git a/chromium/mojo/public/cpp/system/tests/BUILD.gn b/chromium/mojo/public/cpp/system/tests/BUILD.gn
index c08f3c1099e..0dabd992cc7 100644
--- a/chromium/mojo/public/cpp/system/tests/BUILD.gn
+++ b/chromium/mojo/public/cpp/system/tests/BUILD.gn
@@ -8,12 +8,12 @@ source_set("tests") {
sources = [
"core_unittest.cc",
"data_pipe_drainer_unittest.cc",
- "file_data_pipe_producer_unittest.cc",
+ "data_pipe_producer_unittest.cc",
"handle_signal_tracker_unittest.cc",
"handle_signals_state_unittest.cc",
"scope_to_message_pipe_unittest.cc",
"simple_watcher_unittest.cc",
- "string_data_pipe_producer_unittest.cc",
+ "string_data_source_unittest.cc",
"wait_set_unittest.cc",
"wait_unittest.cc",
]
diff --git a/chromium/mojo/public/interfaces/bindings/interface_control_messages.mojom b/chromium/mojo/public/interfaces/bindings/interface_control_messages.mojom
index 0a1904206a5..f9f24103876 100644
--- a/chromium/mojo/public/interfaces/bindings/interface_control_messages.mojom
+++ b/chromium/mojo/public/interfaces/bindings/interface_control_messages.mojom
@@ -57,6 +57,9 @@ struct RunOrClosePipeMessageParams {
};
union RunOrClosePipeInput {
RequireVersion require_version;
+ EnableIdleTracking enable_idle_tracking;
+ MessageAck message_ack;
+ NotifyIdle notify_idle;
};
// If the specified version of the user-defined interface is not supported, the
@@ -65,3 +68,24 @@ union RunOrClosePipeInput {
struct RequireVersion {
uint32 version;
};
+
+// Sent by a remote caller endpoint to a receiving endpoint to enable idle state
+// tracking. Once a receiving endpoint receives this message, it will begin
+// acknowledging all received interface messages with a MessageAck, and may send
+// arbitrarily many NotifyIdle messages any time it believes itself to have been
+// idle for a continuous period at least as long as |timeout_in_microseconds|.
+struct EnableIdleTracking {
+ // NOTE: It would be nice to use mojo_base.mojom.TimeDelta here, but currently
+ // that results in a tricky dependency cycle for JS bindings.
+ int64 timeout_in_microseconds;
+};
+
+// Sent by a receiving endpoint to its client to acknowledge message receipt.
+// Should only be sent by endpoints which have previously received an
+// EnableIdleTracking message.
+struct MessageAck {};
+
+// Sent by a receiving endpoint to its client to indicate that the receiver is
+// currently idle. Should only be sent by endpoints which have previously
+// received and EnableIdleTracking message.
+struct NotifyIdle {};
diff --git a/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn b/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn
index a5efd42d93c..97f241a74aa 100644
--- a/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn
+++ b/chromium/mojo/public/interfaces/bindings/tests/BUILD.gn
@@ -301,6 +301,7 @@ mojom("test_interfaces") {
":echo",
":test_mojom_import",
":test_mojom_import2",
+ "//mojo/public/mojom/base",
]
support_lazy_serialization = true
diff --git a/chromium/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom b/chromium/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom
index 5960d756657..1bcd7502950 100644
--- a/chromium/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom
+++ b/chromium/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom
@@ -7,6 +7,8 @@
Foo = "hello world"]
module sample;
+import "mojo/public/mojom/base/generic_pending_receiver.mojom";
+
const uint64 kLong = 4405;
enum Enum {
@@ -30,3 +32,7 @@ interface IntegerAccessor {
[MinVersion=1]
SetInteger(int64 data, [MinVersion=3] Enum type);
};
+
+interface InterfaceFactory {
+ BindInterface(mojo_base.mojom.GenericPendingReceiver receiver);
+};
diff --git a/chromium/mojo/public/java/system/BUILD.gn b/chromium/mojo/public/java/system/BUILD.gn
index 49b2dbcaebf..c493a9dbd36 100644
--- a/chromium/mojo/public/java/system/BUILD.gn
+++ b/chromium/mojo/public/java/system/BUILD.gn
@@ -21,8 +21,6 @@ generate_jni("jni_headers") {
public_deps = [
":system_impl_java_jni_headers",
]
-
- jni_package = "mojo"
}
generate_jni("system_impl_java_jni_headers") {
@@ -31,8 +29,6 @@ generate_jni("system_impl_java_jni_headers") {
"src/org/chromium/mojo/system/impl/CoreImpl.java",
"src/org/chromium/mojo/system/impl/WatcherImpl.java",
]
-
- jni_package = "mojo"
}
source_set("native_support") {
@@ -174,5 +170,6 @@ instrumentation_test_apk("mojo_test_apk") {
shared_libraries = [ ":mojo_java_unittests" ]
apk_name = "MojoTest"
android_manifest = "javatests/AndroidManifest.xml"
+ target_sdk_version = 21
enable_multidex = false
}
diff --git a/chromium/mojo/public/java/system/base_run_loop.cc b/chromium/mojo/public/java/system/base_run_loop.cc
index 5b14852b130..012ce48c187 100644
--- a/chromium/mojo/public/java/system/base_run_loop.cc
+++ b/chromium/mojo/public/java/system/base_run_loop.cc
@@ -8,10 +8,10 @@
#include "base/android/scoped_java_ref.h"
#include "base/bind.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
-#include "jni/BaseRunLoop_jni.h"
+#include "base/task/single_thread_task_executor.h"
+#include "mojo/public/java/system/system_impl_java_jni_headers/BaseRunLoop_jni.h"
using base::android::JavaParamRef;
@@ -21,8 +21,9 @@ namespace android {
static jlong JNI_BaseRunLoop_CreateBaseRunLoop(
JNIEnv* env,
const JavaParamRef<jobject>& jcaller) {
- base::MessageLoop* message_loop = new base::MessageLoop;
- return reinterpret_cast<uintptr_t>(message_loop);
+ base::SingleThreadTaskExecutor* task_executor =
+ new base::SingleThreadTaskExecutor;
+ return reinterpret_cast<uintptr_t>(task_executor);
}
static void JNI_BaseRunLoop_Run(JNIEnv* env,
@@ -57,7 +58,7 @@ static void JNI_BaseRunLoop_PostDelayedTask(
// use it across threads. |RunJavaRunnable| will acquire a new JNIEnv before
// running the Runnable.
runnable_ref.Reset(env, runnable);
- reinterpret_cast<base::MessageLoop*>(runLoopID)
+ reinterpret_cast<base::SingleThreadTaskExecutor*>(runLoopID)
->task_runner()
->PostDelayedTask(FROM_HERE,
base::BindOnce(&RunJavaRunnable, runnable_ref),
@@ -68,9 +69,9 @@ static void JNI_BaseRunLoop_DeleteMessageLoop(
JNIEnv* env,
const JavaParamRef<jobject>& jcaller,
jlong runLoopID) {
- base::MessageLoop* message_loop =
- reinterpret_cast<base::MessageLoop*>(runLoopID);
- delete message_loop;
+ base::SingleThreadTaskExecutor* task_executor =
+ reinterpret_cast<base::SingleThreadTaskExecutor*>(runLoopID);
+ delete task_executor;
}
} // namespace android
diff --git a/chromium/mojo/public/java/system/core_impl.cc b/chromium/mojo/public/java/system/core_impl.cc
index 33f0576a4c4..97278a0d78a 100644
--- a/chromium/mojo/public/java/system/core_impl.cc
+++ b/chromium/mojo/public/java/system/core_impl.cc
@@ -8,9 +8,9 @@
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/scoped_java_ref.h"
-#include "jni/CoreImpl_jni.h"
#include "mojo/public/c/system/core.h"
#include "mojo/public/cpp/system/message_pipe.h"
+#include "mojo/public/java/system/system_impl_java_jni_headers/CoreImpl_jni.h"
namespace mojo {
namespace android {
diff --git a/chromium/mojo/public/java/system/javatests/AndroidManifest.xml b/chromium/mojo/public/java/system/javatests/AndroidManifest.xml
index 84b217bdcfc..04abc64e684 100644
--- a/chromium/mojo/public/java/system/javatests/AndroidManifest.xml
+++ b/chromium/mojo/public/java/system/javatests/AndroidManifest.xml
@@ -8,8 +8,6 @@
xmlns:tools="http://schemas.android.com/tools"
package="org.chromium.mojo.tests">
- <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="21" />
-
<uses-permission android:name="android.permission.INJECT_EVENTS"
tools:ignore="ProtectedPermissions"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
diff --git a/chromium/mojo/public/java/system/javatests/mojo_test_rule.cc b/chromium/mojo/public/java/system/javatests/mojo_test_rule.cc
index be37af1bb6e..52e2b047bc4 100644
--- a/chromium/mojo/public/java/system/javatests/mojo_test_rule.cc
+++ b/chromium/mojo/public/java/system/javatests/mojo_test_rule.cc
@@ -8,13 +8,13 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
+#include "base/task/single_thread_task_executor.h"
#include "base/test/test_support_android.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "jni/MojoTestRule_jni.h"
#include "mojo/core/embedder/embedder.h"
+#include "mojo/public/java/system/jni_headers/MojoTestRule_jni.h"
using base::android::JavaParamRef;
@@ -24,7 +24,7 @@ struct TestEnvironment {
TestEnvironment() {}
base::ShadowingAtExitManager at_exit;
- base::MessageLoop message_loop;
+ base::SingleThreadTaskExecutor main_task_executor;
};
} // namespace
diff --git a/chromium/mojo/public/java/system/javatests/validation_test_util.cc b/chromium/mojo/public/java/system/javatests/validation_test_util.cc
index 7aa1098ead2..7c3c0a64edd 100644
--- a/chromium/mojo/public/java/system/javatests/validation_test_util.cc
+++ b/chromium/mojo/public/java/system/javatests/validation_test_util.cc
@@ -9,8 +9,8 @@
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/test/test_support_android.h"
-#include "jni/ValidationTestUtil_jni.h"
#include "mojo/public/cpp/bindings/tests/validation_test_input_parser.h"
+#include "mojo/public/java/system/jni_headers/ValidationTestUtil_jni.h"
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
diff --git a/chromium/mojo/public/java/system/watcher_impl.cc b/chromium/mojo/public/java/system/watcher_impl.cc
index 36196487ebc..e251d2e6cbb 100644
--- a/chromium/mojo/public/java/system/watcher_impl.cc
+++ b/chromium/mojo/public/java/system/watcher_impl.cc
@@ -8,9 +8,9 @@
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "base/bind.h"
-#include "jni/WatcherImpl_jni.h"
#include "mojo/public/cpp/system/handle.h"
#include "mojo/public/cpp/system/simple_watcher.h"
+#include "mojo/public/java/system/system_impl_java_jni_headers/WatcherImpl_jni.h"
namespace mojo {
namespace android {
diff --git a/chromium/mojo/public/js/interface_support.js b/chromium/mojo/public/js/interface_support.js
index 77ab0f966c3..36ec5dd7f0c 100644
--- a/chromium/mojo/public/js/interface_support.js
+++ b/chromium/mojo/public/js/interface_support.js
@@ -11,7 +11,7 @@ goog.provide('mojo.internal.interfaceSupport');
/**
- * Handles incoming interface control messages on a proxy or router endpoint.
+ * Handles incoming interface control messages on a remote or router endpoint.
*/
mojo.internal.interfaceSupport.ControlMessageHandler = class {
/** @param {!MojoHandle} handle */
@@ -72,8 +72,8 @@ mojo.internal.interfaceSupport.ControlMessageHandler = class {
};
/**
- * Captures metadata about a request which was sent by a local proxy, for which
- * a response is expected.
+ * Captures metadata about a request which was sent by a remote, for which a
+ * response is expected.
*/
mojo.internal.interfaceSupport.PendingResponse = class {
/**
@@ -150,16 +150,16 @@ mojo.internal.interfaceSupport.ConnectionErrorEventRouter = class {
};
/**
- * Generic helper used to implement all generated proxy classes. Knows how to
+ * Generic helper used to implement all generated remote classes. Knows how to
* serialize requests and deserialize their replies, both according to
* declarative message structure specs.
* @template T
* @export
*/
-mojo.internal.interfaceSupport.InterfaceProxyBase = class {
+mojo.internal.interfaceSupport.InterfaceRemoteBase = class {
/**
* @param {!function(new:T, !MojoHandle)} requestType
- * @param {MojoHandle=} opt_handle The message pipe handle to use as a proxy
+ * @param {MojoHandle=} opt_handle The message pipe handle to use as a remote
* endpoint. If null, this object must be bound with bindHandle before
* it can be used to send any messages.
* @public
@@ -196,7 +196,7 @@ mojo.internal.interfaceSupport.InterfaceProxyBase = class {
/**
* @return {!T}
*/
- createRequest() {
+ bindNewPipeAndPassReceiver() {
let {handle0, handle1} = Mojo.createMessagePipe();
this.bindHandle(handle0);
return new this.requestType_(handle1);
@@ -208,7 +208,7 @@ mojo.internal.interfaceSupport.InterfaceProxyBase = class {
*/
bindHandle(handle) {
if (this.handle)
- throw new Error('Proxy already bound.');
+ throw new Error('Remote already bound.');
this.handle = handle;
const reader = new mojo.internal.interfaceSupport.HandleReader(handle);
@@ -253,7 +253,8 @@ mojo.internal.interfaceSupport.InterfaceProxyBase = class {
sendMessage(ordinal, paramStruct, responseStruct, args) {
if (!this.handle) {
throw new Error(
- 'Attempting to use an unbound proxy. Try $.createRequest() first.')
+ 'Attempting to use an unbound remote. Try ' +
+ '$.bindNewPipeAndPassReceiver() first.')
}
// The pipe has already been closed, so just drop the message.
@@ -344,33 +345,42 @@ mojo.internal.interfaceSupport.InterfaceProxyBase = class {
};
/**
- * Wrapper around mojo.internal.interfaceSupport.InterfaceProxyBase that
- * exposes the subset of InterfaceProxyBase's method that users are allowed
+ * Wrapper around mojo.internal.interfaceSupport.InterfaceRemoteBase that
+ * exposes the subset of InterfaceRemoteBase's method that users are allowed
* to use.
* @template T
* @export
*/
-mojo.internal.interfaceSupport.InterfaceProxyBaseWrapper = class {
+mojo.internal.interfaceSupport.InterfaceRemoteBaseWrapper = class {
/**
- * @param {!mojo.internal.interfaceSupport.InterfaceProxyBase<T>} proxy
+ * @param {!mojo.internal.interfaceSupport.InterfaceRemoteBase<T>} remote
* @public
*/
- constructor(proxy) {
- /** @private {!mojo.internal.interfaceSupport.InterfaceProxyBase<T>} */
- this.proxy_ = proxy;
+ constructor(remote) {
+ /** @private {!mojo.internal.interfaceSupport.InterfaceRemoteBase<T>} */
+ this.remote_ = remote;
}
+ // TODO(ortuno): Remove once new names are used in the exposed interfaces.
/**
* @return {!T}
* @export
*/
createRequest() {
- return this.proxy_.createRequest();
+ return this.remote_.bindNewPipeAndPassReceiver();
+ }
+
+ /**
+ * @return {!T}
+ * @export
+ */
+ bindNewPipeAndPassReceiver() {
+ return this.remote_.bindNewPipeAndPassReceiver();
}
/** @export */
close() {
- this.proxy_.close();
+ this.remote_.close();
}
/**
@@ -378,7 +388,7 @@ mojo.internal.interfaceSupport.InterfaceProxyBaseWrapper = class {
* @export
*/
flushForTesting() {
- return this.proxy_.flushForTesting();
+ return this.remote_.flushForTesting();
}
}
@@ -417,7 +427,7 @@ mojo.internal.interfaceSupport.CallbackRouter = class {
* messages to listeners.
* @export
*/
-mojo.internal.interfaceSupport.InterfaceCallbackTarget = class {
+mojo.internal.interfaceSupport.InterfaceCallbackReceiver = class {
/**
* @public
* @param {!mojo.internal.interfaceSupport.CallbackRouter} callbackRouter
@@ -449,7 +459,7 @@ mojo.internal.interfaceSupport.InterfaceCallbackTarget = class {
* @return {!Function}
* @export
*/
- createTargetHandler(expectsResponse) {
+ createReceiverHandler(expectsResponse) {
if (expectsResponse)
return this.dispatchWithResponse_.bind(this);
return this.dispatch_.bind(this);
@@ -488,7 +498,7 @@ mojo.internal.interfaceSupport.InterfaceCallbackTarget = class {
};
/**
- * Wraps message handlers attached to an InterfaceTarget.
+ * Wraps message handlers attached to an InterfaceReceiver.
*/
mojo.internal.interfaceSupport.MessageHandler = class {
/**
@@ -510,20 +520,28 @@ mojo.internal.interfaceSupport.MessageHandler = class {
};
/**
- * Listens for incoming request messages on a message pipe, dispatching them to
- * any registered handlers. Handlers are registered against a specific ordinal
- * message number.
+ * Generic helper that listens for incoming request messages on a message pipe,
+ * dispatching them to any registered handlers. Handlers are registered against
+ * a specific ordinal message number. It has methods to perform operations
+ * related to the interface pipe e.g. bind the pipe, close it, etc. Should only
+ * be used by the generated receiver classes.
+ * @template T
* @export
*/
-mojo.internal.interfaceSupport.InterfaceTarget = class {
- /** @public */
- constructor() {
+mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal = class {
+ /**
+ * @param {!function(new:T)} remoteType
+ * @public
+ */
+ constructor(remoteType) {
/**
* @private {!Map<MojoHandle,
* !mojo.internal.interfaceSupport.HandleReader>}
*/
this.readers_ = new Map;
+ /** @private {!function(new:T)} */
+ this.remoteType_ = remoteType;
/**
* @private {!Map<number, !mojo.internal.interfaceSupport.MessageHandler>}
*/
@@ -565,6 +583,16 @@ mojo.internal.interfaceSupport.InterfaceTarget = class {
new mojo.internal.interfaceSupport.ControlMessageHandler(handle);
}
+ /**
+ * @return {!T}
+ * @export
+ */
+ bindNewPipeAndPassRemote() {
+ let remote = new this.remoteType_;
+ this.bindHandle(remote.$.bindNewPipeAndPassReceiver().handle);
+ return remote;
+ }
+
/** @export */
closeBindings() {
for (const reader of this.readers_.values())
@@ -592,7 +620,7 @@ mojo.internal.interfaceSupport.InterfaceTarget = class {
if (this.controlMessageHandler_.maybeHandleControlMessage(header, buffer))
return;
if (header.flags & mojo.internal.kMessageFlagIsResponse)
- throw new Error('Received unexpected response on interface target');
+ throw new Error('Received unexpected response on interface receiver');
const handler = this.messageHandlers_.get(header.ordinal);
if (!handler)
throw new Error('Received unknown message');
@@ -653,9 +681,68 @@ mojo.internal.interfaceSupport.InterfaceTarget = class {
};
/**
+ * Generic helper used to perform operations related to the interface pipe e.g.
+ * bind the pipe, close it, flush it for testing, etc. Wraps
+ * mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal and exposes a
+ * subset of methods that meant to be used by users of a receiver class.
+ *
+ * @template T
+ * @export
+ */
+mojo.internal.interfaceSupport.InterfaceReceiverHelper = class {
+ /**
+ * @param {!mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal<T>}
+ * helper_internal
+ * @public
+ */
+ constructor(helper_internal) {
+ /**
+ * @private {!mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal<T>}
+ */
+ this.helper_internal_ = helper_internal;
+ }
+
+ /**
+ * Binds a new handle to this object. Messages which arrive on the handle will
+ * be read and dispatched to this object.
+ *
+ * @param {!MojoHandle} handle
+ * @export
+ */
+ bindHandle(handle) {
+ this.helper_internal_.bindHandle(handle);
+ }
+
+ // TODO(ortuno): Remove once new names are used in the exposed interfaces.
+ /**
+ * Returns a remote for this interface which sends messages directly to this
+ * object. Any number of proxies may be created to the same object.
+ *
+ * @return {!T}
+ * @export
+ */
+ createProxy() {
+ return this.helper_internal_.bindNewPipeAndPassRemote();
+ }
+
+ /**
+ * @return {!T}
+ * @export
+ */
+ bindNewPipeAndPassRemote() {
+ return this.helper_internal_.bindNewPipeAndPassRemote();
+ }
+
+ /** @export */
+ close() {
+ this.helper_internal_.closeBindings();
+ }
+}
+
+/**
* Watches a MojoHandle for readability or peer closure, forwarding either event
- * to one of two callbacks on the reader. Used by both InterfaceProxyBase and
- * InterfaceTarget to watch for incoming messages.
+ * to one of two callbacks on the reader. Used by both InterfaceRemoteBase and
+ * InterfaceReceiverHelperInternal to watch for incoming messages.
*/
mojo.internal.interfaceSupport.HandleReader = class {
/**
diff --git a/chromium/mojo/public/js/test/BUILD.gn b/chromium/mojo/public/js/test/BUILD.gn
index 8816cc14c29..00fb5213d01 100644
--- a/chromium/mojo/public/js/test/BUILD.gn
+++ b/chromium/mojo/public/js/test/BUILD.gn
@@ -13,6 +13,19 @@ mojom("test_mojom") {
"module_b_1.test-mojom",
"module_b_2.test-mojom",
]
+
+ use_old_js_lite_bindings_names = false
+}
+
+mojom("test_old_names_mojom") {
+ testonly = true
+ sources = [
+ "module_a_old_names.test-mojom",
+ "module_b_1_old_names.test-mojom",
+ "module_b_2_old_names.test-mojom",
+ ]
+
+ use_old_js_lite_bindings_names = true
}
if (enable_mojom_closure_compile || closure_compile) {
@@ -22,6 +35,7 @@ if (enable_mojom_closure_compile || closure_compile) {
]
deps = [
":test_mojom_js_library_for_compile",
+ ":test_old_names_mojom_js_library_for_compile",
]
}
@@ -32,6 +46,7 @@ if (enable_mojom_closure_compile || closure_compile) {
deps = [
":compile_test_sources",
":test_mojom_js_library_for_compile",
+ ":test_old_names_mojom_js_library_for_compile",
]
closure_flags = strict_error_checking_closure_args + [
"compilation_level=ADVANCED_OPTIMIZATIONS",
diff --git a/chromium/mojo/public/mojom/base/BUILD.gn b/chromium/mojo/public/mojom/base/BUILD.gn
index e6c8e1a76c4..c1a5d9e6c73 100644
--- a/chromium/mojo/public/mojom/base/BUILD.gn
+++ b/chromium/mojo/public/mojom/base/BUILD.gn
@@ -13,9 +13,12 @@ mojom_component("base") {
"file_error.mojom",
"file_info.mojom",
"file_path.mojom",
+ "generic_pending_receiver.mojom",
"memory_allocator_dump_cross_process_uid.mojom",
"memory_pressure_level.mojom",
+ "message_loop_type.mojom",
"process_id.mojom",
+ "read_only_buffer.mojom",
"ref_counted_memory.mojom",
"shared_memory.mojom",
"string16.mojom",
@@ -40,9 +43,3 @@ mojom_component("base") {
output_prefix = "mojo_base_mojom"
macro_prefix = "MOJO_BASE_MOJOM"
}
-
-mojom("read_only_buffer") {
- sources = [
- "read_only_buffer.mojom",
- ]
-}
diff --git a/chromium/mojo/public/mojom/base/generic_pending_receiver.mojom b/chromium/mojo/public/mojom/base/generic_pending_receiver.mojom
new file mode 100644
index 00000000000..67dda272651
--- /dev/null
+++ b/chromium/mojo/public/mojom/base/generic_pending_receiver.mojom
@@ -0,0 +1,16 @@
+// Copyright 2019 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_base.mojom;
+
+// Convenience helper to wrap the pairing of a receiving pipe endpoint and the
+// name of the interface expected by the remote endpoint.
+//
+// This should be used sparingly, in cases where APIs need to dynamically pass
+// different types of receivers that cannot or should not be known at compile
+// time.
+struct GenericPendingReceiver {
+ string interface_name;
+ handle<message_pipe> receiving_pipe;
+};
diff --git a/chromium/mojo/public/mojom/base/message_loop_type.mojom b/chromium/mojo/public/mojom/base/message_loop_type.mojom
new file mode 100644
index 00000000000..d0d87757d5f
--- /dev/null
+++ b/chromium/mojo/public/mojom/base/message_loop_type.mojom
@@ -0,0 +1,21 @@
+// Copyright 2019 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_base.mojom;
+
+// Mirror of base::MessageLoop::Type.
+enum MessageLoopType {
+ kDefault,
+ kUi,
+ kCustom,
+ kIo,
+ [EnableIf=is_android]
+ kJava,
+ [EnableIf=is_mac]
+ kNsRunloop,
+ [EnableIf=is_ios]
+ kNsRunloop,
+ [EnableIf=is_win]
+ kUiWithWmQuitSupport,
+};
diff --git a/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index d70eb62df58..25384ccd0ad 100644
--- a/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/chromium/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -3,8 +3,7 @@
# found in the LICENSE file.
_typemap_imports = [
- "//ash/public/interfaces/typemaps.gni",
- "//chrome/chrome_cleaner/interfaces/typemaps/typemaps.gni",
+ "//chrome/chrome_cleaner/mojom/typemaps/typemaps.gni",
"//chrome/common/importer/typemaps.gni",
"//chrome/common/media_router/mojo/typemaps.gni",
"//chrome/typemaps.gni",
@@ -15,14 +14,15 @@ _typemap_imports = [
"//chromeos/services/secure_channel/public/mojom/typemaps.gni",
"//components/arc/common/typemaps.gni",
"//components/chromeos_camera/common/typemaps.gni",
- "//components/sync/mojo/typemaps.gni",
+ "//components/sync/mojom/typemaps.gni",
"//components/typemaps.gni",
- "//content/common/bluetooth/typemaps.gni",
+ "//content/browser/typemaps.gni",
"//content/common/typemaps.gni",
"//content/public/common/typemaps.gni",
"//device/bluetooth/public/mojom/typemaps.gni",
"//device/bluetooth/public/mojom/test/typemaps.gni",
"//device/gamepad/public/cpp/typemaps.gni",
+ "//fuchsia/mojo/test_typemaps.gni",
"//gpu/ipc/common/typemaps.gni",
"//ipc/typemaps.gni",
"//media/capture/mojom/typemaps.gni",
@@ -51,13 +51,11 @@ _typemap_imports = [
"//ui/accessibility/mojom/typemaps.gni",
"//ui/base/accelerators/mojo/typemaps.gni",
"//ui/base/ime/mojo/typemaps.gni",
- "//ui/base/mojo/typemaps.gni",
- "//ui/display/mojo/typemaps.gni",
- "//ui/events/devices/mojo/typemaps.gni",
+ "//ui/base/mojom/typemaps.gni",
+ "//ui/display/mojom/typemaps.gni",
"//ui/events/mojo/typemaps.gni",
"//ui/gfx/typemaps.gni",
"//ui/latency/mojo/typemaps.gni",
- "//ui/message_center/public/mojo/typemaps.gni",
"//ui/ozone/public/interfaces/typemaps.gni",
"//url/mojom/typemaps.gni",
]
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 304098680d8..8ad699bad15 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
@@ -291,7 +291,7 @@ bool {{class_name}}_{{method.name}}_ForwardToCallback::Accept(
message->SerializeIfNecessary();
} else {
if (!callback_.is_null())
- context->Dispatch(&callback_);
+ context->Dispatch(message, &callback_);
return true;
}
}
@@ -358,9 +358,9 @@ bool {{class_name}}_{{method.name}}_HandleSyncResponse::Accept(
message->SerializeIfNecessary();
} else {
context->HandleSyncResponse(
-{%- for param in method.response_parameters %}
+ message
+{%- for param in method.response_parameters %},
out_{{param.name}}_
-{%- if not loop.last -%}, {% endif -%}
{%- endfor %});
*result_ = true;
mojo::internal::SyncMessageResponseSetup::SetCurrentSyncResponseMessage(
@@ -421,7 +421,7 @@ bool {{class_name}}StubDispatch::Accept(
// Force serialization before dispatch in this case.
message->SerializeIfNecessary();
} else {
- context->Dispatch(impl);
+ context->Dispatch(message, impl);
return true;
}
}
@@ -484,7 +484,7 @@ bool {{class_name}}StubDispatch::AcceptWithResponder(
message->request_id(),
message->has_flag(mojo::Message::kFlagIsSync),
std::move(responder));
- context->Dispatch(impl, std::move(callback));
+ context->Dispatch(message, impl, std::move(callback));
return true;
}
}
diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
index e2ca7eafe2a..67940021e20 100644
--- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
+++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/interface_macros.tmpl
@@ -120,10 +120,21 @@ class {{message_typename}}
}
{% if not is_response %}
- void Dispatch({{interface.name}}* impl
+ void Dispatch(
+ mojo::Message* message,
+ {{interface.name}}* impl
{%- if method.response_parameters != None -%}
, {{interface.name}}::{{method.name}}Callback callback
{%- endif -%}) {
+ if (message->receiver_connection_group()) {
+{%- for param in parameters -%}
+{%- if param.kind|is_receiver_kind %}
+ param_{{param.name}}_.set_connection_group(
+ *message->receiver_connection_group());
+{%- endif %}
+{%- endfor %}
+ }
+
impl->{{method.name}}(
{%- for param in parameters -%}
{%- if param.kind|is_interface_kind %}
@@ -138,7 +149,17 @@ class {{message_typename}}
{%- endif -%});
}
{%- else %}
- void Dispatch({{interface.name}}::{{method.name}}Callback* callback) {
+ void Dispatch(mojo::Message* message,
+ {{interface.name}}::{{method.name}}Callback* callback) {
+ if (message->receiver_connection_group()) {
+{%- for param in parameters -%}
+{%- if param.kind|is_receiver_kind %}
+ param_{{param.name}}_.set_connection_group(
+ *message->receiver_connection_group());
+{%- endif %}
+{%- endfor %}
+ }
+
std::move(*callback).Run(
{%- for param in parameters -%}
{%- if param.kind|is_interface_kind %}
@@ -152,10 +173,20 @@ class {{message_typename}}
{% if method.sync %}
void HandleSyncResponse(
-{% for param in parameters %}
+ mojo::Message* message
+{% for param in parameters %},
{{param.kind|cpp_wrapper_call_type}}* out_{{param.name}}
- {%- if not loop.last -%}, {% endif -%}
{%- endfor -%}) {
+
+ if (message->receiver_connection_group()) {
+{%- for param in parameters -%}
+{%- if param.kind|is_receiver_kind %}
+ param_{{param.name}}_.set_connection_group(
+ *message->receiver_connection_group());
+{%- endif %}
+{%- endfor %}
+ }
+
{% for param in parameters -%}
{%- if param.kind|is_interface_kind %}
out_{{param.name}}->Bind(std::move(param_{{param.name}}_));
diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl
index 007e89e34e6..5df13c5127e 100644
--- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl
+++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/module-forward.h.tmpl
@@ -190,17 +190,21 @@ typedef mojo::StructPtr<{{union.name}}> {{union.name}}Ptr;
{#--- Interface Forward Declarations -#}
{% for interface in interfaces %}
class {{interface.name}};
+{{ kythe_annotation("%s.%s"|format(module_prefix, interface.name)) }}
using {{interface.name}}Ptr = mojo::InterfacePtr<{{interface.name}}>;
using {{interface.name}}PtrInfo = mojo::InterfacePtrInfo<{{interface.name}}>;
using ThreadSafe{{interface.name}}Ptr =
mojo::ThreadSafeInterfacePtr<{{interface.name}}>;
+{{ kythe_annotation("%s.%s"|format(module_prefix, interface.name)) }}
using {{interface.name}}Request = mojo::InterfaceRequest<{{interface.name}}>;
+{{ kythe_annotation("%s.%s"|format(module_prefix, interface.name)) }}
using {{interface.name}}AssociatedPtr =
mojo::AssociatedInterfacePtr<{{interface.name}}>;
using ThreadSafe{{interface.name}}AssociatedPtr =
mojo::ThreadSafeAssociatedInterfacePtr<{{interface.name}}>;
using {{interface.name}}AssociatedPtrInfo =
mojo::AssociatedInterfacePtrInfo<{{interface.name}}>;
+{{ kythe_annotation("%s.%s"|format(module_prefix, interface.name)) }}
using {{interface.name}}AssociatedRequest =
mojo::AssociatedInterfaceRequest<{{interface.name}}>;
{% endfor %}
diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
index 801c01523bd..0679323afd5 100644
--- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
+++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
@@ -3,6 +3,8 @@
{{ kythe_annotation(struct_prefix) }}
class {{export_attribute}} {{struct.name}} {
public:
+ template <typename T>
+ using EnableIfSame = std::enable_if_t<std::is_same<{{struct.name}}, T>::value>;
using DataView = {{struct.name}}DataView;
using Data_ = internal::{{struct.name}}_Data;
@@ -54,9 +56,7 @@ class {{export_attribute}} {{struct.name}} {
// Equals() is a template so it is only instantiated if it is used. Thus, the
// bindings generator does not need to know whether Equals() or == operator
// are available for members.
- template <typename T,
- typename std::enable_if<std::is_same<
- T, {{struct.name}}>::value>::type* = nullptr>
+ template <typename T, {{struct.name}}::EnableIfSame<T>* = nullptr>
bool Equals(const T& other) const;
{%- if struct|is_hashable %}
@@ -136,3 +136,24 @@ class {{export_attribute}} {{struct.name}} {
DISALLOW_COPY_AND_ASSIGN({{struct.name}});
{%- endif %}
};
+
+// The comparison operators are templates, so they are only instantiated if they
+// are used. Thus, the bindings generator does not need to know whether
+// comparison operators are available for members.
+template <typename T, {{struct.name}}::EnableIfSame<T>* = nullptr>
+bool operator<(const T& lhs, const T& rhs);
+
+template <typename T, {{struct.name}}::EnableIfSame<T>* = nullptr>
+bool operator<=(const T& lhs, const T& rhs) {
+ return !(rhs < lhs);
+}
+
+template <typename T, {{struct.name}}::EnableIfSame<T>* = nullptr>
+bool operator>(const T& lhs, const T& rhs) {
+ return rhs < lhs;
+}
+
+template <typename T, {{struct.name}}::EnableIfSame<T>* = nullptr>
+bool operator>=(const T& lhs, const T& rhs) {
+ return !(lhs < rhs);
+}
diff --git a/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl
index fab27cd8d00..32bf674804c 100644
--- a/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl
+++ b/chromium/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_template_definition.tmpl
@@ -8,9 +8,7 @@ template <typename StructPtrType>
);
}
-template <typename T,
- typename std::enable_if<std::is_same<
- T, {{struct.name}}>::value>::type*>
+template <typename T, {{struct.name}}::EnableIfSame<T>*>
bool {{struct.name}}::Equals(const T& other_struct) const {
{%- for field in struct.fields %}
if (!mojo::Equals(this->{{field.name}}, other_struct.{{field.name}}))
@@ -18,3 +16,14 @@ bool {{struct.name}}::Equals(const T& other_struct) const {
{%- endfor %}
return true;
}
+
+template <typename T, {{struct.name}}::EnableIfSame<T>*>
+bool operator<(const T& lhs, const T& rhs) {
+{%- for field in struct.fields %}
+ if (lhs.{{field.name}} < rhs.{{field.name}})
+ return true;
+ if (rhs.{{field.name}} < lhs.{{field.name}})
+ return false;
+{%- endfor %}
+ return false;
+}
diff --git a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl
index 094f0dd80e2..295987a6882 100644
--- a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl
+++ b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/interface_definition.tmpl
@@ -18,15 +18,18 @@
{% endmacro %}
{% if generate_closure_exports -%}
+{% if not use_old_names -%}
goog.provide('{{module.namespace}}.{{interface.name}}');
+{% endif %}
+goog.provide('{{module.namespace}}.{{interface.name}}{{primitives_names.receiver}}');
goog.provide('{{module.namespace}}.{{interface.name}}CallbackRouter');
goog.provide('{{module.namespace}}.{{interface.name}}Interface');
-goog.provide('{{module.namespace}}.{{interface.name}}Proxy');
-goog.provide('{{module.namespace}}.{{interface.name}}Request');
+goog.provide('{{module.namespace}}.{{interface.name}}{{primitives_names.remote}}');
+goog.provide('{{module.namespace}}.{{interface.name}}{{primitives_names.pending_receiver}}');
{% endif %}
/** @export */
-{{module.namespace}}.{{interface.name}}Request = class {
+{{module.namespace}}.{{interface.name}}{{primitives_names.pending_receiver}} = class {
/** @param {!MojoHandle} handle */
constructor(handle) {
/** @public {!MojoHandle} */
@@ -52,21 +55,21 @@ goog.provide('{{module.namespace}}.{{interface.name}}Request');
* @export
* @implements { {{module.namespace}}.{{interface.name}}Interface }
*/
-{{module.namespace}}.{{interface.name}}Proxy = class {
+{{module.namespace}}.{{interface.name}}{{primitives_names.remote}} = class {
/** @param {MojoHandle=} opt_handle */
constructor(opt_handle) {
/**
- * @private {!mojo.internal.interfaceSupport.InterfaceProxyBase<!{{module.namespace}}.{{interface.name}}Request>}
+ * @private {!mojo.internal.interfaceSupport.InterfaceRemoteBase<!{{module.namespace}}.{{interface.name}}{{primitives_names.pending_receiver}}>}
*/
this.proxy =
- new mojo.internal.interfaceSupport.InterfaceProxyBase(
- {{module.namespace}}.{{interface.name}}Request,
+ new mojo.internal.interfaceSupport.InterfaceRemoteBase(
+ {{module.namespace}}.{{interface.name}}{{primitives_names.pending_receiver}},
opt_handle);
/**
- * @public {!mojo.internal.interfaceSupport.InterfaceProxyBaseWrapper<!{{module.namespace}}.{{interface.name}}Request>}
+ * @public {!mojo.internal.interfaceSupport.InterfaceRemoteBaseWrapper<!{{module.namespace}}.{{interface.name}}{{primitives_names.pending_receiver}}>}
*/
- this.$ = new mojo.internal.interfaceSupport.InterfaceProxyBaseWrapper(this.proxy);
+ this.$ = new mojo.internal.interfaceSupport.InterfaceRemoteBaseWrapper(this.proxy);
/** @public {!mojo.internal.interfaceSupport.ConnectionErrorEventRouter} */
this.onConnectionError = this.proxy.getConnectionErrorEventRouter();
@@ -109,16 +112,24 @@ goog.provide('{{module.namespace}}.{{interface.name}}Request');
*
* @export
*/
-{{module.namespace}}.{{interface.name}} = class {
+{{module.namespace}}.{{interface.name}}{{primitives_names.receiver}} = class {
/**
* @param {!{{module.namespace}}.{{interface.name}}Interface } impl
*/
constructor(impl) {
- this.target_ = new mojo.internal.interfaceSupport.InterfaceTarget;
+ /** @private {!mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal<!{{module.namespace}}.{{interface.name}}{{primitives_names.remote}}>} */
+ this.helper_internal_ = new mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal(
+ {{module.namespace}}.{{interface.name}}{{primitives_names.remote}});
+
+ /**
+ * @public {!mojo.internal.interfaceSupport.InterfaceReceiverHelper<!{{module.namespace}}.{{interface.name}}{{primitives_names.remote}}>}
+ */
+ this.$ = new mojo.internal.interfaceSupport.InterfaceReceiverHelper(this.helper_internal_);
+
{% for method in interface.methods %}
{%- set interface_message_id =
interface.mojom_name ~ "_" ~ method.mojom_name %}
- this.target_.registerHandler(
+ this.helper_internal_.registerHandler(
{{method.ordinal}},
{{module.namespace}}.{{interface_message_id}}_ParamsSpec.$,
{%- if method.response_parameters != None %}
@@ -129,29 +140,10 @@ goog.provide('{{module.namespace}}.{{interface.name}}Request');
impl.{{method.name}}.bind(impl));
{%- endfor %}
/** @public {!mojo.internal.interfaceSupport.ConnectionErrorEventRouter} */
- this.onConnectionError = this.target_.getConnectionErrorEventRouter();
- }
-
- /**
- * Binds a new handle to this object. Messages which arrive on the handle will
- * be read and dispatched to this object.
- *
- * @param {!MojoHandle} handle
- * @export
- */
- bindHandle(handle) {
- this.target_.bindHandle(handle);
- }
-
- /**
- * Closes all bindings bound to this target.
- *
- * @export
- */
- closeBindings() {
- this.target_.closeBindings();
+ this.onConnectionError = this.helper_internal_.getConnectionErrorEventRouter();
}
+ {% if use_old_names -%}
/**
* Returns a proxy for this interface which sends messages to the browser.
* The browser must have an interface request binder registered for this
@@ -163,22 +155,17 @@ goog.provide('{{module.namespace}}.{{interface.name}}Request');
static getProxy() {
let proxy = new {{module.namespace}}.{{interface.name}}Proxy;
Mojo.bindInterface('{{mojom_namespace}}.{{interface.name}}',
- proxy.$.createRequest().handle);
+ proxy.$.bindNewPipeAndPassReceiver().handle);
return proxy;
}
/**
- * Returns a proxy for this interface which sends messages directly to this
- * object. Any number of proxies may be created to the same object.
- *
- * @return {!{{module.namespace}}.{{interface.name}}Proxy}
- * @export
+ * @return {!string}
*/
- createProxy() {
- let proxy = new {{module.namespace}}.{{interface.name}}Proxy;
- this.target_.bindHandle(proxy.$.createRequest().handle);
- return proxy;
+ static get $interfaceName() {
+ return "{{mojom_namespace}}.{{interface.name}}";
}
+ {% endif %}
};
{#--- Enums #}
@@ -189,80 +176,79 @@ goog.provide('{{module.namespace}}.{{interface.name}}Request');
enum) }}
{%- endfor %}
+{% if not use_old_names -%}
+
/**
- * @const {string}
- * @export
+ * @export
*/
-{{module.namespace}}.{{interface.name}}.$interfaceName =
- '{{mojom_namespace}}.{{interface.name}}';
+{{module.namespace}}.{{interface.name}} = class {
+ /**
+ * @return {!string}
+ */
+ static get $interfaceName() {
+ return "{{mojom_namespace}}.{{interface.name}}";
+ }
+
+ /**
+ * Returns a remote for this interface which sends messages to the browser.
+ * The browser must have an interface request binder registered for this
+ * interface and accessible to the calling document's frame.
+ *
+ * @return {!{{module.namespace}}.{{interface.name}}Remote}
+ * @export
+ */
+ static getRemote() {
+ let remote = new {{module.namespace}}.{{interface.name}}Remote;
+ Mojo.bindInterface(this.$interfaceName,
+ remote.$.bindNewPipeAndPassReceiver().handle);
+ return remote;
+ }
+};
+
+{% endif %}
/**
* An object which receives request messages for the {{interface.name}}
- * mojom interface and dispatches them as callbacks. One callback target exists
+ * mojom interface and dispatches them as callbacks. One callback receiver exists
* on this object for each message defined in the mojom interface, and each
- * target can have any number of listeners added to it.
+ * receiver can have any number of listeners added to it.
*
* @export
*/
{{module.namespace}}.{{interface.name}}CallbackRouter = class {
constructor() {
- this.target_ = new mojo.internal.interfaceSupport.InterfaceTarget;
+ this.helper_internal_ = new mojo.internal.interfaceSupport.InterfaceReceiverHelperInternal(
+ {{module.namespace}}.{{interface.name}}{{primitives_names.remote}});
+
+ /**
+ * @public {!mojo.internal.interfaceSupport.InterfaceReceiverHelper<!{{module.namespace}}.{{interface.name}}{{primitives_names.remote}}>}
+ */
+ this.$ = new mojo.internal.interfaceSupport.InterfaceReceiverHelper(this.helper_internal_);
+
this.router_ = new mojo.internal.interfaceSupport.CallbackRouter;
{% for method in interface.methods %}
{%- set interface_message_id =
interface.mojom_name ~ "_" ~ method.mojom_name %}
/**
- * @public {!mojo.internal.interfaceSupport.InterfaceCallbackTarget}
+ * @public {!mojo.internal.interfaceSupport.InterfaceCallbackReceiver}
*/
this.{{method.name}} =
- new mojo.internal.interfaceSupport.InterfaceCallbackTarget(
+ new mojo.internal.interfaceSupport.InterfaceCallbackReceiver(
this.router_);
- this.target_.registerHandler(
+ this.helper_internal_.registerHandler(
{{method.ordinal}},
{{module.namespace}}.{{interface_message_id}}_ParamsSpec.$,
{%- if method.response_parameters != None %}
{{module.namespace}}.{{interface_message_id}}_ResponseParamsSpec.$,
- this.{{method.name}}.createTargetHandler(true /* expectsResponse */));
+ this.{{method.name}}.createReceiverHandler(true /* expectsResponse */));
{%- else %}
null,
- this.{{method.name}}.createTargetHandler(false /* expectsResponse */));
+ this.{{method.name}}.createReceiverHandler(false /* expectsResponse */));
{%- endif %}
{%- endfor %}
/** @public {!mojo.internal.interfaceSupport.ConnectionErrorEventRouter} */
- this.onConnectionError = this.target_.getConnectionErrorEventRouter();
- }
-
- /**
- * Binds a new handle to this object. Messages which arrive on the handle will
- * be read and dispatched as callbacks on this object.
- *
- * @param {!MojoHandle} handle
- * @export
- */
- bindHandle(handle) {
- this.target_.bindHandle(handle);
- }
-
- /**
- * Closes all bindings bound to this target. The target will not receive any
- * further message message events unless rebound to one or more handles.
- */
- closeBindings() {
- this.target_.closeBindings();
- }
-
- /**
- * Returns a proxy for this interface which sends messages directly to this
- * object. Any number of proxies may be created to the same object.
- *
- * @return {!{{module.namespace}}.{{interface.name}}Proxy}
- * @export
- */
- createProxy() {
- let proxy = new {{module.namespace}}.{{interface.name}}Proxy;
- this.target_.bindHandle(proxy.$.createRequest().handle);
- return proxy;
+ this.onConnectionError = this.helper_internal_.getConnectionErrorEventRouter();
}
/**
diff --git a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/test/BUILD.gn b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/test/BUILD.gn
index ec085c5f674..d3c94dbc139 100644
--- a/chromium/mojo/public/tools/bindings/generators/js_templates/lite/test/BUILD.gn
+++ b/chromium/mojo/public/tools/bindings/generators/js_templates/lite/test/BUILD.gn
@@ -12,8 +12,17 @@ mojom("mojo_bindings") {
]
}
+mojom("mojo_old_names_bindings") {
+ testonly = true
+ sources = [
+ "test_old_names.test-mojom",
+ ]
+ use_old_js_lite_bindings_names = true
+}
+
js_type_check("closure_compile") {
deps = [
+ ":old_names_test",
":test",
]
}
@@ -21,5 +30,12 @@ js_type_check("closure_compile") {
js_library("test") {
deps = [
":mojo_bindings_js_library_for_compile",
+ ":mojo_old_names_bindings_js_library_for_compile",
+ ]
+}
+
+js_library("old_names_test") {
+ deps = [
+ ":mojo_old_names_bindings_js_library_for_compile",
]
}
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 8bb05221397..fb6e0827b4a 100644
--- a/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
+++ b/chromium/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -353,6 +353,7 @@ class Generator(generator.Generator):
"is_enum_kind": mojom.IsEnumKind,
"is_integral_kind": mojom.IsIntegralKind,
"is_interface_kind": mojom.IsInterfaceKind,
+ "is_receiver_kind": self._IsReceiverKind,
"is_native_only_kind": IsNativeOnlyKind,
"is_any_handle_kind": mojom.IsAnyHandleKind,
"is_any_interface_kind": mojom.IsAnyInterfaceKind,
@@ -643,6 +644,10 @@ class Generator(generator.Generator):
return True
return False
+ def _IsReceiverKind(self, kind):
+ return (mojom.IsPendingReceiverKind(kind) or
+ mojom.IsInterfaceRequestKind(kind))
+
def _IsCopyablePassByValue(self, kind):
if not self._IsTypemappedKind(kind):
return False
diff --git a/chromium/mojo/public/tools/bindings/generators/mojom_java_generator.py b/chromium/mojo/public/tools/bindings/generators/mojom_java_generator.py
index fcef5453cba..60ae83cf859 100644
--- a/chromium/mojo/public/tools/bindings/generators/mojom_java_generator.py
+++ b/chromium/mojo/public/tools/bindings/generators/mojom_java_generator.py
@@ -152,7 +152,7 @@ def GetNameForElement(element):
raise Exception('Unexpected element: %s' % element)
def GetInterfaceResponseName(method):
- return UpperCamelCase(method.name + 'Response')
+ return UpperCamelCase(method.name + '_Response')
def ParseStringAttribute(attribute):
assert isinstance(attribute, basestring)
diff --git a/chromium/mojo/public/tools/bindings/generators/mojom_js_generator.py b/chromium/mojo/public/tools/bindings/generators/mojom_js_generator.py
index 19a94f273ba..eb8d3b6f44a 100644
--- a/chromium/mojo/public/tools/bindings/generators/mojom_js_generator.py
+++ b/chromium/mojo/public/tools/bindings/generators/mojom_js_generator.py
@@ -264,7 +264,9 @@ class Generator(generator.Generator):
"unions": self.module.unions,
"generate_fuzzing": self.generate_fuzzing,
"generate_closure_exports": for_compile,
- }
+ "use_old_names": self.use_old_js_lite_bindings_names,
+ "primitives_names": self._GetPrimitivesNames(),
+ }
@staticmethod
def GetTemplatePrefix():
@@ -339,15 +341,15 @@ class Generator(generator.Generator):
def _GenerateExterns(self):
return self._GetParameters()
- @UseJinja("lite/mojom-lite.js.tmpl")
- def _GenerateLiteBindings(self):
- return self._GetParameters()
-
@UseJinja("lite/mojom.html.tmpl")
def _GenerateLiteHtml(self):
return self._GetParameters()
@UseJinja("lite/mojom-lite.js.tmpl")
+ def _GenerateLiteBindings(self):
+ return self._GetParameters()
+
+ @UseJinja("lite/mojom-lite.js.tmpl")
def _GenerateLiteBindingsForCompile(self):
return self._GetParameters(for_compile=True)
@@ -368,7 +370,7 @@ class Generator(generator.Generator):
self.Write(self._GenerateLiteHtml(), "%s.html" % self.module.path)
self.Write(self._GenerateLiteBindings(), "%s-lite.js" % self.module.path)
self.Write(self._GenerateLiteBindingsForCompile(),
- "%s-lite-for-compile.js" % self.module.path)
+ "%s-lite-for-compile.js" % self.module.path)
def _SetUniqueNameForImports(self):
used_names = set()
@@ -464,9 +466,9 @@ class Generator(generator.Generator):
mojom.IsEnumKind(kind)):
return name
if mojom.IsInterfaceKind(kind) or mojom.IsPendingRemoteKind(kind):
- return name + "Proxy"
+ return name + self._GetPrimitivesNames()["remote"]
if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind):
- return name + "Request"
+ return name + self._GetPrimitivesNames()["pending_receiver"]
# TODO(calamity): Support associated interfaces properly.
if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
@@ -561,17 +563,21 @@ class Generator(generator.Generator):
mojom.IsEnumKind(kind)):
return "%sSpec.$" % name
if mojom.IsInterfaceKind(kind) or mojom.IsPendingRemoteKind(kind):
- return "mojo.internal.InterfaceProxy(%sProxy)" % name
+ remote_name = name + self._GetPrimitivesNames()["remote"]
+ return "mojo.internal.InterfaceProxy(%s)" % remote_name
if mojom.IsInterfaceRequestKind(kind) or mojom.IsPendingReceiverKind(kind):
- return "mojo.internal.InterfaceRequest(%sRequest)" % name
+ request_name = name + self._GetPrimitivesNames()["pending_receiver"]
+ return "mojo.internal.InterfaceRequest(%s)" % request_name
if (mojom.IsAssociatedInterfaceKind(kind) or
mojom.IsPendingAssociatedRemoteKind(kind)):
+ remote_name = name + self._GetPrimitivesNames()["remote"]
# TODO(rockot): Implement associated interfaces.
- return "mojo.internal.AssociatedInterfaceProxy(%sProxy)" % (
- name)
+ return "mojo.internal.AssociatedInterfaceProxy(%s)" % (
+ remote_name)
if (mojom.IsAssociatedInterfaceRequestKind(kind) or
mojom.IsPendingAssociatedReceiverKind(kind)):
- return "mojo.internal.AssociatedInterfaceRequest(%s)" % name
+ request_name = name + self._GetPrimitivesNames()["pending_receiver"]
+ return "mojo.internal.AssociatedInterfaceRequest(%s)" % request_name
return name
@@ -810,6 +816,20 @@ class Generator(generator.Generator):
return self._ExpressionToText(token)
+ def _GetPrimitivesNames(self):
+ if self.use_old_js_lite_bindings_names:
+ return {
+ "remote": "Proxy",
+ "receiver": "",
+ "pending_receiver": "Request",
+ }
+ else:
+ return {
+ "remote": "Remote",
+ "receiver": "Receiver",
+ "pending_receiver": "PendingReceiver",
+ }
+
def _GenerateHtmlImports(self):
result = []
for full_import in self.module.imports:
diff --git a/chromium/mojo/public/tools/bindings/mojom.gni b/chromium/mojo/public/tools/bindings/mojom.gni
index 8310a1bc1fe..8cdf5931304 100644
--- a/chromium/mojo/public/tools/bindings/mojom.gni
+++ b/chromium/mojo/public/tools/bindings/mojom.gni
@@ -282,6 +282,10 @@ if (enable_mojom_typemapping) {
# correct dependency order. Note that this only has an effect if
# the |enable_mojom_closure_compile| global arg is set to |true| as well.
#
+# use_old_js_lite_bindings_names (optional)
+# Use old names i.e. FooProxy, Foo, getProxy(), etc. instead of the new
+# names i.e. FooRemote, FooReceiver, getRemote(), etc.
+#
# The following parameters are used to support the component build. They are
# needed so that bindings which are linked with a component can use the same
# export settings for classes. The first three are for the chromium variant, and
@@ -1267,6 +1271,11 @@ template("mojom") {
if (generate_fuzzing) {
args += [ "--generate_fuzzing" ]
}
+
+ if (defined(invoker.use_old_js_lite_bindings_names) &&
+ invoker.use_old_js_lite_bindings_names) {
+ args += [ "--use_old_js_lite_bindings_names" ]
+ }
}
}
diff --git a/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py b/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py
index 72f23d86fa9..d8a2118eb2b 100755
--- a/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py
+++ b/chromium/mojo/public/tools/bindings/mojom_bindings_generator.py
@@ -214,6 +214,7 @@ class MojomProcessor(object):
variant=args.variant, bytecode_path=args.bytecode_path,
for_blink=args.for_blink,
js_bindings_mode=args.js_bindings_mode,
+ use_old_js_lite_bindings_names=args.use_old_js_lite_bindings_names,
export_attribute=args.export_attribute,
export_header=args.export_header,
generate_non_variant_code=args.generate_non_variant_code,
@@ -466,6 +467,11 @@ def main():
"be \"new\" to generate new-style lite JS bindings in addition to the "
"old, or \"old\" to only generate old bindings.")
generate_parser.add_argument(
+ "--use_old_js_lite_bindings_names", action="store_true",
+ help="This option only affects the JavaScript bindings. Specifying this "
+ "argument causes the generated new-style lite JS bindings to use the old"
+ "names for primitives e.g. Foo, FooProxy, getProxy(), etc.")
+ generate_parser.add_argument(
"--export_attribute", default="",
help="Optional attribute to specify on class declaration to export it "
"for the component build.")
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 fe4fce20ec4..6487635ed43 100644
--- a/chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
+++ b/chromium/mojo/public/tools/bindings/pylib/mojom/generate/generator.py
@@ -165,7 +165,9 @@ class Generator(object):
# files to stdout.
def __init__(self, module, output_dir=None, typemap=None, variant=None,
bytecode_path=None, for_blink=False,
- js_bindings_mode="new", export_attribute=None,
+ js_bindings_mode="new",
+ use_old_js_lite_bindings_names=False,
+ export_attribute=None,
export_header=None, generate_non_variant_code=False,
support_lazy_serialization=False, disallow_native_types=False,
disallow_interfaces=False, generate_message_ids=False,
@@ -177,6 +179,7 @@ class Generator(object):
self.bytecode_path = bytecode_path
self.for_blink = for_blink
self.js_bindings_mode = js_bindings_mode
+ self.use_old_js_lite_bindings_names = use_old_js_lite_bindings_names
self.export_attribute = export_attribute
self.export_header = export_header
self.generate_non_variant_code = generate_non_variant_code