power: refactor power change state wait API
authorYoungjae Cho <y0.cho@samsung.com>
Thu, 8 Dec 2022 08:16:35 +0000 (17:16 +0900)
committerChanwoo Choi <cw00.choi@samsung.com>
Fri, 16 Dec 2022 06:33:42 +0000 (15:33 +0900)
Hide state index enumeration into source code
 - It has been changed to be defined by enumeration
   DEVICE_POWER_STATE_*.

Introduce enumeration for transition reason
 - power_transition_reason_e

Rearrange value of enumeration device_power_state_e
 and device_power_transient_state_e
 - Previously, those enumerations share bit not to overlap each other.
   This somehow implies those enumerations are related each other. To
   clarify that they have nothing to do with each other, rearranged bit.
 - From the above change, the APIs have changed to support exclusive
   register/unregister/callback subroutine by enumeration type.
    • device_power_add_state_wait_callback()
    • device_power_add_transient_state_wait_callback()
    • device_power_remove_state_wait_callback()
    • device_power_remove_transient_wait_callback()
 - Each callback has parameter of corresponding state enumeration type.
 - Callback now receives each information directly from parameter
   instead of struct device_change_state_info. The struct
   device_change_state_info has been removed.
 - Only the device_power_wait_done() has left unchanged in that it
   can be utilized by callback of both enumeration type.

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

index f79cd57..bf6989a 100644 (file)
@@ -40,72 +40,79 @@ extern "C" {
  */
 int device_power_poweroff(void);
 
-enum {
-       DEVICE_POWER_STATE_MIN_INDEX = 4,
-       DEVICE_POWER_STATE_START_INDEX = DEVICE_POWER_STATE_MIN_INDEX,
-       DEVICE_POWER_STATE_NORMAL_INDEX,
-       DEVICE_POWER_STATE_SLEEP_INDEX,
-       DEVICE_POWER_STATE_POWEROFF_INDEX,
-       DEVICE_POWER_STATE_REBOOT_INDEX,
-       DEVICE_POWER_STATE_EXIT_INDEX,
-       DEVICE_POWER_STATE_MAX_INDEX,
-};
-
-enum {
-       DEVICE_POWER_STATE_TRANSIENT_MIN_INDEX = DEVICE_POWER_STATE_MAX_INDEX + 1,
-       DEVICE_POWER_STATE_TRANSIENT_RESUMING_EARLY_INDEX = DEVICE_POWER_STATE_TRANSIENT_MIN_INDEX,
-       DEVICE_POWER_STATE_TRANSIENT_RESUMING_INDEX,
-       DEVICE_POWER_STATE_TRANSIENT_RESUMING_LATE_INDEX,
-       DEVICE_POWER_STATE_TRANSIENT_SUSPENDING_EARLY_INDEX,
-       DEVICE_POWER_STATE_TRANSIENT_SUSPENDING_INDEX,
-       DEVICE_POWER_STATE_TRANSIENT_SUSPENDING_LATE_INDEX,
-       DEVICE_POWER_STATE_TRANSIENT_MAX_INDEX,
-};
+/**
+ * @platform
+ * @brief Reason for what triggered transition.
+ * @since_tizen 7.0
+ */
+typedef enum {
+       DEVICE_POWER_TRANSITION_REASON_UNKNOWN,                /**< Unknown reason */
+       DEVICE_POWER_TRANSITION_REASON_POWER_KEY,              /**< Power key pressed */
+       DEVICE_POWER_TRANSITION_REASON_BATTERY_NORMAL_LEVEL,   /**< Battery capacity reaches normal level*/
+       DEVICE_POWER_TRANSITION_REASON_BATTERY_WARNING_LEVEL,  /**< Battery capacity reaches warning level */
+       DEVICE_POWER_TRANSITION_REASON_BATTERY_CRITICAL_LEVEL, /**< Battery capacity reaches critical level */
+       DEVICE_POWER_TRANSITION_REASON_BATTERY_POWEROFF_LEVEL, /**< Battery capacity reaches poweroff level */
+       DEVICE_POWER_TRANSITION_REASON_DISPLAY_OFF,            /**< Display off */
+
+       DEVICE_POWER_TRANSITION_REASON_CUSTOM = 1000,          /**< Define custom reason from here */
+} device_power_transition_reason_e;
 
 /**
  * @brief Enumeration for power state.
  * @since_tizen 6.5
  */
 typedef enum {
-       DEVICE_POWER_STATE_START            = (1ULL << DEVICE_POWER_STATE_START_INDEX), /**< initial state of power module */
-       DEVICE_POWER_STATE_NORMAL           = (1ULL << DEVICE_POWER_STATE_NORMAL_INDEX), /**< normal state */
-       DEVICE_POWER_STATE_SLEEP            = (1ULL << DEVICE_POWER_STATE_SLEEP_INDEX), /**< sleep state */
-       DEVICE_POWER_STATE_POWEROFF         = (1ULL << DEVICE_POWER_STATE_POWEROFF_INDEX), /**< poweroff state */
-       DEVICE_POWER_STATE_REBOOT           = (1ULL << DEVICE_POWER_STATE_REBOOT_INDEX), /**< reboot state */
-       DEVICE_POWER_STATE_EXIT             = (1ULL << DEVICE_POWER_STATE_EXIT_INDEX), /**< exit state */
-       DEVICE_POWER_STATE_ALL              = ((1ULL << DEVICE_POWER_STATE_MAX_INDEX) - (1ULL << DEVICE_POWER_STATE_MIN_INDEX)), /**< all the above states */
+       DEVICE_POWER_STATE_START        = (1ULL << 4), /**< Initial state of power module. It is especially meaningful in that
+                                                       this can be used to identify the first transition and implement
+                                                       booting UX */
+       DEVICE_POWER_STATE_NORMAL       = (1ULL << 5), /**< System keeps running */
+       DEVICE_POWER_STATE_SLEEP        = (1ULL << 6), /**< System may be suspended at any time */
+       DEVICE_POWER_STATE_POWEROFF     = (1ULL << 7), /**< Prepare for poweroff and perform `systemctl poweroff` */
+       DEVICE_POWER_STATE_REBOOT       = (1ULL << 8), /**< Prepare for reboot and perform `systemctl reboot` */
+       DEVICE_POWER_STATE_EXIT         = (1ULL << 9), /**< Prepare for exit and perform `systemctl exit` */
 } device_power_state_e;
 
 /**
  * @brief Enumeration for transient state.
- * @details Each enum denotes transient state between static state #power_state_e.
+ * @details Each enum denotes transient state between static state #device_power_state_e.
  * @since_tizen 7.0
  */
 typedef enum {
-       DEVICE_POWER_STATE_TRANSIENT_RESUMING_EARLY   = (1ULL << DEVICE_POWER_STATE_TRANSIENT_RESUMING_EARLY_INDEX), /**< the first step of transitioning from sleep to normal */
-       DEVICE_POWER_STATE_TRANSIENT_RESUMING         = (1ULL << DEVICE_POWER_STATE_TRANSIENT_RESUMING_INDEX), /**< the second step of transitioning from sleep to normal */
-       DEVICE_POWER_STATE_TRANSIENT_RESUMING_LATE    = (1ULL << DEVICE_POWER_STATE_TRANSIENT_RESUMING_LATE_INDEX), /**< the last step of transitioning from sleep to normal */
-       DEVICE_POWER_STATE_TRANSIENT_SUSPENDING_EARLY = (1ULL << DEVICE_POWER_STATE_TRANSIENT_SUSPENDING_EARLY_INDEX), /**< the first step of transitioning from normal to sleep */
-       DEVICE_POWER_STATE_TRANSIENT_SUSPENDING       = (1ULL << DEVICE_POWER_STATE_TRANSIENT_SUSPENDING_INDEX), /**< the second step of transitioning from normal to sleep */
-       DEVICE_POWER_STATE_TRANSIENT_SUSPENDING_LATE  = (1ULL << DEVICE_POWER_STATE_TRANSIENT_SUSPENDING_LATE_INDEX), /**< the last step of transitioning from normal to sleep */
+       DEVICE_POWER_TRANSIENT_STATE_RESUMING_EARLY     = (1ULL << 4), /**< The first step of transitioning from sleep to normal */
+       DEVICE_POWER_TRANSIENT_STATE_RESUMING           = (1ULL << 5), /**< The second step of transitioning from sleep to normal */
+       DEVICE_POWER_TRANSIENT_STATE_RESUMING_LATE      = (1ULL << 6), /**< The last step of transitioning from sleep to normal */
+       DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_EARLY   = (1ULL << 7), /**< The first step of transitioning from normal to sleep */
+       DEVICE_POWER_TRANSIENT_STATE_SUSPENDING         = (1ULL << 8), /**< The second step of transitioning from normal to sleep */
+       DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_LATE    = (1ULL << 9), /**< The last step of transitioning from normal to sleep */
 } device_power_transient_state_e;
 
-struct device_change_state_info {
-       uint64_t prev_state; /* previous state before the state transition, one of POWER_STATE_* */
-       uint64_t next_state; /* current state that has been transitioned, one of POWER_STATE_* */
-       uint64_t id;         /* unique id for each transition. it is used for wait-done */
-       int reason;          /* integer that signifies what event has triggered the transition */
-};
+/**
+ * @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 function only works on the id received from device_power_state_wait_callback() and device_power_transient_state_wait_callback().
+ * @since_tizen 6.5
+ * @param[in] wait_done_id Change state id to confirm waiting
+ * @return 0 on success,
+ *         otherwise a negative error value
+ * @retval #DEVICE_ERROR_NONE Successful
+ * @retval #DEVICE_ERROR_OPERATION_FAILED Operation failed
+ * @see    device_power_state_wait_callback()
+ * @see    device_power_transient_state_wait_callback()
+ */
+int device_power_wait_done(uint64_t wait_done_id);
 
 /**
  * @brief Called when a device power state is changed.
- * @details If both device_power_change_state_wait_callback() and device_power_change_state_callback() have registered to the same power state, \n
- *          then the device_power_change_state_wait_callback() will be invoked first and the device_power_change_state_callback() will follow.
+ * @details If both device_power_state_wait_callback() and device_power_change_state_callback() have registered to the same power state, \n
+ *          then the device_power_state_wait_callback() will be invoked first and the device_power_change_state_callback() will follow.
  * @since_tizen 6.5
- * @param[out] info Information about state change
+ * @param[out] state Power state to be changed by the transition
+ * @param[out] wait_done_id Transition id
+ * @param[out] transition_reason Reason for what triggered the transition
  * @param[out] user_data User data passed from the callback registration
  */
-typedef void (*device_power_change_state_wait_callback) (const struct device_change_state_info *info, void *user_data);
+typedef void (*device_power_state_wait_callback) (device_power_state_e state,
+       uint64_t wait_done_id, device_power_transition_reason_e transition_reason, void *user_data);
 
 /**
  * @brief Add a callback to observe power state change.
@@ -122,14 +129,33 @@ typedef void (*device_power_change_state_wait_callback) (const struct device_cha
  *         otherwise a negative error value
  * @retval #DEVICE_ERROR_NONE Successful
  * @retval #DEVICE_ERROR_OPERATION_FAILED Operation failed
+ * @see    device_power_state_wait_callback()
  */
-int device_power_add_change_state_wait_callback(device_power_state_e state_bits, device_power_change_state_wait_callback cb, void *user_data);
+int device_power_add_state_wait_callback(device_power_state_e state_bits, device_power_state_wait_callback cb, void *user_data);
+
+/**
+ * @brief Remove callback that has registered to power state.
+ * @since_tizen 6.5
+ * @param[in] state_bits Bitwise ORed #device_power_state_e
+ */
+void device_power_remove_state_wait_callback(device_power_state_e state_bits);
+
+/**
+ * @brief Called when a device power state is changed.
+ * @since_tizen 6.5
+ * @param[out] transient_state Transient state to be changed by the transition
+ * @param[out] wait_done_id Transition id
+ * @param[out] transition_reason Reason for what triggered the transition
+ * @param[out] user_data User data passed from the callback registration
+ */
+typedef void (*device_power_transient_state_wait_callback) (device_power_transient_state_e transient_state,
+       uint64_t wait_done_id, device_power_transition_reason_e transition_reason, 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
+ *          The callback will be invoked in the middle of transition process. \n
+ *          Similar to the device_power_add_change_state_wait_callback(), it withholds transition \n
  *          until it is confirmed to be ready to go. \n
  * @since_tizen 7.0
  * @param[in] transient_bits Bitwise ORed #device_power_transient_state_e
@@ -139,28 +165,10 @@ int device_power_add_change_state_wait_callback(device_power_state_e state_bits,
  *         otherwise a negative error value
  * @retval #DEVICE_ERROR_NONE Successful
  * @retval #DEVICE_ERROR_OPERATION_FAILED Operation failed
+ * @see    device_power_transient_state_wait_callback()
  */
-int device_power_add_transient_state_wait_callback(device_power_transient_state_e transient_bits, device_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 function only works on the id received from device_power_change_state_wait_callback().
- * @since_tizen 6.5
- * @param[in] id Id of a state change
- * @return 0 on success,
- *         otherwise a negative error value
- * @retval #DEVICE_ERROR_NONE Successful
- * @retval #DEVICE_ERROR_OPERATION_FAILED Operation failed
- */
-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 #device_power_state_e
- */
-void device_power_remove_change_state_wait_callback(device_power_state_e state_bits);
+int device_power_add_transient_state_wait_callback(device_power_transient_state_e transient_bits,
+       device_power_transient_state_wait_callback cb, void *user_data);
 
 /**
  * @brief Remove callback that has registered to transient power state.
@@ -171,14 +179,14 @@ void device_power_remove_transient_state_wait_callback(device_power_transient_st
 
 /**
  * @brief Async callback of device_power_change_state().
- * @details If both device_power_change_state_wait_callback() and device_power_change_state_callback() have registered to the same power state, \n
- *          then the device_power_change_state_wait_callback() will be invoked first and the device_power_change_state_callback() will follow.
+ * @details If both device_power_state_wait_callback() and device_power_change_state_callback() have registered to the same power state, \n
+ *          then the device_power_state_wait_callback() will be invoked first and the device_power_change_state_callback() will follow.
  * @since_tizen 6.5
  * @param[out] state State to be changed
  * @param[out] retval Return of change state
  * @param[out] user_data The user data passed from the change state function
  */
-typedef void (*device_power_change_state_callback) (uint64_t state, int retval, void *user_data);
+typedef void (*device_power_change_state_callback) (device_power_state_e state, int retval, void *user_data);
 
 /**
  * @brief Send request for changing power state asynchronously.
@@ -192,7 +200,7 @@ typedef void (*device_power_change_state_callback) (uint64_t state, int retval,
  * @retval #DEVICE_ERROR_NONE Successful
  * @retval #DEVICE_ERROR_OPERATION_FAILED Operation failed
  */
-int device_power_change_state(uint64_t state, int timeout_sec, device_power_change_state_callback cb, void *user_data);
+int device_power_change_state(device_power_state_e state, int timeout_sec, device_power_change_state_callback cb, void *user_data);
 
 /**
  * @brief Check if reboot is possible on the current device state.
index ae5bb8b..f74604c 100644 (file)
@@ -1,6 +1,8 @@
+#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 #include <gio/gio.h>
+
 #include <libsyscommon/libgdbus.h>
 #include <hal/device/hal-board.h>
 
@@ -9,8 +11,49 @@
 
 #define DBUS_METHOD_SYNC_CALL_TIMEOUT_MS    10000 /* 10 second */
 
-struct power_change_state_wait_handler {
-       device_power_change_state_wait_callback callback;
+#define LSB_INDEX(val)                  (__builtin_ctzll(val))
+#define IS_IN_BETWEEN(val, le, gt)      (((le) <= (val) && (val) < (gt)))
+#define IS_STATE_BIT(bit)               IS_IN_BETWEEN(bit, \
+                                                      (1ULL << DEVICE_POWER_STATE_MIN_INDEX), \
+                                                      (1ULL << DEVICE_POWER_STATE_MAX_INDEX))
+#define IS_TRANSIENT_STATE_BIT(bit)     IS_IN_BETWEEN(bit, \
+                                                      (1ULL << DEVICE_POWER_TRANSIENT_STATE_MIN_INDEX), \
+                                                      (1ULL << DEVICE_POWER_TRANSIENT_STATE_MAX_INDEX))
+
+enum {
+       DEVICE_POWER_STATE_START_INDEX          = LSB_INDEX(DEVICE_POWER_STATE_START),
+       DEVICE_POWER_STATE_NORMAL_INDEX         = LSB_INDEX(DEVICE_POWER_STATE_NORMAL),
+       DEVICE_POWER_STATE_SLEEP_INDEX          = LSB_INDEX(DEVICE_POWER_STATE_SLEEP),
+       DEVICE_POWER_STATE_POWEROFF_INDEX       = LSB_INDEX(DEVICE_POWER_STATE_POWEROFF),
+       DEVICE_POWER_STATE_REBOOT_INDEX         = LSB_INDEX(DEVICE_POWER_STATE_REBOOT),
+       DEVICE_POWER_STATE_EXIT_INDEX           = LSB_INDEX(DEVICE_POWER_STATE_EXIT),
+       /* add state here */
+
+       DEVICE_POWER_STATE_MAX_INDEX,
+       DEVICE_POWER_STATE_MIN_INDEX = DEVICE_POWER_STATE_START_INDEX,
+};
+
+enum {
+       DEVICE_POWER_TRANSIENT_STATE_RESUMING_EARLY_INDEX       = LSB_INDEX(DEVICE_POWER_TRANSIENT_STATE_RESUMING_EARLY),
+       DEVICE_POWER_TRANSIENT_STATE_RESUMING_INDEX             = LSB_INDEX(DEVICE_POWER_TRANSIENT_STATE_RESUMING),
+       DEVICE_POWER_TRANSIENT_STATE_RESUMING_LATE_INDEX        = LSB_INDEX(DEVICE_POWER_TRANSIENT_STATE_RESUMING_LATE),
+       DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_EARLY_INDEX     = LSB_INDEX(DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_EARLY),
+       DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_INDEX           = LSB_INDEX(DEVICE_POWER_TRANSIENT_STATE_SUSPENDING),
+       DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_LATE_INDEX      = LSB_INDEX(DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_LATE),
+       /* add transient state here */
+
+       DEVICE_POWER_TRANSIENT_STATE_MAX_INDEX,
+       DEVICE_POWER_TRANSIENT_STATE_MIN_INDEX = DEVICE_POWER_TRANSIENT_STATE_RESUMING_EARLY_INDEX,
+};
+
+static int state_signal_id[DEVICE_POWER_STATE_MAX_INDEX];
+static int transient_state_signal_id[DEVICE_POWER_TRANSIENT_STATE_MAX_INDEX];
+
+struct power_wait_handler {
+       union {
+               device_power_state_wait_callback state_wait_callback;
+               device_power_transient_state_wait_callback transient_state_wait_callback;
+       };
        void *user_data;
 };
 
@@ -20,16 +63,14 @@ struct power_change_state_handler {
        uint64_t state;
 };
 
-static int change_state_signal_id[DEVICE_POWER_STATE_TRANSIENT_MAX_INDEX];
-
 static void signal_unsubscribed_callback(void *data)
 {
-       struct power_change_state_wait_handler *h = (struct power_change_state_wait_handler *) data;
+       struct power_wait_handler *h = (struct power_wait_handler *) data;
 
        free(h);
 }
 
-static void signal_callback(GDBusConnection *connection,
+static void state_signal_callback(GDBusConnection *connection,
        const gchar *sender_name,
        const gchar *object_path,
        const gchar *interface_name,
@@ -37,65 +78,59 @@ static void signal_callback(GDBusConnection *connection,
        GVariant *parameters,
        gpointer user_data)
 {
-       struct device_change_state_info info;
-       struct power_change_state_wait_handler *h;
+       struct power_wait_handler *h;
+       uint64_t prev_state, next_state, id;
+       int reason;
 
-       h = (struct power_change_state_wait_handler *) user_data;
+       h = (struct power_wait_handler *) user_data;
 
-       if (!h || !h->callback)
-               return;
+       assert(h->state_wait_callback);
 
-       g_variant_get(parameters, "(ttti)", &info.prev_state, &info.next_state, &info.id, &info.reason);
+       g_variant_get(parameters, "(ttti)", &prev_state, &next_state, &id, &reason);
 
-       h->callback(&info, h->user_data);
+       h->state_wait_callback(next_state, id, reason, h->user_data);
 }
 
-static int __register_signal_callback(GDBusConnection *connection,
-       int index, device_power_change_state_wait_callback cb, void *data)
+static int __register_state_signal_callback(GDBusConnection *connection,
+       int index, device_power_state_wait_callback cb, void *data)
 {
-       static const char *signame[DEVICE_POWER_STATE_TRANSIENT_MAX_INDEX] = {
+       static const char *signame[DEVICE_POWER_STATE_MAX_INDEX] = {
                [DEVICE_POWER_STATE_START_INDEX]                      = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_START,
                [DEVICE_POWER_STATE_NORMAL_INDEX]                     = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_NORMAL,
                [DEVICE_POWER_STATE_SLEEP_INDEX]                      = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SLEEP,
                [DEVICE_POWER_STATE_POWEROFF_INDEX]                   = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_POWEROFF,
                [DEVICE_POWER_STATE_REBOOT_INDEX]                     = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_REBOOT,
                [DEVICE_POWER_STATE_EXIT_INDEX]                       = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_EXIT,
-               [DEVICE_POWER_STATE_TRANSIENT_RESUMING_EARLY_INDEX]   = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING_EARLY,
-               [DEVICE_POWER_STATE_TRANSIENT_RESUMING_INDEX]         = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING,
-               [DEVICE_POWER_STATE_TRANSIENT_RESUMING_LATE_INDEX]    = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING_LATE,
-               [DEVICE_POWER_STATE_TRANSIENT_SUSPENDING_EARLY_INDEX] = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING_EARLY,
-               [DEVICE_POWER_STATE_TRANSIENT_SUSPENDING_INDEX]       = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING,
-               [DEVICE_POWER_STATE_TRANSIENT_SUSPENDING_LATE_INDEX]  = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING_LATE,
        };
-       struct power_change_state_wait_handler *h;
 
-       if (change_state_signal_id[index] > 0)
-               return DEVICE_ERROR_ALREADY_IN_PROGRESS;
+       struct power_wait_handler *h;
+
+       assert(state_signal_id[index] == 0);
 
-       h = malloc(sizeof(struct power_change_state_wait_handler));
+       h = malloc(sizeof(struct power_wait_handler));
        if (!h) {
                _E("Failed to alloc user data");
                return DEVICE_ERROR_OPERATION_FAILED;
        }
 
-       h->callback = cb;
+       h->state_wait_callback = cb;
        h->user_data = data;
 
-       change_state_signal_id[index] = g_dbus_connection_signal_subscribe(connection,
+       state_signal_id[index] = g_dbus_connection_signal_subscribe(connection,
                DEVICED_BUS_NAME,
                DEVICED_INTERFACE_POWER,
                signame[index],
                DEVICED_PATH_POWER,
                NULL,
                G_DBUS_SIGNAL_FLAGS_NONE,
-               signal_callback,
+               state_signal_callback,
                h,
                signal_unsubscribed_callback);
 
        return DEVICE_ERROR_NONE;
 }
 
-static int register_signal_callback(uint64_t states, device_power_change_state_wait_callback cb, void *data)
+static int register_state_signal_callback(uint64_t states, device_power_state_wait_callback cb, void *data)
 {
        GDBusConnection *connection;
        GVariant *retgv = NULL;
@@ -130,37 +165,134 @@ static int register_signal_callback(uint64_t states, device_power_change_state_w
        }
 
        // subscribe signal
-       for (int index = 0; index < DEVICE_POWER_STATE_TRANSIENT_MAX_INDEX; ++index)
-               if((states & (1ULL << index)) && (change_state_signal_id[index] == 0))
-                       __register_signal_callback(connection, index, cb, data);
-
+       for (int index = DEVICE_POWER_STATE_MIN_INDEX; index < DEVICE_POWER_STATE_MAX_INDEX; ++index)
+               if((states & (1ULL << index)) && (state_signal_id[index] == 0))
+                       __register_state_signal_callback(connection, index, cb, data);
 
        return DEVICE_ERROR_NONE;
 }
 
-int device_power_add_change_state_wait_callback(device_power_state_e state_bits, device_power_change_state_wait_callback cb, void *data)
+int device_power_add_state_wait_callback(device_power_state_e state_bits,
+       device_power_state_wait_callback cb, void *data)
 {
-       uint64_t valid = (1ULL << DEVICE_POWER_STATE_MAX_INDEX) - (1ULL << DEVICE_POWER_STATE_MIN_INDEX);
-       uint64_t invalid = (state_bits & ~valid);
-
-       if (invalid)
+       if (!IS_STATE_BIT(state_bits))
                return DEVICE_ERROR_INVALID_PARAMETER;
 
-       return register_signal_callback(state_bits, cb, data);
+       return register_state_signal_callback(state_bits, cb, data);
+}
+
+static void transient_state_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)
+{
+       struct power_wait_handler *h;
+       uint64_t prev_state, next_state, id;
+       int reason;
+
+       h = (struct power_wait_handler *) user_data;
+
+       assert(h->transient_state_wait_callback);
+
+       g_variant_get(parameters, "(ttti)", &prev_state, &next_state, &id, &reason);
+
+       h->transient_state_wait_callback(next_state, id, reason, h->user_data);
+}
+
+static int __register_transient_state_signal_callback(GDBusConnection *connection,
+       int index, device_power_transient_state_wait_callback cb, void *data)
+{
+       static const char *signame[DEVICE_POWER_TRANSIENT_STATE_MAX_INDEX] = {
+               [DEVICE_POWER_TRANSIENT_STATE_RESUMING_EARLY_INDEX]     = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING_EARLY,
+               [DEVICE_POWER_TRANSIENT_STATE_RESUMING_INDEX]           = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING,
+               [DEVICE_POWER_TRANSIENT_STATE_RESUMING_LATE_INDEX]      = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_RESUMING_LATE,
+               [DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_EARLY_INDEX]   = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING_EARLY,
+               [DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_INDEX]         = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING,
+               [DEVICE_POWER_TRANSIENT_STATE_SUSPENDING_LATE_INDEX]    = DEVICED_SIGNAL_POWER_CHANGE_STATE_TO_SUSPENDING_LATE,
+       };
+
+       struct power_wait_handler *h;
+
+       assert(transient_state_signal_id[index] == 0);
+
+       h = malloc(sizeof(struct power_wait_handler));
+       if (!h) {
+               _E("Failed to alloc user data");
+               return DEVICE_ERROR_OPERATION_FAILED;
+       }
+
+       h->transient_state_wait_callback = cb;
+       h->user_data = data;
+
+       transient_state_signal_id[index] = g_dbus_connection_signal_subscribe(connection,
+               DEVICED_BUS_NAME,
+               DEVICED_INTERFACE_POWER,
+               signame[index],
+               DEVICED_PATH_POWER,
+               NULL,
+               G_DBUS_SIGNAL_FLAGS_NONE,
+               transient_state_signal_callback,
+               h,
+               signal_unsubscribed_callback);
+
+       return DEVICE_ERROR_NONE;
 }
 
-int device_power_add_transient_state_wait_callback(device_power_transient_state_e transient_bits, device_power_change_state_wait_callback cb, void *data)
+static int register_transient_state_signal_callback(uint64_t states, device_power_transient_state_wait_callback cb, void *data)
 {
-       uint64_t valid = (1ULL << DEVICE_POWER_STATE_TRANSIENT_MAX_INDEX) - (1ULL << DEVICE_POWER_STATE_TRANSIENT_MIN_INDEX);
-       uint64_t invalid = (transient_bits & ~valid);
+       GDBusConnection *connection;
+       GVariant *retgv = NULL;
+       GError *err = NULL;
 
-       if (invalid)
+       if (states == 0)
+               return DEVICE_ERROR_NONE;
+
+       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;
+       }
+
+       // add change state wait
+       retgv = g_dbus_connection_call_sync(connection,
+                       DEVICED_BUS_NAME,
+                       DEVICED_PATH_POWER,
+                       DEVICED_INTERFACE_POWER,
+                       "AddChangeTransientStateWait",
+                       g_variant_new("(t)", states),
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
+                       NULL,
+                       &err);
+       if (!retgv || err) {
+               _E("Failed to request AddChangeTransientStateWait, %s", err->message);
+               g_error_free(err);
+               return DEVICE_ERROR_OPERATION_FAILED;
+       }
+
+       // subscribe signal
+       for (int index = DEVICE_POWER_TRANSIENT_STATE_MIN_INDEX; index < DEVICE_POWER_TRANSIENT_STATE_MAX_INDEX; ++index)
+               if((states & (1ULL << index)) && (transient_state_signal_id[index] == 0))
+                       __register_transient_state_signal_callback(connection, index, cb, data);
+
+       return DEVICE_ERROR_NONE;
+}
+
+int device_power_add_transient_state_wait_callback(device_power_transient_state_e transient_bits,
+       device_power_transient_state_wait_callback cb, void *data)
+{
+       if (!IS_TRANSIENT_STATE_BIT(transient_bits))
                return DEVICE_ERROR_INVALID_PARAMETER;
 
-       return register_signal_callback(transient_bits, cb, data);
+       return register_transient_state_signal_callback(transient_bits, cb, data);
 }
 
-int device_power_change_state_wait_done(uint64_t id)
+int device_power_wait_done(uint64_t id)
 {
        GDBusConnection *connection;
        GVariant *retgv;
@@ -199,16 +331,16 @@ int device_power_change_state_wait_done(uint64_t id)
        return DEVICE_ERROR_NONE;
 }
 
-static void  __unregister_signal_callback(GDBusConnection *connection, int index)
+static void  __unregister_state_signal_callback(GDBusConnection *connection, int index)
 {
-       if (change_state_signal_id[index] == 0)
+       if (state_signal_id[index] == 0)
                return;
 
-       g_dbus_connection_signal_unsubscribe(connection, change_state_signal_id[index]);
-       change_state_signal_id[index] = 0;
+       g_dbus_connection_signal_unsubscribe(connection, state_signal_id[index]);
+       state_signal_id[index] = 0;
 }
 
-static void unregister_signal_callback(uint64_t states)
+static void unregister_state_signal_callback(uint64_t states)
 {
        GError *err = NULL;
        GDBusConnection *connection;
@@ -224,9 +356,9 @@ static void unregister_signal_callback(uint64_t states)
        }
 
        // unsubscribe signal
-       for (int index = 0; index < DEVICE_POWER_STATE_TRANSIENT_MAX_INDEX; ++index)
-               if((states & (1ULL << index)) && (change_state_signal_id[index] > 0))
-                       __unregister_signal_callback(connection, index);
+       for (int index = DEVICE_POWER_STATE_MIN_INDEX; index < DEVICE_POWER_STATE_MAX_INDEX; ++index)
+               if((states & (1ULL << index)) && (state_signal_id[index] > 0))
+                       __unregister_state_signal_callback(connection, index);
 
        //remove change state wait
        g_dbus_connection_call_sync(connection,
@@ -240,30 +372,65 @@ static void unregister_signal_callback(uint64_t states)
                DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
                NULL,
                NULL);
-
 }
 
-void device_power_remove_change_state_wait_callback(device_power_state_e state_bits)
+void device_power_remove_state_wait_callback(device_power_state_e state_bits)
 {
-       uint64_t valid = (1ULL << DEVICE_POWER_STATE_MAX_INDEX) - (1ULL << DEVICE_POWER_STATE_MIN_INDEX);
-       uint64_t invalid = (state_bits & ~valid);
+       if (!IS_STATE_BIT(state_bits))
+               return;
 
-       if (invalid)
+       unregister_state_signal_callback(state_bits);
+}
+
+static void  __unregister_transient_state_signal_callback(GDBusConnection *connection, int index)
+{
+       if (transient_state_signal_id[index] == 0)
                return;
 
-       unregister_signal_callback(state_bits);
+       g_dbus_connection_signal_unsubscribe(connection, transient_state_signal_id[index]);
+       transient_state_signal_id[index] = 0;
 }
 
-void device_power_remove_transient_state_wait_callback(device_power_transient_state_e transient_bits)
+static void unregister_transient_state_signal_callback(uint64_t states)
 {
-       uint64_t valid = (1ULL << DEVICE_POWER_STATE_TRANSIENT_MAX_INDEX) - (1ULL << DEVICE_POWER_STATE_TRANSIENT_MIN_INDEX);
-       uint64_t invalid = (transient_bits & ~valid);
+       GError *err = NULL;
+       GDBusConnection *connection;
 
-       if (invalid)
+       if (states == 0)
                return;
 
-       unregister_signal_callback(transient_bits);
+       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;
+       }
+
+       // unsubscribe signal
+       for (int index = DEVICE_POWER_TRANSIENT_STATE_MIN_INDEX; index < DEVICE_POWER_TRANSIENT_STATE_MAX_INDEX; ++index)
+               if((states & (1ULL << index)) && (transient_state_signal_id[index] > 0))
+                       __unregister_transient_state_signal_callback(connection, index);
 
+       //remove change state wait
+       g_dbus_connection_call_sync(connection,
+               DEVICED_BUS_NAME,
+               DEVICED_PATH_POWER,
+               DEVICED_INTERFACE_POWER,
+               "RemoveChangeTransientStateWait",
+               g_variant_new("(t)", states),
+               NULL,
+               G_DBUS_CALL_FLAGS_NONE,
+               DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
+               NULL,
+               NULL);
+}
+
+void device_power_remove_transient_state_wait_callback(device_power_transient_state_e transient_bits)
+{
+       if (!IS_TRANSIENT_STATE_BIT(transient_bits))
+               return;
+
+       unregister_transient_state_signal_callback(transient_bits);
 }
 
 static void change_state_async_callback(GObject *source_object, GAsyncResult *res, gpointer user_data)
@@ -303,16 +470,13 @@ cleanup:
        free(h);
 }
 
-int device_power_change_state(uint64_t state, int timeout_sec, device_power_change_state_callback cb, void *user_data)
+int device_power_change_state(device_power_state_e state, int timeout_sec, device_power_change_state_callback cb, void *user_data)
 {
        GError *err = NULL;
        GDBusConnection *connection;
        struct power_change_state_handler *h = NULL;
 
-       uint64_t valid = (1ULL << DEVICE_POWER_STATE_MAX_INDEX) - (1ULL << DEVICE_POWER_STATE_MIN_INDEX);
-       uint64_t invalid = (state & ~valid);
-
-       if (invalid)
+       if (!IS_STATE_BIT(state))
                return DEVICE_ERROR_INVALID_PARAMETER;
 
        if (!device_power_check_reboot_allowed()) {