Skip to content

Instantly share code, notes, and snippets.

@onomatopellan
Last active January 9, 2026 11:59
Show Gist options
  • Select an option

  • Save onomatopellan/c5220c0efddaff69aaff77cca80b7b8e to your computer and use it in GitHub Desktop.

Select an option

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 some ports that are 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,67,68
    
  • 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
    
@wray-lee
Copy link

So, there's currently no method for GPU acceleration?

@ausarhuy
Copy link

Can I use ubuntu 24.04 or must it be ubuntu 25.04?

@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 ?

@onomatopellan
Copy link
Author

@pilafov Didn't notice any difference. Remember the modules.vhdx is not loaded in memory. Its content is just mounted to the path /usr/lib/modules/6.6.87.2-microsoft-standard-WSL2+ and modules are individually loaded in memory only when needed.

@valertos08
Copy link

valertos08 commented Oct 21, 2025

I compiled the kernel completely as in the instructions, and it worked, waydroid is running. But there is a problem that I can't run vkmark.
valertos08@WIN-N6CDG2DAGBV:/mnt/c/Users/Administrator$ vkmark
Error: filesystem error: directory iterator cannot open directory: No such file or directory [/dev/dri]
So, vulkan. doesn't work for me. Do I need to configure the kernel differently before building it?
If I return a regular kernel, then vkmark runs without an error.

2025-10-21.23-31-43.mp4

@onomatopellan
Copy link
Author

@valertos08 It seems for /dev/dri you will need to load the vgem kernel module with sudo modprobe vgem

@palchrb
Copy link

palchrb commented Nov 13, 2025

Followed you guide and was able to start waydroid successfully - BUT it has not internet? Is there a wsl setting or something that i would need to tweak to make it work?

EDIT: forget it, i added ´sudo iptables -A FORWARD -i waydroid0 -j ACCEPT´ and now it works

Edit2: i got it to work that one time.. It even started up full screen in windows by just selecting the waydroid shortcut in the start menu - but now everytime i try to start it up again after a wsl shutdown it just freezes on waydroid session start..

@onomatopellan
Copy link
Author

onomatopellan commented Nov 13, 2025

@palchrb No need to modify iptables. If you are in Windows 11 make sure your networking mode in WSL Settings is "Mirrored" and follow the tip from the first post.

@arkni8
Copy link

arkni8 commented Dec 17, 2025

I built the kernel as per instruction but when I am trying to install Ubuntu 25, its giving me this error.

The parameter is incorrect.
Error code: Wsl/Service/RegisterDistro/CreateVm/HCS/E_INVALIDARG

Sorry, if this has been discusssed before but I am not able to search the whole thread, so I guess I am asking it again. If anyone got ideas, I would love to hear. First time compiling loonix kernel haha. Took about an hour so ideally wouldnt want to do it again lol. But let's hear what silly thing I may have done.

@onomatopellan
Copy link
Author

onomatopellan commented Dec 17, 2025

@arkni8 Which distro did you use for compiling the kernel? Please post the outputs of wsl.exe --version and wsl.exe -l -v from Powershell.

@arkni8
Copy link

arkni8 commented Dec 18, 2025

I compiled the kernel using Ubuntu 25.

PS C:\Users\knigh> wsl.exe --version
WSL version: 2.6.1.0
Kernel version: 6.6.87.2-1
WSLg version: 1.0.66
MSRDC version: 1.2.6353
Direct3D version: 1.611.1-81528511
DXCore version: 10.0.26100.1-240331-1435.ge-release
Windows version: 10.0.26100.7462

This output below is incomplete because in trying to make the thing run, I tried to uninstall and reinstall Ubuntu 25, and it failed to install again with the same error as I posted previous. Invalid argument. So I dont have a running loonix wsl at the moment.

PS C:\Users\knigh> wsl.exe -l -v
  NAME      STATE           VERSION
* Debian    Stopped         2

I guess I can change the custom kernel parameters to original and it will run, so if you really want to see the output of wsl -l -v, I can do it.

@onomatopellan
Copy link
Author

@arkni8 Yes, it seems the kernel was not compiled correctly and it wont let you install any distro so you should change it back to the original.

Maybe you downloaded de kernel in a windows folder (/mnt/c/...)? It's known it causes issues, hence the /home/user/ directory recommendation.

@arkni8
Copy link

arkni8 commented Dec 18, 2025

No, I pretty much installed as written in the original post. cloned the git within home directory, replaced the wsl-config file with the modified config with the android specific lines. executed the make command after that and so on. shrug I guess this wasn't meant to be. Kernel doesnt get built fast enough for me to try again unfortunately. Maybe some other time. Stoopid MS and them killing WSA. shaking my fist Thanks for listening to me tho!

@julianxhokaxhiu
Copy link

julianxhokaxhiu commented Dec 25, 2025

Thanks a lot for the build instructions. For anyone using Arch Linux on WSL2, I built an AUR package that simplifies the setup: https://aur.archlinux.org/packages/linux-wsl2-waydroid

Setup instructions:

  1. Install via AUR linux-wsl2-waydroid
  2. Copy the Linux Kernel and the modules.vhdx somewhere on the Windows drive ( see postinstall instructions )
  3. Configure WSL to use them
  4. Restart your WSL instance

Once done, you can launch waydroid by simply installing the package waydroid, enabling dbus-broker ( systemctl enable --now dbus-broker.service ) and finally launching it using waydroid show-full-ui.

Remember to set the Network mode as NAT if you use Mirrored. I did try to use the ignoredPorts setting but it didn't work for me ( WSL 2.6.3.0 ), always throwing an error on DHCP binding issue.

Merry Christmas! 🎄

//EDIT: If you use docker as well, remember to set this property in your /etc/docker/daemon.json then restart the service to ensure the network works in waydroid.

@onomatopellan
Copy link
Author

@julianxhokaxhiu Thanks! I'm sure that AUR package will be very useful for WSL2 Arch Linux users.

@Bushido76
Copy link

Thank you very much for the valuable tutorial and the exchange. I would like to use waydroid on my MS Surface on ARM64. I managed to compile the kernel and the waydroid container is booting up. When launching the UI (in non-mirrored WSL mode or in mirrored WSL mode with experimental port 53 option) I see the following errors in the waydroid log:

(502) [Sun, 28 Dec 2025 08:41:23] lxc-start: waydroid: ../src/lxc/network.c: netdev_configure_server_veth: 711 No such file or directory - Failed to attach "vethsagZfA" to bridge "waydroid0", bridge interface doesn't exist
(502) [Sun, 28 Dec 2025 08:41:23] lxc-start: waydroid: ../src/lxc/network.c: lxc_create_network_priv: 3427 No such file or directory - Failed to create network device

When I inject the bridge link (in non mirror mode) manually the UI does start, but Android does not assign an IP in Android settings and I have no network inside the container:

sudo ip link add name waydroid0 type bridge
sudo ip addr add 192.168.240.1/24 dev waydroid0
sudo ip link set waydroid0 up

So I'm still wondering, what I would have to adapt to get waydroid running in mirrored WSL mode and to have full network access (IP + DNS) inside the container/session. It would be great if you could give me a hint.

In advance, thank you very much for your support.

@onomatopellan
Copy link
Author

onomatopellan commented Dec 29, 2025

@Bushido76 I just updated the list of ignored ports (53, 67, 68) that are needed to launch the lxc-net service in MIRRORED networking mode. Waydroid needs a working lxc-net in order to create the waydroid0 bridge. What's your output for systemctl status lxc-net.service ?

edit: I presume your kernel is properly compiled using Microsoft/config-wsl-arm64 instead of Microsoft/config-wsl

@Bushido76
Copy link

Dear @onomatopellan, thank you very much for your response. Indeed I used Microsoft/config-wsl because I was not aware of a dedicated ARM64 config. But even in this constellation, I managed to setup the waydroid0 interface and now I can see an IP in the container. In general great progess, but it seems that there is one last blocking stone. In the waydroid shell the network is working great (DNS + ping + curl), but when I try to access WebPages in the Android browser it's only a few (simple) pages working. For most of the WebPages, the progress bar does stuck around 50% and the browser page stays empty. Do you have an idea what the reason for this behaviour could be? I played around with MTU, firewall settings and some GPU parameters, but had to give up at the end...

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