summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2012-07-11 15:06:04 +0100
committerRichard Hughes <richard@hughsie.com>2012-07-11 18:11:39 +0100
commit44189f8129edff56668cad6846579adc0e64f8f3 (patch)
treecd59904458b38f983769ddcf64837eeb24422219 /src
parent7bad068a2d9fbbd509d0a53bcf6c2ffde6a4ef77 (diff)
downloadupower-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.am12
-rw-r--r--src/dummy/up-backend.c6
-rw-r--r--src/freebsd/up-backend.c6
-rw-r--r--src/linux/Makefile.am3
-rw-r--r--src/linux/up-backend.c67
-rwxr-xr-xsrc/notify-upower.sh6
-rw-r--r--src/openbsd/up-backend.c6
-rw-r--r--src/up-backend.h2
-rw-r--r--src/up-daemon.c61
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;
}