Skip to content

Instantly share code, notes, and snippets.

@onomatopellan
Last active September 15, 2025 23:48
Show Gist options
  • Save onomatopellan/c5220c0efddaff69aaff77cca80b7b8e to your computer and use it in GitHub Desktop.
Save onomatopellan/c5220c0efddaff69aaff77cca80b7b8e to your computer and use it in GitHub Desktop.
Waydroid in WSL2 with sound (Weston on top of Weston approach)

Waydroid in WSL2 with sound

Requirements

Recommended to install Waydroid in a brand new Ubuntu 25.04 install. Waydroid needs a custom linux kernel. Actually just needs latest kernel for WSL2 with just these changes before compiling:

CONFIG_ANDROID_BINDER_IPC=y
CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder"

Make sure WSL2 uses the custom kernel and modules modifying .wslconfig (or using WSL Settings)

[wsl2]
kernel=D:\\mykernel\\bzImage-6.6.87.ANDROID
kernelModules=D:\\mykernel\\modules.vhdx
Compiling the 6.6.x kernel: Step-by-step guide Instructions for building an x86_64 WSL2 6.6.x kernel with an Ubuntu distribution using bash are as follows:
  • Install the build dependencies:
    sudo apt install build-essential flex bison dwarves libssl-dev libelf-dev cpio qemu-utils

  • Download de kernel (always in a /home/user/ directory)
    git clone https://github.com/microsoft/WSL2-Linux-Kernel.git --depth=1

  • Change directory to kernel's directory root
    cd WSL2-Linux-Kernel

  • Modify WSL2 kernel configs:
    make menuconfig KCONFIG_CONFIG=Microsoft/config-wsl

Device Drivers --> Android --> Select "Android Binder IPC Driver" -> Save

  • Build the kernel using the WSL2 kernel configuration and put the modules in a modules folder under the current working directory:
    make -j$(nproc) KCONFIG_CONFIG=Microsoft/config-wsl && make INSTALL_MOD_PATH="$PWD/modules" modules_install

  • Strip symbols from modules (skip this step if you are insterested in debugging kernel's memory dumps)
    find ./modules/lib/modules/$(make -s kernelrelease) -name '*.ko' -exec strip --strip-unneeded {} \;

  • Then, you can use a provided script to create a VHDX containing the modules:
    sudo ./Microsoft/scripts/gen_modules_vhdx.sh "$PWD/modules" $(make -s kernelrelease) modules.vhdx

  • Copy de generated kernel and modules to the desired folder
    cp arch/x86/boot/bzImage /mnt/d/mykernel/bzImage-6.6.87.2.ANDROID
    cp modules.vhdx /mnt/d/mykernel/modules.ANDROID.vhdx

  • Open WSL Settings -> Developer -> Select Custom kernel, Custom modules

  • Shutdown WSL2 VM
    wsl.exe --shutdown

Setup

Download ubuntu-25.04-wsl-amd64.wsl distro from https://releases.ubuntu.com/plucky/

Double click on the .wsl file to install.

Run Ubuntu 25.04 and make sure is updated

sudo apt update && sudo apt upgrade -y

Install weston

sudo apt install weston

Install Waydroid

curl -s https://repo.waydro.id | sudo bash
sudo apt install waydroid

Configure Waydroid to only use software rendering (SwiftShader)

sudo nano /var/lib/waydroid/waydroid_base.prop

    ro.hardware.gralloc=default
    ro.hardware.egl=swiftshader

Make weston detect gpu for some acceleration

export GALLIUM_DRIVER=d3d12

Run weston

weston --backend=wayland-backend.so 

Inside weston desktop shell open a terminal and run

waydroid session start

When it shows 'Android with user 0 is ready' then open another terminal inside the weston desktop and run

waydroid show-full-ui

Tips:

  • If Waydroid shows some weird dbus errors make sure you shutdown the WSL2 VM (wsl.exe --shutdown) and try again.

  • By default Waydroid only launches correctly if the WSL2 networking mode is not MIRRORED. This is because dnsmasq tries to reserve port 53 that is already used in Windows. If you want to keep using MIRRORED networking you will need to add this to your .wslconfig (or using WSL Settings)

    [experimental]
    ignoredPorts=53
    
  • Every time the WSL2 kernel changes significantly (from ASHMEM support in 5.15.x to none in 6.6.x) you need to reconfigure Waydroid or it wont boot.

      sudo waydroid upgrade --offline
    
@onomatopellan
Copy link
Author

@wray-lee No. But I'm keeping an eye on this thread waydroid/waydroid#564
Capturing the opengl calls and sending them to WSL2 mesa sounds like a plausible solution, on paper.

@ausarhuy Yes, if systemd is enabled it works even in Ubuntu 20.04.

@pilafov
Copy link

pilafov commented Sep 6, 2025

Thanks for this guide. It worked very well for me, including the custom kernel and modules.
After few days of using it I wanted to adjust the main window size by "waydroid prop set persist.waydroid ..." options.
At one point, I noticed waydroid switched to full screen but it was connecting directly to WSLg.

To confirm it, I fully uninstalled weston and waydroid is still working as it should.

Is there any advantage of using (second) weston (on top of weston/WSLg) ?

It's also likely that we can get better hardware support under WSLg.

@onomatopellan
Copy link
Author

@pilafov I was unable to launch it in full screen (1920x1080) that's why I had to launch weston first. Can you please post the props you changed? You should be able to get the applied values with waydroid prop get ....

Indeed WSLg is running over weston already. The additional weston uses wayland-1 as WAYLAND_DISPLAY when you launch it inside the weston desktop and WSLg uses wayland-0. Hardware acceleration should be the same on both, since it only accelerates the 2D presentation, not the 3D OpenGL calls.

@pilafov
Copy link

pilafov commented Sep 6, 2025

This is what I got

$ waydroid prop get waydroid.display_width
1366
$ waydroid prop get waydroid.display_hight
768

$ waydroid prop get persist.waydroid.width
$ waydroid prop get persist.waydroid.hight
$

My exact screen dimensions are indeed 1366x768.
I don't know why "waydroid prop get persist.*" is not returning any value but I think I used these with "set".
I didn't play with other "prop set" settings.

@onomatopellan
Copy link
Author

onomatopellan commented Sep 6, 2025

@pilafov Thanks. I did set

waydroid prop set persist.waydroid.width 1920
waydroid prop set persist.waydroid.height 1080

and I had a black screen but after running waydroid prop set persist.waydroid.no_background_subsurface true I finally can use the weston from WSLg for full screen too.

@pilafov
Copy link

pilafov commented Sep 6, 2025

Well done !
I was beginning to wonder if I did something else meanwhile and if I might not be able to reproduce it.
Now that I tried to remember, I did something funny on the Android's side which made me re-init Waydroid.

waydroid init -f

No, this is the first time I have seen this "persist.waydroid.no_background_subsurface" property, so I don't think I did that.
Again, the "get" option won't give us the current value.

$ waydroid prop get persist.waydroid.no_background_subsurface
$

Another (small) improvement I made was to automate your playlist (the startup + the waiting part).
Take a look at this script "android-startup.sh".

#!/bin/bash

if [[ $(pgrep -u $UID -f "dbus-daemon --session") ]]; then
    echo "Found a running instance of 'dbus-daemon'"
else
    dbus-daemon --session --address=$DBUS_SESSION_BUS_ADDRESS --nofork --nopidfile --syslog-only &
    echo "Spawned a new instance of 'dbus-daemon'"
fi

export GALLIUM_DRIVER=d3d12
WAYDROID_SESS_LOG=/tmp/waydroid_session_start.out
waydroid session start >$WAYDROID_SESS_LOG 2>&1 &

WAYDROID_SESS_PID=$!
echo WAYDROID_SESS_PID=$WAYDROID_SESS_PID

while [[ true ]]; do
    echo "Waiting for 10s longer ..."
    sleep 10
    WAYDROID_SESS_ACTIVE=$(ps --no-headers -o pid -p $WAYDROID_SESS_PID)
    #echo "PID: [$WAYDROID_SESS_ACTIVE] is running"

    grep --quiet --no-messages --regexp 'Android.*is ready$' $WAYDROID_SESS_LOG
    if [[ "$WAYDROID_SESS_ACTIVE" -eq "$WAYDROID_SESS_PID" && "$?" -eq 0 ]]; then
        waydroid show-full-ui
        break
    fi
    #ps -p $WAYDROID_SESS_PID
done

@onomatopellan
Copy link
Author

@pilafov Ok so I was running an old image with Lineage 18. After uninstalling waydroid and reinstalling it downloaded Lineage 20 image and now everything seems to work from the beginning without the need to change the persist.waydroid.no_background_subsurface prop.

@pilafov
Copy link

pilafov commented Sep 6, 2025

@onomatopellan I've only used Lineage 20 (based on Android 13) from the beginning. It's possible that I just accidentally forgot to bring up weston.

@pilafov
Copy link

pilafov commented Sep 10, 2025

One more question of behalf of everybody who noticed.
After re-building the custom kernel I got the following two.

File Size
bzImage-6.6.87.2.ANDROID 15,704 KB 15.3 MB
modules.ANDROID.vhdx 2,236,416 KB 2.13 GB

Did you get similar numbers ?
For which version of the kernel ?

I'm questioning the 2.13GB for modules which feels excessive. Is there a way to shrink it?

@onomatopellan
Copy link
Author

onomatopellan commented Sep 12, 2025

@pilafov Same numbers here with same version. It can't be compacted because that's the actual uncompressed size of those .ko modules. Just the gpu modules size are already 720Mb and the network modules 400Mb. Compressed in 7z everything is ~600Mb.

I don't know if the way is compiled has lots of debug symbols or something. I just know the official WSL2 release includes a 15Mb kernel file and a 190Mb modules.vhd file.

@pilafov
Copy link

pilafov commented Sep 14, 2025

@onomatopellan

... I just know the official WSL2 release includes a 15Mb kernel file and a 190Mb modules.vhd file.

That's exactly why the new/custom size of "modules.vhd" (2.13GB) feels very excessive. It's over 10 times bigger.

In addition, the standard WSL2 contains "system.vhd" (388 MB) which is a separate distro where WSLg runs. Isn't that where all GPU drivers and such are expected to live ? At least, that would be a good explanation for the 388MB size.

@onomatopellan
Copy link
Author

onomatopellan commented Sep 15, 2025

@pilafov I asked Copilot and it recommended to strip the debug symbols of the modules. Now the modules.vhdx size is 192Mb. I updated the guide with the line find ./modules/lib/modules/$(make -s kernelrelease) -name '*.ko' -exec strip --strip-unneeded {} \;

The system.vhd is the system distro (Common Base Linux Mariner) that indeed contains WSLg. You can access to that system distro with wsl.exe -d Ubuntu-25.04 --system. There is no kernel or modules, just the files it needs for running Pulseaudio, wayland and mesa.

system

@pilafov
Copy link

pilafov commented Sep 15, 2025

@onomatopellan
This is great news, thanks!
I can't wait to try it out myself but I'm out of luck as I already removed the whole kernel source tree.
I'll have to start from the beginning.
I'm sure this will greatly improve WSL2 startup time.

What about Waydroid startup ?
Did you notice any difference ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment