English | 简体中文
Anland runs the graphical Linux apps of a container on a rooted Android device and shows each of them as a native Android window — its own entry in the app switcher, its own Surface, its own soft-keyboard focus. There is no virtual screen and no mirroring: every app gets a real window, and Android's own compositor keeps drawing the screen.
It ships as a SukiSU/KernelSU module (anland-awl): a root daemon, a host APK, the session inside the container, and an audio bridge. The companion launcher anland-shell manages the containers and starts the apps.
A standard Wayland compositor — Weston, Sway, a desktop session — takes over a machine's display: it owns the whole screen, composites every client into one output, reads input from evdev, and clients reach it through the wayland-0 socket. On a phone that model degrades into "one fullscreen remote-desktop window". Anland keeps the protocol half of a compositor and replaces the display half with Android itself:
| Standard compositor | Anland | |
|---|---|---|
| Screen | Owns the display, composites everything into one output | Owns no display — Android's SurfaceFlinger keeps compositing |
| Windows | Internal window management inside a single output | Every xdg_toplevel becomes one real Android window (its own Activity and Surface) |
| Connection | A wayland-0 unix socket file |
No socket file — connections are fds passed over Android binder |
| Client identity | All clients are the same session user | Every client connects with its own uid; windows are owned per app |
| Input | evdev/libinput from DRM devices | Each window's Android touch/key/IME events, translated to Wayland |
| Lifecycle | A user session process | A root daemon in its own SELinux domain — not an app uid, so OEM "battery optimization" cannot freeze it |
What that design buys you:
- Linux windows are first-class Android windows. They appear in the app switcher, split-screen and behave like ordinary app windows — each with its own focus and its own IME state, candidates following the cursor.
- Hidden windows park their clients. With no Android surface attached, the daemon stops draining that window's buffers, so a minimized Linux app neither spins nor burns GPU frames.
- Foreground apps are scheduled like foreground apps. While a window is attached, its client's whole process tree is moved into Android's top-app cgroups — the Linux app in front of you is scheduled like any foreground Android app, not like a background daemon.
- Sound included. A PulseAudio bridge plays the container's audio through Android's own audio stack.
- X11 apps included. The in-container session runs a patched rootless Xwayland, so X11 apps show up as windows the same way Wayland apps do.
- Real-device fixes the stock stack lacks. A bubblewrap that survives KernelSU+SuSFS fake mount ids, and an Xwayland that does accelerated GL on Adreno GPUs (kgsl/turnip) — see
patches/. - Any Android app can join in. The
libawlclient library lets a third-party app connect over binder and host its own Wayland windows, scoped to that app's uid.
flowchart LR
subgraph LC ["Linux container (Droidspaces)"]
APP ["GUI apps — Wayland & X11"]
SESS ["anlandx session<br/>Xwayland + session D-Bus"]
end
subgraph AND ["Android"]
D ["waylandbridge root daemon<br/>Wayland protocol + GPU"]
H ["host APK<br/>one Activity per window"]
SF ["SurfaceFlinger"]
P ["PulseAudio bridge"]
end
APP --> SESS
SESS -- "wayland socket" --> D
D -- "binder: attach / control / input" --> H
H -- "per-window Surfaces" --> SF
APP -- "pulse socket" --> P
The pieces:
waylandbridge— the daemon: a single statically-linked ELF holding both the Wayland protocol side and the GPU renderer. It renders each window's frames directly into the Surface of that window's Android Activity.- Host APK (
com.anlandnext) — spawns one Activity per window, feeds it input, and provides the window list and settings UI. libawl— the client library (AAR) that third-party apps embed to host their own windows.- anlandx — the session inside the container: links the daemon's socket, runs rootless Xwayland with a small X window manager, and publishes the app environment.
- pulse — PulseAudio for Android (OpenSL ES / AAudio sinks) so container apps have sound.
- module — the SukiSU/KernelSU packaging: boot service, SELinux domain, contexts generated at flash time from the device's live system files.
- A rooted arm64 device (SukiSU or KernelSU)
- A Droidspaces Linux container
- The host APK installed — windows attach through it, and audio requires it
-
Get the three artifacts:
build/module/anland-awl.zip,build/anland-wayland.apk,build/anlandx.tar.gz— build them (below) or take them from CI. -
Flash the zip in your root manager and reboot. The daemon starts at boot (log:
/data/local/tmp/awl_daemon.log). -
Install
anland-wayland.apk. -
Inside the container, set up the session:
tar xzf anlandx.tar.gz && bash anlandx/setupanlandx.sh -
Manage containers and launch apps with anland-shell.
Linux host with JDK 17, an Android SDK (ANDROID_HOME and JAVA_HOME set; missing pieces are auto-installed), plus meson/ninja/patch for the audio part.
git submodule update --init --recursive
make # waylandbridge + host APK + module zip + anlandx tarballCI builds every push/PR and uploads the artifacts.
- anland-shell — the launcher: container management and the app grid that drives all of this.
GPL-3.0. Bundled third-party components (libwayland, PulseAudio, bubblewrap, Xwayland, …) keep their own licenses.