// 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 { class UrgentMessageObserver; // 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 { … }; // 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 { … }; } // namespace IPC #endif // IPC_IPC_MOJO_BOOTSTRAP_H_