Silverblue at 1

It has been a bit more than a year that we’ve set up the Atomic Workstation SIG. A little later,  we settled on the name Silverblue, and did a preview release with Fedora 29.

The recent F30 beta release is an good opportunity to look back. What have we achieved?

When we set out to turn Atomic Workstation into an every-day-usable desktop, we had a list of items that we knew needed to be addressed. As it turns out, we have solved most of them, or are very close to that.

Here is an unsorted list.

Full Flatpak support

GNOME Software already had support for installing Flatpaks, a year ago, so this is not 100% new. But the support has been greatly improved with the port to libflatpak – GNOME Software is now using the same code as the Flatpak commandline. And  more recently, it learned to display information about sandbox permissions, so that users can see what level of system access the installed applications have.

This information is now also available in the new Application Settings panel. The panel also offers some control over permissions and lets you clean up storage per application.

A Flatpak registry

Flathub is a great place to find desktop applications – there are over 500 now. But since we can’t enable Flathub by default, we have looked for an alternative, and started to provide Flatpak apps in the Fedora container registry. This is taking advantage of Flatpaks support for the OCI format, and uses the Fedora module-build-system.

GNOME Software support for rpm-ostree

GNOME Software was designed as an application installer, but it also provides the UI for OS updates and upgrades. On a Silverblue system, that means supporting rpm-ostree. GNOME Software has learned to do this.

Another bit of functionality for which GNOME Software was traditionally talking to PackageKit is Addons. These are things that could be classified as system extensions: fonts, language support, shell extensions,, etc.  On a Silverblue system, the direct replacement is to use the rpm-ostree layering capability to add such packages to the OS image. GNOME Software knows how to do this now. It is not ideal, since you probably don’t expect to have to reboot your system for installing a font. But it gets us the basic functionality back until we have better solutions for system extensions.

Nvidia driver support

One class of system extensions that I haven’t mention in the previous section is drivers.  If you have an Nvidia graphics card, you may want the Nvidia driver to make best use of your hardware.  The situation with the Nvidia drivers is a little more complicated than with plain rpms, since the rpm needs to match your kernel, and if you don’t have the right driver, your system may boot to a black screen.

These complications are not unique to Silverblue, and the traditional solution for this in Fedora is to use the akmod system to build drivers that match your kernel. With Fedora 30, we put the necessary changes in place in rpm-ostree and the OS image to make this work for Silverblue as well.

Third-party rpms

Fedora contains a lot of apps, but there’s always the odd one that you can’t find in the repositories. A popular app in this category is the Chrome browser. Thankfully, Google provides an rpm that works on Fedora. But, it installs its content into /opt. That is not technically wrong, but causes a problem on Silverblue, since rpm-ostree has so far insisted on keeping packaged content under its tight control in /usr.

Ultimatively, we  want to see apps shipped as Flatpaks, but for Fedora 30, we have managed to get rpm-ostree to handle this situation, so chrome and similar 3rd party rpms can now be installed via package layering on Silverblue.

A toolbox

An important target audience for Fedora Workstation is developers. Not being able to install toolchains and libraries (because the OS is immutable) is obviously not going to make this audience happy.

The short answer is: switch to container-based workflows. Its the future!

But that doesn’t excuse us  from making these workflows easy and convenient for people who are used to the power of the commandline. So, we had to come up with a better answer, and started to develop the toolbox. The toolbox is a commandline tool to take the pain out of working with ‘pet’ containers. With a single command,

toolbox enter

it gives you a ‘traditional’ Fedora environment with dnf,  where you can install the packages you need. The toolbox has the infrastructure to manage multiple named containers, so you can work on different projects in parallel without interference.

Whats missing?

There are many bigger and smaller things that can still be improved – software is never finished. To name just a few:

  • Make IDEs work well with containers on an immutable OS
  • Codec availability and installation
  • Handle “difficult” applications such as virtualbox well
  • Find better ways to handle system extensions

But we’ve come a long way in the one year since I’ve started using Atomic Workstation as my day-to-day OS.

If you want to see for yourself, download the F30 beta image and give it a try!

Whats new in Flatpak 1.2

Time flies, Flatpak 1.0 was released four months ago.  Today we released the next major version, Flatpak 1.2. Lets take a look at what’s new.

New User Experience

A lot of effort since 1.0 has gone into improving the commandline user experience. This includes everything from better progress reporting to search and completion.

I’ve already written a detailed post about this aspect of the Flatpak 1.2 work, so I not going to say much more about it here.

Life-cycle control

1.2 includes new commands which make it easier to manage running Flatpaks.

Like other containers, Flatpaks are just regular processes, so traditional tools like ps and kill can be used with them. But there is often a bit more to a Flatpak sandbox than just a single process – there’s a babysitter, and D-Bus proxies,  and it can be a little daunting to identify the right process to kill, in a process listing.

To make this easy and obvious, we’ve added two new commands, flatpak ps and flatpak kill. For now, flatpak ps just lists basic information, but it is the natural place to show e.g. resource consumption in the future.

This functionality is available to other Flatpak front ends as well, in the form of the FlatpakInstance API in libflatpak.

Logging

Installing software is serious business, and it is well worth keeping a record of changes over time.

Flatpak now logs changes to installations and installed apps in the systemd journal. We take advantage of the capabilities offered by the journal, and write structured logs that contain useful fields like the affected remote, the commit IDs, and so on.

A particularly nice feature of the journal is that it keeps track of the originator of changes for us, so even if Flatpaks system-helper service is modifying the system installation, we still record the user who initiated the change.

You can of course use journalctl to study these logs. We also added a flatpak history command, which may be a bit more convenient, since it offers filtering and display that is more tailored to the specfics of Flatpak.

In the ecosystem

Portals are an important part of the Flatpak approach, and we’ve made releases of the portals to go along with the new Flatpak.  The 1.2 release of the portals brings a new location portal, a new portal for toolkit settings, respecting desktop lockdown settings, and better validation of input in all portals.

Flatpak itself also got some changes that will improve sandboxing in the future. One noteworthy change is that Flatpak will now bind dconf defaults and locks into the sandbox.  This will become useful with the next GLib release, when GSettings will no longer be using the dconf backend, allowing us to close an all-to-common sandbox hole.

In a similar vein, Flatpak is now creating a fontconfig configuration snipplet that will be used by a future fontconfig release to map font directories to their caches.

The common theme in these changes is that the libraries in the runtime need some changes to work well in a sandboxed setting. Getting these changes in place takes time, but we’re making steady progress.

Over the fence

On the desktop side, both GNOME Settings and GNOME Software will show Flatpak permissions in more detail in their upcoming releases.

Looking ahead

Now that Flatpak 1.2 is out, we are getting  ready to unveil a much-improved Flathub. Stay tuned!

Flatpak commandline design

Flatpak is made to run desktop apps, and there are apps like KDE Discover or GNOME Software that let you manage the Flatpak installations on your system.

Of course, we still need a way to handle Flatpak from the commandline. The flatpak commandline tool in 1.0 is powerful without being overwhelming (like git) and way friendlier than some other tools (for example, ostree).

But we can always do better. For Flatpak 1.2, we’ve gone back to the drawing board and did some designs for the commandline user experience (yes, that needs design too).

Powerful: Columns

Many Flatpak commands produce information in tabular form. You can list remotes, apps, documents, etc. And all these have a bunch information that can be displayed. It can be overwhelming when you only need a particular piece of information (and overflowing the available space in a terminal).

To help with that, we’ve introduced a –columns option which you select which information you want to see.

You can explore the available columns using –columns=help. In Flatpak 1.2, all the list-producing commands will support the –columns option: list, search, remotes, remote-ls, ps, history.

One nice side-effect of having –columns is that we can add more information to the output of these commands without overflowing the display, by adding optional columns that are not included in the default output.

Concise: Errors

It happens all the time, I want to type search, but my c key is sticky, and it comes out as searh. Flatpak used to react to unknown command by dumping out its –help option, which is long and a bit overwhelming.

Now we try to be more concise and more helpful at the same time, by making a guess at what was meant, and just pointing out the –help option.

Friendly: Search

In the same vein, the reverse-DNS style application ID that Flatpak relies on has been criticized as unwieldy and hard to handle. Nobody wants to type

flatpak install flathub org.gnome.meld

and commandline completion does not help too much if you have no idea what the application ID might be.

Thankfully, that is no longer necessary. With Flatpak 1.2, you can type

flatpak install meld

and Flatpak will ask you a few questions to confirm which remote to use and what exact application you meant. Much friendlier. This search also works for the uninstall command, and may be added to more commands in the future.

Informative: Descriptions

Flatpak repos contain appstream data describing the apps in detail. That is what e.g. GNOME Software uses on its detail page for an application.

So far, the Flatpak commandline has not used appstream data at all. But that is changing. In 1.2, a number of commands will show useful information from appstream data, such as the description shown here by the list and info commands:

If you pay close attention you may notice that column names can be abbreviated with –columns.

Fun: Prompts

Here’s the commandline version of theming. We now set a custom prompt. to let you know what context you are in when using a shell in a flatpak sandbox.

You can customize the prompt using

flatpak override --env=PS1="..."

The application ID for the sandbox is available in the FLATPAK_ID environment variable.

The beast: Progress

Updates and installs can take a long time – there are possibly big downloads and there may be dependencies that need to be updated as well, etc. For a good user experience it is  important to provide some feedback on the progress and the expected remaining time.

The Ostree library which Flatpak uses for downloads provides progress information, but it is very detailed and hard to digest.  To make this even more challenging, there is not that much space in a terminal window to display all the relevant information.

For 1.2, we’ve come up with  a combination of a table that gets updated to display overall status and a progress line for the current operation:

A similar, but simpler layout is used for uninstalls.

Coming Soon

All of these improvements will appear in Flatpak 1.2, hopefully very soon after the New Year. Something to look forward to.  📦📦📦

A PolicyKit refresher

PolicyKit has been around for a long time, and it is a mature system that basically does its job. I recently spent some time to improve the PolicyKit integration in Flatpak and thought it might be useful to write up some of the details.

Details, details

It is irritating when a dialog  pops up unexpectedly and asks questions without providing sufficient details to really know where it is coming from and what the context is. Like

Authentication is required to install software

It would be much better to say what software is being installed, and where it is coming from:

PolicyKit lets you do this by using variables in your message and providing the replacement for them via a PolkitDetails object:

Authentication is required to install $(ref) from $(origin)
polkit_details_insert (details, "origin", origin);
polkit_details_insert (details, "ref", ref);

No display – no problem

Its nice to get a  PolicyKit dialog when you are using a desktop app that needs to carry out a privileged operation. But PolicyKit is also used by commandline tools, such as flatpak. If you are running a command in a terminal, a dialog might still be ok. But what if you are using the flatpak on the console? A dialog is not available here, so privileged operations will fail.

PolicyKit provides the necessary plumbing to solve this situation, by letting apps register their own ‘agent’, which can handle authorization requests if no other agent is available. (In a graphical session, GNOME Shell provides an agent.)

Glancing over some details,  the code to do this looks roughly like this:

listener = polkit_agent_text_listener_new (NULL,
                                         &error);
polkit_agent_listener_register (listener,
            flags, subject, NULL, NULL, &error);

And it yields a result like this:If PolicyKits built-in text agent does not fit your needs, you can implement a PolkitAgentListener yourself. That is what I ended up doing for Flatpak.

Psst, don’t interrupt

As I said earlier, unexpected dialogs are annoying. Ideally, PolicyKit dialogs should only ever appear in response to a direct user action. For example, a dialog is ok if I am clicking the “Install” button in GNOME Software, but not if GNOME Software decides on it own that it is time to install some updates.

PolicyKit has a means to achieve this, by not passing the

POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION

flag when checking for authorization. But this check happens in the system service (or mechanism, in PolicyKit lingo), not in your client. In order to take advantage of this flag, the client needs to pass information about  user interaction along whenever it calls a privileged method of the mechanism.

In the Flatpak case, I added a ‘no-interaction’ flag to all the flatpak-system-helper methods, and library API that GNOME Software can use to set this flag for background operations.

So there should be less unexpected PolicyKit dialogs in the future.

Update: A useful PolicyKit feature that I forgot to mention is implications. If the the permissions (or actions, in PolicyKit lingo) are ordered in some way (e.g. if you are allowed to install applications, you should also be allowed to update them), you can express these relations with “imply” annotations. This can further reduce the need for duplicate dialogs.`

An update on Flatpak updates

A while ago, I’ve described how to handle restarting Flatpak apps when they are updated.

While I showed working code back then, the example was a bit  contrived, since it had to work around GApplication’s built-in uniqueness features.

With the just-landed support for replacement in GApplication, this is now much more straightforward, and I’ve updated my example to show how it works.

Restart yourself

There are a few steps to this.

First, we need to opt into allowing replacement by passing G_APPLICATION_ALLOW_REPLACEMENT when creating our GApplication:

app = g_object_new (portal_test_app_get_type (),
        "application-id", "org.gnome.PortalTest",
        "flags", G_APPLICATION_ALLOW_REPLACEMENT,
        NULL);

This flag makes GApplication handle a –gapplication-replace commandline option, which we will see in action later.

Next, we monitor the /app/.updated file. Flatpak creates this file inside a running sandbox when a new version of the app is available, so this is our signal to restart ourselves:

file = g_file_new_for_path ("/app/.updated");
update_monitor =
       g_file_monitor_file (file, 0, NULL, NULL);
g_signal_connect (update_monitor, "changed",
       G_CALLBACK (update_monitor_changed), win);

The update_monitor_changed function presents a dialog that offers the user to restart the app:

 if (response == GTK_RESPONSE_OK)
      portal_test_app_restart (app);

The portal_test_app_restart function is where we take advantage of the new GApplication functionality:

const char *argv[3] = {
    "/app/bin/portal-test",
    "--gapplication-replace",
    NULL
};

xdp_flatpak_call_spawn (flatpak, cwd, argv, ...);

We call the Spawn method of the Flatpak portal, passing –gapplication-replace as an commandline option, and everything else is handled for us. Easy!

Update 1: If D-Bus is not your thing, there is a simple commandline tool called flatpak-spawn that can be used for the same purpose. It is available inside the sandbox.

Update 2: I forgot to mention that GApplication has also gained a name-lost signal. It can be used to save state in the old instance that can then be loaded in the new instance.

Flatpak, after 1.0

Flatpak 1.0 has happened a while ago, and we now have a stable base. We’re up to the 1.0.3 bug-fix release at this point, and hope to get 1.0.x adopted in all major distros before too long.

Does that mean that Flatpak is done ? Far from it! We have just created a stable branch and started landing some queued-up feature work on the master branch. This includes things like:

  • Better life-cycle control with ps and kill commands
  • Logging and history
  • File copy-paste and DND
  • A better testsuite, including coverage reports

Beyond these, we have a laundry list of things we want to work on in the near future, including

  • Using  host GL drivers (possibly with libcapsule)
  • Application renaming and end-of-life migration
  • A portal for dconf/gsettings (a stopgap measure until we have D-Bus container support)
  • A portal for webcam access
  • More tests!

We are also looking at improving the scalability of the flathub infrastructure. The repository has grown to more than 400 apps, and buildbot is not really meant for using it the way we do.

What about releases?

We have not set a strict schedule, but the consensus seems to be that we are aiming for roughly quarterly releases, with more frequent devel snapshots as needed. Looking at the calendar, that would mean we should expect a stable 1.2 release around the end of the year.

Open for contribution

One of the easiest ways to help Flatpak is to get your favorite applications on flathub, either by packaging it yourself, or by convincing the upstream to do it.

If you feel like contributing to Flatpak itself,  please do! Flatpak is still a young project, and there are plenty of small to medium-size features that can be added. The tests are also a nice place to stick your toe in and see if you can improve the coverage a bit and maybe find a bug or two.

Or, if that is more your thing, we have a nice design for improving the flatpak commandline user experience that is waiting to be implemented.

On Flatpak dependencies

Package managers have to deal with dependencies – too many of them. Over time things have gotten complicated: there are now soft dependencies, reverse dependencies and boolean conditions. So complicated that you can probably do general computation in the dependency solver now.

Thankfully flatpak is a lot simpler: there’s apps, and there’s runtimes, and every app depends on exactly one runtime. Simple and beautiful.

Of course, thats not the whole story.  Lets take a look.

Dependencies

The only hard dependencies in Flatpak are between an app and the runtime that it uses.

Every app uses exactly one runtime. When installing the app, Flatpak will automatically install the runtime it needs, and it will refuse to uninstall the runtime as long as there are apps using it. You can override this using the –force-remove option.

Related refs

The common term Flatpak uses for apps and runtimes is refs. Apart from dependencies, Flatpak has a notion of related refs. These are what other packaging systems might classify as soft dependencies, and they come in various forms and shapes.

The first group are standard pieces that get split off at build time, like .Locale and .Debug refs. The first contain translations and are similar to what other packaging systems call langpacks. The second contain debug information for binaries, and are the equivalent of debuginfo packages in other systems.

The next group are extensions. Both applications and runtimes can declare extension points,  and flatpak will look for refs that match those when setting up a sandbox, and mounts the ones it finds inside the sandbox.

Some extensions are a bit more special, in that they are conditional on some condition of the system. For example, they might only be relevant if the system has an Nvidia GPU, or apply for a certain GTK+ theme.

Another kind of relationship exists between a runtime and its matching sdk.

Whats used ?

The Flatpak uninstall command has a –unused option that makes an educated guess about what refs are no longer needed on your system. For each ref, it looks if it is an application, or the runtime of an installed application, or related to one of these. In each of these cases, it considers the ref used and skips it. Whatever is left afterwards get removed.

There are some heuristics involved when looking at related refs, and we are still fine-tuning these. One change that we’re recently made is to consider sdks used, to make –unused usable for developers.

There is still more fine-tuning to be done. For example, Flatpak will happily use a runtime from the system installation to run an application from the user installation. But the uninstall command works only on a single installation, so it does not see these dependencies, and might remove the runtime. Thankfully, it is easy to recover, should this happen to you: just install the runtime again.

About Flatpak installations

If you have tried Flatpak, you probably know that it can install apps per user or system-wide.  Installing an app system-wide has the advantage that all users on the system can use it. Installing per-user has the advantage that it doesn’t require privileges.

Most of the time, that’s more than enough choice. But there is more.

Standard locations

Before moving on, it is useful to briefly look at where Flatpak installs apps by default.

flatpak install --system flathub org.gnome.Todo

When you install an app like this. it ends up in in /var/lib/flatpak. If you instead use the –user option, it ends up in ~/.local/share/flatpak. To be 100% correct, I should say $XDG_DATA_HOME/flatpak, since Flatpak does respect the XDG basedir spec.

Anatomy of an installation

Flatpak calls the places where it installs apps installations. Every installation has a few subdirectories that are useful to know:

  • repo – this is the OSTree repository where the files for the installed apps and runtimes reside. It is a single repository, so all the apps and runtimes that are part of the same installation get the benefit of deduplication via content-addressing.
  • exports – when an app is installed, Flatpak extracts some files that need to be visible to the outside world, such a desktop files, icons, D-Bus services files, and this is where they end up.
  • appstream – a flatpak repository contains the appstream data for the apps it contains as a separate branch, and Flatpak extracts it on the client-side for consumers like KDE’s Discover or GNOME Software.
  • app, runtime – the deployed versions of apps and runtimes get checked out here. Diving deeper, you see the files of an app in app/org.gimp.GIMP/current/active/files. This directory is what gets mounted in the sandbox as /app if you run the GIMP.

Custom installations

So far, so good. But maybe you have a setup with dozens of machines, and have an existing setup where /opt is shared. Wouldn’t it be nice to have a flatpak installation there, instead of duplicating it in /var on every machine ? This is where custom installations come in.

You can tell Flatpak about another place to  install apps by dropping a file in /etc/flatpak/installations.d/. It can be as simple as the following:

[Installation "bigleaf"]
Path=/opt/flatpak
DisplayName=bigleaf

See the flatpak-installation man page for all the details about this file.

GNOME Software currently doesn’t know such custom installations, and you will have to adjust the shell glue in /etc/profile.d/flatpak.sh for GNOME shell to see apps from there, but that is easy enough.

A patch to make flatpak.sh pick up custom installations automatically would be a welcome contribution!

Apps on a stick

Flatpak has a few more tricks up its sleeve when it comes to sharing apps between machines. A pretty cool one is the recently added create-usb command. It lets you copy one (or more) apps on a usb stick, and install it from there on another machine. While trying this out, I hit a few hurdles, that I’ll briefly point out here.

To make this work, Flatpak relies on an extra piece of information about the remote, the collection ID. The collection ID is a property of the actual remote repository. Flathub has one, org.flathub.Stable.

To make use of it, we need to add it to the configuration for the remote, like this:

$ flatpak remote-modify --collection-id=org.flathub.Stable flathub
$ flatpak update

If you don’t add the collection ID to your remote configuration, you will be greeted by an error saying “Remote ‘flathub’ does not have a collection ID set”. If you omit the flatpak update, the error will say “No such branch (org.flathub.Stable, ostree-metadata) in repository”.

Another error you may hit is “fsetxattr: Operation not supported”.  I think the create-usb command is meant to work with FAT-formatted usb sticks, so this will hopefully be fixed soon. For now, just format your usb stick as EXT4.

After these preparations, we are ready for:

$ flatpak --verbose create-usb /run/media/mclasen/Flatpak org.gimp.GIMP

which will take some time to copy things to the usb stick (which happes to be mounted at /run/media/mclasen/Flatpak) . When this command is done, we can inspect the contents of the OSTree repository like this:

$ flatpak remote-ls file:///run/media/mclasen/Flatpak/.ostree/repo
Ref 
org.freedesktop.Platform.Icontheme.Adwaita
org.freedesktop.Platform.VAAPI.Intel 
org.freedesktop.Platform.ffmpeg 
org.gimp.GIMP 
org.gnome.Platform

Flatpak copied not just the GIMP itself, but also runtimes and extensions that it uses. This ensures that we can install the app from the usb stick even if some of these related refs are missing on the target system.

But of course, we still need to see it work! So I uninstalled the GIMP, disabled my network, plugged the usb stick back in, and:

$ flatpak install --user flathub org.gimp.GIMP
0 metadata, 0 content objects imported; 569 B transferred in 0 seconds

flatpak install: Error updating remote metadata for 'flathub': [6] Couldn't resolve host name
Installing in user:
org.gimp.GIMP/x86_64/stable flathub 1eb97e2d4cde
permissions: ipc, network, wayland, x11
file access: /tmp, host, xdg-config/GIMP, xdg-config/gtk-3.0
dbus access: org.gtk.vfs, org.gtk.vfs.*
Is this ok [y/n]: y
Installing for user: org.gimp.GIMP/x86_64/stable from flathub
[####################] 495 metadata, 4195 content objects imported; 569 B transferred in 1 seconds
Now at 1eb97e2d4cde.

Voilà, an offline installation of a Flatpak. I left the error message in there as proof that I was actually offline :) A nice detail of the collection ID approach is that Flatpak knows that it can still update the GIMP from flathub when I’m online.

Coming soon, peer-to-peer

This post is already too long, so I’ll leave peer-to-peer and advertising Flatpak repositories on the local network via avahi for another time.

Until then, happy Flatpaking! 💓📦💓📦

 

Flatpak portal experiments

One of the signs that a piece of software is reaching a mature state is its ability to serve  use cases that nobody had anticipated when it was started. I’ve recently had this experience with Flatpak.

We have been discussing some possible new directions for the GTK+ file chooser. And it occurred to me that it might be convenient to use the file chooser portal as a way to experiment with different file choosers without having to change either GTK+ itself or the applications.

To verify this idea, I wrote a quick portal implementation that uses the venerable GTK+ 2 file chooser.

Here is Corebird (a GTK+ 3 application) using the GTK+ 2 file chooser to select an image.

On Flatpak updates

Maybe you remember times when updating your system was risky business – your web browser might crash of start to behave funny because the update pulled data files or fonts out from underneath the running process, leading to fireworks or, more likely, crashes.

Flatpak updates on the other hand are 100% safe. You can call

 flatpak update

and the running instances of are not affected in any way. Flatpak keeps existing deployments around until the last user is gone.  If you quit the application and restart it, you will get the updated version, though.

This is very nice, and works just fine. But maybe we can do even better?

Improving the system

It would be great if the system was aware of the running instances, and offered me to restart them to take advantage of the new version that is now available. There is a good chance that GNOME Software will gain this feature before too long.

But for now, it does not have it.

Do it yourself

Many apps, in particular those that are not native to the Linux distro world, expect to update themselves, and we have had requests to enable this functionality in flatpak. We do think that updating software is a system responsibility that should be controlled by global policies and be under the users control, so we haven’t quite followed the request.

But Flatpak 1.0 does have an API that is useful in this context, the “Flatpak portal“. It has a Spawn method that allows applications to launch a process in a new sandbox.

Spawn (IN  ay    cwd_path,
       IN  aay   argv,
       IN  a{uh} fds,
       IN  a{ss} envs,
       IN  u     flags,
       IN  a{sv} options,
       OUT u     pid)

There are several use cases for this, from sandboxing thumbnailers (which create thumbnails for possibly untrusted content files) to sandboxing web browser tabs individually. The use case we are interested in here is restarting the latest version of the app itself.

One complication that I’ve run into when trying this out is the “unique application” pattern that is built into GApplication and similar application classes: Since there is already an owner for the application ID on the session bus, my newly spawned version will just back off and exit. Which is clearly not what I intended in this case.

Make it stop

The workaround I came up with is not very pretty, but functional. It requires several parts.

First, I need a “quit” action exported on the session bus. The newly spawned version will activate this action of the running instance to convince it to go away. Thankfully, my example app already had this action, for the Quit item in the app menu.

I don’t want this to happen unconditionally, but only if I am spawning a new version. To achieve this, I made my app only activate “quit” if the –replace option is present, and add that option to the commandline that I pass to the “Spawn” call.

The code for this part is less pretty than it could be, since GApplication gets in the way a bit. I have to manually check for the –replace option and do the “quit” D-Bus call by hand.

Doing the “quit” call synchronously is not quite enough to avoid a race condition between the running instance dropping the bus name and my new instance attempting to take it. Therefore, I explicitly wait for the bus name to become unowned before entering g_application_run().

But it all works fine. To test it, i exported a “restart” action and added it to the app menu.

Tell me about it

But who can remember to open the app menu and click “Restart”. That is just too cumbersome. Thankfully, flatpak has a solution for this: When you update an app that is running, it creates a marker file named

/app/.updated

inside the sandbox for each running instance.

That makes it very easy for the app to find out when it has been updated, by just monitoring this file. Once the file appears, it can pop up a dialog that offers the user to restart the newer version of the app. A good quality implementation of this will of course save and restore the state when doing this.

Voilá, updates made easy!

You can find the working example in the portal-test repository.

css.php