Debugging Graphical Apps on Ubuntu Core

Ubuntu Core is Canonical’s secure operating system for embedded devices. Software on Ubuntu Core is installed via Snaps. This post can help you:

  • Set up an Ubuntu Core virtual machine

  • Download and “try” a snap such that you can easily modify and debug it

  • Run graphical snaps (such as Flutter apps) on Ubuntu core

Create an Ubuntu Core VM

Download the Image

First, we’ll download and Ubuntu Core image. It’s currently easiest to get core18 working. In the most common case (running on an x86 computer) you’ll want to grab the ubuntu-core-18-amd64.img.xz image.

Install qemu-virgil

In this post, we’ll be using qemu-virgil because it supports OpenGL. You may use a different VM system if the snap you’re debugging isn’t graphical.

$ sudo snap install qemu-virgil

$ sudo snap connect qemu-virgil:kvm

Prepare to SSH

The primary means of interacting with the VM will be SSH. In order to be able to SSH in, you’ll want to have a Launchpad account with a public SSH key attached. If you need to create a new SSH key, GitHub has a good tutorial.

Decompress the Image

You can do it from the command line or your archive manager.

$ unxz -k ~/Downloads/ubuntu-core-*.img.xz

$ mv ~/Downloads/ubuntu-core-*.img where/you/want/the/image/

The resulting image will be several GB, most of which is initially empty space inside your VM for data and software.

Start the VM

To start the VM, run the following with the last argument the actual path to the image you extracted:

$ qemu-virgil -enable-kvm -m 512 -device virtio-vga,virgl=on -display sdl,gl=on -netdev user,id=ethernet.0,hostfwd=tcp::10022-:22 -device rtl8139,netdev=ethernet.0 -soundhw ac97 ~/path/to/ubuntu-core-*.img

Troubleshooting (skip if the VM works)

If you get

Could not access KVM kernel module: Operation not permitted

qemu-system-x86_64: failed to initialize KVM: Operation not permitted

it probably means you forgot to connect qemu-virgil:kvm (see above). I’ve also seen

qemu-system-x86_64: -soundhw ac97: Could not open '/media/wmww/Auxiliary/vm-disks/ubuntu-core-18-amd64.img': Permission denied

When the image was outside of my home directory. Moving it to be under home fixed this.

Set Up The VM

In the window that pops up, you will be prompted to set up the system. Use the default network configuration. When it asks for your email, make sure to put one that is attached to the Launchpad account that holds your public SSH keys, else you won’t be able to SSH in.

SSH Into The VM

It will tell you to SSH in with some specific IP address. This is not what you want to do, as this is an IP internal to qemu. Instead, we set up port forwarding on localhost - use this (with username changed with your actual username):

$ ssh -p 10022 username@localhost

You should now be inside your VM.

Debug a Snap

For starters, we’re going to download a simple, non-graphical snap: youtube-dl from the store (downloading, not directly installing).

Acquire the Snap

From the SSH session:

$ snap download youtube-dl

Alternatively you could transfer a snap built on the host into the VM. From the host you would run:

$ scp -P 10022 path/to/app.snap username@localhost:/home/username

Try a Snap

If we installed the snap normally, it’s contents would be read-only and we wouldn’t be able to experiment with it. Instead, we’re going to uncompress it’s contents into a directory called youtube-dl-root:

$ unsquashfs -d youtube-dl-root ./youtube-dl*.snap

and “try” the snap from the new directory - this treats the folder as if it was a snap package:

$ snap try youtube-dl-root

$ youtube-dl --version


Modify a Snap In Place

We can now make changes to the contents of squashfs-root and have those immediately reflected (except those in meta/, you’ll need to snap try again for those to get picked up). For example:

$ cp ./youtube-dl-root/bin/youtube-dl ./youtube-dl-root/bin/youtube-dl.old

$ echo 'echo "Snap has been modified!"' > ./youtube-dl-root/bin/youtube-dl

$ youtube-dl --version

Snap has been modified!

How exactly you’ll need to modify your snap to debug whatever issue you’re facing is out of scope here. Depending on the type of snap and issue, you may need to change the code directly, swap in binaries or libraries you’ve built on the host system, or modify config files.

Access a Snap’s Environment

To get access to the environment a Snap runs in, run:

snap run --shell appname

You will then get a shell that has all the environment variables set (like $SNAP).

Run a Graphical Snap

To run a snap with graphics, you’ll generally need two parts:

  1. The app, which does the interesting things you care about

  2. A display server, which on Ubuntu Core is generally Mir Kiosk

The app talks to the display server (generally over the Wayland protocol), and the display server puts the app on the screen.

Install Mir Kiosk

If we wanted to modify and debug Mir Kiosk we could download and try it, but we probably wont need to change it so we’ll install it normally.

$ snap install mir-kiosk

As soon as it’s installed it starts a daemon. You may notice an orange flash in the VM window, which indicates Mir Kiosk has started. At any time you can the Mir Kiosk daemon with:

$ snap set mir-kiosk daemon=false

And start it again with:

$ snap set mir-kiosk daemon=true

You know it works if you see an orange flash when you start it.

“Try” a Flutter Snap

Now we’ll download, unsquash and try a graphical snap built with Flutter. The commands should look similar to what we did with youtube-dl above:

$ snap download --edge flutter-gallery

$ unsquashfs -d flutter-gallery-root ./flutter-gallery*.snap

$ snap try flutter-gallery-root

Assuming the Mir Kiosk daemon is running, flutter-gallery should automatically start and you should be able to play with it.