negative zero

Running Android Apps on Qubes OS with Anbox

2021 July 9

[android] [debian] [phone] [qubes] [tech] [tutorial]


Qubes OS (onion) is a security-focused operating system. Its approach is security through compartmentalization, where your compartments are different virtual machines.

One might suppose that for an operating system that runs everything in VMs, the easiest way to run Android apps would be to make an Android-x86 or Bliss OS VM. The problem with this is that these prebuilt images assume that your hard drive will be in a normal place like /dev/sda. Qubes puts the virtual drives at /dev/xvd* instead, and the installer can't find these. You could recompile the image yourself, but it ends up being easier to just run Anbox in a Debian VM.

Anbox is a tool for running Android apps on GNU/Linux systems. In this tutorial, we'll be installing Anbox in a Debian VM in Qubes OS 4.0.

This guide may also be helpful if you're not running Qubes but want to install Android apps on Debian. Just ignore the Qubes-specific steps in that case.

Since this guide involves running commands in multiple devices, I'll use the convention here of starting commands with the user prompt. A dollar sign ($) indicates that the command should be run as the user, and a number sign (#) indicates that it should be run as root (with sudo, for instance).


Requirements:


Step 1: Install a Debian template

In dom0, open a terminal.

First, we'll install a Debian template in Qubes. Debian is a good template for Anbox because its kernel already includes the ashmem and binder kernel modules required for Anbox to run, and Anbox is packaged for Debian in the contrib repo. We'll install a minimal Debian template because we only need it for Anbox:

[root@dom0 ~]# qubes-dom0-update qubes-template-debian-10-minimal

Now, we'll make a clone of this template for use as an "Android" template.

[user@dom0 ~]$ qvm-clone debian-10-minimal android

You can now remove the debian-10-minimal template if you want. We won't use it after this.

[root@dom0 ~]# dnf remove qubes-template-debian-10-minimal


Step 2: Prepare Debian

Launch a root shell in the new "Android" template:

[user@dom0 ~]$ qvm-run -u root android xterm

This will launch a terminal running in the android template as root.

Personally, I want to avoid the non-free Debian repo (which is enabled by default), so I'll disable it. We'll need the contrib repo enabled, though, because Anbox is in there.

root@android:~# sed -i 's/main contrib non-free/main contrib/g' /etc/apt/sources.list

(This command just replaces all instances of "main contrib non-free" in /etc/apt/sources.list with "main contrib" instead.)

Now, run a software update:

root@android:~# apt update

root@android:~# apt upgrade

There are some utilities which will be useful to us. Let's install those now.

root@android:~# apt install <your terminal emulator of choice> qubes-core-agent-passwordless-root bash-completion curl qubes-core-agent-networking

This will make the rest of our terminal use more pleasant. Now you can launch your terminal from the applications menu or with qvm-run android <your terminal emulator of choice>. qubes-core-agent-passwordless-root will enable us to elevate to root with sudo or su. bash-completion will let us tab to auto-complete.

We'll use curl later to download an Android image. (wget would work just as well; I just like curl better.)

qubes-core-agent-networking is required to give our Android qubes Internet access.

Now, we need a kernel. We want to use the Debian kernel, rather than the Qubes kernel from dom0, because it has the kernel modules we need for Anbox. We'll also install Linux headers, GRUB2, and the qubes-kernel-vm-support package which are needed to boot the in-VM kernel.

root@android:~# apt install linux-image-amd64 linux-headers-amd64 grub2 qubes-kernel-vm-support

Shut down the qube. Now that we have our kernel installed, we need to set Qubes to use the installed kernel before booting again.

user@android:~$ sudo poweroff

(This command is given with sudo instead of just indicating root shell due to path reasons. If you elevate to root, you will still need to use sudo or specify the full path of the command as /usr/sbin/poweroff or /sbin/poweroff.)


Step 3: Set the Debian kernel

In order to use the Debian kernel in our android qube in PVH mode, we'll need to install grub2-xen-pvh in dom0.

[user@dom0 ~]# qubes-dom0-update grub2-xen-pvh

After this, we'll set the android qube to use its own kernel by setting its kernel to pvgrub2-pvh.

[user@dom0 ~]$ qvm-prefs android kernel pvgrub2-pvh


Step 4: Installing Anbox

Start the android qube again and run a terminal.

[user@dom0 ~]$ qvm-run android <your terminal emulator of choice>


Installing Anbox

Now, install Anbox:

root@android:~# apt install anbox


Modify the Anbox systemd service

(This step is specific to Qubes OS.)

By default, Anbox on Debian uses the /var/lib/anbox/ directory to store all its data. The problem with this on Qubes is that if you modify system directories in AppVMs, your changes will not persist across reboots. In other words, if you make an "Android" AppVM, every time you start it, all your changes to the stock Android image will go away. No persistent data, no persistent app installations.

/usr/local/ is persistent, so we'll make a /usr/local/lib/anbox/ directory and use that for our Anbox data. (Another approach would be to make /var/lib/anbox/ persistent.)

First, copy the Anbox systemd service to /etc/systemd/system/.

root@android:~# cp /usr/lib/systemd/system/anbox-container-manager.service /etc/systemd/system/

Now, replace all instances of "/var/lib/anbox" in this file with "/usr/local/lib/anbox".

root@android:~# sed -i 's:/var/lib/anbox:/usr/local/lib/anbox:g' /etc/systemd/system/anbox-container-manager.service

This should change two lines:

  1. The ConditionPathExists argument should change to "ConditionPathExists=/usr/local/lib/anbox/android.img".
  2. The ExecStart argument should change to "ExecStart=/usr/bin/anbox container-manager --daemon --privileged --data-path=/usr/local/lib/anbox".

Here's what my service file looks like after this change:

[Unit]
Description=Anbox Container Manager
Documentation=man:anbox(1)
After=network.target
Wants=network.target
ConditionPathExists=/usr/local/lib/anbox/android.img

[Service]
ExecStartPre=/sbin/modprobe ashmem_linux
ExecStartPre=/sbin/modprobe binder_linux
ExecStartPre=/usr/share/anbox/anbox-bridge.sh start
ExecStart=/usr/bin/anbox container-manager --daemon --privileged --data-path=/usr/local/lib/anbox
ExecStopPost=/usr/share/anbox/anbox-bridge.sh stop

[Install]
WantedBy=multi-user.target

(Note that this references an android.img file which we don't have yet. We'll put this directly into the AppVM in step 5.)

You'll have to daemon-reload before this change is applied.

root@android:~# systemctl daemon-reload


Install adb

In order to install APKs, we will need the Android Debug Bridge (ADB). Install it from apt.

root@android:~# apt install adb


Step 5: Making an Android AppVM

Finally, we're ready to start using Android!

First, shut down the android TemplateVM.

Now, make a new AppVM based on the android TemplateVM. I'll call mine "phone" here. Increase the max private storage space in the qube, as the default amount of space is insufficient. (Anbox will be very slow, and apps will fail to open.) I set mine at 20480MiB. You can increase as you need.

Launch a terminal in that qube.


Getting an Android image

In order for Anbox to run, we need to provide it with an Android image. The Anbox project provides these at https://build.anbox.io/android-images/, but they haven't built a new one in 3 years, so we'll be using an old image running Android 7. Factor that into your security model or find/compile a newer image. This is a basic AOSP image. If you need a different version with Open GApps or something, go find that instead.

Download the newest android_amd64.img file from https://build.anbox.io/android-images/ (or get it from another source).

user@phone:~$ curl -O https://build.anbox.io/android-images/2018/07/19/android_amd64.img

Also download the SHA256 hash to verify the file's integrity.

user@phone:~$ curl -O https://build.anbox.io/android-images/2018/07/19/android_amd64.img.sha256sum

Check the file's integrity:

user@phone:~$ sha256sum -c android_amd64.img.sha256sum

If all goes well, it will output "android_amd64.img: OK".

Assuming all went well, move this file to /usr/local/lib/anbox/android.img.

root@android:~# mkdir -p /usr/local/lib/anbox

root@android:~# mv /home/user/android_amd64.img /usr/local/lib/anbox/android.img

(Bear in mind that with this setup, if you want to run multiple Android qubes, you'll need a separate copy of this file in each. There's probably some way to make this more efficient.)

Restart the Anbox service.

root@android:~# systemctl restart anbox-container-manager.service

If all goes well, it should now work, and you'll be able to launch Anbox from the application menu or with the command:

anbox launch --package=org.anbox.appmgr --component=org.anbox.appmgr.AppViewActivity


Installing apps

The Android image we downloaded comes with very few preinstalled apps and no app store. Unless you can make do with Calculator, Calendar, Clock, Contacts, Email, Files, Gallery, Music, Settings, and WebView Shell, you'll need to install at least one app through ADB (or maybe by downloading the APK with the WebView Shell...). I recommend installing F-Droid then using it for most other apps.

If you have an APK you want to install (like F-Droid.apk), first enable installation from unknown sources:

  1. Open the Anbox Application Manager.
  2. Open the Settings app.
  3. Open the Security settings.
  4. Under "Device administration", enable "Unknown sources".

After that, the command is simple:

user@phone:~$ adb install F-Droid.apk

(replacing F-Droid.apk with the name of your .apk file)

ADB sometimes has issues finding the Anbox process. If you get "error: device offline" or something similar, then restart adb and anbox-container-manager and try again.

user@phone:~$ adb kill-server

root@phone:~# systemctl restart anbox-container-manager.service

user@phone:~$ adb install F-Droid.apk


End

Congratulations! You can now run Android apps on Qubes OS!