power: Add checker to verify request before doing transition 54/324154/1 accepted/tizen_7.0_unified tizen_7.0 accepted/tizen/7.0/unified/20250514.161413
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 10:13:00 +0000 (19:13 +0900)
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 9ccf8de256ef4cefec555a10aac402a67712dc27..2c88044bc6e583e58bd4d958e3082dffbe60f086 100644 (file)
@@ -333,8 +333,6 @@ static void post_action_sleep(void *udata)
 
 static void pre_action_poweroff(void *data)
 {
-       // do not transition anymore after poweroff
-       unregister_notifier(DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE, transition_request_callback);
        poweroff_prepare(current);
 }
 
@@ -746,12 +744,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 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 trans_info *t = NULL;
        struct trans_info ti = { 0 , };
        uint64_t available;
+       int ret;
 
        if (!data)
                return 0;
@@ -769,12 +798,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 trans_info) {
                .curr = available,
                .next = t->next,
@@ -782,6 +805,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) {