A native Wayland compositor for Android that runs full Linux desktop environments with GPU-accelerated graphics via Vulkan (Zink/Turnip) inside a chroot — no VNC, no SSH, no streaming.
XFCE desktop running on LabWC + Wayland, rendered natively on an Android SurfaceView
- Native Wayland compositor built with Smithay — no VNC/RDP/streaming overhead
- Vulkan hardware acceleration via Zink (OpenGL-on-Vulkan) using Turnip driver on Adreno GPUs
- OpenGL ES path via Android HardwareBuffers for devices without Vulkan
- XWayland support for legacy X11 applications
- Dynamic resolution with persistent scale locking across Android lifecycle events
- Multi-display ready architecture
- Direct touch mapping — pixel-accurate absolute positioning
- Relative trackpad emulation — delta-coordinate gestures for desktop-style cursor control
- External mouse — full desktop-grade pointer support via USB/Bluetooth
- Physical keyboard — complete keymap handling with XKB, multi-key shortcuts
- Native audio playback — Zero-copy PCM audio routed via Oboe (AAudio) between chroot PulseAudio and Android audio hardware through a named FIFO pipe
- Native microphone input — Android mic captured via Oboe (AAudio) at 44.1kHz mono 16-bit and streamed into chroot PulseAudio through a dedicated FIFO pipe; fully native with no VNC/streaming overhead
- Ubuntu 24.04 (Noble) and Kali Nethunter rootfs support
- XFCE desktop session running on LabWC (Wayland compositor)
- Automatic rootfs download, extraction, and dependency installation
- BusyBox-based bootstrap for reliable chroot setup
┌─────────────────────────────────────────────────────┐
│ Android Device │
│ ┌──────────────────────────────────────────────┐ │
│ │ Android App (Kotlin) │ │
│ │ ┌─────────┐ ┌──────────┐ ┌──────────────┐ │ │
│ │ │Dashboard│ │ Terminal │ │ Settings │ │ │
│ │ │(Compose)│ │ (Termux) │ │ (Compose) │ │ │
│ │ └────┬────┘ └──────────┘ └──────────────┘ │ │
│ │ │ │ │
│ │ ┌────▼──────────────────────────────────┐ │ │
│ │ │ WinlandService │ │ │
│ │ │ (Foreground Service, Audio Bridge) │ │ │
│ │ └──────────────────┬───────────────────┘ │ │
│ │ │ │ │
│ │ ┌──────────────────▼───────────────────┐ │ │
│ │ │ DisplayActivity │ │ │
│ │ │ (SurfaceView + Touch/Keyboard) │ │ │
│ │ └──────────────────┬───────────────────┘ │ │
│ └─────────────────────┼─────────────────────────┘ │
│ │ UniFFI (JNA) │
│ ┌─────────────────────▼─────────────────────────┐ │
│ │ Rust Core (libuniffi_winland_core) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │
│ │ │ Wayland │ │ Input │ │ Audio/Camera │ │ │
│ │ │Compositor│ │ Bridge │ │ Bridge │ │ │
│ │ │(Smithay) │ │ │ │ │ │ │
│ │ └────┬─────┘ └──────────┘ └──────────────┘ │ │
│ └───────┼────────────────────────────────────────┘ │
│ │ │
│ ┌───────▼────────────────────────────────────────┐ │
│ │ Linux Chroot (Ubuntu/Kali) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │
│ │ │ XFCE │ │ LabWC │ │ XWayland │ │ │
│ │ │ Desktop │ │(Wayland) │ │ (X11 Apps) │ │ │
│ │ └──────────┘ └──────────┘ └──────────────┘ │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │ PulseAud.│ │ Zink + │ │ │
│ │ │(Audio) │ │ Turnip │ │ │
│ │ └──────────┘ └──────────┘ │ │
│ └────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
| Layer | Technology |
|---|---|
| UI | Kotlin, Jetpack Compose, Material3 |
| Compositor | Rust + Smithay (patched fork) |
| FFI Bridge | UniFFI (Mozilla) + JNA |
| Graphics | Vulkan (Turnip), OpenGL ES, HardwareBuffer |
| Input | Android MotionEvent → Rust compositor |
| Audio | Native Oboe (AAudio) — playback FIFO + mic FIFO ↔ PulseAudio inside chroot |
| Chroot | BusyBox + shell scripts |
| Compiler | Rust → NDK (aarch64-linux-android), Meson (C libs), Gradle (Kotlin) |
| Requirement | Details |
|---|---|
| Root | Magisk or KernelSU (for chroot mounts) |
| Device | ARM64 (arm64-v8a) |
| Android | API 26+ (Android 8.0 Oreo) |
| GPU | Adreno 650+ recommended (Vulkan 1.1+ for Turnip) |
| Storage | 8 GB+ free for rootfs + apps |
| Optional | USB/Bluetooth mouse & keyboard |
- Download the latest APK from Releases
- Install on your device (enable "Install from unknown sources")
- Open the app → grant root permission → select your distro → Install
- Wait for rootfs download + setup
- Press Run — XFCE desktop starts in a native Wayland session
- Android SDK 34 + NDK 26 (or later)
- Rust toolchain with
aarch64-linux-androidtarget - Meson + Ninja (for libxkbcommon)
# Clone
git clone https://github.com/your-org/winland-android.git
cd winland-android
# Set up environment
cp .env.example .env
# Edit .env with your SDK/NDK paths
# Full ARM64 build (Rust + C + Gradle)
bash build-arm64.sh
# APK will be at:
# app/build/outputs/apk/debug/app-debug.apk# 1. Build libxkbcommon (C library for keyboard)
cd libxkbcommon
meson setup build-android --cross-file android-arm64.ini
ninja -C build-android libxkbcommon.so
cd ..
# 2. Build terminal JNI library
cd terminal-emulator/src/main
ndk-build NDK_PROJECT_PATH=. APP_ABI=arm64-v8a APP_PLATFORM=android-31
cd ../..
# 3. Build Rust core library
export CC_aarch64_linux_android=/path/to/ndk/aarch64-linux-android31-clang
export CXX_aarch64_linux_android=/path/to/ndk/aarch64-linux-android31-clang++
cd native
cargo build --release --lib --target aarch64-linux-android --features smithay_android
cd ..
# 4. Copy native libs
cp native/target/aarch64-linux-android/release/libuniffi_winland_core.so app/src/main/jniLibs/arm64-v8a/
cp terminal-emulator/src/main/libs/arm64-v8a/libtermux.so app/src/main/jniLibs/arm64-v8a/
# 5. Build Android APK
./gradlew assembleDebug-
Bootstrapping: The app downloads a compressed Linux rootfs (Ubuntu or Kali) and extracts it into the app's private data directory.
-
Chroot Setup: With root privileges, the app mounts
/proc,/sys,/dev, and bind-mounts the Wayland socket and audio FIFO into the chroot. -
Compositor: The Rust-based Smithay compositor creates a Wayland socket inside the app's data directory. This socket is bind-mounted into the chroot so Linux GUI apps can connect to it.
-
Desktop Launch: Inside the chroot, LabWC (a Wayland compositor) starts as the window manager, XFCE as the desktop environment, and XWayland for X11 app compatibility.
-
Input Routing: Touch events, keyboard input, and mouse events from Android are forwarded through UniFFI to the Rust compositor, which injects them into the Wayland protocol.
-
Audio Bridge (Native): PulseAudio inside the chroot writes PCM audio to a named FIFO; the Rust audio bridge reads it via Oboe (AAudio) for zero-copy playback on Android speakers. For microphone input, Oboe captures 44.1kHz mono 16-bit audio from the Android mic and writes to a second FIFO, which PulseAudio reads as the
AndroidMicsource — all natively with no streaming overhead. -
Rendering: The compositor renders directly onto an Android
SurfaceViewusing Vulkan (Zink/Turnip) or OpenGL ES via HardwareBuffers.
Create a .env file in the project root (see .env.example):
| Variable | Default | Description |
|---|---|---|
ANDROID_SDK_ROOT |
$HOME/Android/Sdk |
Android SDK path |
ANDROID_NDK_VERSION |
25.2.9519653 |
NDK version |
RUST_TARGET |
aarch64-linux-android |
Rust compilation target |
BUILD_JOBS |
4 |
Parallel build jobs |
ENABLE_LTO |
true |
Link-time optimization |
ENABLE_NEON |
true |
NEON SIMD for ARM64 |
- GPU Acceleration: Set
MESA_LOADER_DRIVER_OVERRIDE=zinkto enable Vulkan-to-OpenGL translation - Input Mode: Switch between direct touch, trackpad, and external mouse in the app's input settings
- Desktop Scale: Adjustable in settings (locked across Android lifecycle restarts)
├── app/ # Android app module (Kotlin)
│ ├── src/main/assets/ # Shell scripts + BusyBox
│ ├── src/main/kotlin/ # UI, engine, services
│ ├── src/main/jniLibs/ # Prebuilt native .so files
│ └── build.gradle.kts # App build config
├── native/ # Rust compositor core
│ ├── src/ # Wayland compositor, audio, input, camera
│ │ ├── android/ # Android JNI bridge modules
│ │ └── core/ # Core utilities
│ ├── Cargo.toml
│ └── lib/ # Patched forks (Smithay, Winit)
├── terminal-emulator/ # Termux terminal emulator (Java + C)
├── terminal-view/ # Terminal View (Android UI)
├── libxkbcommon/ # XKB keyboard library (C)
├── build-arm64.sh # Full build script
└── .github/workflows/android.yml # CI pipeline
Contributions are welcome — whether it's fixing bugs, adding features, or improving documentation.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-idea) - Commit your changes (
git commit -m 'Add amazing idea') - Push to the branch (
git push origin feature/amazing-idea) - Open a Pull Request
- The Rust compositor is the most performance-critical component — profile carefully
- Use
build-arm64.shfor a full rebuild (Rust → C → Kotlin) - For Kotlin-only changes,
./gradlew assembleDebugis sufficient if native libs are prebuilt - Debug logs:
logcat -s WinlandServer WinlandNative
This project is licensed under the MIT License — see the LICENSE file for details.
| Component | License |
|---|---|
| Smithay | MIT |
| Winit | Apache 2.0 / MIT |
| libxkbcommon | MIT / Public Domain |
| Termux | GPL-3.0 |
| UniFFI | MPL-2.0 |
| BusyBox | GPL-2.0 |
- The Smithay project for the Wayland compositor library
- The Turnip driver team for Vulkan-on-Adreno support
- Termux for the terminal emulator
- The Android Linux chroot community for pioneering the approach
Built with ❤️ for the Android Linux enthusiast community