summaryrefslogtreecommitdiff
path: root/chromium/ipc/ipc_mojo_bootstrap.h
blob: 43156e541d5ba445470b6f1e70f74a700ee35ef6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// 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/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_