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.
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.
Waydroid needs Wayland so we will install sway
Wayland compositor for it:
apt install sway -y
qubes-core-agent-networking
package to enable networking in minimal qube:
apt install qubes-core-agent-networking -y
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
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
https_proxy=http://127.0.0.1:8082 http_proxy=http://127.0.0.1:8082 waydroid init -s GAPPS
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.
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
git config --global http.proxy http://127.0.0.1:8082
git clone https://github.com/cdown/clipnotify.git
git config --global http.proxy ""
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
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
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
pyclip
required by Waydroidapt 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
For Qubes OS 4.2:
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
For Qubes OS 4.1:
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/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
RemainAfterExit=yes
[Install]
WantedBy=waydroid-container.service
EOF
systemctl daemon-reload
systemctl enable waydroid-firewall.service
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
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
}
}
.desktop
file to start Waydroid in sway using qube app menuWhen 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
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
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
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
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
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.
To add the Waydroid App menu shortcut to the newly created qubes you need to set default-menu-items
feature for Waydroid template.
Open dom0 terminal and run this command to set the default App menu items for qubes based on this template:
qvm-features d12m-waydroid default-menu-items "Waydroid-Sway.desktop debian-xterm.desktop"
Waydroid-Sway
app shortcut for your newly created Waydroid qube:
https://www.qubes-os.org/doc/app-menu-shortcut-troubleshooting/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
In a DisposableVM:
qvm-copy
it to your Waydroid AppVM or DisposableVMIn your Waydroid AppVM or DisposableVM:
waydroid-install-apk
(see above) with the path to the apk file e.g.:
waydroid-install-apk /home/user/QubesIncoming/disp1629/F-Droid.apk
Settings -> Languages & input -> Physical keyboard -> wayland_keyboard Add layouts. Change keyboard layout with Ctrl+Space.
The Waydroid internal storage is located in this path:
/home/user/.local/share/waydroid/data/media/0/
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:
https://www.qubes-os.org/doc/managing-vm-kernels/#using-kernel-installed-in-the-vm
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
Solution: From dom0 Qubes Domain traybar, for the AppVM, choose Shutdown.