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);
}
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;
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,
.data = t->data,
};
+ ret = check_transition(&ti);
+ if (ret < 0)
+ return ret;
+
// TODO: immediate handling of poweroff?
if (!delayed_init_done || transition_context.ongoing) {