
Bug: 1416710 Change-Id: Ie2d356ba778be1424c99ff8094f45290a15a01ac Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4318344 Commit-Queue: Peter Kasting <pkasting@chromium.org> Reviewed-by: Ken Rockot <rockot@google.com> Cr-Commit-Position: refs/heads/main@{#1114795}
135 lines
6.0 KiB
C++
135 lines
6.0 KiB
C++
// Copyright 2014 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef IPC_IPC_MOJO_BOOTSTRAP_H_
|
|
#define IPC_IPC_MOJO_BOOTSTRAP_H_
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <memory>
|
|
|
|
#include "base/auto_reset.h"
|
|
#include "base/component_export.h"
|
|
#include "base/memory/ref_counted.h"
|
|
#include "base/task/single_thread_task_runner.h"
|
|
#include "build/build_config.h"
|
|
#include "ipc/ipc.mojom.h"
|
|
#include "ipc/ipc_channel.h"
|
|
#include "ipc/ipc_listener.h"
|
|
#include "mojo/public/cpp/bindings/associated_group.h"
|
|
#include "mojo/public/cpp/bindings/associated_remote.h"
|
|
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
|
|
#include "mojo/public/cpp/system/message_pipe.h"
|
|
|
|
namespace IPC {
|
|
|
|
// Incoming legacy IPCs have always been dispatched to one of two threads: the
|
|
// IO thread (when an installed MessageFilter handles the message), or the
|
|
// thread which owns the corresponding ChannelProxy receiving the message. There
|
|
// were no other places to route legacy IPC messages, so when a message arrived
|
|
// the legacy IPC system would run through its MessageFilters and if the message
|
|
// was still unhandled, it would be posted to the ChannelProxy thread for
|
|
// further processing.
|
|
//
|
|
// Mojo on the other hand allows for mutually associated endpoints (that is,
|
|
// endpoints which locally share the same message pipe) to span any number of
|
|
// threads while still guaranteeing that each endpoint on a given thread
|
|
// preserves FIFO order of messages dispatched there. This means that if a
|
|
// message arrives carrying a PendingAssociatedRemote/Receiver endpoint, and
|
|
// then another message arrives which targets that endpoint, the entire pipe
|
|
// will be blocked from dispatch until the endpoint is bound: otherwise we have
|
|
// no idea where to dispatch the message such that we can uphold the FIFO
|
|
// guarantee between the new endpoint and any other endpoints on the thread it
|
|
// ends up binding to.
|
|
//
|
|
// Channel-associated interfaces share a message pipe with the legacy IPC
|
|
// Channel, and in order to avoid nasty surprises during the migration process
|
|
// we decided to constrain how incoming Channel-associated endpoints could be
|
|
// bound: you must either bind them immediately as they arrive on the IO thread,
|
|
// or you must immediately post a task to the ChannelProxy thread to bind them.
|
|
// This allows all aforementioned FIFO guaratees to be upheld without ever
|
|
// stalling dispatch of legacy IPCs (particularly on the IO thread), because
|
|
// when we see a message targeting an unbound endpoint we can safely post it to
|
|
// the ChannelProxy's task runner before forging ahead to dispatch subsequent
|
|
// messages. No stalling.
|
|
//
|
|
// As there are some cases where a Channel-associated endpoint really wants to
|
|
// receive messages on a different TaskRunner, we want to allow that now. It's
|
|
// safe as long as the application can guarantee that the endpoint in question
|
|
// will be bound to a task runner *before* any messages are received for that
|
|
// endpoint.
|
|
//
|
|
// HOWEVER, it turns out that we cannot simply adhere to the application's
|
|
// wishes when an alternative TaskRunner is provided at binding time: over time
|
|
// we have accumulated application code which binds Channel-associated endpoints
|
|
// to task runners which -- while running tasks exclusively on the ChannelProxy
|
|
// thread -- are not the ChannelProxy's own task runner. Such code now
|
|
// implicitly relies on the behavior of Channel-associated interfaces always
|
|
// dispatching their messages to the ChannelProxy task runner. This is tracked
|
|
// by https://crbug.com/1209188.
|
|
//
|
|
// Finally, the point: if you really know you want to bind your endpoint to an
|
|
// alternative task runner and you can really guarantee that no messages may
|
|
// have already arrived for it on the IO thread, you can do the binding within
|
|
// the extent of a ScopedAllowOffSequenceChannelAssociatedBindings. This will
|
|
// flag the endpoint such that it honors your binding configuration, and its
|
|
// incoming messages will actually dispatch to the task runner you provide.
|
|
class COMPONENT_EXPORT(IPC)
|
|
[[maybe_unused,
|
|
nodiscard]] ScopedAllowOffSequenceChannelAssociatedBindings {
|
|
public:
|
|
ScopedAllowOffSequenceChannelAssociatedBindings();
|
|
~ScopedAllowOffSequenceChannelAssociatedBindings();
|
|
|
|
private:
|
|
const base::AutoReset<bool> resetter_;
|
|
};
|
|
|
|
// MojoBootstrap establishes a pair of associated interfaces between two
|
|
// processes in Chrome.
|
|
//
|
|
// Clients should implement MojoBootstrap::Delegate to get the associated pipes
|
|
// from MojoBootstrap object.
|
|
//
|
|
// This lives on IO thread other than Create(), which can be called from
|
|
// UI thread as Channel::Create() can be.
|
|
class COMPONENT_EXPORT(IPC) MojoBootstrap {
|
|
public:
|
|
virtual ~MojoBootstrap() {}
|
|
|
|
// Create the MojoBootstrap instance, using |handle| as the message pipe, in
|
|
// mode as specified by |mode|. The result is passed to |delegate|.
|
|
static std::unique_ptr<MojoBootstrap> Create(
|
|
mojo::ScopedMessagePipeHandle handle,
|
|
Channel::Mode mode,
|
|
const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
|
|
const scoped_refptr<base::SingleThreadTaskRunner>& proxy_task_runner);
|
|
|
|
// Initialize the Channel pipe and interface endpoints. This performs all
|
|
// setup except actually starting to read messages off the pipe.
|
|
virtual void Connect(
|
|
mojo::PendingAssociatedRemote<mojom::Channel>* sender,
|
|
mojo::PendingAssociatedReceiver<mojom::Channel>* receiver) = 0;
|
|
|
|
// Enable incoming messages to start being read off the pipe and routed to
|
|
// endpoints. Must not be called until the pending endpoints created by
|
|
// Connect() are actually bound somewhere.
|
|
virtual void StartReceiving() = 0;
|
|
|
|
// Stop transmitting messages and start queueing them instead.
|
|
virtual void Pause() = 0;
|
|
|
|
// Stop queuing new messages and start transmitting them instead.
|
|
virtual void Unpause() = 0;
|
|
|
|
// Flush outgoing messages which were queued before Start().
|
|
virtual void Flush() = 0;
|
|
|
|
virtual mojo::AssociatedGroup* GetAssociatedGroup() = 0;
|
|
};
|
|
|
|
} // namespace IPC
|
|
|
|
#endif // IPC_IPC_MOJO_BOOTSTRAP_H_
|