diff options
author | Matthias Clasen <mclasen@redhat.com> | 2012-07-11 15:06:04 +0100 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2012-07-11 18:11:39 +0100 |
commit | 44189f8129edff56668cad6846579adc0e64f8f3 (patch) | |
tree | cd59904458b38f983769ddcf64837eeb24422219 /src | |
parent | 7bad068a2d9fbbd509d0a53bcf6c2ffde6a4ef77 (diff) | |
download | upower-44189f8129edff56668cad6846579adc0e64f8f3.tar.gz |
Use systemd for suspend and hibernate
When running under systemd, call into systemd for suspend and
hibernate instead of pm-utils. To capture resume events, install
a small script that gets executed by systemd after resume and
sends a dbus signal back to upower.
To make this work, the upower backends gain a new signal, ::resuming,
that they can optionally emit to signal that a resume happened.
Backends opt in to this by returning TRUE from up_backend_emits_resuming().
In this case, upower doesn't assume the sleep command to block until
resume, but instead waits for the ::resuming signal from the backend.
The only backend that uses this mechanism is the linux backend when
built with systemd support.
Signed-off-by: Richard Hughes <richard@hughsie.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 12 | ||||
-rw-r--r-- | src/dummy/up-backend.c | 6 | ||||
-rw-r--r-- | src/freebsd/up-backend.c | 6 | ||||
-rw-r--r-- | src/linux/Makefile.am | 3 | ||||
-rw-r--r-- | src/linux/up-backend.c | 67 | ||||
-rwxr-xr-x | src/notify-upower.sh | 6 | ||||
-rw-r--r-- | src/openbsd/up-backend.c | 6 | ||||
-rw-r--r-- | src/up-backend.h | 2 | ||||
-rw-r--r-- | src/up-daemon.c | 61 |
9 files changed, 145 insertions, 24 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 0166861..0bf1165 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -122,7 +122,13 @@ upowerd_LDADD += \ linux/libupshared.la \ $(USB_LIBS) \ $(GUDEV_LIBS) \ - $(IDEVICE_LIBS) + $(IDEVICE_LIBS) \ + $(SYSTEMD_LIBS) + +if HAVE_SYSTEMDUTILDIR +systemsleepdir = $(systemdutildir)/system-sleep +systemsleep_SCRIPTS = notify-upower.sh +endif if UP_BUILD_TESTS DBUS_LAUNCH=$(shell which dbus-launch) @@ -196,7 +202,7 @@ dbusconf_DATA = $(dbusconf_in_files:.conf.in=.conf) $(dbusconf_DATA): $(dbusconf_in_files) Makefile cp $< $@ -if HAVE_SYSTEMD +if HAVE_SYSTEMDSYSTEMUNITDIR systemdservicedir = $(systemdsystemunitdir) systemdservice_in_files = upower.service.in systemdservice_DATA = $(systemdservice_in_files:.service.in=.service) @@ -223,6 +229,8 @@ EXTRA_DIST = \ org.freedesktop.UPower.KbdBacklight.xml \ org.freedesktop.UPower.Wakeups.xml \ up-marshal.list \ + $(systemsleep_SCRIPTS) \ + $(systemdservice_in_files) \ $(dbusservice_in_files) \ $(dbusconf_in_files) diff --git a/src/dummy/up-backend.c b/src/dummy/up-backend.c index 834e37d..b860eff 100644 --- a/src/dummy/up-backend.c +++ b/src/dummy/up-backend.c @@ -297,3 +297,9 @@ up_backend_get_powersave_command (UpBackend *backend, gboolean powersave) { return "/bin/true"; } + +gboolean +up_backend_emits_resuming (UpBackend *backend) +{ + return FALSE; +} diff --git a/src/freebsd/up-backend.c b/src/freebsd/up-backend.c index e1dd22a..40e8b2b 100644 --- a/src/freebsd/up-backend.c +++ b/src/freebsd/up-backend.c @@ -326,6 +326,12 @@ up_backend_get_hibernate_command (UpBackend *backend) return UP_BACKEND_HIBERNATE_COMMAND; } +gboolean +up_backend_emits_resuming (UpBackend *backend) +{ + return FALSE; +} + /** * up_backend_kernel_can_suspend: **/ diff --git a/src/linux/Makefile.am b/src/linux/Makefile.am index 520b4cf..2081a66 100644 --- a/src/linux/Makefile.am +++ b/src/linux/Makefile.am @@ -12,7 +12,8 @@ INCLUDES = \ $(GUDEV_CFLAGS) \ $(POLKIT_CFLAGS) \ $(GLIB_CFLAGS) \ - $(IDEVICE_CFLAGS) + $(IDEVICE_CFLAGS) \ + $(SYSTEMD_CFLAGS) if BACKEND_TYPE_LINUX noinst_LTLIBRARIES = libupshared.la diff --git a/src/linux/up-backend.c b/src/linux/up-backend.c index be01763..ddd4472 100644 --- a/src/linux/up-backend.c +++ b/src/linux/up-backend.c @@ -45,6 +45,17 @@ #include "up-device-idevice.h" #endif /* HAVE_IDEVICE */ +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> + +#ifdef HAVE_SYSTEMD +#include <systemd/sd-daemon.h> + +#define SD_HIBERNATE_COMMAND "gdbus call --system --dest org.freedesktop.login1 --object-path /org/freedesktop/login1 --method org.freedesktop.login1.Manager.Hibernate 'true'" +#define SD_SUSPEND_COMMAND "gdbus call --system --dest org.freedesktop.login1 --object-path /org/freedesktop/login1 --method org.freedesktop.login1.Manager.Suspend 'true'" + +#endif + static void up_backend_class_init (UpBackendClass *klass); static void up_backend_init (UpBackend *backend); static void up_backend_finalize (GObject *object); @@ -59,11 +70,13 @@ struct UpBackendPrivate UpDeviceList *managed_devices; UpDock *dock; UpConfig *config; + DBusConnection *connection; }; enum { SIGNAL_DEVICE_ADDED, SIGNAL_DEVICE_REMOVED, + SIGNAL_RESUMING, SIGNAL_LAST }; @@ -564,6 +577,11 @@ out: const gchar * up_backend_get_suspend_command (UpBackend *backend) { +#ifdef HAVE_SYSTEMD + if (sd_booted ()) + return SD_SUSPEND_COMMAND; + else +#endif return UP_BACKEND_SUSPEND_COMMAND; } @@ -573,9 +591,24 @@ up_backend_get_suspend_command (UpBackend *backend) const gchar * up_backend_get_hibernate_command (UpBackend *backend) { +#ifdef HAVE_SYSTEMD + if (sd_booted ()) + return SD_HIBERNATE_COMMAND; + else +#endif return UP_BACKEND_HIBERNATE_COMMAND; } +gboolean +up_backend_emits_resuming (UpBackend *backend) +{ +#ifdef HAVE_SYSTEMD + return TRUE; +#else + return FALSE; +#endif +} + /** * up_backend_get_powersave_command: **/ @@ -609,10 +642,32 @@ up_backend_class_init (UpBackendClass *klass) G_STRUCT_OFFSET (UpBackendClass, device_removed), NULL, NULL, up_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); + signals [SIGNAL_RESUMING] = + g_signal_new ("resuming", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (UpBackendClass, resuming), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); g_type_class_add_private (klass, sizeof (UpBackendPrivate)); } +static DBusHandlerResult +message_filter (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + UpBackend *backend = user_data; + + if (dbus_message_is_signal (message, "org.freedesktop.UPower", "Resuming")) { + g_debug ("received Resuming signal"); + g_signal_emit (backend, signals[SIGNAL_RESUMING], 0); + return DBUS_HANDLER_RESULT_HANDLED; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + /** * up_backend_init: **/ @@ -624,6 +679,15 @@ up_backend_init (UpBackend *backend) backend->priv->daemon = NULL; backend->priv->device_list = NULL; backend->priv->managed_devices = up_device_list_new (); + +#ifdef HAVE_SYSTEMD + if (sd_booted ()) { + DBusGConnection *bus; + bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL); + backend->priv->connection = dbus_g_connection_get_connection (bus); + dbus_connection_add_filter (backend->priv->connection, message_filter, backend, NULL); + } +#endif } /** @@ -648,6 +712,9 @@ up_backend_finalize (GObject *object) g_object_unref (backend->priv->managed_devices); + if (backend->priv->connection) + dbus_connection_remove_filter (backend->priv->connection, message_filter, backend); + G_OBJECT_CLASS (up_backend_parent_class)->finalize (object); } diff --git a/src/notify-upower.sh b/src/notify-upower.sh new file mode 100755 index 0000000..d88ae5e --- /dev/null +++ b/src/notify-upower.sh @@ -0,0 +1,6 @@ +#!/bin/bash +[ "$1" = "post" ] && exec /usr/bin/dbus-send \ + --system --type=signal \ + --dest=org.freedesktop.UPower \ + /org/freedesktop/UPower \ + org.freedesktop.UPower.Resuming diff --git a/src/openbsd/up-backend.c b/src/openbsd/up-backend.c index 9d724ba..b25fb44 100644 --- a/src/openbsd/up-backend.c +++ b/src/openbsd/up-backend.c @@ -205,6 +205,12 @@ up_backend_get_hibernate_command (UpBackend *backend) return NULL; } +gboolean +up_backend_emits_resuming (UpBackend *backend) +{ + return FALSE; +} + /** * up_backend_kernel_can_suspend: **/ diff --git a/src/up-backend.h b/src/up-backend.h index 154e2c6..08dac8b 100644 --- a/src/up-backend.h +++ b/src/up-backend.h @@ -59,6 +59,7 @@ typedef struct void (* device_removed) (UpBackend *backend, GObject *native, UpDevice *device); + void (* resuming) (UpBackend *backend); } UpBackendClass; GType up_backend_get_type (void); @@ -75,6 +76,7 @@ const gchar *up_backend_get_suspend_command (UpBackend *backend); const gchar *up_backend_get_hibernate_command (UpBackend *backend); const gchar *up_backend_get_powersave_command (UpBackend *backend, gboolean powersave); +gboolean up_backend_emits_resuming (UpBackend *backend); G_END_DECLS diff --git a/src/up-daemon.c b/src/up-daemon.c index 6165fab..be416ab 100644 --- a/src/up-daemon.c +++ b/src/up-daemon.c @@ -380,8 +380,40 @@ typedef struct { UpDaemon *daemon; DBusGMethodInvocation *context; gchar *command; + gulong handler; } UpDaemonDeferredSleep; +static void +emit_resuming (UpDaemonDeferredSleep *sleep) +{ + UpDaemon *daemon = sleep->daemon; + UpDaemonPrivate *priv = daemon->priv; + + /* emit signal for session components */ + g_debug ("emitting resuming"); + g_signal_emit (daemon, signals[SIGNAL_RESUMING], 0); + g_signal_emit (daemon, signals[SIGNAL_NOTIFY_RESUME], 0, + priv->sleep_kind); + + /* reset the about-to-sleep logic */ + g_timer_reset (priv->about_to_sleep_timer); + g_timer_stop (priv->about_to_sleep_timer); + + /* actually return from the DBus call now */ + dbus_g_method_return (sleep->context, NULL); + + /* clear timer */ + priv->about_to_sleep_id = 0; + priv->sent_sleeping_signal = FALSE; + + /* delete temp object */ + if (sleep->handler) + g_signal_handler_disconnect (priv->backend, sleep->handler); + g_object_unref (sleep->daemon); + g_free (sleep->command); + g_free (sleep); +} + /** * up_daemon_deferred_sleep_cb: **/ @@ -396,7 +428,13 @@ up_daemon_deferred_sleep_cb (UpDaemonDeferredSleep *sleep) UpDaemon *daemon = sleep->daemon; UpDaemonPrivate *priv = daemon->priv; + if (up_backend_emits_resuming (priv->backend)) { + sleep->handler = g_signal_connect_swapped (priv->backend, "resuming", + G_CALLBACK (emit_resuming), sleep); + } + /* run the command */ + g_debug ("Running %s", sleep->command); ret = g_spawn_command_line_sync (sleep->command, &stdout, &stderr, NULL, &error_local); if (!ret) { error = g_error_new (UP_DAEMON_ERROR, @@ -408,32 +446,13 @@ up_daemon_deferred_sleep_cb (UpDaemonDeferredSleep *sleep) goto out; } - /* emit signal for session components */ - g_debug ("emitting resuming"); - g_signal_emit (daemon, signals[SIGNAL_RESUMING], 0); - g_signal_emit (daemon, signals[SIGNAL_NOTIFY_RESUME], 0, - priv->sleep_kind); - - /* reset the about-to-sleep logic */ - g_timer_reset (priv->about_to_sleep_timer); - g_timer_stop (priv->about_to_sleep_timer); - - /* actually return from the DBus call now */ - dbus_g_method_return (sleep->context, NULL); + if (!up_backend_emits_resuming (priv->backend)) + emit_resuming (sleep); out: - /* clear timer */ - priv->about_to_sleep_id = 0; - priv->sent_sleeping_signal = FALSE; - g_free (stdout); g_free (stderr); - /* delete temp object */ - g_object_unref (sleep->daemon); - g_free (sleep->command); - g_free (sleep); - return FALSE; } |