From 7d851ddb5d84b1a24255906a301b71ea7350b811 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Thu, 18 Nov 2021 13:14:51 +0900 Subject: [PATCH] power: add internal function for deferring sleep Someone who wants to defer sleep can now request for deferring sleep to system using device_power_add_sleep_callback(). The callback is invoked when the system is going to sleep. Do your todo list for sleep in this callback, and return DEVICE_SLEEP_READY, which notifies the system you are ready to sleep. Change-Id: I5dfbe60abbfaa30991124cfd5eea243f85a80d02 Signed-off-by: Youngjae Cho --- include/power-internal.h | 17 ++++++ src/power-internal.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 src/power-internal.c diff --git a/include/power-internal.h b/include/power-internal.h index 294c765..dde31b7 100644 --- a/include/power-internal.h +++ b/include/power-internal.h @@ -21,6 +21,9 @@ extern "C" { #endif +#include +#include + /** * @platform * @brief Power off the device. @@ -37,6 +40,20 @@ extern "C" { */ int device_power_poweroff(void); +enum sleep_ready { + DEVICE_SLEEP_READY, + DEVICE_SLEEP_NOT_READY, +}; + +/* This callback is invoked when system is going to sleep. + * Return DEVICE_SLEEP_READY to notify system that I am ready to sleep. + * sleep_time_ms: realtime in milisecond when the sleep signal emitted */ +typedef int (*sleep_callback) (guint64 sleep_time_ms, void *user_data); + +/* return DEVICE_ERROR_NONE on success */ +int device_power_add_sleep_callback(sleep_callback cb, void *user_data); +void device_power_remove_sleep_callback(void); + #ifdef __cplusplus } #endif diff --git a/src/power-internal.c b/src/power-internal.c new file mode 100644 index 0000000..2a01a33 --- /dev/null +++ b/src/power-internal.c @@ -0,0 +1,145 @@ +#include +#include +#include + +#include "power-internal.h" +#include "common.h" + +#define SLEEP_DBUS_SIGNAME "sleep" +#define DBUS_METHOD_SYNC_CALL_TIMEOUT_MS 10000 /* 10 second */ + +struct userdata { + void *data; + sleep_callback callback; +}; + +static int signal_subscribe_id = -1; + +static void signal_unsubscribed_callback(void *data) +{ + struct userdata *ud = (struct userdata *) data; + + free(ud); +} + +static void signal_callback(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + guint64 sleep_time_ms; + guint64 sleep_id; + struct userdata *ud = (struct userdata *) user_data; + int retval; + + g_variant_get(parameters, "(tt)", &sleep_time_ms, &sleep_id); + + if (!ud || !ud->callback) + return; + + retval = ud->callback(sleep_time_ms, ud->data); + if (retval == DEVICE_SLEEP_READY) { + g_dbus_connection_call_sync(connection, + DEVICED_BUS_NAME, + DEVICED_PATH_POWER, + DEVICED_INTERFACE_POWER, + "ConfirmSleepWait", + g_variant_new("(i)", sleep_id), + NULL, + G_DBUS_CALL_FLAGS_NONE, + DBUS_METHOD_SYNC_CALL_TIMEOUT_MS, + NULL, + NULL); + } +} + +int device_power_add_sleep_callback(sleep_callback cb, void *data) +{ + GDBusConnection *connection; + GVariant *retval; + GError *err = NULL; + struct userdata *ud; + + if (signal_subscribe_id != -1) + return DEVICE_ERROR_ALREADY_IN_PROGRESS; + + connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); + if (!connection) { + _E("Failed to get dbus connection, %s", err->message); + g_clear_error(&err); + return DEVICE_ERROR_OPERATION_FAILED; + } + + ud = malloc(sizeof(struct userdata)); + if (!ud) { + _E("Failed to alloc user data"); + return DEVICE_ERROR_OPERATION_FAILED; + } + + retval = g_dbus_connection_call_sync(connection, + DEVICED_BUS_NAME, + DEVICED_PATH_POWER, + DEVICED_INTERFACE_POWER, + "AddSleepWait", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + DBUS_METHOD_SYNC_CALL_TIMEOUT_MS, + NULL, + &err); + if (!retval || err) { + _E("Failed to request AddSleepWait, %s", err->message); + g_error_free(err); + return DEVICE_ERROR_OPERATION_FAILED; + } + + ud->data = data; + ud->callback = cb; + + signal_subscribe_id = g_dbus_connection_signal_subscribe(connection, + DEVICED_BUS_NAME, + DEVICED_INTERFACE_POWER, + SLEEP_DBUS_SIGNAME, + DEVICED_PATH_POWER, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + signal_callback, + ud, + signal_unsubscribed_callback); + + return DEVICE_ERROR_NONE; +} + +void device_power_remove_sleep_callback(void) +{ + GError *err = NULL; + GDBusConnection *connection; + + if (signal_subscribe_id == -1) + return; + + connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); + if (!connection) { + _E("Failed to get dbus connection, %s", err->message); + g_clear_error(&err); + return; + } + + g_dbus_connection_signal_unsubscribe(connection, signal_subscribe_id); + signal_subscribe_id = -1; + + g_dbus_connection_call_sync(connection, + DEVICED_BUS_NAME, + DEVICED_PATH_POWER, + DEVICED_INTERFACE_POWER, + "RemoveSleepWait", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + DBUS_METHOD_SYNC_CALL_TIMEOUT_MS, + NULL, + NULL); +} -- 2.7.4