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
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169

mojo / docs / basics.md [blame]

# Mojo Basics

This document aims to provide a brief overview of the different concepts in Mojo
and how they work together.  For more details about more complex and/or
Chrome-specific Mojo use cases, please consult [Intro to Mojo & Services](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/mojo_and_services.md).

[TOC]

## Interfaces

Mojo provides a [C++-like interface definition language][mojo-idl] for defining
interfaces for making interprocess calls (IPCs):

```
module math.mojom;

interface Math {
  // Adds two int32s and returns the result as an int64 (to avoid
  // overflow issues).
  Add(int32 x, int32 y) => (int64 sum);
};
```

Interfaces are built using the `mojom` (or `mojom_component`) [GN
template][gn-template]:
```
mojom("mojom") {
  sources = ["math.mojom"]
}
```

This will generate C++ (and optionally, Java and JavaScript) interfaces. Writing
code to handle IPCs is a simple matter of implementing the generated interface:

```c++
class MathImpl : public math::mojom::Math {
 public:
  explicit MathImpl(mojo::PendingReceiver<math::mojom::Math> receiver)
      : receiver_(this, std::move(receiver)) {}

  // math::mojom::Math overrides:
  // Note: AddCallback is a type alias for base::OnceCallback<void(int64_t)>.
  // The parameters to the callback are the reply parameters specified in the
  // Mojo IDL method definition. This is part of the boilerplate generated by
  // Mojo: invoking |reply| will send a reply to the caller.
  void Add(int32_t x, int32_t y, AddCallback reply) override {
    // Note: Mojo always returns results via callback. While it is possible to
    // make a sync IPC which blocks on the reply, the handler will always return
    // the result via callback.
    std::move(reply).Run(static_cast<int64_t>(x) + y);
  }

 private:
  // Wraps a message pipe endpoint that receives incoming messages. See the
  // message pipes section below for more information.
  mojo::Receiver<math::mojom::Math> receiver_;
};
```

Note: the build process also generates proxy classes (e.g. `MathProxy`) which
encapsulate the details of making the actual cross-process call. These are
used internally and are an implementation detail that can typically be ignored.

## Message Pipes

Interfaces are layered on top of low-level [message pipes][message-pipe]. Each
message pipe has two bidirectional endpoints. The Mojo bindings enforce
additional conventions on top of message pipes, where one endpoint is the
sender/caller, represented as:

```c++
// Wraps a message pipe endpoint for making remote calls. May only be used on
// the sequence where the mojo::Remote was bound.
mojo::Remote<math::mojom::Math> remote_math = ...;
```

And the other endpoint is the receiving/callee, represented as:

```c++
// Usually a class member. Wraps a message pipe endpoint that receives incoming
// messages. Routes and dispatches IPCs to the handler—typically |this|—on the
// sequence where the mojo::Receiver was bound.
mojo::Receiver<math::mojom::Math> receiver_;
```

This allows limited bidirectional communication. For one interface, the sender
(A) may make any number of calls to the receiver (B). (B) may send a single
reply for each call from (A). More expressive APIs are often implemented as a
pair of interfaces (with two underlying message pipes), allowing calls to be
made in either direction between (A) and (B).

Message pipe endpoints are typically created using one of:

### mojo::Remote<T>::BindNewPipeAndPassReceiver

Used when the sender/caller creates the endpoints. One endpoint is retained for
itself to send IPCs, and the other endpoint is returned as an unbound
`mojo::PendingReceiver<T>` for the receiver/callee to bind to a
`mojo::Receiver<T>`.

```c++
mojo::Remote<math::mojom::Math> remote_math;

// BindNewPipeAndPassReceiver() returns a
// mojo::PendingReceiver<math::mojom::Math>. This may be bound to a
// mojo::Receiver<math::mojom::Math> to handle calls received from
// |remote_math|.
LaunchAndBindRemoteMath(remote_math.BindNewPipeAndPassReceiver());

// |remote_math| may be immediately used. The Add() call will be buffered by the
// receiving end and dispatched when mojo::PendingReceiver<math::mojom::Math> is
// bound to a mojo::Receiver<math::mojom::Math>.
remote_math->Add(2, 2, base::BindOnce(...));
```

### mojo::Receiver<T>::BindNewPipeAndPassRemote

Used when the receiver/callee creates the endpoints. One endpoint is retained
for itself to receive IPCs, and the other endpoint is returned as an unbound
`mojo::PendingRemote<T>` for the sender/caller to bind to a `mojo::Remote<T>`.

```c++
class MathImpl : public math::mojom::MathImpl {
  // ...addition to the previous MathImpl definition...

  mojo::PendingRemote<math::mojom::Math> GetRemoteMath() {
    // BindNewPipeAndPassRemote() returns a
    // `mojo::PendingRemote<math::mojom::Math>`. This may be bound to a
    // `mojo::Remote<math::mojom::Math> which can be used to send IPCs that will
    // be handled by |this|.
    return receiver_.BindNewPipeAndPassRemote();
  }
};
```

### mojo::PendingRemote<T>::InitWithNewPipeAndPassReceiver

Less common, but similar to `mojo::Remote<T>::BindNewPipeAndPassReceiver()`.
Typically used by broker code that needs to hand off a `mojo::PendingRemote<T>`
to the sender/caller side and hand off a `mojo::PendingReceiver<T>` to the
receiver/callee side.

### mojo::Remote<T>/mojo::Receiver<T> and mojo::PendingRemote<T>/mojo::PendingReceiver<T>

Both `mojo::Remote<T>` and `mojo::Receiver<T>` have a corresponding unbound
version: this allows either endpoint to be passed between sequences in the same
process or even between processes over IPC.

```c++
mojo::Remote<math::mojom::MathImpl> remote = ...;
// |pending_remote| is movable and may be passed around. While unbound, the
// endpoint cannot be used to send IPCs. The pending remote may be passed to
// the mojo::Remote<T> constructor or mojo::Remote<T>::Bind() to rebind the
// endpoint.
mojo::PendingRemote<math::mojom::MathImpl> pending_remote = remote.Unbind();
```

```c++
mojo::Receiver<math::mojom::MathImpl> receiver = ...;
// |pending_receiver| is movable and may be passed around. While unbound,
// received IPCs are buffered and not processed. The pending receiver may be
// passed to the mojo::Receiver<T> constructor or mojo::Receiver<T>::Bind() to
// rebind the endpoint.
mojo::PendingReceiver<math::mojom::MathImpl> pending_receiver = receiver.Unbind();
```

[mojo-idl]: https://chromium.googlesource.com/chromium/src/+/main/mojo/public/tools/bindings/README.md
[gn-template]: https://cs.chromium.org/chromium/src/mojo/public/tools/bindings/mojom.gni
[message-pipe]: https://cs.chromium.org/chromium/src/mojo/public/cpp/system/message_pipe.h