> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cerulion.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Run Cerulion on Android

> Build the Cerulion CLI and your nodes for an Android device from source, or embed a graph in an Android app.

A phone or an Android-based robot controller can run a Cerulion graph, record it, and serve its topics to your desk. There is no prebuilt Android download: you build the CLI and your nodes from a [source checkout](https://github.com/cerulion-inc/cerulion) on a Linux or macOS host and copy them to the device, or link Cerulion into an app.

There are two routes:

| Route | Use it when |
| - | - |
| The CLI on a device | You run `cerulion graph run`, `topic` and `bag` commands in an `adb shell`, the way you would on Linux. |
| Embedded in an app | An Android app runs the graph inside its own process, through a Java facade. |

## Toolchain

The supported targets are `arm64-v8a` and `x86_64`, with Android API 30 or newer, NDK 27.2 and cargo-ndk 4.1.2. Build on a host, never on the device:

```bash theme={null}
cargo ndk -t arm64-v8a --platform 30 check -p cerulion_core
```

Use `-t x86_64` for an x86\_64 device.

## Run the CLI on a device

**1. Build the CLI and the network daemon**

From the source checkout, on the host:

```bash theme={null}
cargo ndk -t arm64-v8a --platform 30 build -p cerulion_cli -p cerulion_netd
```

**2. Build your node workspace**

Node libraries are built on the host too, with any Rust 1.95 or newer: it does not have to be the compiler that built the CLI, but both builds need Android support. From your workspace:

```bash theme={null}
cargo ndk -t arm64-v8a --platform 30 build
```

cargo-ndk puts the libraries under `target/<target-triple>/<profile>`, and the CLI looks there first. Keep that directory when you copy the workspace to the device; do not flatten its libraries into `target/<profile>`. A workspace made by `cerulion workspace create` already carries the iceoryx2 patch block Android needs.

**3. Set up the shell on the device**

In an `adb shell`, give the CLI writable home and temporary directories:

```bash theme={null}
export HOME=/data/local/tmp/cer/home
export TMPDIR=/data/local/tmp/cer/tmp
mkdir -p "$HOME" "$TMPDIR"
```

Run `cerulion login` once in that shell. Then run your graph as on any other machine.

> [!WARNING]
>
> On Android the network gateway refuses every LAN peer unless `CERULION_LAN_ACCESS=open` is set in the shell that starts it. To read the device's topics from a desk over USB, forward the port with `adb forward tcp:7683 tcp:7683`, have the device listen on `tcp/0.0.0.0:7683`, and connect the desk CLI to `tcp/127.0.0.1:7683`.

## Embed a graph in an app

`cerulion_android` gives an app a Java facade, backed by JNI, over an embedded runtime that runs the graph, the gateway and the recorder in the app's process. The app loads one native library: its own runtime crate, which links `cerulion_android` and the app's graph nodes. Nodes are linked into that library, not loaded from separate files.

The sample app in the repository, `crates/cerulion_android/android`, is a complete example: it links the `timer` and `printer` nodes of `examples/basic_timer`, and ships its graph in the APK. Its build steps are in the [Android guide in the repository](https://github.com/cerulion-inc/cerulion/blob/main/docs/android.md).

## What works on Android

| Feature | On Android |
| - | - |
| Pub/sub within a process and between processes | Yes. Shared-memory objects are regular files. |
| `graph run`, `topic list`, `echo`, `info`, `hz`, `bag record`, `info`, `play` | Yes, with the CLI on the device. |
| Network gateway and mDNS discovery | Yes. mDNS needs a multicast lock in an app and a TCP listen port. |
| LAN access default | Paired: LAN peers are refused unless you open it. |
| Node build | On the host only, with cargo-ndk. |
| `cerulion viz` | No. |
| `process_groups:` in an app | No: an app runs its graph in one process. |
| Recovering a lock after a crash | No. Android has no robust mutexes, so a lock held by a process that exited cannot be recovered. |

> [!NOTE]
>
> `cerulion topic list` run on the device cannot see an app's topics; read them from a host through the app's gateway. An emulator does not pass multicast to the host, so test mDNS discovery from a physical device.

## Next steps

> [card] [Installation](https://docs.cerulion.com/cerulion/installation.md)
>
> Set up the host you build from.

> [card] [Network a graph](https://docs.cerulion.com/cerulion/guides/network-and-remote-robots.md)
>
> Reach the device's topics from your desk.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.