• Home
Name Date Size #Lines LOC

..--

BUILD.gnD03-May-20243.3 KiB148127

README.mdD03-May-202410.7 KiB328245

configuration.hD03-May-20242.5 KiB7020

connection_params.ccD03-May-2024749 2917

connection_params.hD03-May-2024908 3521

embedder.ccD03-May-20244.6 KiB159123

embedder.hD03-May-20247.7 KiB17463

embedder_internal.hD03-May-20241 KiB4521

embedder_unittest.ccD03-May-202423.5 KiB663429

entrypoints.ccD03-May-202412.2 KiB309259

entrypoints.hD03-May-2024696 2310

named_platform_channel_pair.hD03-May-20242.6 KiB7437

named_platform_handle.hD03-May-20241.4 KiB5235

pending_process_connection.ccD03-May-20241.5 KiB5135

pending_process_connection.hD03-May-20245 KiB12531

platform_channel_pair.ccD03-May-2024818 3521

platform_channel_pair.hD03-May-20244.2 KiB10745

platform_channel_pair_posix.ccD03-May-20245.7 KiB173125

platform_channel_pair_posix_unittest.ccD03-May-20249.2 KiB262197

platform_channel_pair_win.ccD03-May-20244.6 KiB12488

platform_channel_utils_posix.ccD03-May-20248.9 KiB283215

platform_channel_utils_posix.hD03-May-20244 KiB8839

platform_handle.ccD03-May-20242.3 KiB7543

platform_handle.hD03-May-20242.5 KiB9159

platform_handle_utils.hD03-May-20241.1 KiB3420

platform_handle_utils_posix.ccD03-May-2024733 2513

platform_handle_utils_win.ccD03-May-2024866 2918

platform_handle_vector.hD03-May-20241.1 KiB3621

platform_shared_buffer.ccD03-May-20249.3 KiB326237

platform_shared_buffer.hD03-May-20246.5 KiB17983

scoped_platform_handle.hD03-May-20241.7 KiB6444

test_embedder.ccD03-May-20241 KiB4731

test_embedder.hD03-May-2024978 2911

README.md

1# Mojo Embedder Development Kit (EDK)
2
3The Mojo EDK is a (binary-unstable) API which enables a process to use Mojo both
4internally and for IPC to other Mojo-embedding processes.
5
6Using any of the API surface in `//mojo/edk/embedder` requires (somewhat
7confusingly) a direct dependency on the GN `//mojo/edk/system` target. Despite
8this fact, you should never reference any of the headers in `mojo/edk/system`
9directly, as everything there is considered to be an internal detail of the EDK.
10
11## Basic Initialization
12
13In order to use Mojo in a given process, it's necessary to call
14`mojo::edk::Init` exactly once:
15
16```
17#include "mojo/edk/embedder/embedder.h"
18
19int main(int argc, char** argv) {
20  mojo::edk::Init();
21
22  // Now you can create message pipes, write messages, etc
23
24  return 0;
25}
26```
27
28As it happens though, Mojo is less useful without some kind of IPC support as
29well, and that's a second initialization step.
30
31## IPC Initialization
32
33You also need to provide the system with a background TaskRunner on which it can
34watch for inbound I/O from any of the various other processes you will later
35connect to it.
36
37Here we'll just create a new background thread for IPC and let Mojo use that.
38Note that in Chromium, we use the existing "IO thread" in the browser process
39and content child processes.
40
41```
42#include "base/threading/thread.h"
43#include "mojo/edk/embedder/embedder.h"
44#include "mojo/edk/embedder/scoped_ipc_support.h"
45
46int main(int argc, char** argv) {
47  mojo::edk::Init();
48
49  base::Thread ipc_thread("ipc!");
50  ipc_thread.StartWithOptions(
51      base::Thread::Options(base::MessageLoop::TYPE_IO));
52
53  // As long as this object is alive, all EDK API surface relevant to IPC
54  // connections is usable and message pipes which span a process boundary will
55  // continue to function.
56  mojo::edk::ScopedIPCSupport ipc_support(
57      ipc_thread.task_runner(),
58      mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
59
60  return 0;
61}
62```
63
64This process is now fully prepared to use Mojo IPC!
65
66Note that all existing process types in Chromium already perform this setup
67very early during startup.
68
69## Connecting Two Processes
70
71Now suppose you're running a process which has initialized Mojo IPC, and you
72want to launch another process which you know will also initialize Mojo IPC.
73You want to be able to connect Mojo interfaces between these two processes.
74Rejoice, because this section was written just for you.
75
76NOTE: For legacy reasons, some API terminology may refer to concepts of "parent"
77and "child" as a relationship between processes being connected by Mojo. This
78relationship is today completely orthogonal to any notion of process hierarchy
79in the OS, and so use of these APIs is not constrained by an adherence to any
80such hierarchy.
81
82Mojo requires you to bring your own OS pipe to the party, and it will do the
83rest. It also provides a convenient mechanism for creating such pipes, known as
84a `PlatformChannelPair`.
85
86You provide one end of this pipe to the EDK in the local process via
87`PendingProcessConnection` - which can also be used to create cross-process
88message pipes (see the next section) - and you're responsible for getting the
89other end into the remote process.
90
91```
92#include "base/process/process_handle.h"
93#include "base/threading/thread.h"
94#include "mojo/edk/embedder/embedder.h"
95#include "mojo/edk/embedder/pending_process_connection.h"
96#include "mojo/edk/embedder/platform_channel_pair.h"
97#include "mojo/edk/embedder/scoped_ipc_support.h"
98
99// You write this. It launches a new process, passing the pipe handle
100// encapsulated by |channel| by any means possible (e.g. on Windows or POSIX
101// you may inhert the file descriptor/HANDLE at launch and pass a commandline
102// argument to indicate its numeric value). Returns the handle of the new
103// process.
104base::ProcessHandle LaunchCoolChildProcess(
105    mojo::edk::ScopedPlatformHandle channel);
106
107int main(int argc, char** argv) {
108  mojo::edk::Init();
109
110  base::Thread ipc_thread("ipc!");
111  ipc_thread.StartWithOptions(
112      base::Thread::Options(base::MessageLoop::TYPE_IO));
113
114  mojo::edk::ScopedIPCSupport ipc_support(
115      ipc_thread.task_runner(),
116      mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
117
118  // This is essentially always an OS pipe (domain socket pair, Windows named
119  // pipe, etc.)
120  mojo::edk::PlatformChannelPair channel;
121
122  // This is a scoper which encapsulates the intent to connect to another
123  // process. It exists because process connection is inherently asynchronous,
124  // things may go wrong, and the lifetime of any associated resources is bound
125  // by the lifetime of this object regardless of success or failure.
126  mojo::edk::PendingProcessConnection child;
127
128  base::ProcessHandle child_handle =
129      LaunchCoolChildProcess(channel.PassClientHandle());
130
131  // At this point it's safe for |child| to go out of scope and nothing will
132  // break.
133  child.Connect(child_handle, channel.PassServerHandle());
134
135  return 0;
136}
137```
138
139The launched process code uses `SetParentPipeHandle` to get connected, and might
140look something like:
141
142```
143#include "base/threading/thread.h"
144#include "mojo/edk/embedder/embedder.h"
145#include "mojo/edk/embedder/scoped_ipc_support.h"
146
147// You write this. It acquires the ScopedPlatformHandle that was passed by
148// whomever launched this process (i.e. LaunchCoolChildProcess above).
149mojo::edk::ScopedPlatformHandle GetChannelHandle();
150
151int main(int argc, char** argv) {
152  mojo::edk::Init();
153
154  base::Thread ipc_thread("ipc!");
155  ipc_thread.StartWithOptions(
156      base::Thread::Options(base::MessageLoop::TYPE_IO));
157
158  mojo::edk::ScopedIPCSupport ipc_support(
159      ipc_thread.task_runner(),
160      mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
161
162  mojo::edk::SetParentPipeHandle(GetChannelHandle());
163
164  return 0;
165}
166```
167
168Now you have IPC initialized between two processes. For some practical examples
169of how this is done, you can dig into the various multiprocess tests in the
170`mojo_system_unittests` test suite.
171
172## Bootstrapping Cross-Process Message Pipes
173
174Having internal Mojo IPC support initialized is pretty useless if you don't have
175any message pipes spanning the process boundary. Fortunately, this is made
176trivial by the EDK: `PendingProcessConnection` has a
177`CreateMessagePipe` method which synthesizes a new solitary message pipe
178endpoint for your immediate use, while also generating a magic token string that
179can be exchanged for the other end of the pipe via
180`mojo::edk::CreateChildMessagePipe`.
181
182The token exchange can be done by the same process (which is sometimes useful),
183or by the process that is eventually connected via `Connect()` on that
184`PendingProcessConnection`. This means that you can effectively pass message
185pipes on the commandline by passing a token string.
186
187We can modify our existing sample code as follows:
188
189```
190#include "base/command_line.h"
191#include "base/process/process_handle.h"
192#include "base/threading/thread.h"
193#include "mojo/edk/embedder/embedder.h"
194#include "mojo/edk/embedder/pending_process_connection.h"
195#include "mojo/edk/embedder/platform_channel_pair.h"
196#include "mojo/edk/embedder/scoped_ipc_support.h"
197#include "mojo/public/cpp/system/message_pipe.h"
198#include "local/foo.mojom.h"  // You provide this
199
200base::ProcessHandle LaunchCoolChildProcess(
201    const base::CommandLine& command_line,
202    mojo::edk::ScopedPlatformHandle channel);
203
204int main(int argc, char** argv) {
205  mojo::edk::Init();
206
207  base::Thread ipc_thread("ipc!");
208  ipc_thread.StartWithOptions(
209      base::Thread::Options(base::MessageLoop::TYPE_IO));
210
211  mojo::edk::ScopedIPCSupport ipc_support(
212      ipc_thread.task_runner(),
213      mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
214
215  mojo::edk::PlatformChannelPair channel;
216
217  mojo::edk::PendingProcessConnection child;
218
219  base::CommandLine command_line;  // Assume this is appropriately initialized
220
221  // Create a new message pipe with one end being retrievable in the new
222  // process. Note that it doesn't matter whether we call CreateMessagePipe()
223  // before or after Connect(), and we can create as many different pipes as
224  // we like.
225  std::string pipe_token;
226  mojo::ScopedMessagePipeHandle my_pipe = child.CreateMessagePipe(&pipe_token);
227  command_line.AppendSwitchASCII("primordial-pipe", pipe_token);
228
229  base::ProcessHandle child_handle =
230      LaunchCoolChildProcess(command_line, channel.PassClientHandle());
231
232  child.Connect(child_handle, channel.PassServerHandle());
233
234  // We can start using our end of the pipe immediately. Here we assume the
235  // other end will eventually be bound to a local::mojom::Foo implementation,
236  // so we can start making calls on that interface.
237  //
238  // Note that this could even be done before the child process is launched and
239  // it would still work as expected.
240  local::mojom::FooPtr foo;
241  foo.Bind(local::mojom::FooPtrInfo(std::move(my_pipe), 0));
242  foo->DoSomeStuff(42);
243
244  return 0;
245}
246```
247
248and for the launched process:
249
250
251```
252#include "base/command_line.h"
253#include "base/run_loop/run_loop.h"
254#include "base/threading/thread.h"
255#include "mojo/edk/embedder/embedder.h"
256#include "mojo/edk/embedder/scoped_ipc_support.h"
257#include "mojo/public/cpp/bindings/binding.h"
258#include "mojo/public/cpp/system/message_pipe.h"
259#include "local/foo.mojom.h"  // You provide this
260
261mojo::edk::ScopedPlatformHandle GetChannelHandle();
262
263class FooImpl : local::mojom::Foo {
264 public:
265  explicit FooImpl(local::mojom::FooRequest request)
266      : binding_(this, std::move(request)) {}
267  ~FooImpl() override {}
268
269  void DoSomeStuff(int32_t n) override {
270    // ...
271  }
272
273 private:
274  mojo::Binding<local::mojom::Foo> binding_;
275
276  DISALLOW_COPY_AND_ASSIGN(FooImpl);
277};
278
279int main(int argc, char** argv) {
280  base::CommandLine::Init(argc, argv);
281
282  mojo::edk::Init();
283
284  base::Thread ipc_thread("ipc!");
285  ipc_thread.StartWithOptions(
286      base::Thread::Options(base::MessageLoop::TYPE_IO));
287
288  mojo::edk::ScopedIPCSupport ipc_support(
289      ipc_thread.task_runner(),
290      mojo::edk::ScopedIPCSupport::ShutdownPolicy::CLEAN);
291
292  mojo::edk::SetParentPipeHandle(GetChannelHandle());
293
294  mojo::ScopedMessagePipeHandle my_pipe = mojo::edk::CreateChildMessagePipe(
295      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
296          "primordial-pipe"));
297
298  local::mojom::FooRequest foo_request;
299  foo_request.Bind(std::move(my_pipe));
300  FooImpl impl(std::move(foo_request));
301
302  // Run forever!
303  base::RunLoop().Run();
304
305  return 0;
306}
307```
308
309Note that the above samples assume an interface definition in
310`//local/test.mojom` which would look something like:
311
312```
313module local.mojom;
314
315interface Foo {
316  DoSomeStuff(int32 n);
317};
318```
319
320Once you've bootstrapped your process connection with a real mojom interface,
321you can avoid any further mucking around with EDK APIs or raw message pipe
322handles, as everything beyond this point - including the passing of other
323interface pipes - can be handled eloquently using public bindings APIs.
324
325See [additional Mojo documentation](
326    https://www.chromium.org/developers/design-documents/mojo) for more
327information.
328