power: subdivide power state 05/284005/8
authorYoungjae Cho <y0.cho@samsung.com>
Tue, 8 Nov 2022 09:09:48 +0000 (18:09 +0900)
committerYoungjae Cho <y0.cho@samsung.com>
Tue, 6 Dec 2022 06:52:22 +0000 (15:52 +0900)
 Introduce transient state, SUSPENDING/RESUMING and they have 3 variants
each, EARLY, NORMAL and LATE. As the deviced always follows these transient
states in order, those transient state help other processes synchronize
each other by registering callbacks on each transient state.
 As the type of state has been subdivided, static ans transient, the
functions responsible for those types have also been subdivided.

For those static states, such as POWER_STATE_NORMAL,
 - device_power_add_change_state_wait_callback
 - device_power_remove_change_state_wait_callback
 - device_power_change_state_wait_done
 - device_power_change_state

For those transient states, such as POWER_STATE_TRANSIENT_RESUMING,
 - device_power_add_transient_state_wait_callback
 - device_power_remove_transient_state_wait_callback
 - device_power_change_state_wait_done

 In addition, the dbus signal name used by both capi-system-device and
the deviced has been moved to libsyscommon.
 - DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_START
 - DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_NORMAL
 - ...

Change-Id: I7b6d19ace2f2b73388cacc9d9344b717c0fde087
Signed-off-by: Youngjae Cho <y0.cho@samsung.com>
include/power-internal.h
src/power-internal.c

index 6510293..f11eab6 100644 (file)
@@ -25,8 +25,6 @@ extern "C" {
 #include <glib.h>
 #include <gio/gio.h>
 
-#include "device-error.h"
-
 /**
  * @platform
  * @brief Power off the device.
@@ -37,7 +35,6 @@ extern "C" {
  * @return @c 0 on success,
  *         otherwise a negative error value
  * @retval #DEVICE_ERROR_NONE Successful
- * @retval #DEVICE_ERROR_INVALID_PARAMETER Invalid parameter
  * @retval #DEVICE_ERROR_PERMISSION_DENIED Permission denied
  * @retval #DEVICE_ERROR_OPERATION_FAILED Operation failed
  */
@@ -54,20 +51,44 @@ enum {
        POWER_STATE_MAX_INDEX,
 };
 
-#define POWER_STATE_START    (1ULL << POWER_STATE_START_INDEX)
-#define        POWER_STATE_NORMAL   (1ULL << POWER_STATE_NORMAL_INDEX)
-#define        POWER_STATE_SLEEP    (1ULL << POWER_STATE_SLEEP_INDEX)
-#define        POWER_STATE_POWEROFF (1ULL << POWER_STATE_POWEROFF_INDEX)
-#define        POWER_STATE_REBOOT   (1ULL << POWER_STATE_REBOOT_INDEX)
-#define        POWER_STATE_EXIT     (1ULL << POWER_STATE_EXIT_INDEX)
-#define        POWER_STATE_ALL      ((1ULL << POWER_STATE_MAX_INDEX) - (1ULL << POWER_STATE_MIN_INDEX))
-
-#define SIGNAME_CHANGE_STATE_TO_START         "ChangeStateToStart"
-#define SIGNAME_CHANGE_STATE_TO_NORMAL        "ChangeStateToNormal"
-#define SIGNAME_CHANGE_STATE_TO_SLEEP         "ChangeStateToSleep"
-#define SIGNAME_CHANGE_STATE_TO_POWEROFF      "ChangeStateToPowerOff"
-#define SIGNAME_CHANGE_STATE_TO_REBOOT        "ChangeStateToReboot"
-#define SIGNAME_CHANGE_STATE_TO_EXIT          "ChangeStateToExit"
+enum {
+       POWER_STATE_TRANSIENT_MIN_INDEX = POWER_STATE_MAX_INDEX + 1,
+       POWER_STATE_TRANSIENT_RESUMING_EARLY_INDEX = POWER_STATE_TRANSIENT_MIN_INDEX,
+       POWER_STATE_TRANSIENT_RESUMING_INDEX,
+       POWER_STATE_TRANSIENT_RESUMING_LATE_INDEX,
+       POWER_STATE_TRANSIENT_SUSPENDING_EARLY_INDEX,
+       POWER_STATE_TRANSIENT_SUSPENDING_INDEX,
+       POWER_STATE_TRANSIENT_SUSPENDING_LATE_INDEX,
+       POWER_STATE_TRANSIENT_MAX_INDEX,
+};
+
+/**
+ * @brief Enumeration for power state.
+ * @since_tizen 6.5
+ */
+typedef enum {
+       POWER_STATE_START            = (1ULL << POWER_STATE_START_INDEX), /**< initial state of power module */
+       POWER_STATE_NORMAL           = (1ULL << POWER_STATE_NORMAL_INDEX), /**< normal state */
+       POWER_STATE_SLEEP            = (1ULL << POWER_STATE_SLEEP_INDEX), /**< sleep state */
+       POWER_STATE_POWEROFF         = (1ULL << POWER_STATE_POWEROFF_INDEX), /**< poweroff state */
+       POWER_STATE_REBOOT           = (1ULL << POWER_STATE_REBOOT_INDEX), /**< reboot state */
+       POWER_STATE_EXIT             = (1ULL << POWER_STATE_EXIT_INDEX), /**< exit state */
+       POWER_STATE_ALL              = ((1ULL << POWER_STATE_MAX_INDEX) - (1ULL << POWER_STATE_MIN_INDEX)), /**< all the above states */
+} power_state_e;
+
+/**
+ * @brief Enumeration for transient state.
+ * @details Each enum denotes transient state between static state #power_state_e.
+ * @since_tizen 7.0
+ */
+typedef enum {
+       POWER_STATE_TRANSIENT_RESUMING_EARLY   = (1ULL << POWER_STATE_TRANSIENT_RESUMING_EARLY_INDEX), /**< the first step of transitioning from sleep to normal */
+       POWER_STATE_TRANSIENT_RESUMING         = (1ULL << POWER_STATE_TRANSIENT_RESUMING_INDEX), /**< the second step of transitioning from sleep to normal */
+       POWER_STATE_TRANSIENT_RESUMING_LATE    = (1ULL << POWER_STATE_TRANSIENT_RESUMING_LATE_INDEX), /**< the last step of transitioning from sleep to normal */
+       POWER_STATE_TRANSIENT_SUSPENDING_EARLY = (1ULL << POWER_STATE_TRANSIENT_SUSPENDING_EARLY_INDEX), /**< the first step of transitioning from normal to sleep */
+       POWER_STATE_TRANSIENT_SUSPENDING       = (1ULL << POWER_STATE_TRANSIENT_SUSPENDING_INDEX), /**< the second step of transitioning from normal to sleep */
+       POWER_STATE_TRANSIENT_SUSPENDING_LATE  = (1ULL << POWER_STATE_TRANSIENT_SUSPENDING_LATE_INDEX), /**< the last step of transitioning from normal to sleep */
+} power_transient_state_e;
 
 struct device_change_state_info {
        uint64_t prev_state; /* previous state before the state transition, one of POWER_STATE_* */
@@ -77,23 +98,24 @@ struct device_change_state_info {
 };
 
 /**
- * @brief Called when a device power state is changed
- * @details If both power_change_state_wait_callback and power_change_state_callback have registered to the same power state, \n
- *          then the power_change_state_wait_callback will be invoked first and the power_change_state_callback will follow.
+ * @brief Called when a device power state is changed.
+ * @details If both power_change_state_wait_callback() and power_change_state_callback() have registered to the same power state, \n
+ *          then the power_change_state_wait_callback() will be invoked first and the power_change_state_callback() will follow.
+ * @since_tizen 6.5
  * @param[out] info Information about state change
  * @param[out] user_data User data passed from the callback registration
  */
 typedef void (*power_change_state_wait_callback) (const struct device_change_state_info *info, void *user_data);
 
 /**
- * @brief Add a callback to observe power state change
+ * @brief Add a callback to observe power state change.
  * @details Register a callback for specific power state. \n
  *          The callback will be invoked when the deviced changes state to the designated power state. \n
- *          An actual action, such as triggering poweroff on changing state to POWER_STATE_POWEROFF or \n
- *          wake unlock on changing state to POWER_STATE_SLEEP, will be deferred to give a chance \n
+ *          An actual action, such as triggering poweroff on changing state to #POWER_STATE_POWEROFF or \n
+ *          wake unlock on changing state to #POWER_STATE_SLEEP, will be deferred to give a chance \n
  *          for the API caller to prepare for the action.
- * @sinze_tizen 6.5
- * @param[in] state_bits Bitwise ORed power state
+ * @since_tizen 6.5
+ * @param[in] state_bits Bitwise ORed #power_state_e
  * @param[in] cb Callback function
  * @param[in] user_data Data to be passed to the callback function
  * @return 0 on success,
@@ -101,12 +123,29 @@ typedef void (*power_change_state_wait_callback) (const struct device_change_sta
  * @retval #DEVICE_ERROR_NONE Successful
  * @retval #DEVICE_ERROR_OPERATION_FAILED Operation failed
  */
-int device_power_add_change_state_wait_callback(uint64_t state_bits, power_change_state_wait_callback cb, void *user_data);
+int device_power_add_change_state_wait_callback(power_state_e state_bits, power_change_state_wait_callback cb, void *user_data);
+
+/**
+ * @brief Add a callback to observe transient power state.
+ * @details Register a callback for specific transient power state. \n
+ *          The callback will be invoked when the deviced changes state to the designated transient power state. \n
+ *          Similar to the device_power_add_change_state_wait_callback(), it defers transition to the next state \n
+ *          until it is confirmed to be ready to go. \n
+ * @since_tizen 7.0
+ * @param[in] transient_bits Bitwise ORed #power_transient_state_e
+ * @param[in] cb Callback function
+ * @param[in] user_data Data to be passed to the callback function
+ * @return 0 on success,
+ *         otherwise a negative error value
+ * @retval #DEVICE_ERROR_NONE Successful
+ * @retval #DEVICE_ERROR_OPERATION_FAILED Operation failed
+ */
+int device_power_add_transient_state_wait_callback(power_transient_state_e transient_bits, power_change_state_wait_callback cb, void *user_data);
 
 /**
  * @brief Notify the deviced that it is ready for the actual action.
  * @details Notify the deviced that it is ok to take an actual action of change state. \n
- *          This API only works on the id received from power_change_state_wait_callback.
+ *          This function only works on the id received from power_change_state_wait_callback().
  * @since_tizen 6.5
  * @param[in] id Id of a state change
  * @return 0 on success,
@@ -119,14 +158,21 @@ int device_power_change_state_wait_done(uint64_t id);
 /**
  * @brief Remove callback that has registered to power state.
  * @since_tizen 6.5
- * @param[in] state_bits Bitwise ORed power state
+ * @param[in] state_bits Bitwise ORed #power_state_e
+ */
+void device_power_remove_change_state_wait_callback(power_state_e state_bits);
+
+/**
+ * @brief Remove callback that has registered to transient power state.
+ * @since_tizen 7.0
+ * @param[in] transient_bits Bitwise ORed #power_transient_state_e
  */
-void device_power_remove_change_state_wait_callback(uint64_t state_bits);
+void device_power_remove_transient_state_wait_callback(power_transient_state_e transient_bits);
 
 /**
  * @brief Async callback of device_power_change_state().
- * @details If both power_change_state_wait_callback and power_change_state_callback have registered to the same power state, \n
- *          then the power_change_state_wait_callback will be invoked first and the power_change_state_callback will follow.
+ * @details If both power_change_state_wait_callback() and power_change_state_callback() have registered to the same power state, \n
+ *          then the power_change_state_wait_callback() will be invoked first and the power_change_state_callback() will follow.
  * @since_tizen 6.5
  * @param[out] state State to be changed
  * @param[out] retval Return of change state
@@ -149,7 +195,7 @@ typedef void (*power_change_state_callback) (uint64_t state, int retval, void *u
 int device_power_change_state(uint64_t state, int timeout_sec, power_change_state_callback cb, void *user_data);
 
 /**
- * @brief Check if reboot is possible on the current device state
+ * @brief Check if reboot is possible on the current device state.
  * @since_tizen 6.5
  * @return 1 if a device is able to reboot,
  *         otherwise return 0
@@ -160,4 +206,4 @@ int device_power_check_reboot_allowed(void);
 }
 #endif
 
-#endif
+#endif /* __TIZEN_SYSTEM_POWER_INTERNAL_H__ */
index 0679882..0ab5d64 100644 (file)
@@ -20,7 +20,7 @@ struct power_change_state_handler {
        uint64_t state;
 };
 
-static int change_state_signal_id[POWER_STATE_MAX_INDEX];
+static int change_state_signal_id[POWER_STATE_TRANSIENT_MAX_INDEX];
 
 static void signal_unsubscribed_callback(void *data)
 {
@@ -50,16 +50,22 @@ static void signal_callback(GDBusConnection *connection,
        h->callback(&info, h->user_data);
 }
 
-static int __device_power_add_change_state_wait_callback(GDBusConnection *connection,
+static int __register_signal_callback(GDBusConnection *connection,
        int index, power_change_state_wait_callback cb, void *data)
 {
-       static const char *signame[POWER_STATE_MAX_INDEX] = {
-               [POWER_STATE_START_INDEX] = SIGNAME_CHANGE_STATE_TO_START,
-               [POWER_STATE_NORMAL_INDEX] = SIGNAME_CHANGE_STATE_TO_NORMAL,
-               [POWER_STATE_SLEEP_INDEX] = SIGNAME_CHANGE_STATE_TO_SLEEP,
-               [POWER_STATE_POWEROFF_INDEX] = SIGNAME_CHANGE_STATE_TO_POWEROFF,
-               [POWER_STATE_REBOOT_INDEX] = SIGNAME_CHANGE_STATE_TO_REBOOT,
-               [POWER_STATE_EXIT_INDEX] = SIGNAME_CHANGE_STATE_TO_EXIT,
+       static const char *signame[POWER_STATE_TRANSIENT_MAX_INDEX] = {
+               [POWER_STATE_START_INDEX]                      = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_START,
+               [POWER_STATE_NORMAL_INDEX]                     = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_NORMAL,
+               [POWER_STATE_SLEEP_INDEX]                      = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SLEEP,
+               [POWER_STATE_POWEROFF_INDEX]                   = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_POWEROFF,
+               [POWER_STATE_REBOOT_INDEX]                     = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_REBOOT,
+               [POWER_STATE_EXIT_INDEX]                       = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_EXIT,
+               [POWER_STATE_TRANSIENT_RESUMING_EARLY_INDEX]   = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING_EARLY,
+               [POWER_STATE_TRANSIENT_RESUMING_INDEX]         = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING,
+               [POWER_STATE_TRANSIENT_RESUMING_LATE_INDEX]    = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING_LATE,
+               [POWER_STATE_TRANSIENT_SUSPENDING_EARLY_INDEX] = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING_EARLY,
+               [POWER_STATE_TRANSIENT_SUSPENDING_INDEX]       = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING,
+               [POWER_STATE_TRANSIENT_SUSPENDING_LATE_INDEX]  = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING_LATE,
        };
        struct power_change_state_wait_handler *h;
 
@@ -89,13 +95,13 @@ static int __device_power_add_change_state_wait_callback(GDBusConnection *connec
        return DEVICE_ERROR_NONE;
 }
 
-int device_power_add_change_state_wait_callback(uint64_t state_bits, power_change_state_wait_callback cb, void *data)
+static int register_signal_callback(uint64_t states, power_change_state_wait_callback cb, void *data)
 {
        GDBusConnection *connection;
        GVariant *retgv = NULL;
        GError *err = NULL;
 
-       if (state_bits == 0)
+       if (states == 0)
                return DEVICE_ERROR_NONE;
 
        connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
@@ -111,7 +117,7 @@ int device_power_add_change_state_wait_callback(uint64_t state_bits, power_chang
                        DEVICED_PATH_POWER,
                        DEVICED_INTERFACE_POWER,
                        "AddChangeStateWait",
-                       g_variant_new("(t)", state_bits),
+                       g_variant_new("(t)", states),
                        NULL,
                        G_DBUS_CALL_FLAGS_NONE,
                        DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
@@ -124,14 +130,36 @@ int device_power_add_change_state_wait_callback(uint64_t state_bits, power_chang
        }
 
        // subscribe signal
-       for (int index = 0; index < POWER_STATE_MAX_INDEX; ++index)
-               if((state_bits & (1ULL << index)) && (change_state_signal_id[index] == 0))
-                       __device_power_add_change_state_wait_callback(connection, index, cb, data);
+       for (int index = 0; index < POWER_STATE_TRANSIENT_MAX_INDEX; ++index)
+               if((states & (1ULL << index)) && (change_state_signal_id[index] == 0))
+                       __register_signal_callback(connection, index, cb, data);
 
 
        return DEVICE_ERROR_NONE;
 }
 
+int device_power_add_change_state_wait_callback(power_state_e state_bits, power_change_state_wait_callback cb, void *data)
+{
+       uint64_t valid = (1ULL << POWER_STATE_MAX_INDEX) - (1ULL << POWER_STATE_MIN_INDEX);
+       uint64_t invalid = (state_bits & ~valid);
+
+       if (invalid)
+               return DEVICE_ERROR_INVALID_PARAMETER;
+
+       return register_signal_callback(state_bits, cb, data);
+}
+
+int device_power_add_transient_state_wait_callback(power_transient_state_e transient_bits, power_change_state_wait_callback cb, void *data)
+{
+       uint64_t valid = (1ULL << POWER_STATE_TRANSIENT_MAX_INDEX) - (1ULL << POWER_STATE_TRANSIENT_MIN_INDEX);
+       uint64_t invalid = (transient_bits & ~valid);
+
+       if (invalid)
+               return DEVICE_ERROR_INVALID_PARAMETER;
+
+       return register_signal_callback(transient_bits, cb, data);
+}
+
 int device_power_change_state_wait_done(uint64_t id)
 {
        GDBusConnection *connection;
@@ -171,7 +199,7 @@ int device_power_change_state_wait_done(uint64_t id)
        return DEVICE_ERROR_NONE;
 }
 
-static void  __device_power_remove_change_state_wait_callback(GDBusConnection *connection, int index)
+static void  __unregister_signal_callback(GDBusConnection *connection, int index)
 {
        if (change_state_signal_id[index] == 0)
                return;
@@ -180,12 +208,12 @@ static void  __device_power_remove_change_state_wait_callback(GDBusConnection *c
        change_state_signal_id[index] = 0;
 }
 
-void device_power_remove_change_state_wait_callback(uint64_t state_bits)
+static void unregister_signal_callback(uint64_t states)
 {
        GError *err = NULL;
        GDBusConnection *connection;
 
-       if (state_bits == 0)
+       if (states == 0)
                return;
 
        connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
@@ -196,9 +224,9 @@ void device_power_remove_change_state_wait_callback(uint64_t state_bits)
        }
 
        // unsubscribe signal
-       for (int index = 0; index < POWER_STATE_MAX_INDEX; ++index)
-               if((state_bits & (1ULL << index)) && (change_state_signal_id[index] > 0))
-                       __device_power_remove_change_state_wait_callback(connection, index);
+       for (int index = 0; index < POWER_STATE_TRANSIENT_MAX_INDEX; ++index)
+               if((states & (1ULL << index)) && (change_state_signal_id[index] > 0))
+                       __unregister_signal_callback(connection, index);
 
        //remove change state wait
        g_dbus_connection_call_sync(connection,
@@ -206,12 +234,36 @@ void device_power_remove_change_state_wait_callback(uint64_t state_bits)
                DEVICED_PATH_POWER,
                DEVICED_INTERFACE_POWER,
                "RemoveChangeStateWait",
-               g_variant_new("(t)", state_bits),
+               g_variant_new("(t)", states),
                NULL,
                G_DBUS_CALL_FLAGS_NONE,
                DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
                NULL,
                NULL);
+
+}
+
+void device_power_remove_change_state_wait_callback(power_state_e state_bits)
+{
+       uint64_t valid = (1ULL << POWER_STATE_MAX_INDEX) - (1ULL << POWER_STATE_MIN_INDEX);
+       uint64_t invalid = (state_bits & ~valid);
+
+       if (invalid)
+               return;
+
+       unregister_signal_callback(state_bits);
+}
+
+void device_power_remove_transient_state_wait_callback(power_transient_state_e transient_bits)
+{
+       uint64_t valid = (1ULL << POWER_STATE_TRANSIENT_MAX_INDEX) - (1ULL << POWER_STATE_TRANSIENT_MIN_INDEX);
+       uint64_t invalid = (transient_bits & ~valid);
+
+       if (invalid)
+               return;
+
+       unregister_signal_callback(transient_bits);
+
 }
 
 static void change_state_async_callback(GObject *source_object, GAsyncResult *res, gpointer user_data)
@@ -257,6 +309,12 @@ int device_power_change_state(uint64_t state, int timeout_sec, power_change_stat
        GDBusConnection *connection;
        struct power_change_state_handler *h = NULL;
 
+       uint64_t valid = (1ULL << POWER_STATE_MAX_INDEX) - (1ULL << POWER_STATE_MIN_INDEX);
+       uint64_t invalid = (state & ~valid);
+
+       if (invalid)
+               return DEVICE_ERROR_INVALID_PARAMETER;
+
        if (!device_power_check_reboot_allowed()) {
                if (state == POWER_STATE_POWEROFF) {
                        _E("Failed to Poweroff due to partition cloning.");