Split Personality Snaps

Broadly speaking, most snaps in the Snap Store fall into one of two categories, desktop applications and server daemons. The graphical applications such as Chromium and Spotify use desktop files, which ensure they can be opened on demand by any user via a menu or launcher. The server applications such as NextCloud and AdGuard-Home typically have systemd units, which control their automatic (background) startup.

Taking an existing desktop application and converting it to an always-running appliance leads to some interesting engineering challenges. Applications and games tend to have expectations for what programs and services are accessible at runtime, which need mitigating. Application confinement in snaps on Ubuntu Core means some assumptions about file and device access may no longer apply.  

We will typically need to stand-up a configuration in which the application believes it’s running in a standard desktop environment. The application will also need the startup automated in an appliance setting, but launched on demand when in a desktop environment.

We can be quite creative with snaps and build a “split personality” snap that can run both as a desktop application and as an appliance!

Building Blocks

Ubuntu Core doesn’t ship with Xorg or PulseAudio out of the box. This isn’t a problem if the appliance doesn’t require a connected monitor, nor makes any sounds, as is the case with Plex Media Server and Mosquitto but this can be a problem with applications which require access to the display or sound hardware.

Unlike multi-user desktop environments, appliances tend to only require one local system user under which services automatically start. On a desktop system, the logged-in user launches applications on demand, whereas with an appliance, a system user launches the appliance on boot. 

Our snap needs to service the needs of running on a desktop environment where Xorg and PulseAudio exist, and on an Ubuntu Core system where they don’t. It also needs to be capable of being manually launched in a window, but also auto-start full-screen on an appliance.

Multiple Personality Order

Let’s have a look at ScummVM, where we’ve done this work already.

ScummVM is a program that allows you to run a variety of  classic graphical point-and-click adventure games like The Secret of Monkey Island, provided you already have their data files. This makes it a great asset in the hands of old-game fans.

It’s published as a snap in the Snap Store, and runs on many different desktop Linux distributions. We thought it might be fun to make a “ScummVM Appliance” using this snap on top of Ubuntu Core. The goal is to create a single purpose device, which boots directly to the game selection screen, and functions like a ScummVM console. 

As Ubuntu Core has no Xorg, we need to use mir-kiosk to provide a Wayland-compatible display stack to drive an external monitor. Ubuntu Core also ships without PulseAudio, so  we’ll get no in-game sound. This is resolved by installing the pulseaudio snap. Keyboards & mice will just work as expected.

To enable the snap to function both on-demand on a desktop, and launch automatically on an appliance, we need to create two ‘apps’ stanzas in the snapcraft.yaml file that is used to build the ScummVM snap. 

apps:
scummvm:
command: desktop-launch $SNAP/bin/wayland-if-possible.sh $SNAP/bin/scummvm-launch.sh
daemon:
command: daemon-start.sh $SNAP/bin/scummvm-launch.sh -f
daemon: simple

The daemon: simple directive means the specified command will launch automatically on start.

This command includes logic that detects whether the program is running on an Ubuntu Core appliance, and if it is, it will launch using Mir as the Wayland display system. If the logic determines it’s not running on an Ubuntu Core appliance, the script exits immediately.

#!/bin/sh
if [ "$(id -u)" = "0" ] && [ "$(snapctl get daemon)" = "false" ]
then
# If not configured to run as a daemon we have to stop here
# (There's no "snapctl disable …")
snapctl stop $SNAP_NAME.daemon
exit 0
fi
mkdir -p "$XDG_RUNTIME_DIR" -m 700
if [ -z "${WAYLAND_DISPLAY}" ]
then WAYLAND_DISPLAY=wayland-0
fi
real_wayland=$(dirname "$XDG_RUNTIME_DIR")/${WAYLAND_DISPLAY}
while [ ! -O "${real_wayland}" ]; do echo waiting for Wayland socket; sleep 4; done
ln -sf "${real_wayland}" "$XDG_RUNTIME_DIR"
exec "$@"

That’s essentially all we need! One single yaml and a smattering of scripting is all that’s required to make a dual-personality snap that can run on-demand in desktop contexts, and automatically when run as an appliance.

ScummVM running on a traditional Linux desktop


ScummVM running under Ubuntu Core in a Virtual Machine

The ScummVM snap is built for both x86 and arm based CPUs, we could create a simple self-updating boot-to-game device based on a low-cost device like a Raspberry Pi. Plugin a keyboard, screen and mouse, and we can be gaming like it’s 1990 all over again.

If you have an idea for something we could turn into an official Ubuntu Appliance, please join the discourse and post a suggestion in the proposed new appliances category.

Internet of Things

From home control to drones, robots and industrial systems, Ubuntu Core and Snaps provide robust security, app stores and reliable updates for all your IoT devices.

Newsletter signup

Select topics you’re
interested in

In submitting this form, I confirm that I have read and agree to Canonical’s Privacy Notice and Privacy Policy.

Related posts

Stepping Down Gracefully

The Snap Store has been designed to enable upstream developers and enthusiastic community contributors to publish snaps. As with most Linux packaging...

The Expandables – snapcraft extensions and the secret code

If you’re a snap developer, you know that snap development is terribly easy. Or rather complex and difficult. Depending on your application code and...

Security corner: snap interface & snap connections

One of the defining features of snaps is their strong security. Snaps are designed to run isolated from the underlying system, with granular control and...