123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- // Copyright 2014 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 IPC_IPC_MOJO_BOOTSTRAP_H_
- #define IPC_IPC_MOJO_BOOTSTRAP_H_
- #include <stdint.h>
- #include <memory>
- #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/lib/message_quota_checker.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) ScopedAllowOffSequenceChannelAssociatedBindings {
- public:
- ScopedAllowOffSequenceChannelAssociatedBindings();
- ~ScopedAllowOffSequenceChannelAssociatedBindings();
- private:
- const bool outer_flag_;
- };
- // 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,
- const scoped_refptr<mojo::internal::MessageQuotaChecker>& quota_checker);
- // 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_
|