Waydroid template

This guide is for creating Waydroid template that can be used to create AppVMs based on it.
The Android image is installed in template and applications and their configuration will be installed in AppVMs.
This guide is for setting up minimal Waydroid template. You may want to install additional packages like GUI terminal, file manager, passwordless root etc.

Create Waydroid template qube

Install debian-12-minimal template using “Qubes Template Manager” tool if you don’t have it already.

Update debian-12-minimal template using “Qubes Update” tool.

Clone debian-12-minimal and name it d12m-waydroid.

Start d12m-waydroid and open its root terminal using this command in dom0 terminal:

qvm-run -u root d12m-waydroid xterm &

All the commands in this guide must be run in d12m-waydroid qube root terminal if not stated otherwise.

Install required packages for Waydroid

Waydroid needs Wayland so we will install sway Wayland compositor for it:

apt install sway -y

We also need the qubes-core-agent-networking package to enable networking in minimal qube:

apt install qubes-core-agent-networking -y

Install Waydroid

Run these commands to install Waydroid:

apt install curl ca-certificates -y
curl --proxy http://127.0.0.1:8082/ --tlsv1.2 --proto =https --max-time 180 https://repo.waydro.id | https_proxy=http://127.0.0.1:8082 bash
apt install waydroid -y

Link for reference:
Install Instructions - Waydroid

Initialize Waydroid

Run this command to initialize Waydroid, It’ll download VANILLA Android image:

https_proxy=http://127.0.0.1:8082 http_proxy=http://127.0.0.1:8082 waydroid init

Or this command for Waydroid image with GApps support:

https_proxy=http://127.0.0.1:8082 http_proxy=http://127.0.0.1:8082 waydroid init -s GAPPS

Install Waydroid clipboard support

Configure automatic transfer of clipboard content between X11 and Wayland

We need to build and install clipnotify tool from sources to use it for receiving the X11 clipboard change events. You can build it in some other qube based on the same template and copy the built binaries to the d12m-waydroid qube and install them there to keep the d12m-waydroid template minimal or you can build it in the d12m-waydroid qube itself but you’ll need to install additional packages for building.
This example is for the second option.

You can download the clipnotify sources in the Waydroid template directly or in some other qube and transfer them to the Waydroid template.
To download the sources directly in Waydroid template you’ll need to install the additional packages unzip/git.
Since unzip/git probably won’t be used ever again in the Waydroid qube you may want to keep the Waydroid template minimal then you can download the sources in some other qube and transfer them to the Waydroid template.

Option 1: Download the sources directly in Waydroid template

Download and extract the clipnotify sources in some qube with network access:

apt install unzip -y
curl --proxy http://127.0.0.1:8082/ --tlsv1.2 --proto =https --max-time 180 https://codeload.github.com/cdown/clipnotify/zip/refs/heads/master -o clipnotify-master.zip
unzip -j clipnotify-master.zip -d clipnotify

or using git:

git config --global http.proxy http://127.0.0.1:8082
git clone https://github.com/cdown/clipnotify.git
git config --global http.proxy ""

Option 2: Download the sources in some other qube and transfer them to Waydroid template

Download and extract the clipnotify sources in some qube with network access:

curl https://codeload.github.com/cdown/clipnotify/zip/refs/heads/master -o clipnotify-master.zip
unzip -j clipnotify-master.zip -d clipnotify

or using git:

git clone https://github.com/cdown/clipnotify.git

Transfer the clipnotify directory to d12m-waydroid qube:

qvm-copy clipnotify

After getting the sources in d12m-waydroid qube, move to the clipnotify sources directory in d12m-waydroid qube:
If you followed Option 1: Download the sources directly in Waydroid template:

cd clipnotify

If you followed Option 2: Download the sources in some other qube and transfer them to Waydroid template:

mv /home/user/QubesIncoming/*/clipnotify/ /home/user/
cd /home/user/clipnotify

Once you’re in the sources directory, build and install clipnotify:

apt install build-essential libx11-dev libxtst-dev -y
mkdir -p /opt/bin
sed -i "s|/usr/local|/opt|g" Makefile
make
make install
echo 'export PATH="/opt/bin:$PATH"' >> /etc/profile.d/opt-bin.sh

Install X11 and Wayland clipboard cli tools:

apt install xclip wl-clipboard -y

Configure sway to run script that will automatically transfer of clipboard content between X11 and Wayland on sway start:

echo "exec /opt/bin/x11-wl-clip.sh" > /etc/sway/config.d/99-x11-wl-clip.conf
mkdir -p /opt/bin
cat << 'EOF' | tee /opt/bin/x11-wl-clip.sh
#!/bin/bash
x11_wl='while DISPLAY=":0" clipnotify -s clipboard; do xclip -d ":0" -selection clipboard -o | wl-copy; done'
wl_x11='wl-paste -nw xclip -d ":0" -selection clipboard'
eval "${x11_wl}" &>/dev/null &
eval "${wl_x11}" &>/dev/null
pstree -A -p $$ | grep -Eow "[0-9]+" | xargs kill &>/dev/null
EOF
chmod +x /opt/bin/x11-wl-clip.sh

Install pyclip required by Waydroid

apt install xclip wl-clipboard pip python3-venv -y
python3 -m venv /opt/venv/pyclip
source /opt/venv/pyclip/bin/activate
pip install --proxy http://127.0.0.1:8082 pyclip
deactivate
echo 'export PATH="$PATH:/opt/venv/pyclip/bin"' >> /etc/profile.d/python-venv.sh
echo 'export PYTHONPATH="$PYTHONPATH:/opt/venv/pyclip/lib/python3.11/site-packages"' >> /etc/profile.d/python-venv.sh

Links for reference:
General Troubleshooting - Waydroid
No python-pyclips · Issue #981 · waydroid/waydroid · GitHub

Configure firewall for Waydroid

cat << 'EOF' | tee /etc/systemd/system/waydroid-firewall.service
[Unit]
PartOf=waydroid-container.service
Before=waydroid-container.service
Requires=qubes-iptables.service
After=qubes-iptables.service
[Service]
Type=oneshot
ExecStart=/usr/bin/bash -c "if (nft create chain ip qubes waydroid-input) &>/dev/null; then nft add rule ip qubes custom-input jump waydroid-input; fi"
ExecStart=/usr/bin/bash -c "if (nft create chain ip qubes waydroid-forward) &>/dev/null; then nft add rule ip qubes custom-forward jump waydroid-forward; fi"
ExecStart=/usr/sbin/nft add rule ip qubes waydroid-input iifname "waydroid0" meta l4proto {tcp, udp} th dport { 53, 67 } accept
ExecStart=/usr/sbin/nft add rule ip qubes waydroid-forward iifname "waydroid0" oifgroup 1 accept
ExecStart=/usr/sbin/nft add rule ip qubes waydroid-forward oifname "waydroid0" iifgroup 1 accept
ExecStop=/usr/sbin/nft flush chain ip qubes waydroid-input
ExecStop=/usr/sbin/nft flush chain ip qubes waydroid-forward
RemainAfterExit=yes
[Install]
WantedBy=waydroid-container.service
EOF
systemctl daemon-reload
systemctl enable waydroid-firewall.service

Disable sway window title bar and status bar

This will make Waydroid run in fullscreen.

Disable sway window title bar:

echo "default_border none" > /etc/sway/config.d/94-disable-window-titlebar.conf

To disable sway status bar you need to edit the default sway config /etc/sway/config and remove or comment out the entire bar section:

nano /etc/sway/config

Find and remove/comment out the entire bar{} section e.g.:

#
# Status Bar:
#
# Read `man 5 sway-bar` for more information about this section.
bar {
    position top

    # When the status_command prints a new line to stdout, swaybar updates.
    # The default just shows the current date and time.
    status_command while date +'%Y-%m-%d %I:%M:%S %p'; do sleep 1; done

    colors {
        statusline #ffffff
        background #323232
        inactive_workspace #32323200 #32323200 #5c5c5c
    }
}

Create .desktop file to start Waydroid in sway using qube app menu

When you start sway it’ll open the X11 window with sway but when you close this window it won’t cause sway to exit.
To not leave the sway with Waydroid running in background when you close the window we need to track this window and when it’s closed we need to kill the sway and Waydroid processes.
For this we need to install xwininfo tool:

apt install x11-utils -y

Create script to start the sway and Waydroid:

cat << 'EOF' | tee /opt/bin/sway-waydroid.sh
#!/bin/bash
sway &>/dev/null &
WAYLAND_DISPLAY="wayland-1" XDG_SESSION_TYPE="wayland" DISPLAY=":1" waydroid first-launch &>/dev/null &
for i in $(seq 1 3);
do
    if xwininfo -name "wlroots - X11-1" &>/dev/null; then
        break
    fi
    sleep 1
done
while xwininfo -name "wlroots - X11-1" &>/dev/null; do
    sleep 2
done
WAYLAND_DISPLAY="wayland-1" XDG_SESSION_TYPE="wayland" DISPLAY=":1" waydroid session stop &>/dev/null
pstree -A -p $$ | grep -Eow "[0-9]+" | xargs kill &>/dev/null
EOF
chmod +x /opt/bin/sway-waydroid.sh

Create the .desktop file to start Waydroid in sway using qube app menu:

cat << 'EOF' | tee /usr/share/applications/Waydroid-Sway.desktop
[Desktop Entry]
Type=Application
Name=Waydroid-Sway
Exec=/opt/bin/sway-waydroid.sh
Icon=waydroid
Categories=X-WayDroid-App;
X-Purism-FormFactor=Workstation;Mobile;
EOF

Create script to install apk from the terminal

cat << 'EOF' | tee /opt/bin/waydroid-install-apk
WAYLAND_DISPLAY="wayland-1" XDG_SESSION_TYPE="wayland" DISPLAY=":1" waydroid app install $1
EOF
chmod +x /opt/bin/waydroid-install-apk

Enable sound for the Waydroid qube

To get the sound working in the Waydroid qube, for Qubes OS 4.2 you need to install pipewire-qubes package in Waydroid qube template:

apt install pipewire-qubes -y

In case you don’t want for some Waydroid qubes to have sound (e.g. for protection against profiling threat and tracking or increasing attack surface) you can clone the d12m-waydroid template without sound to d12m-waydroid-sound template and install the sound package in d12m-waydroid-sound template.
Then you can choose whatever the Waydroid qube should have the sound or not by setting the suitable template for it.



At this point the template is configured and ready to be used.

When the TemplateVM created

  • create an AppVM, in Settings / Applications, refresh Applications, add Waydroid-Sway
  • create a DispsableVM, in Settings / Applications, refresh Applications, add Waydroid-Sway

Additional information

Update Waydroid image

To update Waydroid image in the future you’ll need to manually run this command in Waydroid template d12m-waydroid:

https_proxy=http://127.0.0.1:8082 http_proxy=http://127.0.0.1:8082 waydroid upgrade

Install application in Waydroid

In a DisposableVM:

  • download an application apk (for example F-Droid from https://f-droid.org/)
  • qvm-copy it to your Waydroid AppVM or DisposableVM

In your Waydroid AppVM or DisposableVM:

  • Run waydroid-install-apk (see above) with the path to the apk file e.g.:
waydroid-install-apk /home/user/QubesIncoming/disp1629/F-Droid.apk

Change keyboard layout in Waydroid

Settings → Languages & input → Physical keyboard → wayland_keyboard
Add layouts.
Change keyboard layout with Ctrl+Space.

Transfer files to/from Waydroid

The Waydroid internal storage is located in this path:

/home/user/.local/share/waydroid/data/media/0/

You can copy files to/from there.
Or you can set up shared folders like this:
Setting up a shared folder - Waydroid

Info about your system that apps in Waydroid will know

Apps installed in Waydroid will be able to see your CPU and system kernel.
Since qubes use kernel provided by dom0 by default then apps in Waydroid can know that you’re running Waydroid in Qubes OS (e.g. 6.7.3-1.qubes.fc37.x86_64). To hide this you can use in-VM kernel instead:

Troubleshootings

1. From Application menu, choose AppVM / Waydroid-Sway, BUT nothing displayed.

Solution:
Application menu, choose AppVM / xterm, in the displayed xterm, manually launch waydroid with this command to see the debug output:

sed "s|&>/dev/null||g" /opt/bin/sway-waydroid.sh | source /dev/stdin

2. How to exit the AppVM ?

Solution:
From dom0 Qubes Domain traybar, for the AppVM, choose Shutdown.

13 Likes

Some additional info:

Aurora Store newer than version 4.2.5 crashes on Waydroid:

Work on Waydroid webcam support:

2 Likes

Thank @apparatus for this very good guide! Below an update proposal.

Small fix for the clipnotify zip

curl https://codeload.github.com/cdown/clipnotify/zip/refs/heads/master -o clipnotify-master.zip
unzip -j clipnotify-master.zip -d clipnotify

apt install unzip -y
curl --proxy http://127.0.0.1:8082/ --tlsv1.2 --proto =https --max-time 180 https://codeload.github.com/cdown/clipnotify/zip/refs/heads/master>
unzip -j clipnotify-master.zip -d clipnotify

When the TemplateVM created

  • create an AppVM, in Settings / Applications, refresh Applications, add Waydroid-Sway
  • create a DispsableVM, in Settings / Applications, refresh Applications, add Waydroid-Sway

Troubleshootings

  1. From Application menu, choose AppVM / Waydroid-Sway, BUT nothing displayed.
    Solution : Application menu, choose AppVM / xterm, in the displayed xterm, manually launch waydroid : /opt/bin/sway-waydroid.sh

  2. How to exit the AppVM ?
    Solution : From dom0 Qubes Domain traybar, for the AppVM, choose Shutdown.

3 Likes

update proposal : add this command to a script file and put it in /etc/skel/, something like :

cat << 'EOF' | tee /etc/skell/install-apk
WAYLAND_DISPLAY="wayland-1" XDG_SESSION_TYPE="wayland" DISPLAY=":1" waydroid app install $1
EOF

Install your first application

In an DisposableVM:

  • download an application apk (for example F-Droid from https://f-droid.org/)
  • qvm-copy it to your Waydroid AppVM or DisposableVM

In your Waydroid AppVM or DisposableVM:

  • Run install-apk (see above) with the apk file (for example : ./install-apk QubesIncoming/disp1629/F-Droid.apk)
1 Like

I’ve thought about it as well but in the end I’ve decided that instead of installing unzip/git in the Waydroid template just to download the sources only once and then never use it again it’d be better to keep the template minimal and just download it in another qube instead.
I’ve added both options so users can choose what fits them best.

Thanks, I’ve added them as well.
Just with some correction to start the waydroid script manually with debug output by removing &>/dev/null from the commands.

1 Like

Thanks, I’ve added this change as well.
With the correction that it’s better to place the script in /opt/bin instead of /etc/skel/ because if you change the script later in your template then this change won’t be propagated to the existing AppVMs based on this template.
The /opt/bin is already in the PATH so you can call it without specifying the full path to the script.

1 Like

Proposal update for sound:

To get sound in the Waydroid AppVM or DisposableVM, in the TemplateVM you should install pipewire-qubes (for Qubes-OS 4.2):

apt install pipewire-qubes -y

Note: to avoid a too big default template (and so a bigger attack surface), I cloned d12m-waydroid to d12m-waydroid-sound and added the above package only in d12m-waydroid-sound. So I choose for an AppVM if I want sound or not.

2 Likes

Thanks, it’s worth mentioning. I’ve added this info to the guide.

1 Like

Thanks for the great guide, have Waydroid all set up in a Template and AppVM.

EDIT: Below was due to being on Qubes 4.1, anyone on 4.2+ shouldn’t have this same problem. Thanks to @apparatus for the reminder.

I did have a problem with no internet connectivity in Waydroid itself. TemplateVM and AppVMs had connectivity just fine, and running ip addr show in terminal showed all the interfaces and assigned IPs. But the Waydroid container itself wasn’t getting any network, and wasn’t showing any assigned IPV4 address.

Solution was found here, in the post by rustyx on April 25th 2023:

No worky in Ubuntu 22.04.

The script /usr/lib/waydroid/data/scripts/waydroid-net.sh prefers nft, iptables-legacy, iptables, in that order.

There are 2 problems with that logic:

  • nftables doesn’t work in combination with iptables rules (which I have on due to Docker)
  • iptables-legacy doesn’t work at all

So the script has no chance of ever working.

With the following patch that disables nft and iptables-legacy I was able to get Internet working:

sudo sed -i~ -E 's/=.\$\(command -v (nft|ip6?tables-legacy).*/=/g' \
     /usr/lib/waydroid/data/scripts/waydroid-net.sh

Now Waydroid is working pretty great!

Do you have Qubes OS 4.1?
It isn’t mentioned in the guide but it is for Qubes OS 4.2 and it’s using nftables because Qubes OS replaced iptables with nftables in Qubes OS 4.2.

2 Likes

Yes you’re right I’m still on 4.1! Completely forgot about the 4.2 switch to nftables. Will edit my post to add.

You can try to replace this:

ExecStart=/usr/bin/bash -c "if (nft create chain ip qubes waydroid-input) &>/dev/null; then nft add rule ip qubes custom-input jump waydroid-input; fi"
ExecStart=/usr/bin/bash -c "if (nft create chain ip qubes waydroid-forward) &>/dev/null; then nft add rule ip qubes custom-forward jump waydroid-forward; fi"
ExecStart=/usr/sbin/nft add rule ip qubes waydroid-input iifname "waydroid0" meta l4proto {tcp, udp} th dport { 53, 67 } accept
ExecStart=/usr/sbin/nft add rule ip qubes waydroid-forward iifname "waydroid0" oifgroup 1 accept
ExecStart=/usr/sbin/nft add rule ip qubes waydroid-forward oifname "waydroid0" iifgroup 1 accept
ExecStop=/usr/sbin/nft flush chain ip qubes waydroid-input
ExecStop=/usr/sbin/nft flush chain ip qubes waydroid-forward

with this:

ExecStart=/usr/sbin/iptables -I INPUT -i waydroid0 -p tcp -m multiport --dports 53,67 -j ACCEPT
ExecStart=/usr/sbin/iptables -I INPUT -i waydroid0 -p udp -m multiport --dports 53,67 -j ACCEPT
ExecStart=/usr/sbin/iptables -I FORWARD 2 -o eth0 -i waydroid0 -j ACCEPT
ExecStart=/usr/sbin/iptables -I FORWARD 2 -i eth0 -o waydroid0 -j ACCEPT
ExecStop=/usr/sbin/iptables -D INPUT -i waydroid0 -p tcp -m multiport --dports 53,67 -j ACCEPT
ExecStop=/usr/sbin/iptables -D INPUT -i waydroid0 -p udp -m multiport --dports 53,67 -j ACCEPT
ExecStop=/usr/sbin/iptables -D FORWARD -o eth0 -i waydroid0 -j ACCEPT
ExecStop=/usr/sbin/iptables -D FORWARD -i eth0 -o waydroid0 -j ACCEPT

untested

1 Like

Confirming that these iptables-version firewall rules work for Waydroid in Qubes 4.1!
Thank you for taking care of us poor souls who haven’t been able to make the jump to 4.2 yet :smiling_face_with_tear:

Qubes os is still handle to Wayland, so I was thinking to use Wayland on Qubes OS, user shall make sys-gui and after separate between X11 and Wayland.
My solution is making two sys-gui, one is managing gui on X11 server of dom0 and normal templates, other one manage Wayland compositor.

But I understood to be able to use Wayland on Qubes os, this solution is greatest!
User can use safely Android apps without Google service, thank you!

Hey There,

  1. ‘create an AppVM, in Settings / Applications, refresh Applications, add Waydroid-Sway’

I have refreshed the apps but i cant find waydroid-sway. Only waydroid. Are they the same thing?

  1. I went ahead and tried opening waydroid. It opened ‘initialize waydroid’ and I chose my android type and downloaded it.

when i try waydroid-install-apk /home/user/QubesIncoming/disp1629/F-Droid.apk it says WayDroid session is stopped

What am i doing wrong here?

It seems that you’ve missed some of the guides steps or there was an error somewhere that you didn’t notice.
Try to create Waydroid template from the beginning.

It seems that you don’t have .desktop file that should’ve been created here:

1 Like

okay, waydroid-sway shows app in qubes settings apps now. I think i had an error on the sway install.

How do I get aurora store 4.2.5? Their gitlab keeps redirecting to their main site where they only have 4.3.5. F-droid doesnt have 4.2.5 either.

You can download it from here:

And verify the signature:

1 Like

I think Droid-ify is privacy safely than F-Droid as client.
So first I install apk of Droid-ify, after I enable F-Droid Archive repository in Droid-ify, Aurora Store v4.2.5 is existing in F-Droid Archive repository, so it can install from here.
And Aurora Store use Exodus for monitor packet of apps, user should install Exodus.

Thanks for making android research and devolpment more easy than ever on qubes with low resource overhead!

Everything seems to work so far only issue i have left is changing size of the output window for highres screens:
Scaling settings in /etc/sway/config seem to have an effect on waydroid but the window size stays the same so the visible part of the screen is about 1/5…
if i resize the window android ist dynamicly rescaling, is that possible to configure? on chromebooks the rescaling works kinda.
I tried also the command waydroid shell wm density 320 and that helped also with with scaling but again the window size is too small.
I also found out that there is a Multi-Window-Mode any expierience with it?