power: Add checker to verify request before doing transition 45/323945/11 accepted/tizen/unified/20250514.114141 accepted/tizen/unified/x/20250515.044736
authorYoungjae Cho <y0.cho@samsung.com>
Fri, 9 May 2025 06:38:55 +0000 (15:38 +0900)
committeryoungjae cho <y0.cho@samsung.com>
Tue, 13 May 2025 09:57:48 +0000 (09:57 +0000)
Previously as for the poweroff/reboot/exit transition, no further
requests should've been handled, and it was accomplished by unsubscribing
requests right before the action_transition(). However, this function could
be deferred depending on how long the other processes hold the transition
using device APIs below, giving chance to receive additional requests.
 - device_power_add_state_wait_callback()
 - device_power_confirm_wait_callback()

To make it thoroughly not receive further requests, checks all the
receiving transition requests before processing it. To this end,
added check_transition(), verifying whether a transition could be
processed, at the beginning of transition routine.

This fixes violation of the below assertions at the head of the
trigger_transition().
 - assert(current != DEVICED_POWER_STATE_POWEROFF);
 - assert(current != DEVICED_POWER_STATE_REBOOT);
 - assert(current != DEVICED_POWER_STATE_EXIT);

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

index 8869ddfb6641cc373cab36c78a04729f455480d8..d2dc0e29827fd734bc356ddd1d34aeb3615ef4a9 100644 (file)
@@ -340,8 +340,6 @@ static void post_action_sleep(const void *udata)
 
 static void pre_action_poweroff(const void *data)
 {
-       // do not transition anymore after poweroff
-       syscommon_notifier_unsubscribe_notify(DEVICED_NOTIFIER_REQUEST_TRANSITION_STATE, transition_request_callback);
        poweroff_prepare(current);
 }
 
@@ -754,12 +752,43 @@ static gint find_ti_by_state(gconstpointer data, gconstpointer udata)
        return -1;
 }
 
+/**
+ * Checks whether the transition can be validated.
+ *
+ * Return 0 on available transition.
+ * Return negative error on transition that must not be processed.
+ */
+static int check_transition(const struct syscommon_plugin_deviced_power_trans_info *ti)
+{
+       if (!ti) {
+               _E("Invalid transition");
+               return -EINVAL;
+       }
+
+       // Don't allow multiple next state
+       if (__builtin_popcountll(ti->next & DEVICED_POWER_STATE_ALL) != 1) {
+               _E("Invalid next state(more then one), curr=%"PRIx64", next=%"PRIx64", reason=%d",
+                       ti->curr, ti->next, ti->reason);
+               return -EINVAL;
+       }
+
+       // Prohibit transition from poweroff/reboot/exit state
+       if (is_poweroff_state(ti->curr)) {
+               _E("Prohibit transition to %s, it is already at the %s",
+                       state_name(ti->next), state_name(ti->curr));
+               return -ESHUTDOWN;
+       }
+
+       return 0;
+}
+
 static int transition_request_callback(void *data)
 {
        GList *ti_list, *l;
        const struct syscommon_plugin_deviced_power_trans_info *t = NULL;
        struct syscommon_plugin_deviced_power_trans_info ti = { 0 , };
        uint64_t available;
+       int ret;
 
        if (!data)
                return 0;
@@ -777,12 +806,6 @@ static int transition_request_callback(void *data)
 
        t = l->data;
 
-       // check invalid next state
-       if (__builtin_popcountll(t->next & DEVICED_POWER_STATE_ALL) != 1) {
-               _E("Invalid next state, curr=%"PRIx64", next=%"PRIx64", reason=%d", t->curr, t->next, t->reason);
-               return 0;
-       }
-
        ti = (struct syscommon_plugin_deviced_power_trans_info) {
                .curr = available,
                .next = t->next,
@@ -790,6 +813,10 @@ static int transition_request_callback(void *data)
                .data = t->data,
        };
 
+       ret = check_transition(&ti);
+       if (ret < 0)
+               return ret;
+
        // TODO: immediate handling of poweroff?
 
        if (!delayed_init_done || transition_context.ongoing) {