power: add internal function for deferring sleep 35/266735/5
authorYoungjae Cho <y0.cho@samsung.com>
Thu, 18 Nov 2021 04:14:51 +0000 (13:14 +0900)
committerYoungjae Cho <y0.cho@samsung.com>
Fri, 19 Nov 2021 07:39:27 +0000 (16:39 +0900)
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 <y0.cho@samsung.com>
include/power-internal.h
src/power-internal.c [new file with mode: 0644]

index 294c765..dde31b7 100644 (file)
@@ -21,6 +21,9 @@
 extern "C" {
 #endif
 
+#include <glib.h>
+#include <gio/gio.h>
+
 /**
  * @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 (file)
index 0000000..2a01a33
--- /dev/null
@@ -0,0 +1,145 @@
+#include <stdlib.h>
+#include <gio/gio.h>
+#include <libsyscommon/libgdbus.h>
+
+#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);
+}