1. Overview

What you’ll learn

In this tutorial we will create a snap of an X11 application to act as the graphical user interface for an IoT or kiosk device. For the introduction to this tutorial series and the Mir display server please visit here.

X11 is a legacy protocol, it is known to be insecure, so we need to take steps to ensure it is secured correctly. To do this we shall embed an intermediary X server based on Mir in the application snap and use snapd’s infrastructure to maintain security.

The combination of Snap, the “mir-kiosk” Wayland server and Ubuntu Core ensures the reliability and security of any graphical embedded device application.

This tutorial assumes you are familiar with the material in Make a Wayland-native Kiosk snap. In particular, techniques for debugging problems in your snap are not repeated here.

Depending on the toolkit your application is written in, it may work on the newer and more secure Wayland protocol. If so, the snapping process is simpler. To check, please read this guide.

What you’ll need

  • An Ubuntu desktop running any current release of Ubuntu, or an Ubuntu Virtual Machine on another OS.
  • A ‘Target Device’ from one of the following:
    • A device running Ubuntu Core 18.
      This guide shows you how to set up a supported device. If there’s no supported image that fits your needs you can create your own core image.

    • A VM. You don’t have to have a physical “Target Device”, you can follow this tutorial using Ubuntu Core in a VM instead.

      • Install the ubuntu-core-vm snap:

        sudo snap install --beta ubuntu-core-vm --devmode

        For the first run, create a VM running the latest Core 18 image:

        sudo ubuntu-core-vm init.

        From then on, you can spin it up with:

        sudo ubuntu-core-vm

        Which should show you a new window with Ubuntu Core running inside. Setting up Ubuntu Core on this VM is the same as for any other device or VM. See, for example, https://developer.ubuntu.com/core/get-started/kvm.

    • Using Ubuntu Classic You don’t have to use Ubuntu Core, you can use also a “Target Device” with Ubuntu Classic. Read this guide to understand how to run kiosk snaps on your desktop, as the particular details won’t be repeated here.


2. X11 on top of Wayland

We use Wayland as the primary display interface. We will use Mir to manage the display and support connections from Wayland clients and Snapd will confine the applications and enable Wayland protocol interactions through Mir, securely.

Wayland is relatively new in the Linux world however. Its predecessor - X11 - has been the dominant graphics technology for decades. As a result, not all toolkits have native support for Wayland - they only support X11.

To deal with the limitations of X11 in a secure fashion we will embed a tiny intermediary X11 server called “Xwayland” inside the application snap, which translates the X11 calls to Wayland ones, allowing the X11 application to talk Wayland - a far more secure protocol.

The Snap security framework then ensures this X11 server is private to the application snap.

x11-snap-architecture

Toolkits without Native support for Wayland

  • GTK2
  • Qt4
  • Electron apps
  • Java apps
  • Windows apps emulated under Wine
  • Chromium

It may also be your application is written using X11 calls directly, in which case this guide is for you.

If your application is written using GTK3/4, Qt5 or SDL2, or another toolkit with native Wayland support, you should follow this guide.


3. Introducing glxgears and Mir support for X11

A large fraction of applications are still written for X11 - there are those written with Qt4 and Gtk2, but also Java, Mono or Wine-based. We can snap these for a kiosk just fine, we just need to add some extra bits to the snap.

We’ll take a trivial example to start with (glxgears). glxgears is again a handy snap to have, as it will help prove OpenGL is working for X11 apps inside Ubuntu Core. For some initial testing “on the desktop” we’ll use egmde, a simple Mir server that enables X11 support.

On your desktop, install the following and launch egmde:

sudo apt install mesa-utils
sudo snap install --classic --beta egmde
egmde

Now, in the “Mir-on-X” egmde window, start a terminal (Ctrl-Alt-Shift-T) and run glxgears

glxgears

You should see the gear animation in the Mir-on-X window. It’s not fullscreen yet, but we’ll deal with that using a special Mir server in our snap.

You can Alt-Tab back to the terminal window and Ctrl-C to exit glxgears, we’ll make use of egmde in further testing, but you can also close that window for now.


4. First Pass Snapping: Test on Desktop

For our first pass we will snap glxgears and run it on our Ubuntu desktop. This guide assumes you are familiar with creating snaps. If not, please read here first.

Create the snap directory by forking https://github.com/MirServer/mir_kiosk_x11-example

git clone https://github.com/MirServer/mir_kiosk_x11-example

Change to the new mir_kiosk_x11-example directory.

cd mir_kiosk_x11-example

Update the “snap/snapcraft.yaml” file with as follows…

Update the metadata:

@@ -1,7 +1,8 @@
-name: mir-kiosk-x11-example     # YOUR SNAP NAME GOES HERE
-version: '0.1'                  # YOUR SNAP VERSION GOES HERE
-summary: example X11 kiosk      # YOUR SUMMARY GOES HERE
-description: example X11 kiosk  # YOUR DESCRIPTION GOES HERE
+name: mir-kiosk-x11-example
+version: '0.1'
+summary: example (glxgears) X11 kiosk, using mir-kiosk-x11
+description: |
+  example (glxgears) X11 kiosk, using mir-kiosk-x11

Add “glxgears” to the app command:

@@ -12,7 +13,7 @@
-    command: usr/local/bin/x11_kiosk_launch ### YOUR COMMAND GOES HERE
+    command: usr/local/bin/x11_kiosk_launch glxgears

Add the packaging commands for glxgears:

-  ### YOUR PART GOES HERE
-  your-part:
+  glxgears:
     plugin: nil
+    stage-packages:
+      - mesa-utils
     stage-snaps: [mir-kiosk-x11]

Here’s the full snapcraft.yaml for reference:

name: mir-kiosk-x11-example
version: '0.1'
summary: example (glxgears) X11 kiosk, using mir-kiosk-x11
description: |
  example (glxgears) X11 kiosk, using mir-kiosk-x11
base: core20
confinement: strict
grade: devel

apps:
  mir-kiosk-x11-example:
#    daemon: simple
#    restart-condition: always
    command-chain:
      - env-setup
    command: usr/local/bin/x11_kiosk_launch glxgears
    plugs:
      - opengl         # For Mir
      - wayland        # For Mir
      - network-bind   # For Mir (to serve X11)

architectures:
  - build-on: amd64
  - build-on: arm64
  - build-on: armhf

parts:
  glxgears:
    plugin: nil
    stage-packages:
      - mesa-utils
    stage-snaps: [mir-kiosk-x11]

layout:
  /usr/share/X11:
    bind: $SNAP/usr/share/X11
  /usr/bin/xkbcomp:
    symlink: $SNAP/usr/bin/xkbcomp
  /usr/share/icons:
    bind: $SNAP/usr/share/icons
  /usr/share/fonts:
    bind: $SNAP/usr/share/fonts
  /etc/fonts:
    bind: $SNAP/etc/fonts

Create the snap by running

snapcraft

You should be left with a “mir-kiosk-x11-example_0.1_amd64.snap” file.

Let’s test it!

egmde&
sudo snap install --dangerous ./mir-kiosk-x11-example_0.1_amd64.snap
mir-kiosk-x11-example

You should see a fullscreen gear animation in the Mir-on-X window.


5. Snapping to use on a device

Now make another update to your snapcraft.yaml file:

-#    daemon: simple
-#    restart-condition: always
+    daemon: simple
+    restart-condition: always

This changes the snap from a simple command to a “daemon” which is how thing are usually run on devices. Check this builds locally before proceeding:

snapcraft

6. Building snaps for different architectures

Your device is likely not the same architecture as your desktop, so you need to build your snap for that architecture. You can do this using remote-build:

snapcraft remote-build

Depending on the load on the builders this can take a few minutes to complete. Once it completes you should have an suitable .snap for your device architecture. (We’ll assume that is “armhf” for these notes, but you can replace that with whatever suits your case best.)


7. Second Pass Snapping: Your Device

Device Setup

Open another terminal and ssh login to your device and from this login install the “mir-kiosk” snap.

snap install mir-kiosk

Now you should have a black screen with a white mouse cursor.

“mir-kiosk” provides the graphical environment needed for running a graphical snap.


8. Deploy the snap on the device

Push the snap you built to your device using your device’s SSH username & IP address details:

scp mir-kiosk-x11-example_0.1_armhf.snap <user>@<ip-address>:~

We now have the .snap file on the device in its home directory. We need to install the snap, configure it to talk Wayland to mir-kiosk and run the application. In your ssh session to your device:

snap install --dangerous ./mir-kiosk-x11-example_0.1_armhf.snap

On your device, you should see the same graphical animations you saw earlier. It will continue to run until you run “snap stop mir-kiosk-x11-example

Your device is now a kiosk! Rebooting will restart mir-kiosk and mir-kiosk-x11-example automatically.

Should you wish to share this snap, the next step would be to push your snap to the Snap Store. And, once you are satisfied that the snap is working well from the store, you should change the grade to stable so that you can publish to the “stable” channel:

- grade: devel
+ grade: stable

9. Congratulations

Congratulations, you have created your first graphical snap of an X11 app for Ubuntu Core.