# 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 receiver) : receiver_(this, std::move(receiver)) {} // math::mojom::Math overrides: // Note: AddCallback is a type alias for base::OnceCallback. // 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(x) + y); } private: // Wraps a message pipe endpoint that receives incoming messages. See the // message pipes section below for more information. mojo::Receiver 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 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 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::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` for the receiver/callee to bind to a `mojo::Receiver`. ```c++ mojo::Remote remote_math; // BindNewPipeAndPassReceiver() returns a // mojo::PendingReceiver. This may be bound to a // mojo::Receiver 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 is // bound to a mojo::Receiver. remote_math->Add(2, 2, base::BindOnce(...)); ``` ### mojo::Receiver::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` for the sender/caller to bind to a `mojo::Remote`. ```c++ class MathImpl : public math::mojom::MathImpl { // ...addition to the previous MathImpl definition... mojo::PendingRemote GetRemoteMath() { // BindNewPipeAndPassRemote() returns a // `mojo::PendingRemote`. This may be bound to a // `mojo::Remote which can be used to send IPCs that will // be handled by |this|. return receiver_.BindNewPipeAndPassRemote(); } }; ``` ### mojo::PendingRemote::InitWithNewPipeAndPassReceiver Less common, but similar to `mojo::Remote::BindNewPipeAndPassReceiver()`. Typically used by broker code that needs to hand off a `mojo::PendingRemote` to the sender/caller side and hand off a `mojo::PendingReceiver` to the receiver/callee side. ### mojo::Remote/mojo::Receiver and mojo::PendingRemote/mojo::PendingReceiver Both `mojo::Remote` and `mojo::Receiver` 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 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 constructor or mojo::Remote::Bind() to rebind the // endpoint. mojo::PendingRemote pending_remote = remote.Unbind(); ``` ```c++ mojo::Receiver 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 constructor or mojo::Receiver::Bind() to // rebind the endpoint. mojo::PendingReceiver 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