How to autostart a snap of a desktop application?

2_32

#1

There are several ISVs working on snaps of their applications that offer an option to launch the application when you login to your desktop environment.

This is achieved by dropping a .desktop file in ~/.config/autostart but due to the way the home interface redefines the home directory location these autostart entries are not being “seen” by desktop environments and therefore ignored.


Making a snap auto-start
New snap: Nextcloud Client
Home access as root from confined snaps
Multiple users and groups in snaps
Home access as root from confined snaps
#2

We don’t want uncontrolled access to this directory with no sanitizing of the desktop file. There are at least a few options OTOH:

  1. expose this as a toplevel concept in snap.yaml (eg, as an interface)
  2. add something like a meta/autostart/*.desktop concept where we perform all the same sanitizing on the desktop file as we do in /var/lib/snapd/desktop/applications
  3. think about this in terms of the in progress (but paused) desktop session services and activation work
  4. add a ‘snap session-autostart foo.bar’ command to do this for the user

Perhaps there are other options but the main point is this needs design.


#3

is the desktop file to be dropped in autostart exactly the same as the regular desktop file?


#4

I think it’s just the same desktop file. We might easily allow flagging particular applications as autostart and copy or link the file in the right place.

We just need to figure what’s the proper way to do that for all users. Would it be okay to drop the file in /etc/xdg/autostart or does it have to be in the user’s home directory? If we need to have it on every user’s home, then one option would be having the user daemon (snap userd) doing that.


#5

My go-to example for this:

It sounds like all of our options break the ability to use that user-friendly check box. Correct?


#6

@kyrofa Yes, you are correct.


#7

That’s unfortunate.

Naive question: how terrible would it be for snapd to setup inotify on ~/snap/*/*/.config/autostart to get pinged when an application drops a .desktop file there? Then snapd can sanitize it and copy it to the correct place (~/.config/autostart/). And do the opposite if it’s removed. That would enable the “simple check box” use-case without requiring that part of the software to be rewritten.


#8

I think it depends on what we are trying to achieve. From the title ‘How to autostart a snap of a desktop application’ I’m going to assume we are simply talking about getting something started and not ‘session services’ or ‘dbus activation of session services’. Leaving session services out of this…

For /etc/xdg/autostart vs ~/.config/autostart, I think it depends. In the deb/rpm world, /etc/xdg/autostart is of course owned by root:root, so the only way applications develeopers could put things there is via packaging install scripts. Some applications are written to have more control and instead they do not ship anything in the deb/rpm for /etc/xdg/autostart and instead on launch by the user, drop something in ~/.config/autostart. I think we would need to allow for both tbh, to accommodate existing software. Unfortunately, while ‘xdg-autostart’ appears to be a thing, it isn’t something that most software uses (ie, it isn’t installed by default).

I think we’d need to work through the design of the feature for how to handle it. For example, it is clear that we would want to generate the desktop files like we do in /var/lib/snapd/desktop/applications.

Less clear is if we want to support something like meta/snap/gui-autostart/foo.desktop (or similar) and just put the file in /etc/xdg/autostart unconditionally, controlled via an interface (and whether that is manual or auto-connected) or controlled via a new ‘snap autostart’ command like we do with aliases (that might have snap declaration support).

Even less clear is how to support ~/.config/autostart since xdg-autostart isn’t readily available and applications like Dropbox will just write to there (and most of the time they would be written to ~/snap/name/version/.config/autostart which is of course allowed, but not picked up by the session). From an isolation POV, we could allow writes to REALHOME/.config/autostart/snap_name_*.desktop (likely controlled via an interface). I can say that both of these worked in 16.04 LTS with Unity (ie, whether symlink or copy, snap_name_....desktop worked):

  • ln -s /var/lib/snapd/desktop/applications/gnome-clocks_gnome-clocks.desktop ~/.config/autostart/snap_gnome-clocks_gnome-clocks.desktop
  • cp /var/lib/snapd/desktop/applications/gnome-clocks_gnome-clocks.desktop ~/.config/autostart/snap_gnome-clocks_gnome-clocks.desktop

Someone from the desktop team would likely need to verify that a differently-named desktop file like this works in other desktop environments.

While writing this I had another idea-- perhaps the snap ships an autostart desktop file (eg, meta/snap/gui-autostart/foo.desktop) and on install snapd puts it in /var/lib/snapd/desktop/autostart/foo_foo.desktop. Then on userd start it looks in /var/lib/snapd/desktop/autostart for missing desktop files, checks if ~/.config/autostart/snap_foo_foo.desktop exists and if not, prompts the user if it should create it (remembering when the user says no). The user can later change her mind via 'snap autostart foo`. This would remove the need for /etc/xdg/autostart or any requirement for direct access to the autostart directories.


#9

This has similar usability as the current non-snap autostart functionality-- specifically, you need to restart your session to have it autostart.


#10

We discussed this during the standup and the current thinking is the following:

  • we have snap userd which is designed to run in the user session
  • when snap userd starts as part of the session startup it can check for ~/snap/*/current/.config/autostart/*.desktop- for each desktop file it need to “sanitize” the content, i.e. ensure
    that the desktop file calls a snap command from the “foo” snap for
    ~/snap/foo/current/.config/autostart - this may require tweaks for
    the apps to write the right command (however if the snap is “foo” and
    has a “Exec=foo --autostart” line things will work)
  • with this sanitized content we can just launch the app from snap userd on session startup.

The above still requires some work:

  • snap userd is currently a dbus session service so it wakes up when it is used via e.g. io.snapcraft.Launcher but not started when the session starts. we need to make this work (maybe by just dropping a desktop file into /etc/xdg/autostart that launches snapd userd).
  • the code to read/execute the autostart desktop files needs to be written

#11

snapd as part of snap install has code to take a desktop file from the snap and sanitize it before writing it out to /var/lib/snapd/desktop/applications. It seems appropriate to reuse this code in userd so that it reads the file to autostart and sanitizes in memory before launching the Exec line.

Curious if you considered the alternate approach of splatting that sanitized file out to the real ~/.config/autostart and if so, why this approach? This means userd doesn’t have to do any launching itself, but does mean it needs to notice new files in ~/snap/foo/curent/.config/autostart so the snap is autostarted on the next session start. (Note: I’m not stating a preference for either atm, just curious about the thinking).


#12

Has there been any consideration regarding autostart items that are system-wide (all users)?


#13

Hello everyone,
would you please have any update on this topic? It actually seems to be quite important when we want to provide seamless experience to the users.

Thank you,

Jonas


#14

It’s likely that more programs - especially GNOME programs but also probably others - will in the near future use systemd units to get themselves started in the session. You’ll still want to support autostart desktop files too, but I wonder if there is any support, either already in place or planned, for systemd user services?

There could be a few kinds of service-

  • Those which install themselves WantedBy (etc.) some unit that’s started with the session, akin to XDG autostart
  • Session D-Bus services with SystemdService in their .service file
  • Units that get activated some other way (.path units for example)

I think they’d all be handled in the same way - exposed to the user service manager but probably mediated by snapd in some way. Like you’d probably want to be careful about who can install .path units and what for. Maybe this is already all addressed for system units and could be reused - not sure. :slight_smile:


#15

The plan described by @mvo above is still current, and we hope to work on this soon. We have a few important features being worked on right now, but I expect that very soon have more bandwidth for this and similar tasks once the other features are released.


#16

Spent some time investigating this today Here are the notes I took in the process:

systemd unit

  • nice & clean idea
  • potential cross-distro integration issues
  • need to access XAUTHORITY, DISPLAY
    • usual way is to do is call systemctl --user import-environment XAUTHORITY DISPLAY
    • automatically done by /etc/X11/xinit/xinitrc.d/50-systemd-user.sh
    • helper is shipped by Arch, Fedora, OpenSUSE
    • not shipped by Ubuntu and Debian, see https://salsa.debian.org/systemd-team/systemd/blob/master/debian/rules#L201 (anyone has a clue as to why?)
    • went through gdm source code, AFAIU the xinitrc.d files are run early in the startup process and the imports will happen before the DE is running
  • I can’t figure out when the ‘user’ units start wrt. applications started by the session (eg. gdm-x-session/gnome-session-binary), my guess is ‘before’, but it would be great if someone knowledgeable could confirm that
  • I had some initial hopes for graphical-session.target, but it does not seem to be activated/used at all
  • prototyped a helper that starts as a user unit for all users, seems to work (16.04 as well)

userd as snap-userd.desktop

  • should work fine, with the exception
  • disable startup notification
  • exit once applications are started
  • there are some graphical tools to control what is started and what is not, those will not work anymore
  • still need to consider the contents of snap desktop files

*.desktop files

  • need to whitelist DE specific entries: eg. X-GNOME-*, X-KDE-*
  • should we interpret specific settings? eg. X-GNOME-Autostart-Delay, X-GNOME-Autostart-Phase=Initialieation (this one is peculiar)
  • interpret OnlyShowIn & friends
  • feels a bit complicated

some alternatives to consider

  • if we could ensure that ‘user’ units run early in the process, we could rewrite the desktop files before the DE starts
  • drop a script that calls userd in xinitrc.d that call userd to populate desktop entries (what about wayland?)

#17

Small update. When working on this feature I stumbled upon some problems matching the autostart files with respective snap apps.

Original desktop file shipped by snap (/var/lib/snapd/snap/discord/current/meta/gui/discord.desktop):

[Desktop Entry]
Name=Discord
StartupWMClass=discord
Comment=All-in-one voice and text chat for gamers that's free, secure, and works on both your desktop and phone.
GenericName=Internet Messenger
Exec=discord %U
Icon=${SNAP}/usr/share/discord/discord.png
Type=Application
Categories=Network;InstantMessaging;

Generated by snapd during installation (/var/lib/snapd/desktop/applications/discord_discord.desktop):

[Desktop Entry]
Name=Discord
StartupWMClass=discord
Comment=All-in-one voice and text chat for gamers that's free, secure, and works on both your desktop and phone.
GenericName=Internet Messenger
Exec=env BAMF_DESKTOP_FILE_HINT=/var/lib/snapd/desktop/applications/discord_discord.desktop /var/lib/snapd/snap/bin/discord %U
Icon=/var/lib/snapd/snap/discord/52/usr/share/discord/discord.png
Type=Application
Categories=Network;InstantMessaging;

Dropped by discord when I enabled autostart, the file is ~/snap/discord/current/.config/autostart/discord-stable.desktop (NOTE the file name is not even named discord.desktop)

[Desktop Entry]
Type=Application
Exec=/snap/discord/52/usr/share/discord/Discord
Hidden=false
NoDisplay=false
Name=Discord
Icon=/snap/discord/52/usr/share/discord/discord.png
Comment=Text and voice chat for gamers.
X-GNOME-Autostart-enabled=true

The Exec=/snap/discord/52/usr/share/discord/Discord stanza is not usable for autostart and looks more like a dump of whatever /proc/self/exe pointed to.

For now I have attempted to explore the idea of matching the application with a snap using its desktop file name. It goes like this:

  1. application foo drops a file named foo.desktop into ~/snap/my-snap/current/.config/autostart, hence we assume snap is my-snap, app is foo
  2. upon seeing the file we determine the snap name and try to locate a file /var/lib/snapd/snap/desktop/applications/my-snap_foo.desktop
    • the file was already patched when the snap was getting installed, so it contains a proper Exec line that references the wrapper /snap/bin/foo
  3. grab the Exec line from autogenerated desktop file, run it
    • special Exec flags such as %U, %c are filtered out
    • no attempt to look at other flags is done, (eg. X-GNOME-Autorstart-enable is ignored)

Clearly this approach of matching snap/app with whatever was dumped into autostart directory involves some guesswork. I have opened a RFC pull request https://github.com/snapcore/snapd/pull/4759

Let’s discuss other options.


#18

My suggestion would be to add a per-app autostart (or perhaps user-autostart? userd/autostart? Something more involved?) to the yaml, and when the user’s session starts we look to see if that file exists, and if so, we start the associated app.

As an example and/or strawman:

apps:
  foo:
    command: foo
    userd:
      autostart-if-exists: .config/autostart/foo.desktop

(of course my personal preference would be to try to go with something less nested at first, but I’m just exploring things here).

I like it because there’s no parsing of the file involved, no guessing, no matching heuristics, nothing. It’d be purely declarative.

Note this supports this use case, but also simpler cases with no desktop files involved at all.

Also note the app doesn’t need to be the exact same one that ships the desktop file, so you could have different options in there (but why would you do that :slight_smile: ).


#19

That’s a good idea. The non-trivial heuristics will cause pain forever otherwise, while we try to accommodate magic matching to the real world.

We might be able to go with something simpler as you suggest, and have sane defaults. Perhaps:

apps:
  foo:
    command: foo
    autostart: foo.desktop

The semantics might be:

  1. When the user session starts, look into ~/snap/*/current/.config/autostart/

  2. If filename matches the value of the field in one of the snap commands, then process the file

  3. The Exec line in the file is parsed out, and the snap command is run

  4. If the Exec value is “some/command -a -b”, the equivalent snap command would be “snap run theapp -a -b”.

What do you think? Anything else we need to cover?

Note that this method opens the door to having autostart: true in the future, or autostart: maybe :slight_smile: which would allow having the same functionality without the requirement of having the desktop files.


#20

Not sure which definition of ‘usable’ you meant but for clarity, if it could be made runnable it would not be viable for snapd since this isn’t using ‘snap run’ or ‘/snap/bin/discord’ and therefore would run outside of confinement.