blob: ecf62d7c74533cd21d512643638f74e494b587d1 [file] [log] [blame] [view]
Ken Rockot686e4132017-04-26 00:03:311# Mojo C++ System API
Ken Rockot929282c2018-05-02 17:07:292This document is a subset of the [Mojo documentation](/mojo/README.md).
rockotf59d2d62017-04-01 02:49:083
4[TOC]
5
6## Overview
7The Mojo C++ System API provides a convenient set of helper classes and
8functions for working with Mojo primitives. Unlike the low-level
Ken Rockot929282c2018-05-02 17:07:299[C API](/mojo/public/c/system/README.md) (upon which this is built) this library
10takes advantage of C++ language features and common STL and `//base` types to
11provide a slightly more idiomatic interface to the Mojo system layer, making it
rockotf59d2d62017-04-01 02:49:0812generally easier to use.
13
14This document provides a brief guide to API usage with example code snippets.
15For a detailed API references please consult the headers in
Ken Rockot929282c2018-05-02 17:07:2916[//mojo/public/cpp/system](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/README.md).
rockotf59d2d62017-04-01 02:49:0817
18Note that all API symbols referenced in this document are implicitly in the
19top-level `mojo` namespace.
20
21## Scoped, Typed Handles
22
23All types of Mojo handles in the C API are simply opaque, integral `MojoHandle`
24values. The C++ API has more strongly typed wrappers defined for different
25handle types: `MessagePipeHandle`, `SharedBufferHandle`,
Ken Rockot7c05e3de2018-06-26 02:54:4526`DataPipeConsumerHandle`, `DataPipeProducerHandle`, `TrapHandle`, and
27`InvitationHandle`.
rockotf59d2d62017-04-01 02:49:0828
29Each of these also has a corresponding, move-only, scoped type for safer usage:
30`ScopedMessagePipeHandle`, `ScopedSharedBufferHandle`, and so on. When a scoped
31handle type is destroyed, its handle is automatically closed via `MojoClose`.
32When working with raw handles you should **always** prefer to use one of the
33scoped types for ownership.
34
35Similar to `std::unique_ptr`, scoped handle types expose a `get()` method to get
36at the underlying unscoped handle type as well as the `->` operator to
37dereference the scoper and make calls directly on the underlying handle type.
38
39## Message Pipes
40
41There are two ways to create a new message pipe using the C++ API. You may
42construct a `MessagePipe` object:
43
44``` cpp
45mojo::MessagePipe pipe;
46
47// NOTE: Because pipes are bi-directional there is no implicit semantic
48// difference between |handle0| or |handle1| here. They're just two ends of a
49// pipe. The choice to treat one as a "client" and one as a "server" is entirely
Chase Phillipsd3e02922018-08-16 21:00:0250// the API user's decision.
rockotf59d2d62017-04-01 02:49:0851mojo::ScopedMessagePipeHandle client = std::move(pipe.handle0);
52mojo::ScopedMessagePipeHandle server = std::move(pipe.handle1);
53```
54
55or you may call `CreateMessagePipe`:
56
57``` cpp
58mojo::ScopedMessagePipeHandle client;
59mojo::ScopedMessagePipeHandle server;
60mojo::CreateMessagePipe(nullptr, &client, &server);
61```
62
63There are also some helper functions for constructing message objects and
64reading/writing them on pipes using the library's more strongly-typed C++
65handles:
66
67``` cpp
68mojo::ScopedMessageHandle message;
69mojo::AllocMessage(6, nullptr, 0, MOJO_ALLOC_MESSAGE_FLAG_NONE, &message);
70
71void *buffer;
72mojo::GetMessageBuffer(message.get(), &buffer);
73
Hyowon Kimdd196c92023-12-04 01:38:4374constexpr std::string_view kMessage = "hello";
Peter Kasting1ed31f52025-01-27 22:15:3575std::ranges::copy(kMessage, static_cast<char*>(buffer));
rockotf59d2d62017-04-01 02:49:0876
77mojo::WriteMessageNew(client.get(), std::move(message),
78 MOJO_WRITE_MESSAGE_FLAG_NONE);
79
80// Some time later...
81
82mojo::ScopedMessageHandle received_message;
83uint32_t num_bytes;
84mojo::ReadMessageNew(server.get(), &received_message, &num_bytes, nullptr,
85 nullptr, MOJO_READ_MESSAGE_FLAG_NONE);
86```
87
88See [message_pipe.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/message_pipe.h)
89for detailed C++ message pipe API documentation.
90
91## Data Pipes
92
93Similar to [Message Pipes](#Message-Pipes), the C++ library has some simple
94helpers for more strongly-typed data pipe usage:
95
96``` cpp
97mojo::DataPipe pipe;
Helen Lie464f722018-07-25 18:47:5798mojo::ScopedDataPipeProducerHandle producer = std::move(pipe.producer_handle);
99mojo::ScopedDataPipeConsumerHandle consumer = std::move(pipe.consumer_handle);
rockotf59d2d62017-04-01 02:49:08100
101// Or alternatively:
102mojo::ScopedDataPipeProducerHandle producer;
103mojo::ScopedDataPipeConsumerHandle consumer;
Robert Sesek3bce5dd2021-02-19 19:27:58104mojo::CreateDataPipe(nullptr, producer, consumer);
Marijn Kruisselbrink283e99182017-05-18 22:08:30105```
106
rockotf59d2d62017-04-01 02:49:08107C++ helpers which correspond directly to the
Ken Rockot929282c2018-05-02 17:07:29108[Data Pipe C API](/mojo/public/c/system/README.md#Data-Pipes) for immediate and
109two-phase I/O are provided as well. For example:
rockotf59d2d62017-04-01 02:49:08110
111``` cpp
112uint32_t num_bytes = 7;
Reilly Grant789c63e2017-08-04 15:30:16113producer.WriteData("hihihi", &num_bytes, MOJO_WRITE_DATA_FLAG_NONE);
rockotf59d2d62017-04-01 02:49:08114
115// Some time later...
116
117char buffer[64];
118uint32_t num_bytes = 64;
Reilly Grant789c63e2017-08-04 15:30:16119consumer.ReadData(buffer, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
rockotf59d2d62017-04-01 02:49:08120```
121
122See [data_pipe.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/data_pipe.h)
123for detailed C++ data pipe API documentation.
124
125## Shared Buffers
126
Chase Phillipsd3e02922018-08-16 21:00:02127A new shared buffer can be allocated like so:
rockotf59d2d62017-04-01 02:49:08128
129``` cpp
130mojo::ScopedSharedBufferHandle buffer =
Noel Gordon00fecee2017-11-21 21:38:05131 mojo::SharedBufferHandle::Create(4096);
rockotf59d2d62017-04-01 02:49:08132```
133
134This new handle can be cloned arbitrarily many times by using the underlying
135handle's `Clone` method:
136
137``` cpp
Tommy Chiang911f99032024-01-02 21:07:48138mojo::ScopedSharedBufferHandle another_handle =
139 buffer->Clone(mojo::SharedBufferHandle::AccessMode::READ_WRITE);
rockotf59d2d62017-04-01 02:49:08140mojo::ScopedSharedBufferHandle read_only_handle =
141 buffer->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY);
142```
143
144And finally the library also provides a scoper for mapping the shared buffer's
145memory:
146
147``` cpp
148mojo::ScopedSharedBufferMapping mapping = buffer->Map(64);
Joonghun Parka7771e72019-06-03 18:12:08149static_cast<int*>(mapping.get())[0] = 42;
rockotf59d2d62017-04-01 02:49:08150
151mojo::ScopedSharedBufferMapping another_mapping = buffer->MapAtOffset(64, 4);
Joonghun Parka7771e72019-06-03 18:12:08152static_cast<int*>(mapping.get())[0] = 43;
rockotf59d2d62017-04-01 02:49:08153```
154
155When `mapping` and `another_mapping` are destroyed, they automatically unmap
156their respective memory regions.
157
158See [buffer.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/buffer.h)
159for detailed C++ shared buffer API documentation.
160
161## Native Platform Handles (File Descriptors, Windows Handles, *etc.*)
162
163The C++ library provides several helpers for wrapping system handle types.
164These are specifically useful when working with a few `//base` types, namely
Ken Rockot7c05e3de2018-06-26 02:54:45165`base::PlatformFile`, `base::SharedMemoryHandle` (deprecated), and various
166strongly-typed shared memory region types like
167`base::ReadOnlySharedMemoryRegion`. See
rockotf59d2d62017-04-01 02:49:08168[platform_handle.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/platform_handle.h)
169for detailed C++ platform handle API documentation.
170
Ken Rockot7c05e3de2018-06-26 02:54:45171## Signals & Traps
rockotf59d2d62017-04-01 02:49:08172
Ken Rockot7c05e3de2018-06-26 02:54:45173For an introduction to the concepts of handle signals and traps, check out
Ken Rockot929282c2018-05-02 17:07:29174the C API's documentation on
Ken Rockot7c05e3de2018-06-26 02:54:45175[Signals & Traps](/mojo/public/c/system/README.md#Signals-Traps).
rockotf59d2d62017-04-01 02:49:08176
177### Querying Signals
178
179Any C++ handle type's last known signaling state can be queried by calling the
180`QuerySignalsState` method on the handle:
181
182``` cpp
183mojo::MessagePipe message_pipe;
184mojo::DataPipe data_pipe;
185mojo::HandleSignalsState a = message_pipe.handle0->QuerySignalsState();
186mojo::HandleSignalsState b = data_pipe.consumer->QuerySignalsState();
187```
188
189The `HandleSignalsState` is a thin wrapper interface around the C API's
190`MojoHandleSignalsState` structure with convenient accessors for testing
191the signal bitmasks. Whereas when using the C API you might write:
192
193``` c
194struct MojoHandleSignalsState state;
195MojoQueryHandleSignalsState(handle0, &state);
196if (state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE) {
197 // ...
198}
199```
200
201the C++ API equivalent would be:
202
203``` cpp
204if (message_pipe.handle0->QuerySignalsState().readable()) {
205 // ...
206}
207```
208
209### Watching Handles
210
211The [`mojo::SimpleWatcher`](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/simple_watcher.h)
Ken Rockot929282c2018-05-02 17:07:29212class serves as a convenient helper for using the
Ken Rockot7c05e3de2018-06-26 02:54:45213[low-level traps API](/mojo/public/c/system/README.md#Signals-Traps)
rockotf59d2d62017-04-01 02:49:08214to watch a handle for signaling state changes. A `SimpleWatcher` is bound to a
Sam McNallyd482b4b2017-07-17 03:45:03215single sequence and always dispatches its notifications on a
216`base::SequencedTaskRunner`.
rockotf59d2d62017-04-01 02:49:08217
218`SimpleWatcher` has two possible modes of operation, selected at construction
219time by the `mojo::SimpleWatcher::ArmingPolicy` enum:
220
221* `MANUAL` mode requires the user to manually call `Arm` and/or `ArmOrNotify`
222 before any notifications will fire regarding the state of the watched handle.
223 Every time the notification callback is run, the `SimpleWatcher` must be
Ken Rockot856f9772017-04-11 19:41:39224 rearmed again before the next one can fire. See
Ken Rockot7c05e3de2018-06-26 02:54:45225 [Arming a Trap](/mojo/public/c/system/README.md#Arming-a-Trap) and the
rockotf59d2d62017-04-01 02:49:08226 documentation in `SimpleWatcher`'s header.
227
228* `AUTOMATIC` mode ensures that the `SimpleWatcher` always either is armed or
229 has a pending notification task queued for execution.
230
231`AUTOMATIC` mode is more convenient but can result in redundant notification
232tasks, especially if the provided callback does not make a strong effort to
233return the watched handle to an uninteresting signaling state (by *e.g.*,
234reading all its available messages when notified of readability.)
235
236Example usage:
237
238``` cpp
239class PipeReader {
240 public:
241 PipeReader(mojo::ScopedMessagePipeHandle pipe)
242 : pipe_(std::move(pipe)),
243 watcher_(mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC) {
244 // NOTE: base::Unretained is safe because the callback can never be run
245 // after SimpleWatcher destruction.
246 watcher_.Watch(pipe_.get(), MOJO_HANDLE_SIGNAL_READABLE,
danakj46326592019-11-28 17:53:35247 base::BindRepeating(&PipeReader::OnReadable,
danakjee3226e92019-12-03 16:39:38248 base::Unretained(this)));
rockotf59d2d62017-04-01 02:49:08249 }
250
251 ~PipeReader() {}
252
253 private:
254 void OnReadable(MojoResult result) {
255 while (result == MOJO_RESULT_OK) {
256 mojo::ScopedMessageHandle message;
257 uint32_t num_bytes;
258 result = mojo::ReadMessageNew(pipe_.get(), &message, &num_bytes, nullptr,
259 nullptr, MOJO_READ_MESSAGE_FLAG_NONE);
260 DCHECK_EQ(result, MOJO_RESULT_OK);
261 messages_.emplace_back(std::move(message));
262 }
263 }
264
265 mojo::ScopedMessagePipeHandle pipe_;
266 mojo::SimpleWatcher watcher_;
267 std::vector<mojo::ScopedMessageHandle> messages_;
268};
269
270mojo::MessagePipe pipe;
271PipeReader reader(std::move(pipe.handle0));
272
273// Written messages will asynchronously end up in |reader.messages_|.
274WriteABunchOfStuff(pipe.handle1.get());
275```
276
277## Synchronous Waiting
278
Sam McNallyd482b4b2017-07-17 03:45:03279The C++ System API defines some utilities to block a calling sequence while
rockotf59d2d62017-04-01 02:49:08280waiting for one or more handles to change signaling state in an interesting way.
Ken Rockot929282c2018-05-02 17:07:29281These threads combine usage of the
Ken Rockot7c05e3de2018-06-26 02:54:45282[low-level traps API](/mojo/public/c/system/README.md#Signals-Traps)
rockotf59d2d62017-04-01 02:49:08283with common synchronization primitives (namely `base::WaitableEvent`.)
284
285While these API features should be used sparingly, they are sometimes necessary.
286
Ken Rockot856f9772017-04-11 19:41:39287See the documentation in
rockotf59d2d62017-04-01 02:49:08288[wait.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/wait.h)
289and [wait_set.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/wait_set.h)
290for a more detailed API reference.
291
292### Waiting On a Single Handle
293
Sam McNallyd482b4b2017-07-17 03:45:03294The `mojo::Wait` function simply blocks the calling sequence until a given
295signal mask is either partially satisfied or fully unsatisfiable on a given
296handle.
rockotf59d2d62017-04-01 02:49:08297
298``` cpp
299mojo::MessagePipe pipe;
300mojo::WriteMessageRaw(pipe.handle0.get(), "hey", 3, nullptr, nullptr,
301 MOJO_WRITE_MESSAGE_FLAG_NONE);
302MojoResult result = mojo::Wait(pipe.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE);
303DCHECK_EQ(result, MOJO_RESULT_OK);
304
305// Guaranteed to succeed because we know |handle1| is readable now.
306mojo::ScopedMessageHandle message;
307uint32_t num_bytes;
308mojo::ReadMessageNew(pipe.handle1.get(), &num_bytes, nullptr, nullptr,
309 MOJO_READ_MESSAGE_FLAG_NONE);
310```
311
312`mojo::Wait` is most typically useful in limited testing scenarios.
313
314### Waiting On Multiple Handles
315
316`mojo::WaitMany` provides a simple API to wait on multiple handles
317simultaneously, returning when any handle's given signal mask is either
318partially satisfied or fully unsatisfiable.
319
320``` cpp
321mojo::MessagePipe a, b;
322GoDoSomethingWithPipes(std:move(a.handle1), std::move(b.handle1));
323
324mojo::MessagePipeHandle handles[2] = {a.handle0.get(), b.handle0.get()};
325MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_READABLE,
326 MOJO_HANDLE_SIGNAL_READABLE};
327size_t ready_index;
328MojoResult result = mojo::WaitMany(handles, signals, 2, &ready_index);
329if (ready_index == 0) {
330 // a.handle0 was ready.
331} else {
332 // b.handle0 was ready.
333}
334```
335
336Similar to `mojo::Wait`, `mojo::WaitMany` is primarily useful in testing. When
Ken Rockot856f9772017-04-11 19:41:39337waiting on multiple handles in production code, you should almost always instead
rockotf59d2d62017-04-01 02:49:08338use a more efficient and more flexible `mojo::WaitSet` as described in the next
339section.
340
341### Waiting On Handles and Events Simultaneously
342
343Typically when waiting on one or more handles to signal, the set of handles and
344conditions being waited upon do not change much between consecutive blocking
345waits. It's also often useful to be able to interrupt the blocking operation
346as efficiently as possible.
347
348[`mojo::WaitSet`](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/wait_set.h)
349is designed with these conditions in mind. A `WaitSet` maintains a persistent
350set of (not-owned) Mojo handles and `base::WaitableEvent`s, which may be
351explicitly added to or removed from the set at any time.
352
353The `WaitSet` may be waited upon repeatedly, each time blocking the calling
Sam McNallyd482b4b2017-07-17 03:45:03354sequence until either one of the handles attains an interesting signaling state
355or one of the events is signaled. For example let's suppose we want to wait up
356to 5 seconds for either one of two handles to become readable:
rockotf59d2d62017-04-01 02:49:08357
358``` cpp
359base::WaitableEvent timeout_event(
360 base::WaitableEvent::ResetPolicy::MANUAL,
361 base::WaitableEvent::InitialState::NOT_SIGNALED);
362mojo::MessagePipe a, b;
363
364GoDoStuffWithPipes(std::move(a.handle1), std::move(b.handle1));
365
366mojo::WaitSet wait_set;
367wait_set.AddHandle(a.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE);
368wait_set.AddHandle(b.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE);
369wait_set.AddEvent(&timeout_event);
370
371// Ensure the Wait() lasts no more than 5 seconds.
kylechar14fec3172019-02-20 17:40:19372bg_thread->task_runner()->PostDelayedTask(FROM_HERE, base::BindOnce([](base::WaitableEvent* e) { e->Signal(); }, &timeout_event);
Peter Kastinge5a38ed2021-10-02 03:06:35373 base::Seconds(5));
rockotf59d2d62017-04-01 02:49:08374
375base::WaitableEvent* ready_event = nullptr;
376size_t num_ready_handles = 1;
377mojo::Handle ready_handle;
378MojoResult ready_result;
379wait_set.Wait(&ready_event, &num_ready_handles, &ready_handle, &ready_result);
380
381// The apex of thread-safety.
382bg_thread->Stop();
383
384if (ready_event) {
385 // The event signaled...
386}
387
388if (num_ready_handles > 0) {
389 // At least one of the handles signaled...
390 // NOTE: This and the above condition are not mutually exclusive. If handle
391 // signaling races with timeout, both things might be true.
392}
393```
Ken Rockot7c05e3de2018-06-26 02:54:45394
395## Invitations
396Invitations are the means by which two processes can have Mojo IPC bootstrapped
397between them. An invitation must be transmitted over some platform-specific IPC
398primitive (*e.g.* a Windows named pipe or UNIX domain socket), and the public
399[platform support library](/mojo/public/cpp/platform/README.md) provides some
400lightweight, cross-platform abstractions for those primitives.
401
402For any two processes looking to be connected, one must send an
403`OutgoingInvitation` and the other must accept an `IncomingInvitation`. The
404sender can attach named message pipe handles to the `OutgoingInvitation`, and
405the receiver can extract them from its `IncomingInvitation`.
406
407Basic usage might look something like this in the case where one process is
408responsible for launching the other.
409
410``` cpp
411#include "base/command_line.h"
412#include "base/process/launch.h"
413#include "mojo/public/cpp/platform/platform_channel.h"
414#include "mojo/public/cpp/system/invitation.h"
415#include "mojo/public/cpp/system/message_pipe.h"
416
417mojo::ScopedMessagePipeHandle LaunchAndConnectSomething() {
418 // Under the hood, this is essentially always an OS pipe (domain socket pair,
419 // Windows named pipe, Fuchsia channel, etc).
420 mojo::PlatformChannel channel;
421
422 mojo::OutgoingInvitation invitation;
423
424 // Attach a message pipe to be extracted by the receiver. The other end of the
425 // pipe is returned for us to use locally.
426 mojo::ScopedMessagePipeHandle pipe =
427 invitation->AttachMessagePipe("arbitrary pipe name");
428
429 base::LaunchOptions options;
430 base::CommandLine command_line("some_executable")
431 channel.PrepareToPassRemoteEndpoint(&options, &command_line);
432 base::Process child_process = base::LaunchProcess(command_line, options);
433 channel.RemoteProcessLaunchAttempted();
434
435 OutgoingInvitation::Send(std::move(invitation), child_process.Handle(),
436 channel.TakeLocalEndpoint());
437 return pipe;
438}
439```
440
441The launched process can in turn accept an `IncomingInvitation`:
442
443``` cpp
444#include "base/command_line.h"
445#include "base/threading/thread.h"
Ken Rockotdba46db2018-07-04 18:41:04446#include "mojo/core/embedder/embedder.h"
447#include "mojo/core/embedder/scoped_ipc_support.h"
Ken Rockot7c05e3de2018-06-26 02:54:45448#include "mojo/public/cpp/platform/platform_channel.h"
449#include "mojo/public/cpp/system/invitation.h"
450#include "mojo/public/cpp/system/message_pipe.h"
451
452int main(int argc, char** argv) {
453 // Basic Mojo initialization for a new process.
Ken Rockotdba46db2018-07-04 18:41:04454 mojo::core::Init();
Ken Rockot7c05e3de2018-06-26 02:54:45455 base::Thread ipc_thread("ipc!");
456 ipc_thread.StartWithOptions(
Chris Sharp7840c582019-08-02 15:45:32457 base::Thread::Options(base::MessagePumpType::IO, 0));
Ken Rockotdba46db2018-07-04 18:41:04458 mojo::core::ScopedIPCSupport ipc_support(
Ken Rockot7c05e3de2018-06-26 02:54:45459 ipc_thread.task_runner(),
Ken Rockotdba46db2018-07-04 18:41:04460 mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN);
Ken Rockot7c05e3de2018-06-26 02:54:45461
462 // Accept an invitation.
463 mojo::IncomingInvitation invitation = mojo::IncomingInvitation::Accept(
464 mojo::PlatformChannel::RecoverPassedEndpointFromCommandLine(
465 *base::CommandLine::ForCurrentProcess()));
466 mojo::ScopedMessagePipeHandle pipe =
467 invitation->ExtractMessagePipe("arbitrary pipe name");
468
469 // etc...
470 return GoListenForMessagesAndRunForever(std::move(pipe));
471}
472```
473
474Now we have IPC initialized between the two processes.
475
476Also keep in mind that bindings interfaces are just message pipes with some
477semantic and syntactic sugar wrapping them, so you can use these primordial
478message pipe handles as mojom interfaces. For example:
479
480``` cpp
481// Process A
482mojo::OutgoingInvitation invitation;
483auto pipe = invitation->AttachMessagePipe("x");
Alexander Timin572daa82020-01-24 17:33:04484mojo::Receiver<foo::mojom::Bar> receiver(
Ken Rockot7c05e3de2018-06-26 02:54:45485 &bar_impl,
Alexander Timin572daa82020-01-24 17:33:04486 mojo::PendingReceiver<foo::mojom::Bar>(std::move(pipe)));
Ken Rockot7c05e3de2018-06-26 02:54:45487
488// Process B
489auto invitation = mojo::IncomingInvitation::Accept(...);
490auto pipe = invitation->ExtractMessagePipe("x");
Alexander Timin572daa82020-01-24 17:33:04491mojo::Remote<foo::mojom::Bar> bar(
492 mojo::PendingRemote<foo::mojom::Bar>(std::move(pipe), 0));
Ken Rockot7c05e3de2018-06-26 02:54:45493
494// Will asynchronously invoke bar_impl.DoSomething() in process A.
495bar->DoSomething();
496```
497
498And just to be sure, the usage here could be reversed: the invitation sender
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40499could just as well treat its pipe endpoint as a `Remote<Bar>` while the receiver
500treats theirs as a `PendingReceiver<Bar>` to be bound.
Ken Rockot7c05e3de2018-06-26 02:54:45501
502### Process Networks
503Accepting an invitation admits the accepting process into the sender's connected
504network of processes. Once this is done, it's possible for the newly admitted
505process to establish communication with any other process in that network via
506normal message pipe passing.
507
508This does not mean that the invited process can proactively locate and connect
509to other processes without assistance; rather it means that Mojo handles created
510by the process can safely be transferred to any other process in the network
511over established message pipes, and similarly that Mojo handles created by any
512other process in the network can be safely passed to the newly admitted process.
513
514### Invitation Restrictions
515A process may only belong to a single network at a time.
516
517Additionally, once a process has joined a network, it cannot join another for
518the remainder of its lifetime even if it has lost the connection to its original
519network. This restriction will soon be lifted, but for now developers must be
520mindful of it when authoring any long-running daemon process that will accept an
521incoming invitation.
522
523### Isolated Invitations
524It is possible to have two independent networks of Mojo-connected processes; for
525example, a long-running system daemon which uses Mojo to talk to child processes
526of its own, as well as the Chrome browser process running with no common
527ancestor, talking to its own child processes.
528
529In this scenario it may be desirable to have a process in one network talk to a
530process in the other network. Normal invitations cannot be used here since both
531processes already belong to a network. In this case, an **isolated** invitation
532can be used. These work just like regular invitations, except the sender must
533call `OutgoingInvitation::SendIsolated` and the receiver must call
534`IncomingInvitation::AcceptIsolated`.
535
536Once a connection is established via isolated invitation, Mojo IPC can be used
537normally, with the exception that transitive process connections are not
538supported; that is, if process A sends a message pipe handle to process B via
539an isolated connection, process B cannot reliably send that pipe handle onward
540to another process in its own network. Isolated invitations therefore may only
541be used to facilitate direct 1:1 communication between two processes.