Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flatpak: Stop time tracking on shutdown (using systemd) #684

Open
salim-b opened this issue Jul 9, 2021 · 7 comments
Open

Flatpak: Stop time tracking on shutdown (using systemd) #684

salim-b opened this issue Jul 9, 2021 · 7 comments

Comments

@salim-b
Copy link
Contributor

salim-b commented Jul 9, 2021

Goal

I've tried to hack together an alternative for the removed GNOME session idle detection running the Hamster Flatpak app (GH actions artifact).

I'm using Ubuntu 20.04, but I think all the stuff described below should apply to any recent Linux distro that uses systemd and GNOME 3.

The approach basically consists of

  1. a bash script that regularly polls user session inactivity from GNOME's window manager Mutter and stops time tracking if the specified threshold is reached and resumes time tracking as soon as user activity is detected again. This works fine. The script is found here.

  2. some more scripts to run from systemd service units with the goal of a) stopping time tracking when the system is powered off and b) suspending and resuming time tracking before and after the system is put to sleep. While b) works fine, a) doesn't do what it's supposed to.

Details

For the second point above, consider the following bash script /usr/local/bin/hamster_tracking/hamster_stop.sh and systemd service unit /etc/systemd/system/hamster_stop.service that executes the former before the system powers off:

hamster_stop.sh
#!/bin/bash

# abort if Hamster Flatpak is not available
if ! command -v flatpak >/dev/null || ! flatpak list --app | grep -q 'org\.gnome\.Hamster'; then
  echo "The Hamster Flatpak is required in order for this script to work, but is not installed. Aborting."
  exit 1
fi

# stop current Hamster activity
current_activity=`flatpak run org.gnome.Hamster current`

if [[ ${current_activity} != "No activity" ]] ; then
  current_activity=`echo ${current_activity} | grep -oP '\S+@\S+'`
  if [[ -f /tmp/last_hamster_activity.txt ]] ; then rm /tmp/last_hamster_activity.txt ; fi
  flatpak run org.gnome.Hamster stop
  notify-send --category=presence.offline --icon=org.gnome.Hamster.GUI "${current_activity} stopped" "Stopped time tracking at `date +"%T"` due to system shutdown."
fi
hamster_stop.service
[Unit]
Description=Stop Hamster activity on system power off
Conflicts=reboot.target
After=user.slice

[Service]
Type=oneshot
RemainAfterExit=true
User=salim
Environment="DISPLAY=:0" "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus"
ExecStart=/usr/bin/true
ExecStop=/usr/local/bin/hamster_tracking/hamster_stop.sh

[Install]
WantedBy=user.slice

Test

  1. Place the above two files at the mentioned filesystem locations and make the bash script executable (sudo chmod +x /usr/local/bin/hamster_tracking/hamster_stop.sh).

  2. In /etc/systemd/system/hamster_stop.service, replace salim with your actual username and 1000 with your actual user ID (UID).

  3. Activate the above service unit using

    sudo systemctl enable hamster_stop.service
  4. Either reboot or manually start the above service unit using:

    sudo systemctl start hamster_stop.service

Problem

My main problem now is: Although the systemd unit hamster_stop.service seems to basically work – tested by a) manually starting and stopping it using sudo systemctl start hamster_stop.service; sudo systemctl stop hamster_stop.service and b) writing a string to file instead of running hamster_stop.sh in ExecStop= – neither flatpak run org.gnome.Hamster stop nor notify-send in hamster_stop.sh seem to work as supposed.

The cause of Hamster not stopping is most probably that systemd already killed the process responsible for the Hamster Flatpak at the time hamster_stop.service is stopped.

Running something on shutdown before systemd starts to kill a specific user process is already tricky. But at least the systemd unit belonging to a specific process ID (PID) can be determined using systemctl status <PID>. Then this unit can be configured as a reverse ordering dependency of a "on shutdown" unit (i.e. putting it in After=). But for the Hamster-related Flatpak processes on my system, systemctl status always revealed only [email protected] which is simply the instance responsible for starting user processes. Setting [email protected] (together with [email protected]) didn't help.

Statements from 2016, 2017 and even systemd author Lennart Poettering himself in 2020 seem to indicate this is impossible to solve with current systemd... ☹

Note that I've put together more stuff I've learned in relation to this venture in this README.

Thanks in advance for any help!

@salim-b salim-b changed the title Flatpak: Run from systemd service unit Flatpak: Stop time tracking on shutdown (using systemd) Jul 10, 2021
@salim-b
Copy link
Contributor Author

salim-b commented Jul 10, 2021

Meanwhile I could solve the original problem – now facing another one – and thus completely overhauled my initial post above as well as the issue title.

@tchernobog
Copy link
Contributor

tchernobog commented Jul 10, 2021

Assuming that what you want is to run hamster for your user "salim", you should be at least using user units in $HOME/.config/systemd/user, and call systemctl with the --user flag. That would remove "sudo" from the equation. And also take in account the use case of the user logging out without rebooting.

I also think a better approach would be to use a DBus message via dbus-send. I believe that would simplify the logic of what you are trying to do. I did not try, but I believe org.gnome.Hamster.StopTracking(Int32 end_time) should do what you need.

@salim-b
Copy link
Contributor Author

salim-b commented Jul 10, 2021

Assuming that what you want is to run hamster for your user "salim", you should be at least using user units in $HOME/.config/systemd/user, and call systemctl with the --user flag. That would remove "sudo" from the equation.

Yeah, initially I thought the same. But this is not possible in the current systemd world – at least not for sleep/shutdown/etc.-related stuff – because "'user' instances currently have no way to depend on systemwide services".

Besides, sudo is not the issue here. :)

I also think a better approach would be to use a DBus message via dbus-send. I believe that would simplify the logic of what you are trying to do. I did not try, but I believe org.gnome.Hamster.StopTracking(Int32 end_time) should do what you need.

Awesome, thanks for pointing out this alternative! I'll test this.

Is there also a D-Bus message/call to query the currently running Hamster activity? Or – more generally – where is Hamster's D-Bus service API documented?

@salim-b
Copy link
Contributor Author

salim-b commented Jul 10, 2021

And also take in account the use case of the user logging out without rebooting.

Good point. I didn't think about this yet (rather irrelevant for my use case since I'm the only user on my system).

@GeraldJansen
Copy link
Contributor

See https://github.com/projecthamster/hamster/blob/master/src/hamster-service.py for Hamster's D-Bus service API.
You can check the last element of GetTodaysFactsJSON(): no end time means the last activity is ongoing. Anyway StopTracking will do nothing if there is no ongoing activity, so you can just call it without checking (use end_time 0 for current time).

@GeraldJansen
Copy link
Contributor

Perhaps you could use dbus-monitor to listen for org.freedesktop.login1 PrepareForShutdown and PrepareForSleep signals? Maybe they get sent before your flatpak hamster process gets killed. (Warning: I know nothing about this stuff!)

@tchernobog
Copy link
Contributor

I don't think this ticket is a proper issue with Hamster itself. I'd like to see it closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants