Skip to content

eirkkk/winland-Android

Repository files navigation

Winland Server

License Platform Architecture Wayland Rust Kotlin Build

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


Features

Display & Graphics

  • 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
  • GPU acceleration per-app: Type gpu in the terminal followed by the game/app name to launch it with the Zink accelerator enabled
  • 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

Input Systems

  • Full touch support with trackpad emulation β€” one-finger cursor, two-finger scroll, tap-to-click
  • 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

Audio (Native)

  • 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

Clipboard

  • Clipboard sync β€” Copy/paste between Android and Linux applications
  • Status: Partial support (X11 clipboard path under active development, will be fully fixed in a future release)

Chroot Environment

  • 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

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  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   β”‚                    β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Tech Stack

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)

Requirements

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

Installation

Pre-built APK

  1. Download the latest APK from Releases
  2. Install on your device (enable "Install from unknown sources")
  3. Open the app β†’ grant root permission β†’ select your distro β†’ Install
  4. Wait for rootfs download + setup
  5. Press Run β€” XFCE desktop starts in a native Wayland session

Build from Source

Prerequisites

  • Android SDK 34 + NDK 26 (or later)
  • Rust toolchain with aarch64-linux-android target
  • Meson + Ninja (for libxkbcommon)

Quick Build

# 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

Step-by-Step

# 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

How It Works

  1. Bootstrapping: The app downloads a compressed Linux rootfs (Ubuntu or Kali) and extracts it into the app's private data directory.

  2. Chroot Setup: With root privileges, the app mounts /proc, /sys, /dev, and bind-mounts the Wayland socket and audio FIFO into the chroot.

  3. 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.

  4. 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.

  5. 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.

  6. 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 AndroidMic source β€” all natively with no streaming overhead.

  7. Rendering: The compositor renders directly onto an Android SurfaceView using Vulkan (Zink/Turnip) or OpenGL ES via HardwareBuffers.


Configuration

Environment Variables

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

Runtime Toggles

  • GPU Acceleration: Set MESA_LOADER_DRIVER_OVERRIDE=zink to 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)

Project Structure

β”œβ”€β”€ 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

Contributing

Contributions are welcome β€” whether it's fixing bugs, adding features, or improving documentation.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-idea)
  3. Commit your changes (git commit -m 'Add amazing idea')
  4. Push to the branch (git push origin feature/amazing-idea)
  5. Open a Pull Request

Development Tips

  • The Rust compositor is the most performance-critical component β€” profile carefully
  • Use build-arm64.sh for a full rebuild (Rust β†’ C β†’ Kotlin)
  • For Kotlin-only changes, ./gradlew assembleDebug is sufficient if native libs are prebuilt
  • Debug logs: logcat -s WinlandServer WinlandNative

License

This project is licensed under the MIT License β€” see the LICENSE file for details.

Third-Party Components

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

Acknowledgments

  • 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

About

No description, website, or topics provided.

Resources

Stars

7 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors