Waydroid in Incus container - mount error

I’m trying to run Waydroid in Incus container, but without luck. When starting Waydroid, I see this error:

RuntimeError: Command failed: % mount -o ro /var/lib/waydroid/images/system.img /var/lib/waydroid/rootfs

Maybe someone solved this problem and can help me a bit?

Container details

Waydroid works, when installed on my vanilla Ubuntu 24.04 host (ZFS backend) and not nested inside Incus. It requires binder_linux kernel module provided by default Ubuntu 24.04 kernel 6.8.0-52-generic (there’s no need for ashmem_linux kernel module).

So for running Waydroid inside Incus, I need to:

  1. Make sure binder_linux kernel module is loaded
  2. Enable system call interception for mount

This is my container:

incus launch images:ubuntu/24.04/cloud waydroid \
-p default \
-p gui \
-c security.nesting=true \
-c linux.kernel_modules=binder_linux \
-c security.syscalls.intercept.mount=true \
-c security.syscalls.intercept.mount.fuse=ext2=fuse2fs

I’m using ext2=fuse2fs because that seem to be the file system of Android images used by Waydroid. Changing ext2 to ext4 didn’t make a difference.

I also tried without fuse2fs:

-c security.syscalls.intercept.mount=true \
-c security.syscalls.intercept.mount.shift=true \
-c security.syscalls.intercept.mount.allowed=ext2

The gui profile for this container is very simple:

gui profile
config:
  raw.idmap: |-
    uid 1000 1000
    gid 1000 1000
description: GUI Wayland and xWayland profile with pipewire and pulseaudio, shifting enabled for all socket.
devices:
  gpu:
    gid: "44"
    type: gpu
  pipewire_manager_socket:
    path: /mnt/.container_sockets/pipewire-0-manager
    shift: "true"
    required: "false"
    source: /run/user/1000/pipewire-0-manager
    type: disk
  pipewire_socket:
    path: /mnt/.container_sockets/pipewire-0
    shift: "true"
    required: "false"
    source: /run/user/1000/pipewire-0
    type: disk
  pulseaudio_socket:
    path: /mnt/.container_sockets/native
    shift: "true"
    required: "false"
    source: /run/user/1000/pulse/native
    type: disk
  wayland_socket:
    path: /mnt/.container_sockets/wayland-0
    shift: "true"
    required: "false"
    source: /run/user/1000/wayland-0
    type: disk
  xauthority_cookie:
    path: /mnt/.container_sockets/.mutter-Xwaylandauth.copy
    shift: "true"
    required: "false"
    source: /run/user/1000/.mutter-Xwaylandauth.copy
    type: disk
  xwayland_socket:
    path: /mnt/.container_sockets/X1
    shift: "true"
    required: "false"
    source: /tmp/.X11-unix/X1
    type: disk

Next I logged into the container, installed fuse2fs and some basic packages, and added ubuntu user to two groups:

incus exec waydroid -- sudo --login --user ubuntu
sudo apt install fuse2fs pulseaudio-utils dbus-user-session nano bash-completion
sudo usermod -a -G video,render "$LOGNAME"

In /home/ubuntu/.profile file, I added some lines that link sockets to their proper locations:

.profile file
[[ ! -d "${/run/user/1000}/pulse" ]] && mkdir -m 700 "${/run/user/1000}/pulse"
[[ -S "${/mnt/.container_sockets}/native" && -d "${/run/user/1000}/pulse" && ! -e "${/run/user/1000}/pulse/native" ]] && ln -s "${/mnt/.container_sockets}/native" "${/run/user/1000}/pulse/native"
[[ -S "${/mnt/.container_sockets}/pipewire-0" && ! -e "${/run/user/1000}/pipewire-0" ]] && ln -s "${/mnt/.container_sockets}/pipewire-0" "${/run/user/1000}/pipewire-0"
[[ -S "${/mnt/.container_sockets}/pipewire-0-manager" && ! -e "${/run/user/1000}/pipewire-0-manager" ]] && ln -s "${/mnt/.container_sockets}/pipewire-0-manager" "${/run/user/1000}/pipewire-0-manager"
[[ -S "${/mnt/.container_sockets}/wayland-0" && ! -e "${/run/user/1000}/wayland-0" ]] && ln -s "${/mnt/.container_sockets}/wayland-0" "${/run/user/1000}/wayland-0"
[[ -S "${/mnt/.container_sockets}/X0" && ! -e "${/tmp/.X11-unix}/X0" ]] && ln -s "${/mnt/.container_sockets}/X0" "${/tmp/.X11-unix}/X0"
[[ -S "${/mnt/.container_sockets}/X1" && ! -e "${/tmp/.X11-unix}/X1" ]] && ln -s "${/mnt/.container_sockets}/X1" "${/tmp/.X11-unix}/X1"
[[ -f "${/mnt/.container_sockets}/.mutter-Xwaylandauth.copy" && ! -e "${/run/user/1000}/.mutter-Xwaylandauth.copy" ]] && cp "${/mnt/.container_sockets}/.mutter-Xwaylandauth.copy" "${/run/user/1000}/.mutter-Xwaylandauth.copy"
export WAYLAND_DISPLAY=wayland-0
export XDG_SESSION_TYPE=wayland
export QT_QPA_PLATFORM=wayland
export DISPLAY=:1
export XAUTHORITY=${/run/user/1000}/.mutter-Xwaylandauth.copy

Finally, I restarted the container:

exit
incus restart waydroid
incus exec waydroid -- sudo --login --user ubuntu

Installing Waydroid

I followed official instructions:

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

Then initialized Waydroid:

sudo waydroid init -s GAPPS

This downloads Android images (seems they are ext2) and starts a service:

$ file /var/lib/waydroid/images/*.img
/var/lib/waydroid/images/system.img: Linux rev 1.0 ext2 filesystem data, UUID=a09c7f74-67d7-4fd8-b092-251f4e05593e (extents) (large files) (huge files)
/var/lib/waydroid/images/vendor.img: Linux rev 1.0 ext2 filesystem data, UUID=5f40d370-5918-427a-9f92-2458da269fc3, volume name "vendor" (extents) (large files) (huge files)

Note: Starting a container with a Waydroid installed takes about 30 seconds, so don’t be surprised.

Error when running Waydroid

When starting Waydroid I get this error:

$ waydroid show-full-ui
[10:57:01] Starting waydroid session
[10:57:01] RuntimeError: Command failed: % mount -o ro /var/lib/waydroid/images/system.img /var/lib/waydroid/rootfs

Logs tell me that the mount failed, because the destination directory doesn’t exist:

$ cat /var/lib/waydroid/waydroid.log
(000372) [10:57:57] % mount -o ro /var/lib/waydroid/images/system.img /var/lib/waydroid/rootfs
mount: /var/lib/waydroid/rootfs: mount failed: No such file or directory.

But that’s not true:

$ ll /var/lib/waydroid/rootfs
total 17K
drwxr-xr-x 2 root root  2 sty 30 22:01 ./
drwxr-xr-x 9 root root 12 sty 31 23:18 ../

When using mount command by hand I get the same error:

$ sudo mount -o ro /var/lib/waydroid/images/system.img /var/lib/waydroid/rootfs
mount: /var/lib/waydroid/rootfs: mount failed: No such file or directory.

But when using fuse2fs (it was installed before any mount operation) I get a success:

$ sudo fuse2fs -o ro /var/lib/waydroid/images/system.img /var/lib/waydroid/rootfs
Mounting read-only.

Unfortunately, Waydroid doesn’t recognize that and won’t start, thinking it wasn’t initialized:

$ waydroid show-full-ui
ERROR: WayDroid is not initialized, run "waydroid init"

Questions

  1. How to get rid of the mount error?
  2. I’m using ZFS backend. Could this be the cause of the issue?
  3. Should I use other value than ext2=fuse2fs for security.syscalls.intercept.mount.fuse? The ext4 didn’t work.

I will be grateful for any help.