Mojo: Introduce GenericPendingAssociatedReceiver
This is analogous to GenericPendingReceiver but for associated interfaces. It's needed for layering associated interfaces on GpuChannel, but will also be useful for cleaning up legacy Channel-associated interface support and for building whatever replaces that in the future of browser-renderer IPC. Bug: 1196476 Change-Id: I1380d1e47e3dc66c1364c82a938a7d30f4b4cf3d Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2903727 Commit-Queue: Ken Rockot <rockot@google.com> Reviewed-by: Robert Sesek <rsesek@chromium.org> Cr-Commit-Position: refs/heads/master@{#889485}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
43ac907206
commit
493a59f3e2
ipc
BUILD.gnipc.mojomipc_channel.hipc_channel_mojo.ccipc_channel_mojo.hipc_channel_mojo_unittest.ccipc_channel_proxy.ccipc_channel_proxy.hipc_message_pipe_reader.ccipc_message_pipe_reader.hipc_mojo_bootstrap_unittest.ccipc_sync_message_filter.ccipc_sync_message_filter.h
mojo/public
@ -192,7 +192,10 @@ mojom_component("mojom") {
|
||||
output_prefix = "ipc_mojom"
|
||||
macro_prefix = "IPC_MOJOM"
|
||||
sources = [ "ipc.mojom" ]
|
||||
public_deps = [ "//mojo/public/interfaces/bindings" ]
|
||||
public_deps = [
|
||||
"//mojo/public/interfaces/bindings",
|
||||
"//mojo/public/mojom/base",
|
||||
]
|
||||
|
||||
cpp_typemaps = [
|
||||
{
|
||||
|
@ -5,10 +5,7 @@
|
||||
module IPC.mojom;
|
||||
|
||||
import "mojo/public/interfaces/bindings/native_struct.mojom";
|
||||
|
||||
// A placeholder interface type since we don't yet support generic associated
|
||||
// message pipe handles.
|
||||
interface GenericInterface {};
|
||||
import "mojo/public/mojom/base/generic_pending_associated_receiver.mojom";
|
||||
|
||||
// Typemapped such that arbitrarily large IPC::Message objects can be sent and
|
||||
// received with minimal copying.
|
||||
@ -28,8 +25,7 @@ interface Channel {
|
||||
|
||||
// Requests a Channel-associated interface.
|
||||
GetAssociatedInterface(
|
||||
string name,
|
||||
pending_associated_receiver<GenericInterface> receiver);
|
||||
mojo_base.mojom.GenericPendingAssociatedReceiver receiver);
|
||||
};
|
||||
|
||||
// A strictly nominal interface used to identify Channel bootstrap requests.
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "ipc/ipc_channel_handle.h"
|
||||
#include "ipc/ipc_message.h"
|
||||
#include "ipc/ipc_sender.h"
|
||||
#include "mojo/public/cpp/bindings/generic_pending_associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
|
||||
#include "mojo/public/cpp/bindings/shared_remote.h"
|
||||
@ -104,9 +105,8 @@ class COMPONENT_EXPORT(IPC) Channel : public Sender {
|
||||
const GenericAssociatedInterfaceFactory& factory) = 0;
|
||||
|
||||
// Requests an associated interface from the remote endpoint.
|
||||
virtual void GetGenericRemoteAssociatedInterface(
|
||||
const std::string& name,
|
||||
mojo::ScopedInterfaceEndpointHandle handle) = 0;
|
||||
virtual void GetRemoteAssociatedInterface(
|
||||
mojo::GenericPendingAssociatedReceiver receiver) = 0;
|
||||
|
||||
// Template helper to add an interface factory to this channel.
|
||||
template <typename Interface>
|
||||
@ -121,14 +121,6 @@ class COMPONENT_EXPORT(IPC) Channel : public Sender {
|
||||
factory));
|
||||
}
|
||||
|
||||
// Template helper to request a remote associated interface.
|
||||
template <typename Interface>
|
||||
void GetRemoteAssociatedInterface(
|
||||
mojo::PendingAssociatedReceiver<Interface> receiver) {
|
||||
GetGenericRemoteAssociatedInterface(Interface::Name_,
|
||||
receiver.PassHandle());
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Interface>
|
||||
static void BindPendingAssociatedReceiver(
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "ipc/trace_ipc_message.h"
|
||||
#include "mojo/public/cpp/bindings/associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/associated_remote.h"
|
||||
#include "mojo/public/cpp/bindings/generic_pending_associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/lib/message_quota_checker.h"
|
||||
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/thread_safe_proxy.h"
|
||||
@ -248,20 +249,22 @@ void ChannelMojo::OnPipeError() {
|
||||
}
|
||||
|
||||
void ChannelMojo::OnAssociatedInterfaceRequest(
|
||||
const std::string& name,
|
||||
mojo::ScopedInterfaceEndpointHandle handle) {
|
||||
mojo::GenericPendingAssociatedReceiver receiver) {
|
||||
GenericAssociatedInterfaceFactory factory;
|
||||
{
|
||||
base::AutoLock locker(associated_interface_lock_);
|
||||
auto iter = associated_interfaces_.find(name);
|
||||
auto iter = associated_interfaces_.find(*receiver.interface_name());
|
||||
if (iter != associated_interfaces_.end())
|
||||
factory = iter->second;
|
||||
}
|
||||
|
||||
if (!factory.is_null())
|
||||
factory.Run(std::move(handle));
|
||||
else
|
||||
listener_->OnAssociatedInterfaceRequest(name, std::move(handle));
|
||||
if (!factory.is_null()) {
|
||||
factory.Run(receiver.PassHandle());
|
||||
} else {
|
||||
const std::string interface_name = *receiver.interface_name();
|
||||
listener_->OnAssociatedInterfaceRequest(interface_name,
|
||||
receiver.PassHandle());
|
||||
}
|
||||
}
|
||||
|
||||
bool ChannelMojo::Send(Message* message) {
|
||||
@ -382,22 +385,20 @@ void ChannelMojo::AddGenericAssociatedInterface(
|
||||
DCHECK(result.second);
|
||||
}
|
||||
|
||||
void ChannelMojo::GetGenericRemoteAssociatedInterface(
|
||||
const std::string& name,
|
||||
mojo::ScopedInterfaceEndpointHandle handle) {
|
||||
void ChannelMojo::GetRemoteAssociatedInterface(
|
||||
mojo::GenericPendingAssociatedReceiver receiver) {
|
||||
if (message_reader_) {
|
||||
if (!task_runner_->RunsTasksInCurrentSequence()) {
|
||||
message_reader_->thread_safe_sender().GetAssociatedInterface(
|
||||
name, mojo::PendingAssociatedReceiver<mojom::GenericInterface>(
|
||||
std::move(handle)));
|
||||
std::move(receiver));
|
||||
return;
|
||||
}
|
||||
message_reader_->GetRemoteInterface(name, std::move(handle));
|
||||
message_reader_->GetRemoteInterface(std::move(receiver));
|
||||
} else {
|
||||
// Attach the associated interface to a disconnected pipe, so that the
|
||||
// associated interface pointer can be used to make calls (which are
|
||||
// dropped).
|
||||
mojo::AssociateWithDisconnectedPipe(std::move(handle));
|
||||
mojo::AssociateWithDisconnectedPipe(receiver.PassHandle());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,8 +92,7 @@ class COMPONENT_EXPORT(IPC) ChannelMojo
|
||||
void OnBrokenDataReceived() override;
|
||||
void OnPipeError() override;
|
||||
void OnAssociatedInterfaceRequest(
|
||||
const std::string& name,
|
||||
mojo::ScopedInterfaceEndpointHandle handle) override;
|
||||
mojo::GenericPendingAssociatedReceiver receiver) override;
|
||||
|
||||
private:
|
||||
ChannelMojo(
|
||||
@ -112,9 +111,8 @@ class COMPONENT_EXPORT(IPC) ChannelMojo
|
||||
void AddGenericAssociatedInterface(
|
||||
const std::string& name,
|
||||
const GenericAssociatedInterfaceFactory& factory) override;
|
||||
void GetGenericRemoteAssociatedInterface(
|
||||
const std::string& name,
|
||||
mojo::ScopedInterfaceEndpointHandle handle) override;
|
||||
void GetRemoteAssociatedInterface(
|
||||
mojo::GenericPendingAssociatedReceiver receiver) override;
|
||||
|
||||
void FinishConnectOnIOThread();
|
||||
|
||||
|
@ -980,7 +980,8 @@ DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE(
|
||||
// Send a bunch of interleaved messages, alternating between the associated
|
||||
// interface and a legacy IPC::Message.
|
||||
mojo::AssociatedRemote<IPC::mojom::SimpleTestDriver> driver;
|
||||
proxy()->GetRemoteAssociatedInterface(&driver);
|
||||
proxy()->GetRemoteAssociatedInterface(
|
||||
driver.BindNewEndpointAndPassReceiver());
|
||||
for (int i = 0; i < ListenerWithSimpleProxyAssociatedInterface::kNumMessages;
|
||||
++i) {
|
||||
driver->ExpectValue(i);
|
||||
@ -1073,7 +1074,8 @@ DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE(
|
||||
// processed on the IO thread.
|
||||
mojo::AssociatedRemote<IPC::mojom::IndirectTestDriver> driver;
|
||||
mojo::AssociatedRemote<IPC::mojom::PingReceiver> ping_receiver;
|
||||
proxy()->GetRemoteAssociatedInterface(&driver);
|
||||
proxy()->GetRemoteAssociatedInterface(
|
||||
driver.BindNewEndpointAndPassReceiver());
|
||||
driver->GetPingReceiver(ping_receiver.BindNewEndpointAndPassReceiver());
|
||||
|
||||
base::RunLoop loop;
|
||||
@ -1194,7 +1196,8 @@ TEST_F(IPCChannelProxyMojoTest, SyncAssociatedInterface) {
|
||||
// while waiting on it
|
||||
listener.set_response_value(42);
|
||||
mojo::AssociatedRemote<IPC::mojom::SimpleTestClient> client;
|
||||
proxy()->GetRemoteAssociatedInterface(&client);
|
||||
proxy()->GetRemoteAssociatedInterface(
|
||||
client.BindNewEndpointAndPassReceiver());
|
||||
int32_t received_value;
|
||||
EXPECT_TRUE(client->RequestValue(&received_value));
|
||||
EXPECT_EQ(42, received_value);
|
||||
@ -1300,7 +1303,8 @@ DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT_WITH_CUSTOM_FIXTURE(SyncAssociatedInterface,
|
||||
RunProxy();
|
||||
|
||||
mojo::AssociatedRemote<IPC::mojom::SimpleTestDriver> driver;
|
||||
proxy()->GetRemoteAssociatedInterface(&driver);
|
||||
proxy()->GetRemoteAssociatedInterface(
|
||||
driver.BindNewEndpointAndPassReceiver());
|
||||
client_impl.set_driver(driver.get());
|
||||
|
||||
// Simple sync message sanity check.
|
||||
@ -1432,7 +1436,8 @@ TEST_F(IPCChannelProxyMojoTest, AssociatedRequestClose) {
|
||||
RunProxy();
|
||||
|
||||
mojo::AssociatedRemote<IPC::mojom::AssociatedInterfaceVendor> vendor;
|
||||
proxy()->GetRemoteAssociatedInterface(&vendor);
|
||||
proxy()->GetRemoteAssociatedInterface(
|
||||
vendor.BindNewEndpointAndPassReceiver());
|
||||
mojo::AssociatedRemote<IPC::mojom::SimpleTestDriver> tester;
|
||||
vendor->GetTestInterface(tester.BindNewEndpointAndPassReceiver());
|
||||
base::RunLoop run_loop;
|
||||
@ -1440,7 +1445,8 @@ TEST_F(IPCChannelProxyMojoTest, AssociatedRequestClose) {
|
||||
run_loop.Run();
|
||||
|
||||
tester.reset();
|
||||
proxy()->GetRemoteAssociatedInterface(&tester);
|
||||
proxy()->GetRemoteAssociatedInterface(
|
||||
tester.BindNewEndpointAndPassReceiver());
|
||||
EXPECT_TRUE(WaitForClientShutdown());
|
||||
DestroyProxy();
|
||||
}
|
||||
|
@ -602,13 +602,10 @@ void ChannelProxy::AddGenericAssociatedInterfaceForIOThread(
|
||||
context()->AddGenericAssociatedInterfaceForIOThread(name, factory);
|
||||
}
|
||||
|
||||
void ChannelProxy::GetGenericRemoteAssociatedInterface(
|
||||
const std::string& name,
|
||||
mojo::ScopedInterfaceEndpointHandle handle) {
|
||||
void ChannelProxy::GetRemoteAssociatedInterface(
|
||||
mojo::GenericPendingAssociatedReceiver receiver) {
|
||||
DCHECK(did_init_);
|
||||
context()->thread_safe_channel().GetAssociatedInterface(
|
||||
name, mojo::PendingAssociatedReceiver<mojom::GenericInterface>(
|
||||
std::move(handle)));
|
||||
context()->thread_safe_channel().GetAssociatedInterface(std::move(receiver));
|
||||
}
|
||||
|
||||
void ChannelProxy::ClearIPCTaskRunner() {
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "ipc/ipc_listener.h"
|
||||
#include "ipc/ipc_sender.h"
|
||||
#include "mojo/public/cpp/bindings/associated_remote.h"
|
||||
#include "mojo/public/cpp/bindings/generic_pending_associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/lib/message_quota_checker.h"
|
||||
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
|
||||
@ -195,15 +196,13 @@ class COMPONENT_EXPORT(IPC) ChannelProxy : public Sender {
|
||||
}
|
||||
|
||||
// Requests an associated interface from the remote endpoint.
|
||||
void GetGenericRemoteAssociatedInterface(
|
||||
const std::string& name,
|
||||
mojo::ScopedInterfaceEndpointHandle handle);
|
||||
void GetRemoteAssociatedInterface(
|
||||
mojo::GenericPendingAssociatedReceiver receiver);
|
||||
|
||||
// Template helper to receive associated interfaces from the remote endpoint.
|
||||
template <typename Interface>
|
||||
void GetRemoteAssociatedInterface(mojo::AssociatedRemote<Interface>* proxy) {
|
||||
GetGenericRemoteAssociatedInterface(
|
||||
Interface::Name_, proxy->BindNewEndpointAndPassReceiver().PassHandle());
|
||||
GetRemoteAssociatedInterface(proxy->BindNewEndpointAndPassReceiver());
|
||||
}
|
||||
|
||||
#if defined(ENABLE_IPC_FUZZER)
|
||||
|
@ -126,13 +126,10 @@ bool MessagePipeReader::Send(std::unique_ptr<Message> message) {
|
||||
}
|
||||
|
||||
void MessagePipeReader::GetRemoteInterface(
|
||||
const std::string& name,
|
||||
mojo::ScopedInterfaceEndpointHandle handle) {
|
||||
mojo::GenericPendingAssociatedReceiver receiver) {
|
||||
if (!sender_.is_bound())
|
||||
return;
|
||||
sender_->GetAssociatedInterface(
|
||||
name, mojo::PendingAssociatedReceiver<mojom::GenericInterface>(
|
||||
std::move(handle)));
|
||||
sender_->GetAssociatedInterface(std::move(receiver));
|
||||
}
|
||||
|
||||
void MessagePipeReader::SetPeerPid(int32_t peer_pid) {
|
||||
@ -165,11 +162,10 @@ void MessagePipeReader::Receive(MessageView message_view) {
|
||||
}
|
||||
|
||||
void MessagePipeReader::GetAssociatedInterface(
|
||||
const std::string& name,
|
||||
mojo::PendingAssociatedReceiver<mojom::GenericInterface> receiver) {
|
||||
mojo::GenericPendingAssociatedReceiver receiver) {
|
||||
DCHECK(thread_checker_.CalledOnValidThread());
|
||||
if (delegate_)
|
||||
delegate_->OnAssociatedInterfaceRequest(name, receiver.PassHandle());
|
||||
delegate_->OnAssociatedInterfaceRequest(std::move(receiver));
|
||||
}
|
||||
|
||||
void MessagePipeReader::OnPipeError(MojoResult error) {
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "ipc/ipc_message.h"
|
||||
#include "mojo/public/cpp/bindings/associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/associated_remote.h"
|
||||
#include "mojo/public/cpp/bindings/generic_pending_associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
|
||||
#include "mojo/public/cpp/bindings/shared_remote.h"
|
||||
@ -55,8 +56,7 @@ class COMPONENT_EXPORT(IPC) MessagePipeReader : public mojom::Channel {
|
||||
virtual void OnBrokenDataReceived() = 0;
|
||||
virtual void OnPipeError() = 0;
|
||||
virtual void OnAssociatedInterfaceRequest(
|
||||
const std::string& name,
|
||||
mojo::ScopedInterfaceEndpointHandle handle) = 0;
|
||||
mojo::GenericPendingAssociatedReceiver receiver) = 0;
|
||||
};
|
||||
|
||||
// Builds a reader that reads messages from |receive_handle| and lets
|
||||
@ -89,8 +89,7 @@ class COMPONENT_EXPORT(IPC) MessagePipeReader : public mojom::Channel {
|
||||
bool Send(std::unique_ptr<Message> message);
|
||||
|
||||
// Requests an associated interface from the other end of the pipe.
|
||||
void GetRemoteInterface(const std::string& name,
|
||||
mojo::ScopedInterfaceEndpointHandle handle);
|
||||
void GetRemoteInterface(mojo::GenericPendingAssociatedReceiver receiver);
|
||||
|
||||
mojo::AssociatedRemote<mojom::Channel>& sender() { return sender_; }
|
||||
mojom::Channel& thread_safe_sender() { return thread_safe_sender_->proxy(); }
|
||||
@ -104,9 +103,7 @@ class COMPONENT_EXPORT(IPC) MessagePipeReader : public mojom::Channel {
|
||||
void SetPeerPid(int32_t peer_pid) override;
|
||||
void Receive(MessageView message_view) override;
|
||||
void GetAssociatedInterface(
|
||||
const std::string& name,
|
||||
mojo::PendingAssociatedReceiver<mojom::GenericInterface> receiver)
|
||||
override;
|
||||
mojo::GenericPendingAssociatedReceiver receiver) override;
|
||||
|
||||
void ForwardMessage(mojo::Message message);
|
||||
|
||||
|
@ -93,9 +93,7 @@ class PeerPidReceiver : public IPC::mojom::Channel {
|
||||
}
|
||||
|
||||
void GetAssociatedInterface(
|
||||
const std::string& name,
|
||||
mojo::PendingAssociatedReceiver<IPC::mojom::GenericInterface> receiver)
|
||||
override {}
|
||||
mojo::GenericPendingAssociatedReceiver receiver) override {}
|
||||
|
||||
int32_t peer_pid() const { return peer_pid_; }
|
||||
|
||||
|
@ -179,23 +179,21 @@ void SyncMessageFilter::SignalAllEvents() {
|
||||
}
|
||||
}
|
||||
|
||||
void SyncMessageFilter::GetGenericRemoteAssociatedInterface(
|
||||
const std::string& interface_name,
|
||||
mojo::ScopedInterfaceEndpointHandle handle) {
|
||||
void SyncMessageFilter::GetRemoteAssociatedInterface(
|
||||
mojo::GenericPendingAssociatedReceiver receiver) {
|
||||
base::AutoLock auto_lock(lock_);
|
||||
DCHECK(io_task_runner_ && io_task_runner_->BelongsToCurrentThread());
|
||||
if (!channel_) {
|
||||
// Attach the associated interface to a disconnected pipe, so that the
|
||||
// associated interface pointer can be used to make calls (which are
|
||||
// dropped).
|
||||
mojo::AssociateWithDisconnectedPipe(std::move(handle));
|
||||
mojo::AssociateWithDisconnectedPipe(receiver.PassHandle());
|
||||
return;
|
||||
}
|
||||
|
||||
Channel::AssociatedInterfaceSupport* support =
|
||||
channel_->GetAssociatedInterfaceSupport();
|
||||
support->GetGenericRemoteAssociatedInterface(
|
||||
interface_name, std::move(handle));
|
||||
support->GetRemoteAssociatedInterface(std::move(receiver));
|
||||
}
|
||||
|
||||
} // namespace IPC
|
||||
|
@ -15,8 +15,7 @@
|
||||
#include "ipc/ipc_sender.h"
|
||||
#include "ipc/ipc_sync_message.h"
|
||||
#include "ipc/message_filter.h"
|
||||
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
|
||||
#include "mojo/public/cpp/bindings/generic_pending_associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
|
||||
|
||||
namespace base {
|
||||
@ -50,12 +49,13 @@ class COMPONENT_EXPORT(IPC) SyncMessageFilter : public MessageFilter,
|
||||
//
|
||||
// NOTE: This must ONLY be called on the Channel's thread, after
|
||||
// OnFilterAdded.
|
||||
void GetRemoteAssociatedInterface(
|
||||
mojo::GenericPendingAssociatedReceiver receiver);
|
||||
|
||||
template <typename Interface>
|
||||
void GetRemoteAssociatedInterface(
|
||||
mojo::PendingAssociatedRemote<Interface>* proxy) {
|
||||
auto receiver = proxy->InitWithNewEndpointAndPassReceiver();
|
||||
GetGenericRemoteAssociatedInterface(Interface::Name_,
|
||||
receiver.PassHandle());
|
||||
GetRemoteAssociatedInterface(proxy->InitWithNewEndpointAndPassReceiver());
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -69,11 +69,6 @@ class COMPONENT_EXPORT(IPC) SyncMessageFilter : public MessageFilter,
|
||||
// Signal all the pending sends as done, used in an error condition.
|
||||
void SignalAllEvents();
|
||||
|
||||
// NOTE: This must ONLY be called on the Channel's thread.
|
||||
void GetGenericRemoteAssociatedInterface(
|
||||
const std::string& interface_name,
|
||||
mojo::ScopedInterfaceEndpointHandle handle);
|
||||
|
||||
// The channel to which this filter was added.
|
||||
Channel* channel_;
|
||||
|
||||
|
@ -88,6 +88,8 @@ component("shared_typemap_traits") {
|
||||
"file_mojom_traits.h",
|
||||
"file_path_mojom_traits.cc",
|
||||
"file_path_mojom_traits.h",
|
||||
"generic_pending_associated_receiver_mojom_traits.cc",
|
||||
"generic_pending_associated_receiver_mojom_traits.h",
|
||||
"generic_pending_receiver_mojom_traits.cc",
|
||||
"generic_pending_receiver_mojom_traits.h",
|
||||
"read_only_buffer_mojom_traits.cc",
|
||||
|
@ -0,0 +1,38 @@
|
||||
// Copyright 2021 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_associated_receiver_mojom_traits.h"
|
||||
|
||||
#include "base/strings/string_piece.h"
|
||||
|
||||
namespace mojo {
|
||||
|
||||
// static
|
||||
bool StructTraits<mojo_base::mojom::GenericPendingAssociatedReceiverDataView,
|
||||
GenericPendingAssociatedReceiver>::
|
||||
IsNull(const GenericPendingAssociatedReceiver& receiver) {
|
||||
return !receiver.is_valid();
|
||||
}
|
||||
|
||||
// static
|
||||
void StructTraits<mojo_base::mojom::GenericPendingAssociatedReceiverDataView,
|
||||
GenericPendingAssociatedReceiver>::
|
||||
SetToNull(GenericPendingAssociatedReceiver* receiver) {
|
||||
receiver->reset();
|
||||
}
|
||||
|
||||
// static
|
||||
bool StructTraits<mojo_base::mojom::GenericPendingAssociatedReceiverDataView,
|
||||
GenericPendingAssociatedReceiver>::
|
||||
Read(mojo_base::mojom::GenericPendingAssociatedReceiverDataView data,
|
||||
GenericPendingAssociatedReceiver* out) {
|
||||
base::StringPiece interface_name;
|
||||
if (!data.ReadInterfaceName(&interface_name))
|
||||
return false;
|
||||
*out = GenericPendingAssociatedReceiver(
|
||||
interface_name, data.TakeReceiver<ScopedInterfaceEndpointHandle>());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace mojo
|
@ -0,0 +1,42 @@
|
||||
// Copyright 2021 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_ASSOCIATED_RECEIVER_MOJOM_TRAITS_H_
|
||||
#define MOJO_PUBLIC_CPP_BASE_GENERIC_PENDING_ASSOCIATED_RECEIVER_MOJOM_TRAITS_H_
|
||||
|
||||
#include "base/component_export.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "mojo/public/cpp/bindings/generic_pending_associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/struct_traits.h"
|
||||
#include "mojo/public/mojom/base/generic_pending_associated_receiver.mojom-shared.h"
|
||||
|
||||
namespace mojo {
|
||||
|
||||
template <>
|
||||
struct COMPONENT_EXPORT(MOJO_BASE_SHARED_TRAITS)
|
||||
StructTraits<mojo_base::mojom::GenericPendingAssociatedReceiverDataView,
|
||||
GenericPendingAssociatedReceiver> {
|
||||
static bool IsNull(const GenericPendingAssociatedReceiver& receiver);
|
||||
static void SetToNull(GenericPendingAssociatedReceiver* receiver);
|
||||
|
||||
static base::StringPiece interface_name(
|
||||
const GenericPendingAssociatedReceiver& receiver) {
|
||||
DCHECK(receiver.interface_name().has_value());
|
||||
return receiver.interface_name().value();
|
||||
}
|
||||
|
||||
static mojo::ScopedInterfaceEndpointHandle receiver(
|
||||
GenericPendingAssociatedReceiver& receiver) {
|
||||
return receiver.PassHandle();
|
||||
}
|
||||
|
||||
static bool Read(
|
||||
mojo_base::mojom::GenericPendingAssociatedReceiverDataView data,
|
||||
GenericPendingAssociatedReceiver* out);
|
||||
};
|
||||
|
||||
} // namespace mojo
|
||||
|
||||
#endif // MOJO_PUBLIC_CPP_BASE_GENERIC_PENDING_ASSOCIATED_RECEIVER_MOJOM_TRAITS_H_
|
@ -138,6 +138,8 @@ component("bindings") {
|
||||
"callback_helpers.h",
|
||||
"connection_error_callback.h",
|
||||
"connector.h",
|
||||
"generic_pending_associated_receiver.cc",
|
||||
"generic_pending_associated_receiver.h",
|
||||
"generic_pending_receiver.cc",
|
||||
"generic_pending_receiver.h",
|
||||
"interface_endpoint_client.h",
|
||||
|
@ -0,0 +1,51 @@
|
||||
// Copyright 2021 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_associated_receiver.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/check.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
|
||||
namespace mojo {
|
||||
|
||||
GenericPendingAssociatedReceiver::GenericPendingAssociatedReceiver() = default;
|
||||
|
||||
GenericPendingAssociatedReceiver::GenericPendingAssociatedReceiver(
|
||||
base::StringPiece interface_name,
|
||||
mojo::ScopedInterfaceEndpointHandle handle)
|
||||
: interface_name_(std::string(interface_name)),
|
||||
handle_(std::move(handle)) {}
|
||||
|
||||
GenericPendingAssociatedReceiver::GenericPendingAssociatedReceiver(
|
||||
GenericPendingAssociatedReceiver&&) = default;
|
||||
|
||||
GenericPendingAssociatedReceiver& GenericPendingAssociatedReceiver::operator=(
|
||||
GenericPendingAssociatedReceiver&&) = default;
|
||||
|
||||
GenericPendingAssociatedReceiver::~GenericPendingAssociatedReceiver() = default;
|
||||
|
||||
void GenericPendingAssociatedReceiver::reset() {
|
||||
interface_name_.reset();
|
||||
handle_.reset();
|
||||
}
|
||||
|
||||
mojo::ScopedInterfaceEndpointHandle
|
||||
GenericPendingAssociatedReceiver::PassHandle() {
|
||||
DCHECK(is_valid());
|
||||
interface_name_.reset();
|
||||
return std::move(handle_);
|
||||
}
|
||||
|
||||
mojo::ScopedInterfaceEndpointHandle
|
||||
GenericPendingAssociatedReceiver::PassHandleIfNameIs(
|
||||
const char* interface_name) {
|
||||
DCHECK(is_valid());
|
||||
if (interface_name_ == interface_name)
|
||||
return PassHandle();
|
||||
return mojo::ScopedInterfaceEndpointHandle();
|
||||
}
|
||||
|
||||
} // namespace mojo
|
@ -0,0 +1,82 @@
|
||||
// Copyright 2021 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_ASSOCIATED_RECEIVER_H_
|
||||
#define MOJO_PUBLIC_CPP_BINDINGS_GENERIC_PENDING_ASSOCIATED_RECEIVER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/component_export.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
|
||||
namespace mojo {
|
||||
|
||||
// GenericPendingAssociatedReceiver encapsulates a pairing of a receiving
|
||||
// associated interface endponit 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.GenericAssociatedPendingReceiver|, and it serves as a
|
||||
// semi-safe wrapper for transporting arbitrary associated interface receivers
|
||||
// in a generic object.
|
||||
//
|
||||
// It is intended to be used in the (relatively rare) scenario where an
|
||||
// interface needs to support sharing its message ordering with interfaces
|
||||
// defined at higher application layers, such that knowledge of those associated
|
||||
// interface(s) would constitute a layering violation.
|
||||
class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) GenericPendingAssociatedReceiver {
|
||||
public:
|
||||
GenericPendingAssociatedReceiver();
|
||||
GenericPendingAssociatedReceiver(base::StringPiece interface_name,
|
||||
mojo::ScopedInterfaceEndpointHandle handle);
|
||||
|
||||
template <typename Interface>
|
||||
GenericPendingAssociatedReceiver(
|
||||
mojo::PendingAssociatedReceiver<Interface> receiver)
|
||||
: GenericPendingAssociatedReceiver(Interface::Name_,
|
||||
receiver.PassHandle()) {}
|
||||
|
||||
GenericPendingAssociatedReceiver(const GenericPendingAssociatedReceiver&) =
|
||||
delete;
|
||||
GenericPendingAssociatedReceiver(GenericPendingAssociatedReceiver&&);
|
||||
GenericPendingAssociatedReceiver& operator=(
|
||||
const GenericPendingAssociatedReceiver&) = delete;
|
||||
GenericPendingAssociatedReceiver& operator=(
|
||||
GenericPendingAssociatedReceiver&&);
|
||||
~GenericPendingAssociatedReceiver();
|
||||
|
||||
bool is_valid() const { return handle_.is_valid(); }
|
||||
explicit operator bool() const { return is_valid(); }
|
||||
|
||||
void reset();
|
||||
|
||||
const absl::optional<std::string>& interface_name() const {
|
||||
return interface_name_;
|
||||
}
|
||||
|
||||
// Takes ownership of the endpoint, invalidating this object.
|
||||
mojo::ScopedInterfaceEndpointHandle PassHandle();
|
||||
|
||||
// Takes ownership of the endpoint, strongly typed as an `Interface` receiver,
|
||||
// if and only if that interface's name matches the stored interface name.
|
||||
template <typename Interface>
|
||||
mojo::PendingAssociatedReceiver<Interface> As() {
|
||||
return mojo::PendingAssociatedReceiver<Interface>(
|
||||
PassHandleIfNameIs(Interface::Name_));
|
||||
}
|
||||
|
||||
private:
|
||||
mojo::ScopedInterfaceEndpointHandle PassHandleIfNameIs(
|
||||
const char* interface_name);
|
||||
|
||||
absl::optional<std::string> interface_name_;
|
||||
mojo::ScopedInterfaceEndpointHandle handle_;
|
||||
};
|
||||
|
||||
} // namespace mojo
|
||||
|
||||
#endif // MOJO_PUBLIC_CPP_BINDINGS_GENERIC_PENDING_ASSOCIATED_RECEIVER_H_
|
@ -131,6 +131,24 @@ struct Serializer<AssociatedInterfaceRequestDataView<Base>,
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Serializer<AssociatedInterfaceRequestDataView<T>,
|
||||
ScopedInterfaceEndpointHandle> {
|
||||
static void Serialize(ScopedInterfaceEndpointHandle& input,
|
||||
AssociatedEndpointHandle_Data* output,
|
||||
Message* message) {
|
||||
DCHECK(!input.is_valid() || input.pending_association());
|
||||
SerializeAssociatedEndpoint(std::move(input), *message, *output);
|
||||
}
|
||||
|
||||
static bool Deserialize(AssociatedEndpointHandle_Data* input,
|
||||
ScopedInterfaceEndpointHandle* output,
|
||||
Message* message) {
|
||||
*output = DeserializeAssociatedEndpointHandle(*input, *message);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Base, typename T>
|
||||
struct Serializer<InterfacePtrDataView<Base>, InterfacePtr<T>> {
|
||||
static_assert(std::is_base_of<Base, T>::value, "Interface type mismatch.");
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "base/test/bind.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "mojo/public/cpp/bindings/associated_remote.h"
|
||||
#include "mojo/public/cpp/bindings/lib/validation_errors.h"
|
||||
#include "mojo/public/cpp/bindings/pending_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/pending_remote.h"
|
||||
@ -584,6 +585,26 @@ TEST_P(ReceiverTest, GenericPendingReceiver) {
|
||||
EXPECT_FALSE(receiver.is_valid());
|
||||
}
|
||||
|
||||
TEST_P(ReceiverTest, GenericPendingAssociatedReceiver) {
|
||||
AssociatedRemote<sample::Service> remote;
|
||||
GenericPendingAssociatedReceiver receiver;
|
||||
EXPECT_FALSE(receiver.is_valid());
|
||||
EXPECT_FALSE(receiver.interface_name().has_value());
|
||||
|
||||
receiver =
|
||||
GenericPendingAssociatedReceiver(remote.BindNewEndpointAndPassReceiver());
|
||||
ASSERT_TRUE(receiver.is_valid());
|
||||
EXPECT_EQ(sample::Service::Name_, receiver.interface_name());
|
||||
|
||||
auto ping_receiver = receiver.As<test::PingService>();
|
||||
EXPECT_FALSE(ping_receiver.is_valid());
|
||||
EXPECT_TRUE(receiver.is_valid());
|
||||
|
||||
auto sample_receiver = receiver.As<sample::Service>();
|
||||
EXPECT_TRUE(sample_receiver.is_valid());
|
||||
EXPECT_FALSE(receiver.is_valid());
|
||||
}
|
||||
|
||||
class RebindTestImpl : public mojom::RebindTestInterface {
|
||||
public:
|
||||
explicit RebindTestImpl(base::WaitableEvent* event) : event_(event) {
|
||||
@ -660,6 +681,13 @@ class TestGenericBinderImpl : public mojom::TestGenericBinder {
|
||||
wait_loop_->Run();
|
||||
}
|
||||
|
||||
void WaitForNextAssociatedReceiver(
|
||||
GenericPendingAssociatedReceiver* storage) {
|
||||
wait_loop_.emplace();
|
||||
next_associated_receiver_storage_ = storage;
|
||||
wait_loop_->Run();
|
||||
}
|
||||
|
||||
// mojom::TestGenericBinder:
|
||||
void BindOptionalReceiver(GenericPendingReceiver receiver) override {
|
||||
if (next_receiver_storage_) {
|
||||
@ -679,6 +707,26 @@ class TestGenericBinderImpl : public mojom::TestGenericBinder {
|
||||
wait_loop_->Quit();
|
||||
}
|
||||
|
||||
void BindOptionalAssociatedReceiver(
|
||||
GenericPendingAssociatedReceiver receiver) override {
|
||||
if (next_associated_receiver_storage_) {
|
||||
*next_associated_receiver_storage_ = std::move(receiver);
|
||||
next_associated_receiver_storage_ = nullptr;
|
||||
}
|
||||
if (wait_loop_)
|
||||
wait_loop_->Quit();
|
||||
}
|
||||
|
||||
void BindAssociatedReceiver(
|
||||
GenericPendingAssociatedReceiver receiver) override {
|
||||
if (next_associated_receiver_storage_) {
|
||||
*next_associated_receiver_storage_ = std::move(receiver);
|
||||
next_associated_receiver_storage_ = nullptr;
|
||||
}
|
||||
if (wait_loop_)
|
||||
wait_loop_->Quit();
|
||||
}
|
||||
|
||||
private:
|
||||
void OnDisconnect() {
|
||||
if (wait_loop_)
|
||||
@ -690,6 +738,7 @@ class TestGenericBinderImpl : public mojom::TestGenericBinder {
|
||||
bool connected_ = true;
|
||||
absl::optional<base::RunLoop> wait_loop_;
|
||||
GenericPendingReceiver* next_receiver_storage_ = nullptr;
|
||||
GenericPendingAssociatedReceiver* next_associated_receiver_storage_ = nullptr;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TestGenericBinderImpl);
|
||||
};
|
||||
@ -711,12 +760,14 @@ TEST_P(ReceiverSerializationTest, NullGenericPendingReceiver) {
|
||||
mojo::Remote<mojom::TestInterface1>().BindNewPipeAndPassReceiver());
|
||||
binder.WaitForNextReceiver(&receiver);
|
||||
EXPECT_TRUE(receiver.is_valid());
|
||||
EXPECT_FALSE(receiver.As<mojom::TestInterface2>());
|
||||
EXPECT_TRUE(receiver.As<mojom::TestInterface1>());
|
||||
|
||||
remote->BindReceiver(
|
||||
mojo::Remote<mojom::TestInterface2>().BindNewPipeAndPassReceiver());
|
||||
binder.WaitForNextReceiver(&receiver);
|
||||
EXPECT_TRUE(receiver.is_valid());
|
||||
EXPECT_FALSE(receiver.As<mojom::TestInterface1>());
|
||||
EXPECT_TRUE(receiver.As<mojom::TestInterface2>());
|
||||
|
||||
mojo::internal::SerializationWarningObserverForTesting observer;
|
||||
@ -745,6 +796,58 @@ TEST_P(ReceiverSerializationTest, NullGenericPendingReceiver) {
|
||||
EXPECT_FALSE(binder.connected());
|
||||
}
|
||||
|
||||
TEST_P(ReceiverSerializationTest, NullGenericPendingAssociatedReceiver) {
|
||||
Remote<mojom::TestGenericBinder> remote;
|
||||
TestGenericBinderImpl binder(remote.BindNewPipeAndPassReceiver());
|
||||
|
||||
// Bind a null, nullable associated receiver.
|
||||
remote->BindOptionalAssociatedReceiver(GenericPendingAssociatedReceiver());
|
||||
GenericPendingAssociatedReceiver receiver;
|
||||
binder.WaitForNextAssociatedReceiver(&receiver);
|
||||
EXPECT_FALSE(receiver.is_valid());
|
||||
|
||||
// Bind some valid non-null, non-nullable associated receivers.
|
||||
remote->BindAssociatedReceiver(mojo::AssociatedRemote<mojom::TestInterface1>()
|
||||
.BindNewEndpointAndPassReceiver());
|
||||
binder.WaitForNextAssociatedReceiver(&receiver);
|
||||
EXPECT_TRUE(receiver.is_valid());
|
||||
EXPECT_FALSE(receiver.As<mojom::TestInterface2>());
|
||||
EXPECT_TRUE(receiver.As<mojom::TestInterface1>());
|
||||
|
||||
remote->BindAssociatedReceiver(mojo::AssociatedRemote<mojom::TestInterface2>()
|
||||
.BindNewEndpointAndPassReceiver());
|
||||
binder.WaitForNextAssociatedReceiver(&receiver);
|
||||
EXPECT_TRUE(receiver.is_valid());
|
||||
EXPECT_FALSE(receiver.As<mojom::TestInterface1>());
|
||||
EXPECT_TRUE(receiver.As<mojom::TestInterface2>());
|
||||
|
||||
mojo::internal::SerializationWarningObserverForTesting observer;
|
||||
|
||||
// Now attempt to send a null associated receiver for a non-nullable argument.
|
||||
EXPECT_TRUE(binder.connected());
|
||||
remote->BindAssociatedReceiver(GenericPendingAssociatedReceiver());
|
||||
|
||||
// We should see a validation warning at serialization time. Normally this
|
||||
// results in a DCHECK, but it's suppressed by the testing observer we have on
|
||||
// the stack. Note that this only works for DCHECK-enabled builds. For
|
||||
// non-DCHECK-enabled builds, serialization will succeed above with no errors,
|
||||
// but the receiver below will still reject the message and disconnect.
|
||||
#if DCHECK_IS_ON()
|
||||
EXPECT_EQ(mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
|
||||
observer.last_warning());
|
||||
#endif
|
||||
|
||||
// `receiver` should not be modified again by the implementation in `binder`,
|
||||
// because the it must never receive the invalid request. Instead the Wait
|
||||
// should be terminated by disconnection.
|
||||
receiver = mojo::AssociatedRemote<mojom::TestInterface1>()
|
||||
.BindNewEndpointAndPassReceiver();
|
||||
binder.WaitForNextAssociatedReceiver(&receiver);
|
||||
EXPECT_TRUE(receiver.is_valid());
|
||||
EXPECT_TRUE(receiver.As<mojom::TestInterface1>());
|
||||
EXPECT_FALSE(binder.connected());
|
||||
}
|
||||
|
||||
using SelfOwnedReceiverTest = BindingsTestBase;
|
||||
|
||||
TEST_P(SelfOwnedReceiverTest, CloseDestroysImplAndPipe) {
|
||||
|
@ -4,11 +4,16 @@
|
||||
|
||||
module mojo.test.receiver_unittest.mojom;
|
||||
|
||||
import "mojo/public/mojom/base/generic_pending_associated_receiver.mojom";
|
||||
import "mojo/public/mojom/base/generic_pending_receiver.mojom";
|
||||
|
||||
interface TestGenericBinder {
|
||||
BindOptionalReceiver(mojo_base.mojom.GenericPendingReceiver? receiver);
|
||||
BindReceiver(mojo_base.mojom.GenericPendingReceiver receiver);
|
||||
BindOptionalAssociatedReceiver(
|
||||
mojo_base.mojom.GenericPendingAssociatedReceiver? receiver);
|
||||
BindAssociatedReceiver(
|
||||
mojo_base.mojom.GenericPendingAssociatedReceiver receiver);
|
||||
};
|
||||
|
||||
interface TestInterface1 {};
|
||||
|
@ -16,6 +16,7 @@ mojom_component("base") {
|
||||
"file_error.mojom",
|
||||
"file_info.mojom",
|
||||
"file_path.mojom",
|
||||
"generic_pending_associated_receiver.mojom",
|
||||
"generic_pending_receiver.mojom",
|
||||
"memory_allocator_dump_cross_process_uid.mojom",
|
||||
"memory_pressure_level.mojom",
|
||||
@ -150,6 +151,21 @@ mojom_component("base") {
|
||||
"//mojo/public/cpp/base:shared_typemap_traits",
|
||||
]
|
||||
},
|
||||
{
|
||||
types = [
|
||||
{
|
||||
mojom = "mojo_base.mojom.GenericPendingAssociatedReceiver"
|
||||
cpp = "::mojo::GenericPendingAssociatedReceiver"
|
||||
move_only = true
|
||||
nullable_is_same_type = true
|
||||
},
|
||||
]
|
||||
traits_headers = [ "//mojo/public/cpp/base/generic_pending_associated_receiver_mojom_traits.h" ]
|
||||
traits_public_deps = [
|
||||
"//mojo/public/cpp/base:shared_typemap_traits",
|
||||
"//mojo/public/cpp/bindings",
|
||||
]
|
||||
},
|
||||
{
|
||||
types = [
|
||||
{
|
||||
|
@ -0,0 +1,25 @@
|
||||
// Copyright 2021 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 associated interface
|
||||
// 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 asspcoated receivers that cannot or should not be known at
|
||||
// compile time.
|
||||
struct GenericPendingAssociatedReceiver {
|
||||
// The name of the interface which defines the messages to be received by
|
||||
// `receiver`.
|
||||
string interface_name;
|
||||
|
||||
// A generic associated interface receiver which is actually expected to
|
||||
// receive messages defined by the interface named by `interface_name` above.
|
||||
pending_associated_receiver<GenericAssociatedInterface> receiver;
|
||||
};
|
||||
|
||||
// A generic placeholder interface for the associated endpoint to be passed by a
|
||||
// GenericPendingAssociatedReceiver.
|
||||
interface GenericAssociatedInterface {};
|
Reference in New Issue
Block a user