Home | History | Annotate | only in /external/libchrome/mojo/public/cpp/system
Up to higher level directory
NameDateSize
buffer.cc22-Oct-20201.7K
buffer.h22-Oct-20202.6K
BUILD.gn22-Oct-20201.7K
core.h22-Oct-2020515
data_pipe.h22-Oct-20206.4K
data_pipe_drainer.cc22-Oct-20201.4K
data_pipe_drainer.h22-Oct-20201.2K
data_pipe_utils.cc22-Oct-20203.1K
data_pipe_utils.h22-Oct-2020991
file_data_pipe_producer.cc22-Oct-20209.8K
file_data_pipe_producer.h22-Oct-20204.6K
functions.h22-Oct-2020810
handle.h22-Oct-20207.4K
handle_signal_tracker.cc22-Oct-20202.5K
handle_signal_tracker.h22-Oct-20202.3K
handle_signals_state.h22-Oct-20203.5K
invitation.cc22-Oct-202010.9K
invitation.h22-Oct-20207.6K
isolated_connection.cc22-Oct-20201.6K
isolated_connection.h22-Oct-20202.5K
message.h22-Oct-20203.1K
message_pipe.cc22-Oct-20203K
message_pipe.h22-Oct-20205.6K
platform_handle.cc22-Oct-202017K
platform_handle.h22-Oct-20207.6K
README.md22-Oct-202020K
scope_to_message_pipe.cc22-Oct-20201.5K
scope_to_message_pipe.h22-Oct-20202K
simple_watcher.cc22-Oct-20209.8K
simple_watcher.h22-Oct-202010K
string_data_pipe_producer.cc22-Oct-20204.4K
string_data_pipe_producer.h22-Oct-20203.6K
system_export.h22-Oct-2020845
tests/22-Oct-2020
trap.cc22-Oct-2020569
trap.h22-Oct-20201.1K
wait.cc22-Oct-20206.2K
wait.h22-Oct-20204K
wait_set.cc22-Oct-202012.3K
wait_set.h22-Oct-20205.1K

README.md

      1 # Mojo C++ System API
      2 This document is a subset of the [Mojo documentation](/mojo/README.md).
      3 
      4 [TOC]
      5 
      6 ## Overview
      7 The Mojo C++ System API provides a convenient set of helper classes and
      8 functions for working with Mojo primitives. Unlike the low-level
      9 [C API](/mojo/public/c/system/README.md) (upon which this is built) this library
     10 takes advantage of C++ language features and common STL and `//base` types to
     11 provide a slightly more idiomatic interface to the Mojo system layer, making it
     12 generally easier to use.
     13 
     14 This document provides a brief guide to API usage with example code snippets.
     15 For a detailed API references please consult the headers in
     16 [//mojo/public/cpp/system](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/README.md).
     17 
     18 Note that all API symbols referenced in this document are implicitly in the
     19 top-level `mojo` namespace.
     20 
     21 ## Scoped, Typed Handles
     22 
     23 All types of Mojo handles in the C API are simply opaque, integral `MojoHandle`
     24 values. The C++ API has more strongly typed wrappers defined for different
     25 handle types: `MessagePipeHandle`, `SharedBufferHandle`,
     26 `DataPipeConsumerHandle`, `DataPipeProducerHandle`, `TrapHandle`, and
     27 `InvitationHandle`.
     28 
     29 Each of these also has a corresponding, move-only, scoped type for safer usage:
     30 `ScopedMessagePipeHandle`, `ScopedSharedBufferHandle`, and so on. When a scoped
     31 handle type is destroyed, its handle is automatically closed via `MojoClose`.
     32 When working with raw handles you should **always** prefer to use one of the
     33 scoped types for ownership.
     34 
     35 Similar to `std::unique_ptr`, scoped handle types expose a `get()` method to get
     36 at the underlying unscoped handle type as well as the `->` operator to
     37 dereference the scoper and make calls directly on the underlying handle type.
     38 
     39 ## Message Pipes
     40 
     41 There are two ways to create a new message pipe using the C++ API. You may
     42 construct a `MessagePipe` object:
     43 
     44 ``` cpp
     45 mojo::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
     50 // a the API user's decision.
     51 mojo::ScopedMessagePipeHandle client = std::move(pipe.handle0);
     52 mojo::ScopedMessagePipeHandle server = std::move(pipe.handle1);
     53 ```
     54 
     55 or you may call `CreateMessagePipe`:
     56 
     57 ``` cpp
     58 mojo::ScopedMessagePipeHandle client;
     59 mojo::ScopedMessagePipeHandle server;
     60 mojo::CreateMessagePipe(nullptr, &client, &server);
     61 ```
     62 
     63 There are also some helper functions for constructing message objects and
     64 reading/writing them on pipes using the library's more strongly-typed C++
     65 handles:
     66 
     67 ``` cpp
     68 mojo::ScopedMessageHandle message;
     69 mojo::AllocMessage(6, nullptr, 0, MOJO_ALLOC_MESSAGE_FLAG_NONE, &message);
     70 
     71 void *buffer;
     72 mojo::GetMessageBuffer(message.get(), &buffer);
     73 
     74 const std::string kMessage = "hello";
     75 std::copy(kMessage.begin(), kMessage.end(), static_cast<char*>(buffer));
     76 
     77 mojo::WriteMessageNew(client.get(), std::move(message),
     78                       MOJO_WRITE_MESSAGE_FLAG_NONE);
     79 
     80 // Some time later...
     81 
     82 mojo::ScopedMessageHandle received_message;
     83 uint32_t num_bytes;
     84 mojo::ReadMessageNew(server.get(), &received_message, &num_bytes, nullptr,
     85                      nullptr, MOJO_READ_MESSAGE_FLAG_NONE);
     86 ```
     87 
     88 See [message_pipe.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/message_pipe.h)
     89 for detailed C++ message pipe API documentation.
     90 
     91 ## Data Pipes
     92 
     93 Similar to [Message Pipes](#Message-Pipes), the C++ library has some simple
     94 helpers for more strongly-typed data pipe usage:
     95 
     96 ``` cpp
     97 mojo::DataPipe pipe;
     98 mojo::ScopedDataPipeProducerHandle producer = std::move(pipe.producer);
     99 mojo::ScopedDataPipeConsumerHandle consumer = std::move(pipe.consumer);
    100 
    101 // Or alternatively:
    102 mojo::ScopedDataPipeProducerHandle producer;
    103 mojo::ScopedDataPipeConsumerHandle consumer;
    104 mojo::CreateDataPipe(null, &producer, &consumer);
    105 ```
    106 
    107 C++ helpers which correspond directly to the
    108 [Data Pipe C API](/mojo/public/c/system/README.md#Data-Pipes) for immediate and
    109 two-phase I/O are provided as well. For example:
    110 
    111 ``` cpp
    112 uint32_t num_bytes = 7;
    113 producer.WriteData("hihihi", &num_bytes, MOJO_WRITE_DATA_FLAG_NONE);
    114 
    115 // Some time later...
    116 
    117 char buffer[64];
    118 uint32_t num_bytes = 64;
    119 consumer.ReadData(buffer, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
    120 ```
    121 
    122 See [data_pipe.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/data_pipe.h)
    123 for detailed C++ data pipe API documentation.
    124 
    125 ## Shared Buffers
    126 
    127 A new shared buffers can be allocated like so:
    128 
    129 ``` cpp
    130 mojo::ScopedSharedBufferHandle buffer =
    131     mojo::SharedBufferHandle::Create(4096);
    132 ```
    133 
    134 This new handle can be cloned arbitrarily many times by using the underlying
    135 handle's `Clone` method:
    136 
    137 ``` cpp
    138 mojo::ScopedSharedBufferHandle another_handle = buffer->Clone();
    139 mojo::ScopedSharedBufferHandle read_only_handle =
    140     buffer->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY);
    141 ```
    142 
    143 And finally the library also provides a scoper for mapping the shared buffer's
    144 memory:
    145 
    146 ``` cpp
    147 mojo::ScopedSharedBufferMapping mapping = buffer->Map(64);
    148 static_cast<int*>(mapping.get()) = 42;
    149 
    150 mojo::ScopedSharedBufferMapping another_mapping = buffer->MapAtOffset(64, 4);
    151 static_cast<int*>(mapping.get()) = 43;
    152 ```
    153 
    154 When `mapping` and `another_mapping` are destroyed, they automatically unmap
    155 their respective memory regions.
    156 
    157 See [buffer.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/buffer.h)
    158 for detailed C++ shared buffer API documentation.
    159 
    160 ## Native Platform Handles (File Descriptors, Windows Handles, *etc.*)
    161 
    162 The C++ library provides several helpers for wrapping system handle types.
    163 These are specifically useful when working with a few `//base` types, namely
    164 `base::PlatformFile`, `base::SharedMemoryHandle` (deprecated), and various
    165 strongly-typed shared memory region types like
    166 `base::ReadOnlySharedMemoryRegion`. See
    167 [platform_handle.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/platform_handle.h)
    168 for detailed C++ platform handle API documentation.
    169 
    170 ## Signals & Traps
    171 
    172 For an introduction to the concepts of handle signals and traps, check out
    173 the C API's documentation on
    174 [Signals & Traps](/mojo/public/c/system/README.md#Signals-Traps).
    175 
    176 ### Querying Signals
    177 
    178 Any C++ handle type's last known signaling state can be queried by calling the
    179 `QuerySignalsState` method on the handle:
    180 
    181 ``` cpp
    182 mojo::MessagePipe message_pipe;
    183 mojo::DataPipe data_pipe;
    184 mojo::HandleSignalsState a = message_pipe.handle0->QuerySignalsState();
    185 mojo::HandleSignalsState b = data_pipe.consumer->QuerySignalsState();
    186 ```
    187 
    188 The `HandleSignalsState` is a thin wrapper interface around the C API's
    189 `MojoHandleSignalsState` structure with convenient accessors for testing
    190 the signal bitmasks. Whereas when using the C API you might write:
    191 
    192 ``` c
    193 struct MojoHandleSignalsState state;
    194 MojoQueryHandleSignalsState(handle0, &state);
    195 if (state.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE) {
    196   // ...
    197 }
    198 ```
    199 
    200 the C++ API equivalent would be:
    201 
    202 ``` cpp
    203 if (message_pipe.handle0->QuerySignalsState().readable()) {
    204   // ...
    205 }
    206 ```
    207 
    208 ### Watching Handles
    209 
    210 The [`mojo::SimpleWatcher`](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/simple_watcher.h)
    211 class serves as a convenient helper for using the
    212 [low-level traps API](/mojo/public/c/system/README.md#Signals-Traps)
    213 to watch a handle for signaling state changes. A `SimpleWatcher` is bound to a
    214 single sequence and always dispatches its notifications on a
    215 `base::SequencedTaskRunner`.
    216 
    217 `SimpleWatcher` has two possible modes of operation, selected at construction
    218 time by the `mojo::SimpleWatcher::ArmingPolicy` enum:
    219 
    220 * `MANUAL` mode requires the user to manually call `Arm` and/or `ArmOrNotify`
    221   before any notifications will fire regarding the state of the watched handle.
    222   Every time the notification callback is run, the `SimpleWatcher` must be
    223   rearmed again before the next one can fire. See
    224   [Arming a Trap](/mojo/public/c/system/README.md#Arming-a-Trap) and the
    225   documentation in `SimpleWatcher`'s header.
    226 
    227 * `AUTOMATIC` mode ensures that the `SimpleWatcher` always either is armed or
    228   has a pending notification task queued for execution.
    229 
    230 `AUTOMATIC` mode is more convenient but can result in redundant notification
    231 tasks, especially if the provided callback does not make a strong effort to
    232 return the watched handle to an uninteresting signaling state (by *e.g.*,
    233 reading all its available messages when notified of readability.)
    234 
    235 Example usage:
    236 
    237 ``` cpp
    238 class PipeReader {
    239  public:
    240   PipeReader(mojo::ScopedMessagePipeHandle pipe)
    241       : pipe_(std::move(pipe)),
    242         watcher_(mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC) {
    243     // NOTE: base::Unretained is safe because the callback can never be run
    244     // after SimpleWatcher destruction.
    245     watcher_.Watch(pipe_.get(), MOJO_HANDLE_SIGNAL_READABLE,
    246                    base::Bind(&PipeReader::OnReadable, base::Unretained(this)));
    247   }
    248 
    249   ~PipeReader() {}
    250 
    251  private:
    252   void OnReadable(MojoResult result) {
    253     while (result == MOJO_RESULT_OK) {
    254       mojo::ScopedMessageHandle message;
    255       uint32_t num_bytes;
    256       result = mojo::ReadMessageNew(pipe_.get(), &message, &num_bytes, nullptr,
    257                                     nullptr, MOJO_READ_MESSAGE_FLAG_NONE);
    258       DCHECK_EQ(result, MOJO_RESULT_OK);
    259       messages_.emplace_back(std::move(message));
    260     }
    261   }
    262 
    263   mojo::ScopedMessagePipeHandle pipe_;
    264   mojo::SimpleWatcher watcher_;
    265   std::vector<mojo::ScopedMessageHandle> messages_;
    266 };
    267 
    268 mojo::MessagePipe pipe;
    269 PipeReader reader(std::move(pipe.handle0));
    270 
    271 // Written messages will asynchronously end up in |reader.messages_|.
    272 WriteABunchOfStuff(pipe.handle1.get());
    273 ```
    274 
    275 ## Synchronous Waiting
    276 
    277 The C++ System API defines some utilities to block a calling sequence while
    278 waiting for one or more handles to change signaling state in an interesting way.
    279 These threads combine usage of the
    280 [low-level traps API](/mojo/public/c/system/README.md#Signals-Traps)
    281 with common synchronization primitives (namely `base::WaitableEvent`.)
    282 
    283 While these API features should be used sparingly, they are sometimes necessary.
    284 
    285 See the documentation in
    286 [wait.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/wait.h)
    287 and [wait_set.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/wait_set.h)
    288 for a more detailed API reference.
    289 
    290 ### Waiting On a Single Handle
    291 
    292 The `mojo::Wait` function simply blocks the calling sequence until a given
    293 signal mask is either partially satisfied or fully unsatisfiable on a given
    294 handle.
    295 
    296 ``` cpp
    297 mojo::MessagePipe pipe;
    298 mojo::WriteMessageRaw(pipe.handle0.get(), "hey", 3, nullptr, nullptr,
    299                       MOJO_WRITE_MESSAGE_FLAG_NONE);
    300 MojoResult result = mojo::Wait(pipe.handle1.get(), MOJO_HANDLE_SIGNAL_READABLE);
    301 DCHECK_EQ(result, MOJO_RESULT_OK);
    302 
    303 // Guaranteed to succeed because we know |handle1| is readable now.
    304 mojo::ScopedMessageHandle message;
    305 uint32_t num_bytes;
    306 mojo::ReadMessageNew(pipe.handle1.get(), &num_bytes, nullptr, nullptr,
    307                      MOJO_READ_MESSAGE_FLAG_NONE);
    308 ```
    309 
    310 `mojo::Wait` is most typically useful in limited testing scenarios.
    311 
    312 ### Waiting On Multiple Handles
    313 
    314 `mojo::WaitMany` provides a simple API to wait on multiple handles
    315 simultaneously, returning when any handle's given signal mask is either
    316 partially satisfied or fully unsatisfiable.
    317 
    318 ``` cpp
    319 mojo::MessagePipe a, b;
    320 GoDoSomethingWithPipes(std:move(a.handle1), std::move(b.handle1));
    321 
    322 mojo::MessagePipeHandle handles[2] = {a.handle0.get(), b.handle0.get()};
    323 MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_READABLE,
    324                                 MOJO_HANDLE_SIGNAL_READABLE};
    325 size_t ready_index;
    326 MojoResult result = mojo::WaitMany(handles, signals, 2, &ready_index);
    327 if (ready_index == 0) {
    328   // a.handle0 was ready.
    329 } else {
    330   // b.handle0 was ready.
    331 }
    332 ```
    333 
    334 Similar to `mojo::Wait`, `mojo::WaitMany` is primarily useful in testing. When
    335 waiting on multiple handles in production code, you should almost always instead
    336 use a more efficient and more flexible `mojo::WaitSet` as described in the next
    337 section.
    338 
    339 ### Waiting On Handles and Events Simultaneously
    340 
    341 Typically when waiting on one or more handles to signal, the set of handles and
    342 conditions being waited upon do not change much between consecutive blocking
    343 waits. It's also often useful to be able to interrupt the blocking operation
    344 as efficiently as possible.
    345 
    346 [`mojo::WaitSet`](https://cs.chromium.org/chromium/src/mojo/public/cpp/system/wait_set.h)
    347 is designed with these conditions in mind. A `WaitSet` maintains a persistent
    348 set of (not-owned) Mojo handles and `base::WaitableEvent`s, which may be
    349 explicitly added to or removed from the set at any time.
    350 
    351 The `WaitSet` may be waited upon repeatedly, each time blocking the calling
    352 sequence until either one of the handles attains an interesting signaling state
    353 or one of the events is signaled. For example let's suppose we want to wait up
    354 to 5 seconds for either one of two handles to become readable:
    355 
    356 ``` cpp
    357 base::WaitableEvent timeout_event(
    358     base::WaitableEvent::ResetPolicy::MANUAL,
    359     base::WaitableEvent::InitialState::NOT_SIGNALED);
    360 mojo::MessagePipe a, b;
    361 
    362 GoDoStuffWithPipes(std::move(a.handle1), std::move(b.handle1));
    363 
    364 mojo::WaitSet wait_set;
    365 wait_set.AddHandle(a.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE);
    366 wait_set.AddHandle(b.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE);
    367 wait_set.AddEvent(&timeout_event);
    368 
    369 // Ensure the Wait() lasts no more than 5 seconds.
    370 bg_thread->task_runner()->PostDelayedTask(
    371     FROM_HERE,
    372     base::Bind([](base::WaitableEvent* e) { e->Signal(); }, &timeout_event);
    373     base::TimeDelta::FromSeconds(5));
    374 
    375 base::WaitableEvent* ready_event = nullptr;
    376 size_t num_ready_handles = 1;
    377 mojo::Handle ready_handle;
    378 MojoResult ready_result;
    379 wait_set.Wait(&ready_event, &num_ready_handles, &ready_handle, &ready_result);
    380 
    381 // The apex of thread-safety.
    382 bg_thread->Stop();
    383 
    384 if (ready_event) {
    385   // The event signaled...
    386 }
    387 
    388 if (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 ```
    394 
    395 ## Invitations
    396 Invitations are the means by which two processes can have Mojo IPC bootstrapped
    397 between them. An invitation must be transmitted over some platform-specific IPC
    398 primitive (*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
    400 lightweight, cross-platform abstractions for those primitives.
    401 
    402 For any two processes looking to be connected, one must send an
    403 `OutgoingInvitation` and the other must accept an `IncomingInvitation`. The
    404 sender can attach named message pipe handles to the `OutgoingInvitation`, and
    405 the receiver can extract them from its `IncomingInvitation`.
    406 
    407 Basic usage might look something like this in the case where one process is
    408 responsible 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 
    417 mojo::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 
    441 The launched process can in turn accept an `IncomingInvitation`:
    442 
    443 ``` cpp
    444 #include "base/command_line.h"
    445 #include "base/threading/thread.h"
    446 #include "mojo/core/embedder/embedder.h"
    447 #include "mojo/core/embedder/scoped_ipc_support.h"
    448 #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 
    452 int main(int argc, char** argv) {
    453   // Basic Mojo initialization for a new process.
    454   mojo::core::Init();
    455   base::Thread ipc_thread("ipc!");
    456   ipc_thread.StartWithOptions(
    457       base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
    458   mojo::core::ScopedIPCSupport ipc_support(
    459       ipc_thread.task_runner(),
    460       mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN);
    461 
    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 
    474 Now we have IPC initialized between the two processes.
    475 
    476 Also keep in mind that bindings interfaces are just message pipes with some
    477 semantic and syntactic sugar wrapping them, so you can use these primordial
    478 message pipe handles as mojom interfaces. For example:
    479 
    480 ``` cpp
    481 // Process A
    482 mojo::OutgoingInvitation invitation;
    483 auto pipe = invitation->AttachMessagePipe("x");
    484 mojo::Binding<foo::mojom::Bar> binding(
    485     &bar_impl,
    486     foo::mojom::BarRequest(std::move(pipe)));
    487 
    488 // Process B
    489 auto invitation = mojo::IncomingInvitation::Accept(...);
    490 auto pipe = invitation->ExtractMessagePipe("x");
    491 foo::mojom::BarPtr bar(foo::mojom::BarPtrInfo(std::move(pipe), 0));
    492 
    493 // Will asynchronously invoke bar_impl.DoSomething() in process A.
    494 bar->DoSomething();
    495 ```
    496 
    497 And just to be sure, the usage here could be reversed: the invitation sender
    498 could just as well treat its pipe endpoint as a `BarPtr` while the receiver
    499 treats theirs as a `BarRequest` to be bound.
    500 
    501 ### Process Networks
    502 Accepting an invitation admits the accepting process into the sender's connected
    503 network of processes. Once this is done, it's possible for the newly admitted
    504 process to establish communication with any other process in that network via
    505 normal message pipe passing.
    506 
    507 This does not mean that the invited process can proactively locate and connect
    508 to other processes without assistance; rather it means that Mojo handles created
    509 by the process can safely be transferred to any other process in the network
    510 over established message pipes, and similarly that Mojo handles created by any
    511 other process in the network can be safely passed to the newly admitted process.
    512 
    513 ### Invitation Restrictions
    514 A process may only belong to a single network at a time.
    515 
    516 Additionally, once a process has joined a network, it cannot join another for
    517 the remainder of its lifetime even if it has lost the connection to its original
    518 network. This restriction will soon be lifted, but for now developers must be
    519 mindful of it when authoring any long-running daemon process that will accept an
    520 incoming invitation.
    521 
    522 ### Isolated Invitations
    523 It is possible to have two independent networks of Mojo-connected processes; for
    524 example, a long-running system daemon which uses Mojo to talk to child processes
    525 of its own, as well as the Chrome browser process running with no common
    526 ancestor, talking to its own child processes.
    527 
    528 In this scenario it may be desirable to have a process in one network talk to a
    529 process in the other network. Normal invitations cannot be used here since both
    530 processes already belong to a network. In this case, an **isolated** invitation
    531 can be used. These work just like regular invitations, except the sender must
    532 call `OutgoingInvitation::SendIsolated` and the receiver must call
    533 `IncomingInvitation::AcceptIsolated`.
    534 
    535 Once a connection is established via isolated invitation, Mojo IPC can be used
    536 normally, with the exception that transitive process connections are not
    537 supported; that is, if process A sends a message pipe handle to process B via
    538 an isolated connection, process B cannot reliably send that pipe handle onward
    539 to another process in its own network. Isolated invitations therefore may only
    540 be used to facilitate direct 1:1 communication between two processes.
    541