Throughout this post, I will document the process that was taken to run Ubuntu 22.04 on a Pixel 6A running Android 14. I leveraged an x86_64 Ubuntu 22.04 machine for this work. $ will be commands to run on your technician machine. # will be commands to run with su on the Android phone using a tool like adb shell or termux.

Install dependencies

$ sudo apt install adb fastboot build-essential debootstrap qemu-user-static
$ rm -rf /usr/local/go && tar -C /usr/local -xzf go1.21.5.linux-amd64.tar.gz

Add this to your ~/.bashrc

export PATH=$PATH:/usr/local/go/bin

Root the device

Follow the guide here to root the device.

Enable KVM

On Pixel 6A, pKVM is not enabled by default.

$ adb reboot bootloader
$ fastboot oem pkvm enable
$ fastboot reboot

Build the kernel

Grab a kernel tarball from kernel.org.

$ tar -xvf linux-x.x.xx.tar.xz
$ cd linux-x.x.xx
$ make ARCH=arm64 defconfig

Enable CONFIG_VSOCKETS

$ CROSS_COMPILE=aarch64-linux-gnu- make ARCH=arm64 -j 8

Cross-compile gVisor Proxy for aarch64

git clone https://github.com/containers/gvisor-tap-vsock gvisor-tap-vsock-arm64
GOARCH=arm64 make

Cross-compile gVisor Proxy for Android

git clone https://github.com/containers/gvisor-tap-vsock gvisor-tap-vsock-android
GOOS=android GOARCH=arm64 make

Create a rootfs

$ mkdir vm-host
$ truncate -s 100G vm-host.ext4
$ mkfs.ext4 vm-host.ext4
$ sudo mount vm-host.ext4 vm-host
$ sudo truncate -s 99G ./vm-host/ubuntu-rootfs.ext4
$ sudo mkfs.ext4 ./vm-host/ubuntu-rootfs.ext4
$ sudo mount ./vm-host/ubuntu-rootfs.ext4 ubuntu-rootfs
$ sudo debootstrap --arch=arm64 jammy ubuntu-rootfs
$ echo "android-vm" | sudo tee ./ubuntu-rootfs/etc/hostname
$ sudo mkdir -p ./ubuntu-rootfs/etc/systemd/resolved.conf.d/
$ sudo vim ./ubuntu-rootfs/etc/systemd/resolved.conf.d/dns_servers.conf

Set the value to the following

[Resolve]
DNS=8.8.8.8 1.1.1.1
$ sudo chroot ./ubuntu-rootfs /bin/bash
$ useradd -m -g sudo <username>
$ passwd <username>
$ chsh -s /bin/bash <username>
$ exit
$ sudo mkdir -p ./ubuntu-rootfs/gvisor-tap-vsock
$ sudo cp -r ./gvisor-tap-vsock-arm64/bin/* ./ubuntu-rootfs/gvisor-tap-vsock
$ sudo mkdir -p ./vm-host/gvisor-tap-vsock
$ sudo cp -r ./gvisor-tap-vsock-android/bin/* ./vm-host/gvisor-tap-vsock
$ sudo umount ./ubuntu-rootfs
$ sudo umount ./vm-host

Prep the package

$ mkdir -p kvm/vm-host
$ mv vm-host.ext4 kvm
$ cp ./linux-x.x.xx/arch/arm64/boot/Image kvm
$ tar -cvf kvm.tar.gz ./kvm -I "pigz -9"

Prep the phone

$ adb push kvm.tar.gz /storage/emulated/0
# cd /storage/emulated/0
# tar -xvf kvm.tar.gz
# cd /storage/emulated/0/kvm
# mount vm-host.ext4 vm-host
# /storage/emulated/0/kvm/vm-host/gvisor-tap-vsock/bin/gvproxy -debug -listen vsock://:1024 -listen unix:///storage/emulated/0/kvm/vm-host/network.sock

In a second terminal

# /apex/com.android.virt/bin/crosvm run --disable-sandbox -p 'init=/sbin/init' --rwroot /storage/emulated/0/kvm/vm-host/ubuntu-rootfs.ext4 /storage/emulated/0/kvm/Image --vsock 3 --mem 4096 --cpus 4
# sudo /gvisor-tap-vsock/bin/gvforwarder -debug &
# ping 8.8.8.8