From f0e7125bb2dd76eae45e5679332734be694c5efb Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Thu, 9 Dec 2021 13:21:05 +0900 Subject: [PATCH 01/16] power: rework sleep-wait The sleep-wait now works based on a single list. Whenever entering to PSM_SLEEP, all sleep-waits, which had been registered by processes through device API, will be added to the list waiting for confirmation. Change-Id: Iebb1b177914847ee9c38ce8bf5fc01bb70d1f3c6 Signed-off-by: Youngjae Cho --- plugins/iot-headless/power/power-state-manager.c | 47 +++- plugins/iot-headless/power/sleep-wait.c | 267 +++++++++-------------- plugins/iot-headless/power/sleep-wait.h | 2 +- 3 files changed, 141 insertions(+), 175 deletions(-) diff --git a/plugins/iot-headless/power/power-state-manager.c b/plugins/iot-headless/power/power-state-manager.c index fdafba5..44f89ac 100644 --- a/plugins/iot-headless/power/power-state-manager.c +++ b/plugins/iot-headless/power/power-state-manager.c @@ -13,7 +13,7 @@ #define KEYPRESS_LOCK_TIMEOUT 4000 /* milisecond */ -/* temporal wakelock of powerkey input */ +/* Temporal wakelock of powerkey input */ #define KEY_PRESSED_TEMPORAL_LOCK "templock" #define TEMPORAL_LOCK_WAKE_MARGIN 1000 /* milisecond */ @@ -25,7 +25,7 @@ static const char *psm_name[PSM_MAX] = { [PSM_POWEROFF] = "PSM_POWEROFF", }; -static int sleep_id = 0; +static unsigned int state_transition_counter = 0; static enum psm_state current; static gboolean temporal_lock_expired_cb(void *data) @@ -76,7 +76,13 @@ static int release_temporal_lock(void * data) static int psm_sleep_wait_done_cb(void *data) { - _D("Sleep-wait done, wake unlock"); + /* for PSM_NORMAL, PSM_POWEROFF, do not wake unlock */ + if (current != PSM_SLEEP) { + _E("Ignore sleep wait done, current=%s", psm_name[current]); + return 0; + } + + _D("Sleep-wait done"); device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_UNLOCK, NULL); return 0; @@ -84,11 +90,21 @@ static int psm_sleep_wait_done_cb(void *data) static void psm_transition_normal_to_sleep(const struct trans_info *ti) { + int n_waiting; + current = PSM_SLEEP; - // TODO: tune parameter of the dbus signal gdbus_signal_emit(NULL, DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER, - "sleep", g_variant_new("(ti)", sleep_id, ti->reason)); - start_sleep_wait(++sleep_id); + "sleep", g_variant_new("(ti)", state_transition_counter, ti->reason)); + n_waiting = start_sleep_wait(state_transition_counter); + if (n_waiting > 0) { + /* There are sleep-waits. Defer wake unlock until all sleep-waits + * receive confirmation. Wake unlock will be done by + * psm_sleep_wait_done_cb() on receiving last confirmation.*/ + _D("Defer wake unlock"); + return; + } + + device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_UNLOCK, NULL); } static void psm_transition_sleep_to_normal(const struct trans_info *ti) @@ -96,17 +112,27 @@ static void psm_transition_sleep_to_normal(const struct trans_info *ti) current = PSM_NORMAL; stop_sleep_wait(); device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL); - // TODO: tune parameter of the dbus signal gdbus_signal_emit(NULL, DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER, - "wakeup", g_variant_new("(i)", ti->reason)); + "wakeup", g_variant_new("(ti)", state_transition_counter, ti->reason)); } static void psm_transition_sleep_to_sleep(const struct trans_info *ti) { + int n_waiting; + device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL); gdbus_signal_emit(NULL, DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER, - "sleep", g_variant_new("(ti)", sleep_id, ti->reason)); - start_sleep_wait(++sleep_id); + "sleep", g_variant_new("(ti)", state_transition_counter, ti->reason)); + n_waiting = start_sleep_wait(state_transition_counter); + if (n_waiting > 0) { + /* There are sleep-waits. Defer wake unlock until all sleep-waits + * receive confirmation. Wake unlock will be done by + * psm_sleep_wait_done_cb() on receiving last confirmation.*/ + _D("Defer wake unlock"); + return; + } + + device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_UNLOCK, NULL); } static void psm_transition_normal_to_poweroff(const struct trans_info *ti) @@ -152,6 +178,7 @@ static int psm_transition_state_cb(void *data) psm_name[current], psm_name[next], ti->reason); /* transition */ + ++state_transition_counter; if (current == PSM_NORMAL) { if (next == PSM_SLEEP) psm_transition_normal_to_sleep(ti); diff --git a/plugins/iot-headless/power/sleep-wait.c b/plugins/iot-headless/power/sleep-wait.c index 4ae4746..85bfd3d 100644 --- a/plugins/iot-headless/power/sleep-wait.c +++ b/plugins/iot-headless/power/sleep-wait.c @@ -9,142 +9,105 @@ #define MAX_WAIT_SECOND 5 /* second */ -struct sleep_wait { +struct proc_info { pid_t pid; char comm[128]; - // int timeout; - // int timer_id; + int killed; }; -/* inactive: This list contains sleep waits added by AddSleepWait dbus method. - * active: All entries of inactive list are moved to this list when sleep is requested. - * Each one moves to inactive list on receiving ConfirmWait dbus method. - * Sleep will be triggered when it becomes empty. */ -static GList *inactive; -static GList *active; +struct sleep_wait { + struct proc_info *pi; + int id; +}; + +static GList *proc_list; +static GList *sleep_waiting; static int max_wait_timer; -static int current_sleep_id; -static void switch_active_list(void) +static void sleep_wait_done(void) { - GList *tmp; - int n; - - n = g_list_length(active); - if (n != 0) - _W("Sleep wait remains in active list, %d", n); + if (max_wait_timer) { + g_source_remove(max_wait_timer); + max_wait_timer = 0; + } - tmp = inactive; - inactive = active; - active = tmp; + device_notify(DEVICE_NOTIFIER_POWER_SLEEP_WAIT_DONE, NULL); } static gboolean max_wait_expired_cb(void *data) { struct sleep_wait *sw; + struct proc_info *pi; GList *elem, *elem_next; max_wait_timer = 0; - /* force confirmation */ - if (g_list_length(active) != 0) { - SYS_G_LIST_FOREACH_SAFE(active, elem, elem_next, sw) { - if (kill(sw->pid, 0) != 0) { - _D("Remove not existing sleep wait of pid=%d(%s)", sw->pid, sw->comm); - active = g_list_remove(active, sw); - free(sw); - } else { /* move to inactive manually */ - _W("pid=%d(%s) hasn't comfirmed sleep wait", sw->pid, sw->comm); - active = g_list_remove(active, sw); - inactive = g_list_append(inactive, sw); - } + SYS_G_LIST_FOREACH_SAFE(sleep_waiting, elem, elem_next, sw) { + if (kill(sw->pi->pid, 0) != 0) + sw->pi->killed = 1; + else + _E("pid=%d(%s) hasn't confirmed sleep wait", sw->pi->pid, sw->pi->comm); + sleep_waiting = g_list_remove_link(sleep_waiting, elem); + g_list_free(elem); + free(sw); + } + + SYS_G_LIST_FOREACH_SAFE(proc_list, elem, elem_next, pi) { + if (pi->killed) { + _D("Clean up not existing pid=%d(%s) from sleep wait", pi->pid, pi->comm); + proc_list = g_list_remove_link(proc_list, elem); + g_list_free(elem); + free(pi); } } + _D("Maximum sleep wait expired, timeout=%ds", MAX_WAIT_SECOND); device_notify(DEVICE_NOTIFIER_POWER_SLEEP_WAIT_DONE, NULL); return G_SOURCE_REMOVE; } -/* It returns - * 0 if sleep_wait is found in inactive list, - * -EBUSY if sleep_wait is found in active list, - * -ESRCH if sleep_wait is not found in both list */ -static int find_sleep_wait(pid_t pid, struct sleep_wait **sw) +int add_sleep_wait(pid_t pid) { - struct sleep_wait *ret = NULL; + struct proc_info *pi; GList *elem; - if (!sw) - return -EINVAL; - - SYS_G_LIST_FOREACH(inactive, elem, ret) { - if (ret->pid == pid) { - *sw = ret; - return 0; - } + SYS_G_LIST_FOREACH(proc_list, elem, pi) { + if (pi->pid == pid) + return -EEXIST; } - SYS_G_LIST_FOREACH(active, elem, ret) { - if (ret->pid == pid) { - *sw = ret; - return -EBUSY; - } - } + pi = calloc(1, sizeof(struct proc_info)); + if (!pi) + return -ENOMEM; - *sw = NULL; - return -ESRCH; -} - -int add_sleep_wait(pid_t pid) -{ - struct sleep_wait *sw; - int ret; - - ret = find_sleep_wait(pid, &sw); - if (ret == -ESRCH) { /* new node */ - sw = calloc(1, sizeof(struct sleep_wait)); - if (!sw) - return -ENOMEM; - - sw->pid = pid; - get_command(pid, sw->comm, sizeof(sw->comm)); - inactive = g_list_append(inactive, sw); + pi->pid = pid; + get_command(pid, pi->comm, sizeof(pi->comm)); + SYS_G_LIST_APPEND(proc_list, pi); - _D("pid=%d(%s) is added to sleep wait list", sw->pid, sw->comm); - } else if (ret == 0 || ret == -EBUSY) { - _D("pid=%d(%s) has already been added to sleep wait list", sw->pid, sw->comm); - } - - return ret; + return 0; } void remove_sleep_wait(pid_t pid) { - struct sleep_wait *sw = NULL; - int retval; - - retval = find_sleep_wait(pid, &sw); - if (retval == -ESRCH) - return; - - if (sw) { - _D("pid=%d(%s) requested removing sleep wait", sw->pid, sw->comm); - - /* remove from where it is contained */ - active = g_list_remove(active, sw); - inactive = g_list_remove(inactive, sw); - - free(sw); + struct sleep_wait *sw; + struct proc_info *pi; + GList *elem, *elem_next; - /* wake unlock when active becomes empty by this operation - * during waiting sleep confirmations */ - if (max_wait_timer != 0 && g_list_length(active) == 0) { - g_source_remove(max_wait_timer); - max_wait_timer = 0; + SYS_G_LIST_FOREACH_SAFE(sleep_waiting, elem, elem_next, sw) { + if (sw->pi->pid == pid) { + sleep_waiting = g_list_remove_link(sleep_waiting, elem); + g_list_free(elem); + free(sw); + } + } - device_notify(DEVICE_NOTIFIER_POWER_SLEEP_WAIT_DONE, NULL); + SYS_G_LIST_FOREACH_SAFE(proc_list, elem, elem_next, pi) { + if (pi->pid == pid) { + sleep_waiting = g_list_remove_link(sleep_waiting, elem); + g_list_free(elem); + free(pi); } } } @@ -152,71 +115,56 @@ void remove_sleep_wait(pid_t pid) int confirm_sleep_wait(pid_t pid, int id) { struct sleep_wait *sw; - int ret = 0; - - ret = find_sleep_wait(pid, &sw); - if (ret == -ESRCH) { - _E("pid=%d hasn't been added to sleep wait list", pid); - return ret; - } - - /* Multiple confirmation or - * confirm request after MAX_WAIT_SECOND */ - if (ret == 0) { - _D("pid=%d(%s) sleep wait has already been confirmed", sw->pid, sw->comm); - return 0; - } + GList *elem, *elem_next; - if (id != current_sleep_id) { - _E("Confirm mismatches sleep_id, current=%d, confirm=%d", current_sleep_id, id); - return -EINVAL; - } + SYS_G_LIST_FOREACH_SAFE(sleep_waiting, elem, elem_next, sw) { + if (sw->pi->pid == pid && sw->id == id) { + _D("pid=%d(%s) confirmed sleep id=%d", sw->pi->pid, sw->pi->comm, sw->id); + sleep_waiting = g_list_remove_link(sleep_waiting, elem); + g_list_free(elem); + free(sw); - /* Move sw from active to inactive list. - * Wake unlock if active becomes empty. */ - if (ret == -EBUSY) { - active = g_list_remove(active, sw); - inactive = g_list_append(inactive, sw); - _D("pid=%d(%s) confirmed sleep wait", sw->pid, sw->comm); - - if (g_list_length(active) == 0) { - /* remove max_wait_timer and wake unlock immediately */ - if (max_wait_timer) { - g_source_remove(max_wait_timer); - max_wait_timer = 0; + if (SYS_G_LIST_LENGTH(sleep_waiting) == 0) { + /* all sleep-waits are checked */ + sleep_wait_done(); + return 0; } - - device_notify(DEVICE_NOTIFIER_POWER_SLEEP_WAIT_DONE, NULL); } - - return 0; } - /* fail */ - _E("Failed to confirm sleep wait, %d", ret); - - return ret; + return 0; } -void start_sleep_wait(int id) +int start_sleep_wait(int id) { - if (max_wait_timer) { - _E("Already sleep waiting"); - return; - } + struct proc_info *pi; + struct sleep_wait *sw; + GList *elem; + int n_sleep_wait; - switch_active_list(); + /* create sleep_wait for every pid of proc_list */ + SYS_G_LIST_FOREACH(proc_list, elem, pi) { + sw = calloc(1, sizeof(struct sleep_wait)); + if (!sw) + continue; - /* no need to defer sleep. wake unlock */ - if (g_list_length(active) == 0) { - device_notify(DEVICE_NOTIFIER_POWER_SLEEP_WAIT_DONE, NULL); - return; + sw->pi = pi; + sw->id = id; + SYS_G_LIST_APPEND(sleep_waiting, sw); } - current_sleep_id = id; + n_sleep_wait = SYS_G_LIST_LENGTH(sleep_waiting); + if (n_sleep_wait == 0) + return 0; + + /* reset timer */ + if (max_wait_timer) + g_source_remove(max_wait_timer); - _D("Sleep wait is triggered, maximum wait timeout=%ds", MAX_WAIT_SECOND); + _D("Sleep wait is triggered, expected number of confirmation=%d", n_sleep_wait); max_wait_timer = g_timeout_add_seconds(MAX_WAIT_SECOND, max_wait_expired_cb, NULL); + + return n_sleep_wait; } void stop_sleep_wait(void) @@ -224,23 +172,14 @@ void stop_sleep_wait(void) struct sleep_wait *sw; GList *elem, *elem_next; - if (max_wait_timer == 0) - return; - - /* cancel sleep wait */ - g_source_remove(max_wait_timer); - max_wait_timer = 0; - - _D("Wake locked during sleep wait, cancel all sleep waits"); + if (max_wait_timer) { + g_source_remove(max_wait_timer); + max_wait_timer = 0; + } - SYS_G_LIST_FOREACH_SAFE(active, elem, elem_next, sw) { - if (kill(sw->pid, 0) != 0) { - _D("Remove not existing sleep wait of %d(%s)", sw->pid, sw->comm); - active = g_list_remove(active, sw); - free(sw); - } else { /* move to inactive manually */ - active = g_list_remove(active, sw); - inactive = g_list_append(inactive, sw); - } + SYS_G_LIST_FOREACH_SAFE(sleep_waiting, elem, elem_next, sw) { + sleep_waiting = g_list_remove_link(sleep_waiting, elem); + g_list_free(elem); + free(sw); } } diff --git a/plugins/iot-headless/power/sleep-wait.h b/plugins/iot-headless/power/sleep-wait.h index e7ca51e..5110e3b 100644 --- a/plugins/iot-headless/power/sleep-wait.h +++ b/plugins/iot-headless/power/sleep-wait.h @@ -6,7 +6,7 @@ int add_sleep_wait(pid_t pid); void remove_sleep_wait(pid_t pid); int confirm_sleep_wait(pid_t pid, int id); -void start_sleep_wait(int id); +int start_sleep_wait(int id); void stop_sleep_wait(void); #endif //__SLEEP_WAIT_H__ -- 2.7.4 From bb9bc6869c40f241c356da660c3d1f642f2d980d Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Thu, 9 Dec 2021 17:21:47 +0900 Subject: [PATCH 02/16] power: fix dbus signal for changestate The dbus siganl is broadcasted on changing state path : /Org/Tizen/System/DeviceD/Power iface: org.tizen.system.deviced.Power name : ChangeState param: "(iti)" int32 : type (0: sleep, 1: wakeup) uint64: state transition id int32 : state transition reason Change-Id: I04c01722fbdbf59fa2c9eae0c9b819e3aee77488 Signed-off-by: Youngjae Cho --- plugins/iot-headless/power/power-state-manager.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/iot-headless/power/power-state-manager.c b/plugins/iot-headless/power/power-state-manager.c index 44f89ac..fa8c579 100644 --- a/plugins/iot-headless/power/power-state-manager.c +++ b/plugins/iot-headless/power/power-state-manager.c @@ -17,6 +17,9 @@ #define KEY_PRESSED_TEMPORAL_LOCK "templock" #define TEMPORAL_LOCK_WAKE_MARGIN 1000 /* milisecond */ +#define EVENT_TYPE_SLEEP 0 +#define EVENT_TYPE_WAKEUP 1 + static guint keypress_temporal_timer_id; static const char *psm_name[PSM_MAX] = { @@ -94,7 +97,7 @@ static void psm_transition_normal_to_sleep(const struct trans_info *ti) current = PSM_SLEEP; gdbus_signal_emit(NULL, DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER, - "sleep", g_variant_new("(ti)", state_transition_counter, ti->reason)); + "ChangeState", g_variant_new("(iti)", EVENT_TYPE_SLEEP, state_transition_counter, ti->reason)); n_waiting = start_sleep_wait(state_transition_counter); if (n_waiting > 0) { /* There are sleep-waits. Defer wake unlock until all sleep-waits @@ -113,7 +116,7 @@ static void psm_transition_sleep_to_normal(const struct trans_info *ti) stop_sleep_wait(); device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL); gdbus_signal_emit(NULL, DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER, - "wakeup", g_variant_new("(ti)", state_transition_counter, ti->reason)); + "ChangeState", g_variant_new("(iti)", EVENT_TYPE_WAKEUP, state_transition_counter, ti->reason)); } static void psm_transition_sleep_to_sleep(const struct trans_info *ti) @@ -122,7 +125,7 @@ static void psm_transition_sleep_to_sleep(const struct trans_info *ti) device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL); gdbus_signal_emit(NULL, DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER, - "sleep", g_variant_new("(ti)", state_transition_counter, ti->reason)); + "ChangeState", g_variant_new("(iti)", EVENT_TYPE_SLEEP, state_transition_counter, ti->reason)); n_waiting = start_sleep_wait(state_transition_counter); if (n_waiting > 0) { /* There are sleep-waits. Defer wake unlock until all sleep-waits -- 2.7.4 From 0ec4e3278d0a930c72fb69c86410fd62c421ec1a Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Fri, 10 Dec 2021 10:06:53 +0900 Subject: [PATCH 03/16] input: broadcast dbus signal on level triggered event Change-Id: I7561ac2086665912e0d5b3c9eec88a7eca1efaa8 Signed-off-by: Youngjae Cho --- plugins/iot-headless/input/input-handler.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/iot-headless/input/input-handler.c b/plugins/iot-headless/input/input-handler.c index 35c5283..4b69c04 100644 --- a/plugins/iot-headless/input/input-handler.c +++ b/plugins/iot-headless/input/input-handler.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "shared/common.h" #include "shared/devices.h" @@ -145,8 +146,9 @@ static int broadcast_input_signal_cb(void *data) if (!ieu) return 0; - _D("Broadcast siganl callback, event=%s(%d)", ieu->name, ieu->id); - // TODO: implement dbus signal broadcast + _D("Broadcast siganl, event=%s(%d)", ieu->name, ieu->id); + gdbus_signal_emit(NULL, DEVICED_PATH_INPUT, DEVICED_INTERFACE_INPUT, + "Key", g_variant_new("(i)", ieu->id)); return 0; } -- 2.7.4 From 64c18b3026939e00d3419fea6a54e2d4fd6b2142 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Mon, 13 Dec 2021 10:37:07 +0900 Subject: [PATCH 04/16] power: remove templock timeout Hold templock on pressing a key unless it is released. Change-Id: Ib7476b9aa8dc2c69b3b8d406464a56aa3a1b9aa9 Signed-off-by: Youngjae Cho --- plugins/iot-headless/power/power-state-manager.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/plugins/iot-headless/power/power-state-manager.c b/plugins/iot-headless/power/power-state-manager.c index fa8c579..751266d 100644 --- a/plugins/iot-headless/power/power-state-manager.c +++ b/plugins/iot-headless/power/power-state-manager.c @@ -11,8 +11,6 @@ #include "power-dbus.h" #include "sleep-wait.h" -#define KEYPRESS_LOCK_TIMEOUT 4000 /* milisecond */ - /* Temporal wakelock of powerkey input */ #define KEY_PRESSED_TEMPORAL_LOCK "templock" #define TEMPORAL_LOCK_WAKE_MARGIN 1000 /* milisecond */ @@ -52,8 +50,6 @@ static int acquire_temporal_lock(void *data) } sys_set_str("/sys/power/wake_lock", KEY_PRESSED_TEMPORAL_LOCK); - keypress_temporal_timer_id = g_timeout_add(KEYPRESS_LOCK_TIMEOUT + TEMPORAL_LOCK_WAKE_MARGIN, - temporal_lock_expired_cb, NULL); return 0; } @@ -70,7 +66,7 @@ static int release_temporal_lock(void * data) keypress_temporal_timer_id = 0; } - /* shorten timeout */ + /* templock margin */ keypress_temporal_timer_id = g_timeout_add(TEMPORAL_LOCK_WAKE_MARGIN, temporal_lock_expired_cb, NULL); -- 2.7.4 From 1f09cb8d649c8e666683b147109b84ccf6639a0e Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Tue, 14 Dec 2021 18:20:25 +0900 Subject: [PATCH 05/16] power: apply wait callback mechanism to all state transitions Generalize sleep-wait mechanism. It now always waits on changing state if some other processes has registered change-state-wait on the state. On transition to a next state, remove all change-state-waits that waiting for other than the next state. If a timeout expires or all change-state-waits are confirmed, invoke wait-done callback. Change-Id: I573ca68c3a6c210cad479e068ee088d6a31ba54f Signed-off-by: Youngjae Cho --- plugins/iot-headless/power/power-dbus.c | 34 ++-- plugins/iot-headless/power/power-state-manager.c | 110 ++++++++---- plugins/iot-headless/power/power-state-manager.h | 2 + plugins/iot-headless/power/power-state-wait.c | 218 +++++++++++++++++++++++ plugins/iot-headless/power/power-state-wait.h | 14 ++ plugins/iot-headless/power/sleep-wait.c | 185 ------------------- plugins/iot-headless/power/sleep-wait.h | 12 -- src/shared/device-notifier.h | 1 - 8 files changed, 326 insertions(+), 250 deletions(-) create mode 100644 plugins/iot-headless/power/power-state-wait.c create mode 100644 plugins/iot-headless/power/power-state-wait.h delete mode 100644 plugins/iot-headless/power/sleep-wait.c delete mode 100644 plugins/iot-headless/power/sleep-wait.h diff --git a/plugins/iot-headless/power/power-dbus.c b/plugins/iot-headless/power/power-dbus.c index 0a0ac50..fc907c1 100644 --- a/plugins/iot-headless/power/power-dbus.c +++ b/plugins/iot-headless/power/power-dbus.c @@ -31,7 +31,7 @@ #include "shared/device-notifier.h" #include "power-state-manager.h" -#include "sleep-wait.h" +#include "power-state-wait.h" #ifndef PROCESS_CHECK_TIMEOUT #define PROCESS_CHECK_TIMEOUT 600000 /* milisecond, 10 minute */ @@ -231,12 +231,13 @@ out: return g_variant_new("(i)", ret); } -static GVariant *dbus_power_add_sleep_wait(GDBusConnection *conn, +static GVariant *dbus_power_add_change_state_wait(GDBusConnection *conn, const gchar *sender, const gchar *path, const gchar *iface, const gchar *name, GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data) { int ret = 0; pid_t pid; + guint64 state; pid = gdbus_connection_get_sender_pid(conn, sender); if (pid == -1 || kill(pid, 0) == -1) { @@ -245,17 +246,20 @@ static GVariant *dbus_power_add_sleep_wait(GDBusConnection *conn, goto out; } - ret = add_sleep_wait(pid); + g_variant_get(param, "(t)", &state); + + ret = add_change_state_wait(pid, state); out: return g_variant_new("(i)", ret); } -static GVariant *dbus_power_remove_sleep_wait(GDBusConnection *conn, +static GVariant *dbus_power_remove_change_state_wait(GDBusConnection *conn, const gchar *sender, const gchar *path, const gchar *iface, const gchar *name, GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data) { pid_t pid; + guint64 state; pid = gdbus_connection_get_sender_pid(conn, sender); if (pid == -1 || kill(pid, 0) == -1) { @@ -263,19 +267,21 @@ static GVariant *dbus_power_remove_sleep_wait(GDBusConnection *conn, goto out; } - remove_sleep_wait(pid); + g_variant_get(param, "(t)", &state); + + remove_change_state_wait(pid, state); out: return gdbus_new_g_variant_tuple(); } -static GVariant *dbus_power_confirm_sleep_wait(GDBusConnection *conn, +static GVariant *dbus_power_confirm_change_state_wait(GDBusConnection *conn, const gchar *sender, const gchar *path, const gchar *iface, const gchar *name, GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data) { int ret = 0; pid_t pid; - int sleep_id; + guint64 sleep_id; pid = gdbus_connection_get_sender_pid(conn, sender); if (pid == -1 || kill(pid, 0) == -1) { @@ -284,20 +290,20 @@ static GVariant *dbus_power_confirm_sleep_wait(GDBusConnection *conn, goto out; } - g_variant_get(param, "(i)", &sleep_id); + g_variant_get(param, "(t)", &sleep_id); - ret = confirm_sleep_wait(pid, sleep_id); + ret = confirm_change_state_wait(pid, sleep_id); out: return g_variant_new("(i)", ret); } static const dbus_method_s dbus_methods[] = { - { "LockCpu", "i", "i", dbus_power_lock_cpu }, - { "UnlockCpu", NULL, "i", dbus_power_unlock_cpu }, - { "AddSleepWait", NULL, "i", dbus_power_add_sleep_wait }, - { "RemoveSleepWait", NULL, NULL, dbus_power_remove_sleep_wait }, - { "ConfirmSleepWait", "i", "i", dbus_power_confirm_sleep_wait }, + { "LockCpu", "i", "i", dbus_power_lock_cpu }, + { "UnlockCpu", NULL, "i", dbus_power_unlock_cpu }, + { "AddChangeStateWait", "t", "i", dbus_power_add_change_state_wait }, + { "RemoveChangeStateWait", "t", NULL, dbus_power_remove_change_state_wait }, + { "ConfirmChangeStateWait", "t", "i", dbus_power_confirm_change_state_wait }, /* Add methods here */ }; diff --git a/plugins/iot-headless/power/power-state-manager.c b/plugins/iot-headless/power/power-state-manager.c index 751266d..959ed9c 100644 --- a/plugins/iot-headless/power/power-state-manager.c +++ b/plugins/iot-headless/power/power-state-manager.c @@ -3,13 +3,14 @@ #include #include #include +#include #include "shared/devices.h" #include "shared/device-notifier.h" #include "shared/log.h" #include "power-state-manager.h" #include "power-dbus.h" -#include "sleep-wait.h" +#include "power-state-wait.h" /* Temporal wakelock of powerkey input */ #define KEY_PRESSED_TEMPORAL_LOCK "templock" @@ -20,13 +21,14 @@ static guint keypress_temporal_timer_id; -static const char *psm_name[PSM_MAX] = { +char *psm_name[PSM_MAX] = { [PSM_NORMAL] = "PSM_NORMAL", [PSM_SLEEP] = "PSM_SLEEP", [PSM_POWEROFF] = "PSM_POWEROFF", + [PSM_REBOOT] = "PSM_REBOOT", }; -static unsigned int state_transition_counter = 0; +static guint64 state_transition_counter = 0; static enum psm_state current; static gboolean temporal_lock_expired_cb(void *data) @@ -73,82 +75,113 @@ static int release_temporal_lock(void * data) return 0; } -static int psm_sleep_wait_done_cb(void *data) +static void psm_wake_unlock(void) { /* for PSM_NORMAL, PSM_POWEROFF, do not wake unlock */ if (current != PSM_SLEEP) { _E("Ignore sleep wait done, current=%s", psm_name[current]); - return 0; + return; } - _D("Sleep-wait done"); device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_UNLOCK, NULL); +} - return 0; +static void psm_trigger_poweroff(void) +{ + const struct device_ops *power_device; + + power_device = find_device("power"); + if (check_default(power_device)) + return; + + if (power_device->execute) { + device_notify(DEVICE_NOTIFIER_REQUEST_DISABLE_AUTOSLEEP, NULL); + power_device->execute("poweroff"); + } +} + +static void broadcast_transition_info(const struct trans_info *ti) +{ + // mapping deviced state to capi signame + static const char *capi_signame[PSM_MAX] = { + [PSM_NORMAL] = SIGNAME_CHANGE_STATE_TO_NORMAL, + [PSM_SLEEP] = SIGNAME_CHANGE_STATE_TO_SLEEP, + [PSM_POWEROFF] = SIGNAME_CHANGE_STATE_TO_POWEROFF, + [PSM_REBOOT] = SIGNAME_CHANGE_STATE_TO_REBOOT, + }; + + // mapping deviced state to capi state + static const guint64 capi_state[PSM_MAX] = { + [PSM_NORMAL] = POWER_STATE_NORMAL, + [PSM_SLEEP] = POWER_STATE_SLEEP, + [PSM_POWEROFF] = POWER_STATE_POWEROFF, + [PSM_REBOOT] = POWER_STATE_REBOOT, + }; + + gdbus_signal_emit(NULL, DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER, capi_signame[ti->next], + g_variant_new("(ttti)", capi_state[ti->curr], capi_state[ti->next], state_transition_counter, ti->reason)); +} + +static void psm_transition_normal_to_normal(const struct trans_info *ti) +{ + broadcast_transition_info(ti); + update_change_state_wait(state_transition_counter, ti, NULL); } static void psm_transition_normal_to_sleep(const struct trans_info *ti) { - int n_waiting; + int waiting; current = PSM_SLEEP; - gdbus_signal_emit(NULL, DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER, - "ChangeState", g_variant_new("(iti)", EVENT_TYPE_SLEEP, state_transition_counter, ti->reason)); - n_waiting = start_sleep_wait(state_transition_counter); - if (n_waiting > 0) { - /* There are sleep-waits. Defer wake unlock until all sleep-waits - * receive confirmation. Wake unlock will be done by - * psm_sleep_wait_done_cb() on receiving last confirmation.*/ + + broadcast_transition_info(ti); + waiting = update_change_state_wait(state_transition_counter, ti, psm_wake_unlock); + if (waiting > 0) { _D("Defer wake unlock"); return; } - device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_UNLOCK, NULL); + psm_wake_unlock(); } static void psm_transition_sleep_to_normal(const struct trans_info *ti) { current = PSM_NORMAL; - stop_sleep_wait(); + + broadcast_transition_info(ti); device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL); - gdbus_signal_emit(NULL, DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER, - "ChangeState", g_variant_new("(iti)", EVENT_TYPE_WAKEUP, state_transition_counter, ti->reason)); + update_change_state_wait(state_transition_counter, ti, NULL); } static void psm_transition_sleep_to_sleep(const struct trans_info *ti) { - int n_waiting; + int waiting; + broadcast_transition_info(ti); device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL); - gdbus_signal_emit(NULL, DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER, - "ChangeState", g_variant_new("(iti)", EVENT_TYPE_SLEEP, state_transition_counter, ti->reason)); - n_waiting = start_sleep_wait(state_transition_counter); - if (n_waiting > 0) { - /* There are sleep-waits. Defer wake unlock until all sleep-waits - * receive confirmation. Wake unlock will be done by - * psm_sleep_wait_done_cb() on receiving last confirmation.*/ + waiting = update_change_state_wait(state_transition_counter, ti, psm_wake_unlock); + if (waiting > 0) { _D("Defer wake unlock"); return; } - device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_UNLOCK, NULL); + psm_wake_unlock(); } static void psm_transition_normal_to_poweroff(const struct trans_info *ti) { - const struct device_ops *power_device; + int waiting; current = PSM_POWEROFF; - power_device = find_device("power"); - if (check_default(power_device)) + broadcast_transition_info(ti); + waiting = update_change_state_wait(state_transition_counter, ti, psm_trigger_poweroff); + if (waiting > 0) { + _D("Defer poweroff"); return; - - if (power_device->execute) { - device_notify(DEVICE_NOTIFIER_REQUEST_DISABLE_AUTOSLEEP, NULL); - _D("Powerkey long pressed"); - power_device->execute("poweroff"); } + + psm_trigger_poweroff(); } static int psm_transition_state_cb(void *data) @@ -179,7 +212,9 @@ static int psm_transition_state_cb(void *data) /* transition */ ++state_transition_counter; if (current == PSM_NORMAL) { - if (next == PSM_SLEEP) + if (next == PSM_NORMAL) + psm_transition_normal_to_normal(ti); + else if (next == PSM_SLEEP) psm_transition_normal_to_sleep(ti); else if (next == PSM_POWEROFF) psm_transition_normal_to_poweroff(ti); @@ -203,7 +238,6 @@ void power_state_manager_init(void *data) register_notifier(DEVICE_NOTIFIER_KEY_PRESS, acquire_temporal_lock); register_notifier(DEVICE_NOTIFIER_KEY_RELEASE, release_temporal_lock); register_notifier(DEVICE_NOTIFIER_INPUT_TRANSITION_STATE, psm_transition_state_cb); - register_notifier(DEVICE_NOTIFIER_POWER_SLEEP_WAIT_DONE, psm_sleep_wait_done_cb); power_plugin_dbus_init(NULL); } diff --git a/plugins/iot-headless/power/power-state-manager.h b/plugins/iot-headless/power/power-state-manager.h index 0497d59..9da0859 100644 --- a/plugins/iot-headless/power/power-state-manager.h +++ b/plugins/iot-headless/power/power-state-manager.h @@ -7,8 +7,10 @@ enum psm_state { PSM_NORMAL, PSM_SLEEP, PSM_POWEROFF, + PSM_REBOOT, PSM_MAX, }; +extern char *psm_name[PSM_MAX]; struct trans_info { int reason; diff --git a/plugins/iot-headless/power/power-state-wait.c b/plugins/iot-headless/power/power-state-wait.c new file mode 100644 index 0000000..a1c5e88 --- /dev/null +++ b/plugins/iot-headless/power/power-state-wait.c @@ -0,0 +1,218 @@ +#include +#include +#include +#include + +#include "shared/log.h" +#include "shared/device-notifier.h" +#include "shared/common.h" + +#include "power-state-wait.h" +#include "power-state-manager.h" + +#define MAX_WAIT_SECOND 5 /* second */ + +struct proc_info { + pid_t pid; + char comm[128]; + guint64 state_bitmap; + int killed; +}; + +struct change_state_wait { + struct proc_info *pi; + guint64 id; + enum psm_state state; +}; + +static GList *proc_list; +static GList *waiting_list; +static int max_wait_timer; +static void (*__change_state_wait_done) (void); +static enum psm_state waiting_state; + +static void change_state_wait_done(void) +{ + _D("%s wait done", psm_name[waiting_state]); + + if (max_wait_timer) { + g_source_remove(max_wait_timer); + max_wait_timer = 0; + } + + if (__change_state_wait_done) { + __change_state_wait_done(); + } +} + +static gboolean max_wait_expired_cb(void *data) +{ + struct change_state_wait *csw; + struct proc_info *pi; + GList *elem, *elem_next; + + max_wait_timer = 0; + + SYS_G_LIST_FOREACH_SAFE(waiting_list, elem, elem_next, csw) { + if (kill(csw->pi->pid, 0) != 0) + csw->pi->killed = 1; + else + _E("pid=%d(%s) hasn't confirmed id=%ld(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]); + waiting_list = g_list_remove_link(waiting_list, elem); + g_list_free(elem); + free(csw); + } + + SYS_G_LIST_FOREACH_SAFE(proc_list, elem, elem_next, pi) { + if (pi->killed) { + _D("Clean up not existing pid=%d(%s)", pi->pid, pi->comm); + proc_list = g_list_remove_link(proc_list, elem); + g_list_free(elem); + free(pi); + } + } + + change_state_wait_done(); + + return G_SOURCE_REMOVE; +} + +int add_change_state_wait(pid_t pid, guint64 state) +{ + struct proc_info *pi; + GList *elem; + + _D("pid=%d added csw for %#lx", pid, state); + + SYS_G_LIST_FOREACH(proc_list, elem, pi) { + if (pi->pid == pid) { + pi->state_bitmap |= state; + return 0; + } + } + + pi = calloc(1, sizeof(struct proc_info)); + if (!pi) + return -ENOMEM; + + pi->pid = pid; + pi->state_bitmap = state; + get_command(pid, pi->comm, sizeof(pi->comm)); + SYS_G_LIST_APPEND(proc_list, pi); + + return 0; +} + +void remove_change_state_wait(pid_t pid, guint64 state) +{ + struct proc_info *pi; + GList *elem, *elem_next; + + _D("pid=%d removed csw for %#lx", pid, state); + + SYS_G_LIST_FOREACH_SAFE(proc_list, elem, elem_next, pi) { + if (pi->pid == pid) { + pi->state_bitmap &= ~state; + if (pi->state_bitmap == 0) { + proc_list = g_list_remove_link(proc_list, elem); + g_list_free(elem); + free(pi); + } + } + } +} + +int confirm_change_state_wait(pid_t pid, guint64 id) +{ + struct change_state_wait *csw; + GList *elem, *elem_next; + + SYS_G_LIST_FOREACH_SAFE(waiting_list, elem, elem_next, csw) { + if (csw->pi->pid == pid && csw->id == id) { + _D("pid=%d(%s) confirmed id=%lu(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]); + waiting_list = g_list_remove_link(waiting_list, elem); + g_list_free(elem); + free(csw); + + if (SYS_G_LIST_LENGTH(waiting_list) == 0) { + change_state_wait_done(); + return 0; + } + } + } + + return 0; +} + +static int check_proc_requested_wait_for_state(struct proc_info *pi, enum psm_state state) +{ + if (!pi) + return 0; + + if (state == PSM_NORMAL) + return (pi->state_bitmap & POWER_STATE_NORMAL); + if (state == PSM_SLEEP) + return (pi->state_bitmap & POWER_STATE_SLEEP); + if (state == PSM_POWEROFF) + return (pi->state_bitmap & POWER_STATE_POWEROFF); + if (state == PSM_REBOOT) + return (pi->state_bitmap & POWER_STATE_REBOOT); + + return 0; +} + +int update_change_state_wait(guint64 id, const struct trans_info *ti, change_state_wait_done_cb callback) +{ + struct proc_info *pi; + struct change_state_wait *csw; + GList *elem, *elem_next; + int n_waiting; + + // initialize timer + if (max_wait_timer) { + g_source_remove(max_wait_timer); + max_wait_timer = 0; + } + + // we are waiting for confirm of transition to the next state + waiting_state = ti->next; + _D("%s wait is triggered, id=%ld", psm_name[waiting_state], id); + + // cancel all ongoing csw that is not a waiting for the next state + SYS_G_LIST_FOREACH_SAFE(waiting_list, elem, elem_next, csw) { + if (csw->state != waiting_state) { + waiting_list = g_list_remove_link(waiting_list, elem); + g_list_free(elem); + _D("Cancel waiting: pid=%d(%s) for id=%ld(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]); + free(csw); + } + } + + // add wait list + SYS_G_LIST_FOREACH(proc_list, elem, pi) { + if (check_proc_requested_wait_for_state(pi, waiting_state)) { + csw = calloc(1, sizeof(struct change_state_wait)); + if (!csw) + continue; + + csw->pi = pi; + csw->id = id; + csw->state = waiting_state; + SYS_G_LIST_APPEND(waiting_list, csw); + } + } + + n_waiting = SYS_G_LIST_LENGTH(waiting_list); + if (n_waiting == 0) { + _D("There were no csw requests for %s, skip waiting", psm_name[waiting_state]); + __change_state_wait_done = NULL; + return 0; + } + + __change_state_wait_done = callback; + + _D("Expected number of wait confirm=%d", n_waiting); + max_wait_timer = g_timeout_add_seconds(MAX_WAIT_SECOND, max_wait_expired_cb, NULL); + + return n_waiting; +} diff --git a/plugins/iot-headless/power/power-state-wait.h b/plugins/iot-headless/power/power-state-wait.h new file mode 100644 index 0000000..45544cd --- /dev/null +++ b/plugins/iot-headless/power/power-state-wait.h @@ -0,0 +1,14 @@ +#ifndef __POWER_STATE_WAIT_H__ +#define __POWER_STATE_WAIT_H__ + +#include +#include "power-state-manager.h" + +typedef void (*change_state_wait_done_cb) (void); + +int add_change_state_wait(pid_t pid, guint64 state); +void remove_change_state_wait(pid_t pid, guint64 state); +int confirm_change_state_wait(pid_t pid, guint64 id); +int update_change_state_wait(guint64 id, const struct trans_info *ti, change_state_wait_done_cb cb); + +#endif //__POWER_STATE_WAIT_H__ diff --git a/plugins/iot-headless/power/sleep-wait.c b/plugins/iot-headless/power/sleep-wait.c deleted file mode 100644 index 85bfd3d..0000000 --- a/plugins/iot-headless/power/sleep-wait.c +++ /dev/null @@ -1,185 +0,0 @@ -#include -#include - -#include "shared/log.h" -#include "shared/device-notifier.h" -#include "shared/common.h" - -#include "sleep-wait.h" - -#define MAX_WAIT_SECOND 5 /* second */ - -struct proc_info { - pid_t pid; - char comm[128]; - int killed; -}; - -struct sleep_wait { - struct proc_info *pi; - int id; -}; - -static GList *proc_list; -static GList *sleep_waiting; - -static int max_wait_timer; - -static void sleep_wait_done(void) -{ - if (max_wait_timer) { - g_source_remove(max_wait_timer); - max_wait_timer = 0; - } - - device_notify(DEVICE_NOTIFIER_POWER_SLEEP_WAIT_DONE, NULL); -} - -static gboolean max_wait_expired_cb(void *data) -{ - struct sleep_wait *sw; - struct proc_info *pi; - GList *elem, *elem_next; - - max_wait_timer = 0; - - SYS_G_LIST_FOREACH_SAFE(sleep_waiting, elem, elem_next, sw) { - if (kill(sw->pi->pid, 0) != 0) - sw->pi->killed = 1; - else - _E("pid=%d(%s) hasn't confirmed sleep wait", sw->pi->pid, sw->pi->comm); - sleep_waiting = g_list_remove_link(sleep_waiting, elem); - g_list_free(elem); - free(sw); - } - - SYS_G_LIST_FOREACH_SAFE(proc_list, elem, elem_next, pi) { - if (pi->killed) { - _D("Clean up not existing pid=%d(%s) from sleep wait", pi->pid, pi->comm); - proc_list = g_list_remove_link(proc_list, elem); - g_list_free(elem); - free(pi); - } - } - - _D("Maximum sleep wait expired, timeout=%ds", MAX_WAIT_SECOND); - device_notify(DEVICE_NOTIFIER_POWER_SLEEP_WAIT_DONE, NULL); - - return G_SOURCE_REMOVE; -} - -int add_sleep_wait(pid_t pid) -{ - struct proc_info *pi; - GList *elem; - - SYS_G_LIST_FOREACH(proc_list, elem, pi) { - if (pi->pid == pid) - return -EEXIST; - } - - pi = calloc(1, sizeof(struct proc_info)); - if (!pi) - return -ENOMEM; - - pi->pid = pid; - get_command(pid, pi->comm, sizeof(pi->comm)); - SYS_G_LIST_APPEND(proc_list, pi); - - return 0; -} - -void remove_sleep_wait(pid_t pid) -{ - struct sleep_wait *sw; - struct proc_info *pi; - GList *elem, *elem_next; - - SYS_G_LIST_FOREACH_SAFE(sleep_waiting, elem, elem_next, sw) { - if (sw->pi->pid == pid) { - sleep_waiting = g_list_remove_link(sleep_waiting, elem); - g_list_free(elem); - free(sw); - } - } - - SYS_G_LIST_FOREACH_SAFE(proc_list, elem, elem_next, pi) { - if (pi->pid == pid) { - sleep_waiting = g_list_remove_link(sleep_waiting, elem); - g_list_free(elem); - free(pi); - } - } -} - -int confirm_sleep_wait(pid_t pid, int id) -{ - struct sleep_wait *sw; - GList *elem, *elem_next; - - SYS_G_LIST_FOREACH_SAFE(sleep_waiting, elem, elem_next, sw) { - if (sw->pi->pid == pid && sw->id == id) { - _D("pid=%d(%s) confirmed sleep id=%d", sw->pi->pid, sw->pi->comm, sw->id); - sleep_waiting = g_list_remove_link(sleep_waiting, elem); - g_list_free(elem); - free(sw); - - if (SYS_G_LIST_LENGTH(sleep_waiting) == 0) { - /* all sleep-waits are checked */ - sleep_wait_done(); - return 0; - } - } - } - - return 0; -} - -int start_sleep_wait(int id) -{ - struct proc_info *pi; - struct sleep_wait *sw; - GList *elem; - int n_sleep_wait; - - /* create sleep_wait for every pid of proc_list */ - SYS_G_LIST_FOREACH(proc_list, elem, pi) { - sw = calloc(1, sizeof(struct sleep_wait)); - if (!sw) - continue; - - sw->pi = pi; - sw->id = id; - SYS_G_LIST_APPEND(sleep_waiting, sw); - } - - n_sleep_wait = SYS_G_LIST_LENGTH(sleep_waiting); - if (n_sleep_wait == 0) - return 0; - - /* reset timer */ - if (max_wait_timer) - g_source_remove(max_wait_timer); - - _D("Sleep wait is triggered, expected number of confirmation=%d", n_sleep_wait); - max_wait_timer = g_timeout_add_seconds(MAX_WAIT_SECOND, max_wait_expired_cb, NULL); - - return n_sleep_wait; -} - -void stop_sleep_wait(void) -{ - struct sleep_wait *sw; - GList *elem, *elem_next; - - if (max_wait_timer) { - g_source_remove(max_wait_timer); - max_wait_timer = 0; - } - - SYS_G_LIST_FOREACH_SAFE(sleep_waiting, elem, elem_next, sw) { - sleep_waiting = g_list_remove_link(sleep_waiting, elem); - g_list_free(elem); - free(sw); - } -} diff --git a/plugins/iot-headless/power/sleep-wait.h b/plugins/iot-headless/power/sleep-wait.h deleted file mode 100644 index 5110e3b..0000000 --- a/plugins/iot-headless/power/sleep-wait.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __SLEEP_WAIT_H__ -#define __SLEEP_WAIT_H__ - -#include - -int add_sleep_wait(pid_t pid); -void remove_sleep_wait(pid_t pid); -int confirm_sleep_wait(pid_t pid, int id); -int start_sleep_wait(int id); -void stop_sleep_wait(void); - -#endif //__SLEEP_WAIT_H__ diff --git a/src/shared/device-notifier.h b/src/shared/device-notifier.h index 07b4ec0..c917049 100644 --- a/src/shared/device-notifier.h +++ b/src/shared/device-notifier.h @@ -38,7 +38,6 @@ enum device_notifier_type { DEVICE_NOTIFIER_DISPLAY_AMBIENT_STATE, DEVICE_NOTIFIER_DISPLAY_LOCK, DEVICE_NOTIFIER_POWER_RESUME, - DEVICE_NOTIFIER_POWER_SLEEP_WAIT_DONE, DEVICE_NOTIFIER_POWEROFF, DEVICE_NOTIFIER_APPLICATION_BACKGROUND, DEVICE_NOTIFIER_APPLICATION_FOREGROUND, -- 2.7.4 From ffa8b66c00e286f3dabfbfba407f33781f0b7653 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Thu, 16 Dec 2021 16:43:20 +0900 Subject: [PATCH 06/16] Fix format specifier of type uint64_t Change-Id: Icaf193fbd700ece2d74482627cf9b3f54441f671 Signed-off-by: Youngjae Cho --- plugins/iot-headless/power/power-state-wait.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/plugins/iot-headless/power/power-state-wait.c b/plugins/iot-headless/power/power-state-wait.c index a1c5e88..bdd7152 100644 --- a/plugins/iot-headless/power/power-state-wait.c +++ b/plugins/iot-headless/power/power-state-wait.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -57,7 +58,7 @@ static gboolean max_wait_expired_cb(void *data) if (kill(csw->pi->pid, 0) != 0) csw->pi->killed = 1; else - _E("pid=%d(%s) hasn't confirmed id=%ld(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]); + _E("pid=%d(%s) hasn't confirmed id=%"PRIu64"(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]); waiting_list = g_list_remove_link(waiting_list, elem); g_list_free(elem); free(csw); @@ -82,7 +83,7 @@ int add_change_state_wait(pid_t pid, guint64 state) struct proc_info *pi; GList *elem; - _D("pid=%d added csw for %#lx", pid, state); + _D("pid=%d added csw for %#"PRIx64, pid, state); SYS_G_LIST_FOREACH(proc_list, elem, pi) { if (pi->pid == pid) { @@ -108,7 +109,7 @@ void remove_change_state_wait(pid_t pid, guint64 state) struct proc_info *pi; GList *elem, *elem_next; - _D("pid=%d removed csw for %#lx", pid, state); + _D("pid=%d removed csw for %#"PRIx64, pid, state); SYS_G_LIST_FOREACH_SAFE(proc_list, elem, elem_next, pi) { if (pi->pid == pid) { @@ -129,7 +130,7 @@ int confirm_change_state_wait(pid_t pid, guint64 id) SYS_G_LIST_FOREACH_SAFE(waiting_list, elem, elem_next, csw) { if (csw->pi->pid == pid && csw->id == id) { - _D("pid=%d(%s) confirmed id=%lu(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]); + _D("pid=%d(%s) confirmed id=%"PRIu64"(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]); waiting_list = g_list_remove_link(waiting_list, elem); g_list_free(elem); free(csw); @@ -176,14 +177,14 @@ int update_change_state_wait(guint64 id, const struct trans_info *ti, change_sta // we are waiting for confirm of transition to the next state waiting_state = ti->next; - _D("%s wait is triggered, id=%ld", psm_name[waiting_state], id); + _D("%s wait is triggered, id=%"PRIu64, psm_name[waiting_state], id); // cancel all ongoing csw that is not a waiting for the next state SYS_G_LIST_FOREACH_SAFE(waiting_list, elem, elem_next, csw) { if (csw->state != waiting_state) { waiting_list = g_list_remove_link(waiting_list, elem); g_list_free(elem); - _D("Cancel waiting: pid=%d(%s) for id=%ld(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]); + _D("Cancel waiting: pid=%d(%s) for id=%"PRIu64"(%s)", csw->pi->pid, csw->pi->comm, csw->id, psm_name[csw->state]); free(csw); } } -- 2.7.4 From dabba2e27aa0fdce9a8e5b38ca6848bda6c90c31 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Mon, 20 Dec 2021 15:41:53 +0900 Subject: [PATCH 07/16] tool: add board opeartions Change-Id: I300c324d1175fe53b1b69520b4c9ba29219a91fc Signed-off-by: Youngjae Cho --- CMakeLists.txt | 4 ++-- packaging/deviced.spec | 5 +++- src/tools/partition-switch/CMakeLists.txt | 15 ------------ src/tools/partition-switch/partition-switch.c | 6 ----- tools/board/CMakeLists.txt | 21 +++++++++++++++++ tools/board/clear-boot-mode.c | 25 ++++++++++++++++++++ tools/board/get-boot-mode.c | 33 +++++++++++++++++++++++++++ tools/board/set-boot-success.c | 25 ++++++++++++++++++++ tools/board/switch-partition.c | 25 ++++++++++++++++++++ {src/tools => tools}/devicectl/CMakeLists.txt | 0 {src/tools => tools}/devicectl/devicectl.c | 0 {src/tools => tools}/devicectl/usb.c | 0 {src/tools => tools}/devicectl/usb.h | 0 13 files changed, 135 insertions(+), 24 deletions(-) delete mode 100644 src/tools/partition-switch/CMakeLists.txt delete mode 100644 src/tools/partition-switch/partition-switch.c create mode 100644 tools/board/CMakeLists.txt create mode 100644 tools/board/clear-boot-mode.c create mode 100644 tools/board/get-boot-mode.c create mode 100644 tools/board/set-boot-success.c create mode 100644 tools/board/switch-partition.c rename {src/tools => tools}/devicectl/CMakeLists.txt (100%) rename {src/tools => tools}/devicectl/devicectl.c (100%) rename {src/tools => tools}/devicectl/usb.c (100%) rename {src/tools => tools}/devicectl/usb.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e4c717..4a47b81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -317,8 +317,8 @@ ENDIF() ADD_SUBDIRECTORY(src/battery-monitor) ADD_SUBDIRECTORY(src/libdeviced) -ADD_SUBDIRECTORY(src/tools/devicectl) -ADD_SUBDIRECTORY(src/tools/partition-switch) +ADD_SUBDIRECTORY(tools/devicectl) +ADD_SUBDIRECTORY(tools/board) IF(TIZEN_FEATURE_USBHOST_TEST STREQUAL on) ADD_SUBDIRECTORY(tests/usb-host-ffs-test-daemon) ENDIF() diff --git a/packaging/deviced.spec b/packaging/deviced.spec index 7191f5d..7adeb77 100644 --- a/packaging/deviced.spec +++ b/packaging/deviced.spec @@ -314,7 +314,10 @@ mv %{_libdir}/iot-headless-power.so %{_libdir}/deviced/power.so #if #{?usb_module} == on ==> always on %{_bindir}/direct_set_debug.sh %{TZ_SYS_DUMPGEN}/dump_pmstate_log.sh -%attr(2551,root,root) %{_bindir}/partition_switch +%attr(2551,root,root) %{_bindir}/device_board_switch_partition +%attr(2551,root,root) %{_bindir}/device_board_set_boot_success +%attr(2551,root,root) %{_bindir}/device_board_clear_boot_mode +%attr(2551,root,root) %{_bindir}/device_board_get_boot_mode #endif %files auto-test diff --git a/src/tools/partition-switch/CMakeLists.txt b/src/tools/partition-switch/CMakeLists.txt deleted file mode 100644 index 402eef8..0000000 --- a/src/tools/partition-switch/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -SET(CMAKE_C_FLAGS ENV${CFLAGS}) - -INCLUDE(FindPkgConfig) -pkg_check_modules(REQUIRED_PKGS REQUIRED hal-api-device) -FOREACH(flag ${REQUIRED_PKGS_CFLAGS}) - SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") -ENDFOREACH(flag) -SET(CMAKE_C_FLAGS ${EXTRA_CFLAGS}) - -ADD_EXECUTABLE(partition_switch partition-switch.c) -SET_TARGET_PROPERTIES(partition_switch PROPERTIES COMPILE_FLAGS "-fPIE") -SET_TARGET_PROPERTIES(partition_switch PROPERTIES LINK_FLAGS "-pie") -TARGET_LINK_LIBRARIES(partition_switch ${REQUIRED_PKGS_LDFLAGS}) - -INSTALL(TARGETS partition_switch DESTINATION bin) diff --git a/src/tools/partition-switch/partition-switch.c b/src/tools/partition-switch/partition-switch.c deleted file mode 100644 index d06fd02..0000000 --- a/src/tools/partition-switch/partition-switch.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main(int argc, char *argv[]) -{ - return hal_device_board_switch_partition(argc, argv); -} diff --git a/tools/board/CMakeLists.txt b/tools/board/CMakeLists.txt new file mode 100644 index 0000000..2ac7eab --- /dev/null +++ b/tools/board/CMakeLists.txt @@ -0,0 +1,21 @@ +SET(CMAKE_C_FLAGS ENV${CFLAGS}) + +INCLUDE(FindPkgConfig) +pkg_check_modules(REQUIRED_PKGS REQUIRED hal-api-device) +FOREACH(flag ${REQUIRED_PKGS_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) +SET(CMAKE_C_FLAGS ${EXTRA_CFLAGS}) + +MACRO(ADD_BOOT_EXECUTABLE BINARY_NAME SRCS) + ADD_EXECUTABLE(${BINARY_NAME} ${SRCS}) + SET_TARGET_PROPERTIES(${BINARY_NAME} PROPERTIES COMPILE_FLAGS "-fPIE") + SET_TARGET_PROPERTIES(${BINARY_NAME} PROPERTIES LINK_FLAGS "-pie") + TARGET_LINK_LIBRARIES(${BINARY_NAME} ${REQUIRED_PKGS_LDFLAGS}) + INSTALL(TARGETS ${BINARY_NAME} DESTINATION bin) +ENDMACRO() + +ADD_BOOT_EXECUTABLE(device_board_switch_partition switch-partition.c) +ADD_BOOT_EXECUTABLE(device_board_set_boot_success set-boot-success.c) +ADD_BOOT_EXECUTABLE(device_board_clear_boot_mode clear-boot-mode.c) +ADD_BOOT_EXECUTABLE(device_board_get_boot_mode get-boot-mode.c) diff --git a/tools/board/clear-boot-mode.c b/tools/board/clear-boot-mode.c new file mode 100644 index 0000000..38075f9 --- /dev/null +++ b/tools/board/clear-boot-mode.c @@ -0,0 +1,25 @@ +/* + * device-board-clear-boot-mode + * + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +int main(int argc, char *argv[]) +{ + return hal_device_board_clear_boot_mode(); +} diff --git a/tools/board/get-boot-mode.c b/tools/board/get-boot-mode.c new file mode 100644 index 0000000..29ddde5 --- /dev/null +++ b/tools/board/get-boot-mode.c @@ -0,0 +1,33 @@ +/* + * device-board-get-boot-mode + * + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include + +int main(int argc, char *argv[]) +{ + char buffer[1024] = { 0, }; + int ret; + + ret = hal_device_board_get_boot_mode(buffer, sizeof(buffer)); + if (ret == 0) + printf("%s", buffer); + + return ret; +} diff --git a/tools/board/set-boot-success.c b/tools/board/set-boot-success.c new file mode 100644 index 0000000..16ec3a5 --- /dev/null +++ b/tools/board/set-boot-success.c @@ -0,0 +1,25 @@ +/* + * device-board-set-boot-success + * + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +int main(int argc, char *argv[]) +{ + return hal_device_board_set_boot_success(); +} diff --git a/tools/board/switch-partition.c b/tools/board/switch-partition.c new file mode 100644 index 0000000..6c8c580 --- /dev/null +++ b/tools/board/switch-partition.c @@ -0,0 +1,25 @@ +/* + * device-board-switch-partition + * + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +int main(int argc, char *argv[]) +{ + return hal_device_board_switch_partition(argc, argv); +} diff --git a/src/tools/devicectl/CMakeLists.txt b/tools/devicectl/CMakeLists.txt similarity index 100% rename from src/tools/devicectl/CMakeLists.txt rename to tools/devicectl/CMakeLists.txt diff --git a/src/tools/devicectl/devicectl.c b/tools/devicectl/devicectl.c similarity index 100% rename from src/tools/devicectl/devicectl.c rename to tools/devicectl/devicectl.c diff --git a/src/tools/devicectl/usb.c b/tools/devicectl/usb.c similarity index 100% rename from src/tools/devicectl/usb.c rename to tools/devicectl/usb.c diff --git a/src/tools/devicectl/usb.h b/tools/devicectl/usb.h similarity index 100% rename from src/tools/devicectl/usb.h rename to tools/devicectl/usb.h -- 2.7.4 From b3a235df18f12c75095ce9e5d099a2bf73f33d41 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Fri, 24 Dec 2021 15:15:55 +0900 Subject: [PATCH 08/16] input: change input.conf format and parser Change-Id: Id6170a4f43ddef3b27f876f3e049dff100ad53a0 Signed-off-by: Youngjae Cho --- conf/iot-headless-input.conf | 48 +++++++------ plugins/iot-headless/input/input-config.c | 110 ++++++++++++------------------ 2 files changed, 71 insertions(+), 87 deletions(-) diff --git a/conf/iot-headless-input.conf b/conf/iot-headless-input.conf index d798628..404bb55 100644 --- a/conf/iot-headless-input.conf +++ b/conf/iot-headless-input.conf @@ -1,36 +1,38 @@ -# [Section] -# Keycode: power -# - set keycode to be configured -# Duration: start,end -# - set interval that filters event -# - end=-1 means infinite -# - level trigger event will be triggered on reaching start time after -# holding a key -# - edge trigger event will be triggered only when a key is released -# in between of the interval -# TriggerType: edge / level -# - edge: trigger event on releaseing key within a specific interval -# - level: trigger event on holding key for a duration -# Action=broadcast -# - broadcast event using dbus signal -# Action=curr,next -# - add state transition event from curr to next +# [EVENT_ACTION] - define event and corresponding action +# Name=string +# - define mnemonic for the event, and it is only used for logging +# Enum=integer +# - define an integer that represents the event. deviced uses this +# integer in broadcasting dbus signal. +# Keycode=integer +# - define keycode to filter key event +# Duration=integer,integer +# - define time window in milisecond for filtering key event. -1 means no limit. +# TriggerType=level/edge +# - define event type +# Action=broadcast +# - define broadcast action for the event. +# Action=current,next +# - define state transition action for the event. -[BLINKKEY_EDGE] +[EVENT_ACTION] +Name=BLINKKEY_EDGE Enum=1000 Keycode=power Duration=0,2000 TriggerType=edge Action=sleep,sleep -[SHORTKEY_LEVEL] +[EVENT_ACTION] +Name=SHORTKEY_LEVEL Enum=1001 Keycode=power Duration=2000,-1 TriggerType=level Action=broadcast -[SHORTKEY_EDGE] +[EVENT_ACTION] +Name=SHORTKEY_EDGE Enum=1002 Keycode=power Duration=2000,7000 @@ -38,14 +40,16 @@ TriggerType=edge Action=normal,sleep Action=sleep,normal -[LONGKEY_LEVEL] +[EVENT_ACTION] +Name=LONGKEY_LEVEL Enum=1003 Keycode=power Duration=7000,-1 TriggerType=level Action=broadcast -[LONGKEY_EDGE] +[EVENT_ACTION] +Name=LONGKEY_EDGE Enum=1004 Keycode=power Duration=7000,-1 diff --git a/plugins/iot-headless/input/input-config.c b/plugins/iot-headless/input/input-config.c index 126eec3..026c7be 100644 --- a/plugins/iot-headless/input/input-config.c +++ b/plugins/iot-headless/input/input-config.c @@ -84,7 +84,7 @@ static enum psm_state convert_action_string_to_psm_state(char *str) return PSM_MAX; } -static void add_action_transition_state(struct input_event_unit *ieu, char *curr, char *next) +static void add_action_transition_info(struct input_event_unit *ieu, char *curr, char *next) { struct trans_info *ti = NULL; GList **action_list = (GList **) &(ieu->user_data); @@ -114,90 +114,70 @@ static void parse_action(struct input_event_unit *ieu, const char *action) } else if (sscanf(action, "%15[^,],%15s", curr, next) == 2) { ieu->notifier = DEVICE_NOTIFIER_INPUT_TRANSITION_STATE; /* append transition info to ieu->user_data */ - add_action_transition_state(ieu, curr, next); + add_action_transition_info(ieu, curr, next); } else { _E("Invalid action=%s", action); } } -static int load_input_config(struct parse_result *result, void *data) +static void parse_event_action_property(gpointer data, gpointer user_data) { - GList **tmp = (GList **) data; - GList *elem; + struct section_property *prop = (struct section_property *) data; + struct input_event_unit *ieu = (struct input_event_unit *) user_data; - /* caching previous ieu */ - static struct input_event_unit *ieu = NULL; - - /* find ieu if the given name is not matched with cached ieu */ - if (!ieu || strncmp(ieu->name, result->section, strlen(ieu->name) + 1)) { - SYS_G_LIST_FOREACH(*tmp, elem, ieu) { - if (!strncmp(ieu->name, result->section, strlen(ieu->name) + 1)) - break; - } - - /* make a new ieu */ - if (!ieu) { - ieu = calloc(1, sizeof(struct input_event_unit)); - if (!ieu) - return -ENOMEM; - ieu->name = strndup(result->section, 32); - SYS_G_LIST_APPEND(*tmp, ieu); - } - } + if (!prop || !ieu) + return; - if (MATCH(result->name, "Enum")) { - sscanf(result->value, "%d", &ieu->id); - } else if (MATCH(result->name, "Keycode")) { - parse_keycode(ieu, result->value); - } else if (MATCH(result->name, "Duration")) { - parse_duration(ieu, result->value); - } else if (MATCH(result->name, "TriggerType")) { - parse_trigger_type(ieu, result->value); - } else if (MATCH(result->name, "Action")) { - parse_action(ieu, result->value); + _D("Key=%s, Value=%s", prop->key, prop->value); + + if (MATCH(prop->key, "Name")) { + ieu->name = strndup(prop->value, 32); + } else if (MATCH(prop->key, "Enum")) { + sscanf(prop->value, "%d", &ieu->id); + } else if (MATCH(prop->key, "Keycode")) { + parse_keycode(ieu, prop->value); + } else if (MATCH(prop->key, "Duration")) { + parse_duration(ieu, prop->value); + } else if (MATCH(prop->key, "TriggerType")) { + parse_trigger_type(ieu, prop->value); + } else if (MATCH(prop->key, "Action")) { + parse_action(ieu, prop->value); } - - return 0; } -static int parse_input_config(void) +static int parse_event_action(const struct parse_result *result, void *data) { - GList *tmp = NULL; - GList *elem; struct input_config *ic; struct input_event_unit *ieu; - /* construct config list by section name */ - config_parse(INPUT_CONF_PATH, load_input_config, (void *) &tmp); - - /* reconstruct config list by keycode */ - SYS_G_LIST_FOREACH(tmp, elem, ieu) { - ic = find_input_config(ieu->keycode); - if (!ic) { - ic = calloc(1, sizeof(struct input_config)); - if (!ic) - return -ENOMEM; - ic->keycode = ieu->keycode; - SYS_G_LIST_APPEND(input_config_list, ic); - } - SYS_G_LIST_APPEND(ic->event_list, ieu); - _D("Input event unit: name=%s, enum=%d, start=%lu, end=%lu, type=%d, action=%d", - ieu->name, ieu->id, ieu->interval[0], ieu->interval[1], ieu->type, ieu->notifier); - if (ieu->notifier == DEVICE_NOTIFIER_INPUT_TRANSITION_STATE) { - struct trans_info *ti; - GList *elem; - SYS_G_LIST_FOREACH((GList *)ieu->user_data, elem, ti) - _D("Transition state event is registered: %d -> %d", ti->curr, ti->next); - } - } + if (!result || !result->props) + return 0; + + if (!MATCH(result->section, "EVENT_ACTION")) + return 0; + + _D("Input section=%s", result->section); - /* cleanup tmp list */ - g_list_free(tmp); + ieu = calloc(1, sizeof(struct input_event_unit)); + if (!ieu) + return 0; + + g_list_foreach(result->props, parse_event_action_property, ieu); + + ic = find_input_config(ieu->keycode); + if (!ic) { + ic = calloc(1, sizeof(struct input_config)); + if (!ic) + return -ENOMEM; + ic->keycode = ieu->keycode; + SYS_G_LIST_APPEND(input_config_list, ic); + } + SYS_G_LIST_APPEND(ic->event_list, ieu); return 0; } void init_input_config(void) { - parse_input_config(); + libsys_config_parse_by_section(INPUT_CONF_PATH, parse_event_action, NULL); } -- 2.7.4 From b3036eb10b5d5ec1820ff9b5e619a1081e629197 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Tue, 4 Jan 2022 18:34:49 +0900 Subject: [PATCH 09/16] device-notifier: add callback that can receive user_data typedef int (*notify_cb_udata)(void *data, void *user_data) >> The callback has an additional parameter, user_data, for receiving user data. typedef void (*destroy_cb_udata)(void *user_data) >> The callback is invoked on removing notifier with parameter user_data. int __register_notifier_udata(enum device_notifier_type type, notify_cb_udata func, void *user_data, destroy_cb_udata func_destroy, const char *caller) >> Returns negative errno on error occured. Otherwise positive integer that denotes notifier id, which can be used for unregistering the notifier. >> There are two additional parameters compared to the original register_notifier(). One is user_data, which is passed as the second parameter to callback and the other is func_destroy, which is invoked on removing notifier. >> It is allowed to register multiple notifier with same callback on a same type, because a user_data might differ even though they have same callback on a same type. int __unregister_notifier_udata(int id, const char *caller) >> Receives notifier id and unregisters matching notifier. Change-Id: I46d1fec98eae19dbd9aaed60dfd84f760d152b9e Signed-off-by: Youngjae Cho --- src/shared/device-notifier.c | 64 +++++++- src/shared/device-notifier.h | 10 ++ .../test-device-notifier.c | 170 ++++++++++++++++++--- 3 files changed, 226 insertions(+), 18 deletions(-) diff --git a/src/shared/device-notifier.c b/src/shared/device-notifier.c index 08044f1..6eacafe 100644 --- a/src/shared/device-notifier.c +++ b/src/shared/device-notifier.c @@ -27,9 +27,15 @@ #define __stringify(x...) __stringify_1(x) struct device_notifier { + int id; + bool deleted; enum device_notifier_type type; int (*func)(void *data); + + int (*func_udata)(void *data, void *user_data); + void (*destroyer)(void *user_data); + void *user_data; }; static GList *device_notifier_list; @@ -110,6 +116,39 @@ int __register_notifier(enum device_notifier_type type, notify_cb func, const ch return 0; } +int __register_notifier_udata(enum device_notifier_type type, + notify_cb_udata func_udata, void *user_data, + destroy_cb_udata func_destroy_udata, const char *caller) +{ + struct device_notifier *notifier; + static int id = 1; + + _I("%s, %p by %s", device_notifier_type_str[type], func_udata, caller); + + if (!func_udata) { + _E("invalid func address! by %s", caller); + return -EINVAL; + } + + notifier = calloc(1, sizeof(struct device_notifier)); + if (!notifier) { + _E("Fail to malloc for %s notifier! by %s", device_notifier_type_str[type], caller); + return -ENOMEM; + } + + notifier->id = id; + notifier->type = type; + notifier->func_udata = func_udata; + notifier->user_data = user_data; + notifier->destroyer = func_destroy_udata; + + SYS_G_LIST_APPEND(device_notifier_list, notifier); + + ++id; + + return notifier->id; +} + int __unregister_notifier(enum device_notifier_type type, notify_cb func, const char *caller) { GList *n; @@ -128,6 +167,22 @@ int __unregister_notifier(enum device_notifier_type type, notify_cb func, const return 0; } +int __unregister_notifier_udata(int id, const char *caller) +{ + GList *n; + struct device_notifier *notifier; + + SYS_G_LIST_FOREACH(device_notifier_list, n, notifier) { + if (notifier->id == id) { + if (notifier->destroyer) + notifier->destroyer(notifier->user_data); + notifier->deleted = true; + } + } + + return 0; +} + static gboolean delete_unused_notifier_cb(void *data) { GList *n; @@ -154,6 +209,8 @@ void device_notify(enum device_notifier_type type, void *data) if (!notifier->deleted && type == notifier->type) { if (notifier->func) notifier->func(data); + else if (notifier->func_udata) + notifier->func_udata(data, notifier->user_data); } } @@ -168,8 +225,13 @@ void device_notify_once(enum device_notifier_type type, void *data) SYS_G_LIST_FOREACH(device_notifier_list, n, notifier) { if (!notifier->deleted && type == notifier->type) { - if (notifier->func) + if (notifier->func) { notifier->func(data); + } else if (notifier->func_udata) { + notifier->func_udata(data, notifier->user_data); + if (notifier->destroyer) + notifier->destroyer(notifier->user_data); + } notifier->deleted = true; } diff --git a/src/shared/device-notifier.h b/src/shared/device-notifier.h index c917049..ec7cfd3 100644 --- a/src/shared/device-notifier.h +++ b/src/shared/device-notifier.h @@ -86,6 +86,8 @@ typedef enum _device_notifier_state { } device_notifier_state_e; typedef int (*notify_cb)(void *data); +typedef int (*notify_cb_udata)(void *data, void *user_data); +typedef void (*destroy_cb_udata)(void *user_data); /* * This is for internal callback method. */ @@ -93,6 +95,14 @@ int __register_notifier(enum device_notifier_type type, notify_cb func, const ch #define register_notifier(type, func) __register_notifier(type, func, __func__) int __unregister_notifier(enum device_notifier_type type, notify_cb func, const char *caller); #define unregister_notifier(type, func) __unregister_notifier(type, func, __func__) + +int __register_notifier_udata(enum device_notifier_type type, notify_cb_udata func, void *user_data, + destroy_cb_udata func_destroy, const char *caller); +#define register_notifier_udata(type, func, user_data, func_destroy) \ + __register_notifier_udata(type, func, user_data, func_destroy, __func__) +int __unregister_notifier_udata(int id, const char *caller); +#define unregister_notifier_udata(id) __unregister_notifier_udata(id, __func__) + void device_notify(enum device_notifier_type type, void *value); void device_notify_once(enum device_notifier_type status, void *data); diff --git a/tests/deviced-common-private-test/test-device-notifier.c b/tests/deviced-common-private-test/test-device-notifier.c index bc86513..b654887 100644 --- a/tests/deviced-common-private-test/test-device-notifier.c +++ b/tests/deviced-common-private-test/test-device-notifier.c @@ -1,64 +1,200 @@ +#include #include #include #include #include "test-main.h" -static int notified; +#define INT_MAX ((~0) >> 1) static int notify_callback(void *data) { - notified = (int)(intptr_t) data; + check_expected(data); return 0; } +static int notify_callback_udata(void *data, void *udata) +{ + check_expected(data); + check_expected(udata); + + return 0; +} + +static void destroy_callback_udata(void *udata) +{ + check_expected(udata); +} + static void test_device_notify_n(void **state) { int retval; retval = register_notifier(DEVICE_NOTIFIER_MAX, NULL); assert_int_equal(retval, -EINVAL); + + retval = register_notifier_udata(DEVICE_NOTIFIER_MAX, NULL, NULL, NULL); + assert_int_equal(retval, -EINVAL); } -static void test_device_notify_p(void **state) +static void test_device_notify_p1(void **state) { int retval; - notified = 999; - retval = register_notifier(DEVICE_NOTIFIER_LCD, notify_callback); assert_int_equal(retval, 0); + expect_value(notify_callback, data, 0x3f3f3f3f); - for (int i = 3; i < 8; ++i) { - device_notify(DEVICE_NOTIFIER_LCD, (void *)(intptr_t) i); - assert_int_equal(notified, i); - } + device_notify(DEVICE_NOTIFIER_LCD, (void *)(intptr_t) 0x3f3f3f3f); } -static void test_device_notify_once_p(void **state) +static void test_device_notify_p2(void **state) { int retval; - int value = 721; + int notify_data; + const int udata2 = 0xaeaeaeae; + const int udata3 = 0x99997777; + + notify_data = 0x12456321; + + /* 1st notifier */ + retval = register_notifier(DEVICE_NOTIFIER_PMQOS, notify_callback); + assert_int_equal(retval, 0); + + /* 2nd notifier */ + retval = register_notifier_udata(DEVICE_NOTIFIER_PMQOS, notify_callback_udata, (void *)(intptr_t) udata2, NULL); + assert_in_range(retval, 1, INT_MAX); + + /* expect invocation of 1st callback and check parameter */ + expect_value(notify_callback, data, notify_data); + /* expect invocation of 2nd callback and check parameter */ + expect_value(notify_callback_udata, data, notify_data); + expect_value(notify_callback_udata, udata, udata2); + + device_notify(DEVICE_NOTIFIER_PMQOS, (void *)(intptr_t) notify_data); + + notify_data = 0x888899dd; + + /* 3rd notifier */ + retval = register_notifier_udata(DEVICE_NOTIFIER_PMQOS, notify_callback_udata, (void *)(intptr_t) udata3, NULL); + assert_in_range(retval, 1, INT_MAX); + + /* expect invocation of 1st callback and check parameter */ + expect_value(notify_callback, data, notify_data); + /* expect invocation of 2nd callback and check parameter */ + expect_value(notify_callback_udata, data, notify_data); + expect_value(notify_callback_udata, udata, udata2); + /* expect invocation of 3rd callback and check parameter */ + expect_value(notify_callback_udata, data, notify_data); + expect_value(notify_callback_udata, udata, udata3); + + device_notify(DEVICE_NOTIFIER_PMQOS, (void *)(intptr_t) notify_data); +} + +static void test_device_notify_p3(void **state) +{ + int notify_data; + int id1, id2; + const int udata1 = 0x41a41a41; + const int udata2 = 0x77777777; + + /* first run */ + notify_data = 0x8575ddff; + + /* 1st notifier */ + id1 = register_notifier_udata(DEVICE_NOTIFIER_POWEROFF, notify_callback_udata, (void *)(intptr_t) udata1, NULL); + assert_in_range(id1, 1, INT_MAX); - notified = 999; + /* 2nd notifier */ + id2 = register_notifier_udata(DEVICE_NOTIFIER_POWEROFF, notify_callback_udata, (void *)(intptr_t) udata2, NULL); + assert_in_range(id2, 1, INT_MAX); + + /* expect invocation of 1st callback and check parameter */ + expect_value(notify_callback_udata, data, notify_data); + expect_value(notify_callback_udata, udata, udata1); + /* expect invocation of 2nd callback and check parameter */ + expect_value(notify_callback_udata, data, notify_data); + expect_value(notify_callback_udata, udata, udata2); + + device_notify(DEVICE_NOTIFIER_POWEROFF, (void *)(intptr_t) notify_data); + + /* second run. at this time device_notify() after unregistering 1st notifier */ + notify_data = 0x345; + + unregister_notifier_udata(id1); + + /* only expect invocation of 2nd callback and check parameter */ + expect_value(notify_callback_udata, data, notify_data); + expect_value(notify_callback_udata, udata, udata2); + + device_notify(DEVICE_NOTIFIER_POWEROFF, (void *)(intptr_t) notify_data); +} + +static void test_device_notify_once_p(void **state) +{ + int retval; retval = register_notifier(DEVICE_NOTIFIER_LCD_OFF, notify_callback); assert_int_equal(retval, 0); - device_notify_once(DEVICE_NOTIFIER_LCD_OFF, (void *)(intptr_t) value); - assert_int_equal(notified, value); + expect_value(notify_callback, data, 0xabcdabcd); + device_notify_once(DEVICE_NOTIFIER_LCD_OFF, (void *)(intptr_t) 0xabcdabcd); + + /* Don't add expect_value() for callback at this time. + * Therefore if the callback is invoked, check_expected() returns error */ + device_notify(DEVICE_NOTIFIER_LCD_OFF, (void *)(intptr_t) 0xabcdabcd); + + retval = register_notifier_udata(DEVICE_NOTIFIER_BATTERY_CHARGING, notify_callback_udata, (void *)(intptr_t) 0xfefefefe, NULL); + assert_in_range(retval, 1, INT_MAX); + + expect_value(notify_callback_udata, data, 0x34343434); + expect_value(notify_callback_udata, udata, 0xfefefefe); + device_notify_once(DEVICE_NOTIFIER_BATTERY_CHARGING, (void *)(intptr_t) 0x34343434); + + /* Don't add expect_value() for callback at this time. + * Therefore if the callback is invoked, check_expected() returns error */ + device_notify(DEVICE_NOTIFIER_BATTERY_CHARGING, (void *)(intptr_t) 0x34343434); +} + +static void test_destroy_callback_p1(void **state) +{ + int id; + + id = register_notifier_udata(DEVICE_NOTIFIER_LOWBAT, notify_callback_udata, + (void *)(intptr_t) 0x4848, destroy_callback_udata); + assert_in_range(id, 1, INT_MAX); + + expect_value(destroy_callback_udata, udata, 0x4848); + + unregister_notifier_udata(id); +} + +static void test_destroy_callback_p2(void **state) +{ + int id; + + id = register_notifier_udata(DEVICE_NOTIFIER_LOWBAT, notify_callback_udata, + (void *)(intptr_t) 0x1177, destroy_callback_udata); + assert_in_range(id, 1, INT_MAX); + + expect_value(notify_callback_udata, data, 0x9a9a9a9a); + expect_value(notify_callback_udata, udata, 0x1177); + expect_value(destroy_callback_udata, udata, 0x1177); - device_notify(DEVICE_NOTIFIER_LCD_OFF, (void *)(intptr_t) (value - 1)); - assert_int_equal(notified, value); + device_notify_once(DEVICE_NOTIFIER_LOWBAT, (void *)(intptr_t) 0x9a9a9a9a); } static int run_device_notifier_test(void) { static const struct CMUnitTest testsuite[] = { cmocka_unit_test(test_device_notify_n), - cmocka_unit_test(test_device_notify_p), + cmocka_unit_test(test_device_notify_p1), + cmocka_unit_test(test_device_notify_p2), + cmocka_unit_test(test_device_notify_p3), cmocka_unit_test(test_device_notify_once_p), + cmocka_unit_test(test_destroy_callback_p1), + cmocka_unit_test(test_destroy_callback_p2), }; return cmocka_run_group_tests(testsuite, NULL, NULL); -- 2.7.4 From 5b0fb32a5c063b817794756160b4c28a06734aa8 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Wed, 5 Jan 2022 18:45:12 +0900 Subject: [PATCH 10/16] device-notifier: add priority to device-notifier The priority is sorted in descending order, therefore the higher a priority is, the earlier it is invoked compared to the lower one. Change-Id: I30c995cdb4d8b84faf1d4542b81e27052b94a9ab Signed-off-by: Youngjae Cho --- src/shared/device-notifier.c | 21 ++++++++++----- src/shared/device-notifier.h | 15 +++++++---- .../test-device-notifier.c | 31 +++++++++++++++++++++- 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/shared/device-notifier.c b/src/shared/device-notifier.c index 6eacafe..661fae7 100644 --- a/src/shared/device-notifier.c +++ b/src/shared/device-notifier.c @@ -17,6 +17,7 @@ */ +#include #include #include "log.h" #include "device-notifier.h" @@ -28,8 +29,9 @@ struct device_notifier { int id; - + int priority; /* descending order */ bool deleted; + enum device_notifier_type type; int (*func)(void *data); @@ -41,7 +43,6 @@ struct device_notifier { static GList *device_notifier_list; static guint idl; - #define FIND_NOTIFIER(a, b, d, e, f) \ SYS_G_LIST_FOREACH(a, b, d) \ if (e == d->e && f == (d->f)) @@ -84,7 +85,13 @@ static const char *device_notifier_type_str[DEVICE_NOTIFIER_MAX] = { NOTIFY_STR(DEVICE_NOTIFIER_ULTRAPOWERSAVING), }; -int __register_notifier(enum device_notifier_type type, notify_cb func, const char *caller) +static gint compare_priority(gconstpointer a, gconstpointer b) +{ + /* descending order */ + return ((const struct device_notifier *)b)->priority - ((const struct device_notifier *)a)->priority + 1; +} + +int __register_notifier(enum device_notifier_type type, notify_cb func, int priority, const char *caller) { GList *n; struct device_notifier *notifier; @@ -109,16 +116,17 @@ int __register_notifier(enum device_notifier_type type, notify_cb func, const ch } notifier->type = type; + notifier->priority = priority; notifier->func = func; - SYS_G_LIST_APPEND(device_notifier_list, notifier); + device_notifier_list = g_list_insert_sorted(device_notifier_list, notifier, compare_priority); return 0; } int __register_notifier_udata(enum device_notifier_type type, notify_cb_udata func_udata, void *user_data, - destroy_cb_udata func_destroy_udata, const char *caller) + destroy_cb_udata func_destroy_udata, int priority, const char *caller) { struct device_notifier *notifier; static int id = 1; @@ -137,12 +145,13 @@ int __register_notifier_udata(enum device_notifier_type type, } notifier->id = id; + notifier->priority = priority; notifier->type = type; notifier->func_udata = func_udata; notifier->user_data = user_data; notifier->destroyer = func_destroy_udata; - SYS_G_LIST_APPEND(device_notifier_list, notifier); + device_notifier_list = g_list_insert_sorted(device_notifier_list, notifier, compare_priority); ++id; diff --git a/src/shared/device-notifier.h b/src/shared/device-notifier.h index ec7cfd3..241b339 100644 --- a/src/shared/device-notifier.h +++ b/src/shared/device-notifier.h @@ -91,15 +91,20 @@ typedef void (*destroy_cb_udata)(void *user_data); /* * This is for internal callback method. */ -int __register_notifier(enum device_notifier_type type, notify_cb func, const char *caller); -#define register_notifier(type, func) __register_notifier(type, func, __func__) +int __register_notifier(enum device_notifier_type type, notify_cb func, int priority, const char *caller); +#define register_notifier(type, func) __register_notifier(type, func, 0, __func__) +#define register_notifier_priority(type, func, prio) __register_notifier(type, func, prio, __func__) + int __unregister_notifier(enum device_notifier_type type, notify_cb func, const char *caller); #define unregister_notifier(type, func) __unregister_notifier(type, func, __func__) -int __register_notifier_udata(enum device_notifier_type type, notify_cb_udata func, void *user_data, - destroy_cb_udata func_destroy, const char *caller); +int __register_notifier_udata(enum device_notifier_type type, notify_cb_udata func, + void *user_data, destroy_cb_udata func_destroy, int priority, const char *caller); #define register_notifier_udata(type, func, user_data, func_destroy) \ - __register_notifier_udata(type, func, user_data, func_destroy, __func__) + __register_notifier_udata(type, func, user_data, func_destroy, 0, __func__) +#define register_notifier_udata_priority(type, func, user_data, func_destroy, prio) \ + __register_notifier_udata(type, func, user_data, func_destroy, prio, __func__) + int __unregister_notifier_udata(int id, const char *caller); #define unregister_notifier_udata(id) __unregister_notifier_udata(id, __func__) diff --git a/tests/deviced-common-private-test/test-device-notifier.c b/tests/deviced-common-private-test/test-device-notifier.c index b654887..6f882a6 100644 --- a/tests/deviced-common-private-test/test-device-notifier.c +++ b/tests/deviced-common-private-test/test-device-notifier.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -185,6 +184,35 @@ static void test_destroy_callback_p2(void **state) device_notify_once(DEVICE_NOTIFIER_LOWBAT, (void *)(intptr_t) 0x9a9a9a9a); } +static void test_device_notify_priority_p1(void **state) +{ + int id1, id2, id3; + + id1 = register_notifier_udata_priority(DEVICE_NOTIFIER_DISPLAY_LOCK, notify_callback_udata, + (void *)(intptr_t) 0x11111111, NULL, -300); + assert_in_range(id1, 1, INT_MAX); + + id2 = register_notifier_udata_priority(DEVICE_NOTIFIER_DISPLAY_LOCK, notify_callback_udata, + (void *)(intptr_t) 0x22222222, NULL, 500); + assert_in_range(id2, 1, INT_MAX); + + id3 = register_notifier_udata_priority(DEVICE_NOTIFIER_DISPLAY_LOCK, notify_callback_udata, + (void *)(intptr_t) 0x33333333, NULL, -300); + assert_in_range(id3, 1, INT_MAX); + + /* id2 will be invoked first */ + expect_value(notify_callback_udata, data, 0x1234); + expect_value(notify_callback_udata, udata, 0x22222222); + /* id1, id3 invocation follows it, + * and those are invoked in the order in which they were registered */ + expect_value(notify_callback_udata, data, 0x1234); + expect_value(notify_callback_udata, udata, 0x11111111); + expect_value(notify_callback_udata, data, 0x1234); + expect_value(notify_callback_udata, udata, 0x33333333); + + device_notify(DEVICE_NOTIFIER_DISPLAY_LOCK, (void *)(intptr_t)0x1234); +} + static int run_device_notifier_test(void) { static const struct CMUnitTest testsuite[] = { @@ -195,6 +223,7 @@ static int run_device_notifier_test(void) cmocka_unit_test(test_device_notify_once_p), cmocka_unit_test(test_destroy_callback_p1), cmocka_unit_test(test_destroy_callback_p2), + cmocka_unit_test(test_device_notify_priority_p1), }; return cmocka_run_group_tests(testsuite, NULL, NULL); -- 2.7.4 From 8e0c7aa7408802684ff9ddce371159858bae3339 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Thu, 6 Jan 2022 14:19:41 +0900 Subject: [PATCH 11/16] tests: add explicit typecast on expect_check() This suppresses mismatch of check_expected() due to sign-extended integer of cmocka framework on 32bit architecture. Change-Id: Ief1b52513c4d78a6373aaba7a36c97ed687768d0 Signed-off-by: Youngjae Cho --- .../test-device-notifier.c | 56 +++++++++++----------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/tests/deviced-common-private-test/test-device-notifier.c b/tests/deviced-common-private-test/test-device-notifier.c index 6f882a6..d049317 100644 --- a/tests/deviced-common-private-test/test-device-notifier.c +++ b/tests/deviced-common-private-test/test-device-notifier.c @@ -43,7 +43,7 @@ static void test_device_notify_p1(void **state) retval = register_notifier(DEVICE_NOTIFIER_LCD, notify_callback); assert_int_equal(retval, 0); - expect_value(notify_callback, data, 0x3f3f3f3f); + expect_value(notify_callback, data, (void *)(intptr_t) 0x3f3f3f3f); device_notify(DEVICE_NOTIFIER_LCD, (void *)(intptr_t) 0x3f3f3f3f); } @@ -66,10 +66,10 @@ static void test_device_notify_p2(void **state) assert_in_range(retval, 1, INT_MAX); /* expect invocation of 1st callback and check parameter */ - expect_value(notify_callback, data, notify_data); + expect_value(notify_callback, data, (void *)(intptr_t) notify_data); /* expect invocation of 2nd callback and check parameter */ - expect_value(notify_callback_udata, data, notify_data); - expect_value(notify_callback_udata, udata, udata2); + expect_value(notify_callback_udata, data, (void *)(intptr_t) notify_data); + expect_value(notify_callback_udata, udata,(void *)(intptr_t) udata2); device_notify(DEVICE_NOTIFIER_PMQOS, (void *)(intptr_t) notify_data); @@ -80,13 +80,13 @@ static void test_device_notify_p2(void **state) assert_in_range(retval, 1, INT_MAX); /* expect invocation of 1st callback and check parameter */ - expect_value(notify_callback, data, notify_data); + expect_value(notify_callback, data, (void *)(intptr_t) notify_data); /* expect invocation of 2nd callback and check parameter */ - expect_value(notify_callback_udata, data, notify_data); - expect_value(notify_callback_udata, udata, udata2); + expect_value(notify_callback_udata, data, (void *)(intptr_t) notify_data); + expect_value(notify_callback_udata, udata, (void *)(intptr_t) udata2); /* expect invocation of 3rd callback and check parameter */ - expect_value(notify_callback_udata, data, notify_data); - expect_value(notify_callback_udata, udata, udata3); + expect_value(notify_callback_udata, data, (void *)(intptr_t) notify_data); + expect_value(notify_callback_udata, udata, (void *)(intptr_t) udata3); device_notify(DEVICE_NOTIFIER_PMQOS, (void *)(intptr_t) notify_data); } @@ -110,11 +110,11 @@ static void test_device_notify_p3(void **state) assert_in_range(id2, 1, INT_MAX); /* expect invocation of 1st callback and check parameter */ - expect_value(notify_callback_udata, data, notify_data); - expect_value(notify_callback_udata, udata, udata1); + expect_value(notify_callback_udata, data, (void *)(intptr_t) notify_data); + expect_value(notify_callback_udata, udata, (void *)(intptr_t) udata1); /* expect invocation of 2nd callback and check parameter */ - expect_value(notify_callback_udata, data, notify_data); - expect_value(notify_callback_udata, udata, udata2); + expect_value(notify_callback_udata, data, (void *)(intptr_t) notify_data); + expect_value(notify_callback_udata, udata, (void *)(intptr_t) udata2); device_notify(DEVICE_NOTIFIER_POWEROFF, (void *)(intptr_t) notify_data); @@ -124,8 +124,8 @@ static void test_device_notify_p3(void **state) unregister_notifier_udata(id1); /* only expect invocation of 2nd callback and check parameter */ - expect_value(notify_callback_udata, data, notify_data); - expect_value(notify_callback_udata, udata, udata2); + expect_value(notify_callback_udata, data, (void *)(intptr_t) notify_data); + expect_value(notify_callback_udata, udata, (void *)(intptr_t) udata2); device_notify(DEVICE_NOTIFIER_POWEROFF, (void *)(intptr_t) notify_data); } @@ -137,7 +137,7 @@ static void test_device_notify_once_p(void **state) retval = register_notifier(DEVICE_NOTIFIER_LCD_OFF, notify_callback); assert_int_equal(retval, 0); - expect_value(notify_callback, data, 0xabcdabcd); + expect_value(notify_callback, data, (void *)(intptr_t) 0xabcdabcd); device_notify_once(DEVICE_NOTIFIER_LCD_OFF, (void *)(intptr_t) 0xabcdabcd); /* Don't add expect_value() for callback at this time. @@ -147,8 +147,8 @@ static void test_device_notify_once_p(void **state) retval = register_notifier_udata(DEVICE_NOTIFIER_BATTERY_CHARGING, notify_callback_udata, (void *)(intptr_t) 0xfefefefe, NULL); assert_in_range(retval, 1, INT_MAX); - expect_value(notify_callback_udata, data, 0x34343434); - expect_value(notify_callback_udata, udata, 0xfefefefe); + expect_value(notify_callback_udata, data, (void *)(intptr_t) 0x34343434); + expect_value(notify_callback_udata, udata, (void *)(intptr_t) 0xfefefefe); device_notify_once(DEVICE_NOTIFIER_BATTERY_CHARGING, (void *)(intptr_t) 0x34343434); /* Don't add expect_value() for callback at this time. @@ -164,7 +164,7 @@ static void test_destroy_callback_p1(void **state) (void *)(intptr_t) 0x4848, destroy_callback_udata); assert_in_range(id, 1, INT_MAX); - expect_value(destroy_callback_udata, udata, 0x4848); + expect_value(destroy_callback_udata, udata, (void *)(intptr_t) 0x4848); unregister_notifier_udata(id); } @@ -177,9 +177,9 @@ static void test_destroy_callback_p2(void **state) (void *)(intptr_t) 0x1177, destroy_callback_udata); assert_in_range(id, 1, INT_MAX); - expect_value(notify_callback_udata, data, 0x9a9a9a9a); - expect_value(notify_callback_udata, udata, 0x1177); - expect_value(destroy_callback_udata, udata, 0x1177); + expect_value(notify_callback_udata, data, (void *)(intptr_t) 0x9a9a9a9a); + expect_value(notify_callback_udata, udata, (void *)(intptr_t) 0x1177); + expect_value(destroy_callback_udata, udata, (void *)(intptr_t) 0x1177); device_notify_once(DEVICE_NOTIFIER_LOWBAT, (void *)(intptr_t) 0x9a9a9a9a); } @@ -201,14 +201,14 @@ static void test_device_notify_priority_p1(void **state) assert_in_range(id3, 1, INT_MAX); /* id2 will be invoked first */ - expect_value(notify_callback_udata, data, 0x1234); - expect_value(notify_callback_udata, udata, 0x22222222); + expect_value(notify_callback_udata, data, (void *)(intptr_t) 0x1234); + expect_value(notify_callback_udata, udata, (void *)(intptr_t) 0x22222222); /* id1, id3 invocation follows it, * and those are invoked in the order in which they were registered */ - expect_value(notify_callback_udata, data, 0x1234); - expect_value(notify_callback_udata, udata, 0x11111111); - expect_value(notify_callback_udata, data, 0x1234); - expect_value(notify_callback_udata, udata, 0x33333333); + expect_value(notify_callback_udata, data, (void *)(intptr_t) 0x1234); + expect_value(notify_callback_udata, udata, (void *)(intptr_t) 0x11111111); + expect_value(notify_callback_udata, data, (void *)(intptr_t) 0x1234); + expect_value(notify_callback_udata, udata, (void *)(intptr_t) 0x33333333); device_notify(DEVICE_NOTIFIER_DISPLAY_LOCK, (void *)(intptr_t)0x1234); } -- 2.7.4 From beca677ef6aa79e84915ff7ee12811faf5fff313 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Wed, 5 Jan 2022 16:44:15 +0900 Subject: [PATCH 12/16] power: introduce eventlock for iot-headless eventlock is another wakelock for guaranteeing subroutine of an event not to go to sleep regardless of power state. Therefore, the eventlock works independently of mainlock, which is affected by power state. The previous templock, which was for key event, has changed to eventlock. Change-Id: Ie6ac4cf2de6989845b2e64eefe06002147736da2 Signed-off-by: Youngjae Cho --- plugins/iot-headless/power/power-event-lock.c | 133 +++++++++++++++++++++++ plugins/iot-headless/power/power-event-lock.h | 7 ++ plugins/iot-headless/power/power-state-manager.c | 54 +-------- 3 files changed, 142 insertions(+), 52 deletions(-) create mode 100644 plugins/iot-headless/power/power-event-lock.c create mode 100644 plugins/iot-headless/power/power-event-lock.h diff --git a/plugins/iot-headless/power/power-event-lock.c b/plugins/iot-headless/power/power-event-lock.c new file mode 100644 index 0000000..0e75814 --- /dev/null +++ b/plugins/iot-headless/power/power-event-lock.c @@ -0,0 +1,133 @@ +#include +#include +#include + +#include "shared/bitmap.h" +#include "shared/device-notifier.h" +#include "shared/log.h" +#include "power-event-lock.h" + +/* eventlock is another wakelock than mainlock. + * + * The eventlock works independently of mainlock, which is controlled by + * power state. The main purpose of eventlock is to prevent the subroutine + * of an event from going to sleep regardless of the power state. */ +#define EVENT_LOCK "eventlock" +#define EVENT_LOCK_MARGIN_MS 1000 + +enum eventlock_type { + EL_MIN, + /* On receiving key event, expands EL_KEY to EL_KEY_* according to keycode */ + EL_KEY, + EL_KEY_POWER = EL_KEY, + EL_KEY_BLUETOOTH, + /* add eventlock type here */ + EL_MAX, +}; + +static struct dd_bitmap *eventlock; +static int notifier_id[EL_MAX][2]; + +static void event_wake_lock(enum eventlock_type type) +{ + int setcount; + + if (type <= EL_MIN || type >= EL_MAX) + return; + + set_bit(eventlock, type); + setcount = count_set_bit(eventlock); + + _D("Set eventlock of type=%d, current number of eventlock=%d", type, setcount); + + if (setcount == 1) { + sys_set_str("/sys/power/wake_lock", EVENT_LOCK); + _D("Acquired eventlock"); + } +} + +static void event_wake_unlock(enum eventlock_type type) +{ + int setcount; + + if (type <= EL_MIN || type >= EL_MAX) + return; + + clear_bit(eventlock, type); + setcount = count_set_bit(eventlock); + + _D("Unset eventlock of type=%d, current number of eventlock=%d", type, setcount); + + if (setcount == 0) { + sys_set_str("/sys/power/wake_unlock", EVENT_LOCK); + _D("Released eventlock"); + } +} + +static enum eventlock_type expand_key_eventlock_type(int keycode) +{ + if (keycode == KEY_POWER) + return EL_KEY_POWER; + if (keycode == KEY_BLUETOOTH) + return EL_KEY_BLUETOOTH; + /* add mapping for keycode to eventlock_type here */ + + return EL_MAX; +} + +static int power_event_lock_callback(void *data, void *udata) +{ + enum eventlock_type type = (enum eventlock_type)(intptr_t) udata; + + if (type == EL_KEY) { + /* On receiving key event, expand EL_KEY to EL_KEY_* according to the keycode */ + int keycode = (int)(intptr_t) data; + type = expand_key_eventlock_type(keycode); + } + + event_wake_lock(type); + + return 0; +} + +static int power_event_unlock_callback(void *data, void *udata) +{ + enum eventlock_type type = (enum eventlock_type)(intptr_t) udata; + + if (type == EL_KEY) { + /* On receiving key event, expand EL_KEY to EL_KEY_* according to the keycode */ + int keycode = (int)(intptr_t) data; + type = expand_key_eventlock_type(keycode); + } + + event_wake_unlock(type); + + return 0; +} + +static void register_power_event_lock_controller(enum eventlock_type type, + enum device_notifier_type lock_notify, + enum device_notifier_type unlock_notify) +{ + /* Acquiring lock must be followed by all the other notifiers, therefore + * give a large enough number as priority to make it be at the head of notifier list. + * On the other hand, releasing lock must follow all the other notifiers, therefore + * give a small enough number as priority to make it be at the tail of notifier list. */ + notifier_id[type][0] = register_notifier_udata_priority(lock_notify, + power_event_lock_callback, (void *)(intptr_t) type, NULL, 1000); + notifier_id[type][1] = register_notifier_udata_priority(unlock_notify, + power_event_unlock_callback, (void *)(intptr_t) type, NULL, -1000); +} + +void power_event_lock_init(void) +{ + eventlock = init_bitmap(EL_MAX); + if (!eventlock) { + _E("Failed to init event lock bitmap"); + return; + } + + register_power_event_lock_controller(EL_KEY, + DEVICE_NOTIFIER_KEY_PRESS, + DEVICE_NOTIFIER_KEY_RELEASE); +} diff --git a/plugins/iot-headless/power/power-event-lock.h b/plugins/iot-headless/power/power-event-lock.h new file mode 100644 index 0000000..f7906c5 --- /dev/null +++ b/plugins/iot-headless/power/power-event-lock.h @@ -0,0 +1,7 @@ +#ifndef __POWER_EVENT_LOCK_H__ +#define __POWER_EVENT_LOCK_H__ + +void power_event_lock_init(void); + +#endif //__POWER_EVENT_LOCK_H__ + diff --git a/plugins/iot-headless/power/power-state-manager.c b/plugins/iot-headless/power/power-state-manager.c index 959ed9c..5232c20 100644 --- a/plugins/iot-headless/power/power-state-manager.c +++ b/plugins/iot-headless/power/power-state-manager.c @@ -11,16 +11,11 @@ #include "power-state-manager.h" #include "power-dbus.h" #include "power-state-wait.h" - -/* Temporal wakelock of powerkey input */ -#define KEY_PRESSED_TEMPORAL_LOCK "templock" -#define TEMPORAL_LOCK_WAKE_MARGIN 1000 /* milisecond */ +#include "power-event-lock.h" #define EVENT_TYPE_SLEEP 0 #define EVENT_TYPE_WAKEUP 1 -static guint keypress_temporal_timer_id; - char *psm_name[PSM_MAX] = { [PSM_NORMAL] = "PSM_NORMAL", [PSM_SLEEP] = "PSM_SLEEP", @@ -31,50 +26,6 @@ char *psm_name[PSM_MAX] = { static guint64 state_transition_counter = 0; static enum psm_state current; -static gboolean temporal_lock_expired_cb(void *data) -{ - sys_set_str("/sys/power/wake_unlock", KEY_PRESSED_TEMPORAL_LOCK); - keypress_temporal_timer_id = 0; - - return G_SOURCE_REMOVE; -} - -static int acquire_temporal_lock(void *data) -{ - int keycode = (int)(intptr_t) data; - - if (keycode != KEY_POWER) - return 0; - - if (keypress_temporal_timer_id) { - g_source_remove(keypress_temporal_timer_id); - keypress_temporal_timer_id = 0; - } - - sys_set_str("/sys/power/wake_lock", KEY_PRESSED_TEMPORAL_LOCK); - - return 0; -} - -static int release_temporal_lock(void * data) -{ - int keycode = (int)(intptr_t) data; - - if (keycode != KEY_POWER) - return 0; - - if (keypress_temporal_timer_id) { - g_source_remove(keypress_temporal_timer_id); - keypress_temporal_timer_id = 0; - } - - /* templock margin */ - keypress_temporal_timer_id = g_timeout_add(TEMPORAL_LOCK_WAKE_MARGIN, - temporal_lock_expired_cb, NULL); - - return 0; -} - static void psm_wake_unlock(void) { /* for PSM_NORMAL, PSM_POWEROFF, do not wake unlock */ @@ -235,11 +186,10 @@ void power_state_manager_init(void *data) device_notify(DEVICE_NOTIFIER_REQUEST_ENABLE_AUTOSLEEP, NULL); device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL); - register_notifier(DEVICE_NOTIFIER_KEY_PRESS, acquire_temporal_lock); - register_notifier(DEVICE_NOTIFIER_KEY_RELEASE, release_temporal_lock); register_notifier(DEVICE_NOTIFIER_INPUT_TRANSITION_STATE, psm_transition_state_cb); power_plugin_dbus_init(NULL); + power_event_lock_init(); } static const struct device_ops power_state_manager_device_ops = { -- 2.7.4 From c2943fb1db7e7098fbff74752e4dde29ae2b69f4 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Mon, 3 Jan 2022 18:35:05 +0900 Subject: [PATCH 13/16] battery: introduce battery-plugin for iot-headless It handles battery event according to the iot-headless policy. Those policies are specified in battery.conf. For now it only handles event about charger connect/disconnect. 1. It triggers power state transition. Those transition actions are specified in EVENT_ACTION section. 2. It might hold wakelock for charger connection. It is specified in CHARGER_WAKELOCK section. Change-Id: Iee6803604a25bacca5ce68953033b71560ed4ba8 Signed-off-by: Youngjae Cho --- CMakeLists.txt | 1 + conf/battery.conf | 23 ++++ packaging/deviced.spec | 2 + plugins/iot-headless/battery/CMakeLists.txt | 18 +++ plugins/iot-headless/battery/battery-plugin.c | 153 +++++++++++++++++++++++ plugins/iot-headless/input/input-config.c | 2 +- plugins/iot-headless/power/power-event-lock.c | 28 ++++- plugins/iot-headless/power/power-state-manager.c | 2 +- src/battery/power-supply.c | 11 +- src/shared/device-notifier.h | 5 +- 10 files changed, 234 insertions(+), 11 deletions(-) create mode 100644 plugins/iot-headless/battery/CMakeLists.txt create mode 100644 plugins/iot-headless/battery/battery-plugin.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a47b81..96d3312 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -333,6 +333,7 @@ ADD_SUBDIRECTORY(plugins/tv/display) ADD_SUBDIRECTORY(plugins/iot-headed/display) ADD_SUBDIRECTORY(plugins/iot-headless/input) ADD_SUBDIRECTORY(plugins/iot-headless/power) +ADD_SUBDIRECTORY(plugins/iot-headless/battery) IF(BATTERY_MODULE STREQUAL on) ADD_SUBDIRECTORY(plugins/mobile/battery) ADD_SUBDIRECTORY(plugins/wearable/battery) diff --git a/conf/battery.conf b/conf/battery.conf index c882320..b376658 100644 --- a/conf/battery.conf +++ b/conf/battery.conf @@ -7,3 +7,26 @@ PowerOff=1 RealOff=0 WarningMethod=warning CriticalMethod=critical + +# hold wakelock if a charger has been connected, iot-headless only +[CHARGER_WAKELOCK] +ChargerWakeLockEnabled=yes + +# define event-action, iot-headless only +# DeviceNotifier= +# - define which event(device-notifiy) is filtered +# Action= +# - define action for the event +[EVENT_ACTION] +Name=CHARGER_CONNECTED +Enum=2001 +DeviceNotifier=DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED +Action=sleep,sleep +Action=normal,normal + +[EVENT_ACTION] +Name=CHARGER_DISCONNECTED +Enum=2002 +DeviceNotifier=DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED +Action=sleep,sleep +Action=normal,normal diff --git a/packaging/deviced.spec b/packaging/deviced.spec index 7adeb77..e32051c 100644 --- a/packaging/deviced.spec +++ b/packaging/deviced.spec @@ -252,6 +252,7 @@ mv %{_sysconfdir}/deviced/iot-headless-input.conf %{_sysconfdir}/deviced/input.c mkdir -p %{_libdir}/deviced mv %{_libdir}/iot-headless-input-handler.so %{_libdir}/deviced/input-handler.so mv %{_libdir}/iot-headless-power.so %{_libdir}/deviced/power.so +mv %{_libdir}/iot-headless-battery.so %{_libdir}/deviced/battery.so %files %manifest %{name}.manifest @@ -375,5 +376,6 @@ mv %{_libdir}/iot-headless-power.so %{_libdir}/deviced/power.so %config %{_sysconfdir}/deviced/iot-headless-input.conf %{_libdir}/iot-headless-input-handler.so %{_libdir}/iot-headless-power.so +%{_libdir}/iot-headless-battery.so %{_unitdir}/rndis.service %{_bindir}/rndis.sh diff --git a/plugins/iot-headless/battery/CMakeLists.txt b/plugins/iot-headless/battery/CMakeLists.txt new file mode 100644 index 0000000..a9ab36c --- /dev/null +++ b/plugins/iot-headless/battery/CMakeLists.txt @@ -0,0 +1,18 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +PROJECT(iot-headless-battery C) + +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(REQUIRED_PKGS REQUIRED + glib-2.0 + dlog + libsyscommon) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../power) + +FILE(GLOB SRCS "*.c") +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES PREFIX "") +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES OUTPUT_NAME iot-headless-battery) +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR} COMPONENT RuntimeLibraries) diff --git a/plugins/iot-headless/battery/battery-plugin.c b/plugins/iot-headless/battery/battery-plugin.c new file mode 100644 index 0000000..e0b2bbd --- /dev/null +++ b/plugins/iot-headless/battery/battery-plugin.c @@ -0,0 +1,153 @@ +#include +#include +#include +#include + +#include "shared/device-notifier.h" +#include "shared/log.h" +#include "battery/battery-ops.h" + +#include "power-state-manager.h" + +#define BATTERY_CONF_PATH "/etc/deviced/battery.conf" + +struct battery_event_handler { + char *name; + int id; + + /* which action to do on receiving an event */ + enum device_notifier_type action; + void *user_data; +}; + +static struct battery_event_handler *handler_connected; +static struct battery_event_handler *handler_disconnected; + +static void parse_device_notifier(struct battery_event_handler *handler, const char *action) +{ + if (MATCH(action, "DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED")) { + handler_connected = handler; + } else if (MATCH(action, "DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED")) { + handler_disconnected = handler; + } +} + +static enum psm_state convert_action_string_to_psm_state(char *str) +{ + if (MATCH(str, "sleep")) + return PSM_SLEEP; + else if (MATCH(str, "normal")) + return PSM_NORMAL; + else if (MATCH(str, "poweroff")) + return PSM_POWEROFF; + + _W("Invalid psm_state=%s", str); + + return PSM_MAX; +} + +static void add_action_transition_info(struct battery_event_handler *handler, char *curr, char *next) +{ + struct trans_info *ti = NULL; + GList **action_list = (GList **) &(handler->user_data); + + ti = calloc(1, sizeof(struct trans_info)); + if (!ti) + return; + + /* In configuration file, Enum= must be followed by Action=. + * Otherwise, handler->id won't be defined at this point.*/ + ti->reason = handler->id; + + ti->curr = convert_action_string_to_psm_state(curr); + ti->next = convert_action_string_to_psm_state(next); + + SYS_G_LIST_APPEND(*action_list, ti); +} + +static void parse_action(struct battery_event_handler *handler, const char *action) +{ + char curr[16] = { 0, }; + char next[16] = { 0, }; + + if (sscanf(action, "%15[^,],%15s", curr, next) == 2) { + handler->action = DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE; + /* append transition info to handler->user_data */ + add_action_transition_info(handler, curr, next); + } else { + _E("Invalid action=%s", action); + } +} + +static void parse_event_action_property(gpointer data, gpointer user_data) +{ + struct section_property *prop = (struct section_property *) data; + struct battery_event_handler *handler = (struct battery_event_handler *) user_data; + + if (!prop) + return; + + _D("Key=%s, Value=%s", prop->key, prop->value); + + if (MATCH(prop->key, "Name")) { + handler->name = strndup(prop->value, 32); + } else if (MATCH(prop->key, "Enum")) { + sscanf(prop->value, "%d", &handler->id); + } else if (MATCH(prop->key, "DeviceNotifier")) { + parse_device_notifier(handler, prop->value); + } else if (MATCH(prop->key, "Action")) { + parse_action(handler, prop->value); + } +} + +static int parse_event_action(const struct parse_result *result, void *data) +{ + struct battery_event_handler *handler = NULL; + + if (!result || !result->props) + return 0; + + if (MATCH(result->section, "EVENT_ACTION")) { + handler = calloc(1, sizeof(struct battery_event_handler)); + if (!handler) + return 0; + + g_list_foreach(result->props, parse_event_action_property, handler); + } + + return 0; +} + +static int charger_connected_callback(void *data) +{ + _D("event=%s(%d), action=%d", handler_connected->name, handler_connected->id, handler_connected->action); + device_notify(handler_connected->action, handler_connected->user_data); + + return 0; +} + +static int charger_disconnected_callback(void *data) +{ + _D("event=%s(%d), action=%d", handler_disconnected->name, handler_disconnected->id, handler_disconnected->action); + device_notify(handler_disconnected->action, handler_disconnected->user_data); + + return 0; +} + +static void battery_plugin_init(void *data) +{ + libsys_config_parse_by_section(BATTERY_CONF_PATH, parse_event_action, NULL); + + if (handler_connected) + register_notifier(DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED, charger_connected_callback); + + if (handler_disconnected) + register_notifier(DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED, charger_disconnected_callback); +} + +static const struct battery_ops battery_plugin_ops = { + .name = "battery-plugin", + .init = battery_plugin_init, +}; + +BATTERY_OPS_REGISTER(&battery_plugin_ops) diff --git a/plugins/iot-headless/input/input-config.c b/plugins/iot-headless/input/input-config.c index 026c7be..ce798cd 100644 --- a/plugins/iot-headless/input/input-config.c +++ b/plugins/iot-headless/input/input-config.c @@ -112,7 +112,7 @@ static void parse_action(struct input_event_unit *ieu, const char *action) ieu->notifier = DEVICE_NOTIFIER_INPUT_BROADCAST_SIGNAL; ieu->user_data = (void *) ieu; } else if (sscanf(action, "%15[^,],%15s", curr, next) == 2) { - ieu->notifier = DEVICE_NOTIFIER_INPUT_TRANSITION_STATE; + ieu->notifier = DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE; /* append transition info to ieu->user_data */ add_action_transition_info(ieu, curr, next); } else { diff --git a/plugins/iot-headless/power/power-event-lock.c b/plugins/iot-headless/power/power-event-lock.c index 0e75814..2e41d6e 100644 --- a/plugins/iot-headless/power/power-event-lock.c +++ b/plugins/iot-headless/power/power-event-lock.c @@ -1,19 +1,21 @@ #include #include #include +#include #include "shared/bitmap.h" #include "shared/device-notifier.h" #include "shared/log.h" #include "power-event-lock.h" +#define BATTERY_CONF_FILE "/etc/deviced/battery.conf" + /* eventlock is another wakelock than mainlock. * * The eventlock works independently of mainlock, which is controlled by * power state. The main purpose of eventlock is to prevent the subroutine * of an event from going to sleep regardless of the power state. */ -#define EVENT_LOCK "eventlock" -#define EVENT_LOCK_MARGIN_MS 1000 +#define EVENT_LOCK "eventlock" enum eventlock_type { EL_MIN, @@ -21,6 +23,8 @@ enum eventlock_type { EL_KEY, EL_KEY_POWER = EL_KEY, EL_KEY_BLUETOOTH, + + EL_CHARGER, /* add eventlock type here */ EL_MAX, }; @@ -119,15 +123,35 @@ static void register_power_event_lock_controller(enum eventlock_type type, power_event_unlock_callback, (void *)(intptr_t) type, NULL, -1000); } +static int check_charger_wakelock(struct parse_result *result, void *user_data) +{ + if (MATCH(result->section, "CHARGER_WAKELOCK") + && MATCH(result->name, "ChargerWakeLockEnabled") + && MATCH(result->value, "yes")) + *(int *) user_data = 1; + + return 0; +} + void power_event_lock_init(void) { + int charger_wakelock = 0; + eventlock = init_bitmap(EL_MAX); if (!eventlock) { _E("Failed to init event lock bitmap"); return; } + config_parse(BATTERY_CONF_FILE, check_charger_wakelock, &charger_wakelock); + register_power_event_lock_controller(EL_KEY, DEVICE_NOTIFIER_KEY_PRESS, DEVICE_NOTIFIER_KEY_RELEASE); + + if (charger_wakelock) { + register_power_event_lock_controller(EL_CHARGER, + DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED, + DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED); + } } diff --git a/plugins/iot-headless/power/power-state-manager.c b/plugins/iot-headless/power/power-state-manager.c index 5232c20..b50fd78 100644 --- a/plugins/iot-headless/power/power-state-manager.c +++ b/plugins/iot-headless/power/power-state-manager.c @@ -186,7 +186,7 @@ void power_state_manager_init(void *data) device_notify(DEVICE_NOTIFIER_REQUEST_ENABLE_AUTOSLEEP, NULL); device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL); - register_notifier(DEVICE_NOTIFIER_INPUT_TRANSITION_STATE, psm_transition_state_cb); + register_notifier(DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE, psm_transition_state_cb); power_plugin_dbus_init(NULL); power_event_lock_init(); diff --git a/src/battery/power-supply.c b/src/battery/power-supply.c index 12f263a..e886782 100644 --- a/src/battery/power-supply.c +++ b/src/battery/power-supply.c @@ -405,26 +405,25 @@ static void charger_state_send_system_event(int state) break; case CHARGE_STATUS_FULL: str = EVT_VAL_BATTERY_CHARGER_DISCHARGING; - CRITICAL_LOG("Battery %s", str); + CRITICAL_LOG("Battery charger: %s", str); break; case CHARGE_STATUS_DISCHARGING: str = EVT_VAL_BATTERY_CHARGER_DISCHARGING; + CRITICAL_LOG("Battery charger: %s", str); break; case CHARGE_STATUS_CONNECTED: str = EVT_VAL_BATTERY_CHARGER_CONNECTED; - CRITICAL_LOG("Battery %s", str); + CRITICAL_LOG("Battery charger: %s", str); break; case CHARGE_STATUS_DISCONNECTED: str = EVT_VAL_BATTERY_CHARGER_DISCONNECTED; - CRITICAL_LOG("Battery %s", str); + CRITICAL_LOG("Battery charger: %s", str); break; default: _E("Invalid parameter: %d", state); return; } - _D("System_event: %s", str); - event_system_send(SYS_EVENT_BATTERY_CHARGER_STATUS, EVT_KEY_BATTERY_CHARGER_STATUS, str); } @@ -577,6 +576,7 @@ static bool update_online(void) extcon_update_count(EXTCON_TA, 1); check_power_supply(online_status); charger_state_send_system_event(CHARGE_STATUS_CONNECTED); + device_notify(DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED, NULL); if (old_battery.charge_status != battery.charge_status) charger_state_send_system_event(battery.charge_status); broadcast = true; @@ -587,6 +587,7 @@ static bool update_online(void) if (old_battery.charge_status != battery.charge_status) charger_state_send_system_event(battery.charge_status); charger_state_send_system_event(CHARGE_STATUS_DISCONNECTED); + device_notify(DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED, NULL); broadcast = true; } else { if (old_battery.charge_status != battery.charge_status) diff --git a/src/shared/device-notifier.h b/src/shared/device-notifier.h index 241b339..6ccae1a 100644 --- a/src/shared/device-notifier.h +++ b/src/shared/device-notifier.h @@ -34,6 +34,8 @@ enum device_notifier_type { DEVICE_NOTIFIER_BATTERY_PRESENT, DEVICE_NOTIFIER_BATTERY_OVP, DEVICE_NOTIFIER_BATTERY_CHARGING, + DEVICE_NOTIFIER_BATTERY_CHARGER_CONNECTED, + DEVICE_NOTIFIER_BATTERY_CHARGER_DISCONNECTED, DEVICE_NOTIFIER_DISPLAY_AMBIENT_CONDITION, DEVICE_NOTIFIER_DISPLAY_AMBIENT_STATE, DEVICE_NOTIFIER_DISPLAY_LOCK, @@ -66,8 +68,6 @@ enum device_notifier_type { /* action triggered by input event */ DEVICE_NOTIFIER_INPUT_TRIGGER_POWEROFF, DEVICE_NOTIFIER_INPUT_BROADCAST_SIGNAL, - DEVICE_NOTIFIER_INPUT_TRANSITION_STATE, - /* Purpose of calling methods of different modules * Use prefix DEVICE_NOTIFIER_REQUEST */ @@ -75,6 +75,7 @@ enum device_notifier_type { DEVICE_NOTIFIER_REQUEST_DISABLE_AUTOSLEEP, DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, DEVICE_NOTIFIER_REQUEST_WAKE_UNLOCK, + DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE, DEVICE_NOTIFIER_MAX, }; -- 2.7.4 From 985da6c9944780d35e532953b87f396b2d9af315 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Fri, 7 Jan 2022 16:47:51 +0900 Subject: [PATCH 14/16] power: add initial power state transition on deviced startup The first transition is specified in init.conf. The transition is selected by /proc/cmdline bootreason=. Change-Id: I7ce713fac9008c5cdcc3f9a76a089bb6ebd16db8 Signed-off-by: Youngjae Cho --- CMakeLists.txt | 1 + conf/init.conf | 11 ++++ packaging/deviced.spec | 1 + plugins/iot-headless/battery/battery-plugin.c | 14 ----- plugins/iot-headless/input/input-config.c | 14 ----- plugins/iot-headless/power/power-config-parse.c | 73 ++++++++++++++++++++++++ plugins/iot-headless/power/power-config-parse.h | 6 ++ plugins/iot-headless/power/power-state-manager.c | 62 +++++++++++++++++--- plugins/iot-headless/power/power-state-manager.h | 20 +++++++ 9 files changed, 166 insertions(+), 36 deletions(-) create mode 100644 conf/init.conf create mode 100644 plugins/iot-headless/power/power-config-parse.c create mode 100644 plugins/iot-headless/power/power-config-parse.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 96d3312..5a5b58e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -277,6 +277,7 @@ IF(BATTERY_MODULE STREQUAL on) ENDIF() IF(POWER_MODULE STREQUAL on) + INSTALL_CONF(conf init) INSTALL_CONF(conf power) ENDIF() diff --git a/conf/init.conf b/conf/init.conf new file mode 100644 index 0000000..6dea3b4 --- /dev/null +++ b/conf/init.conf @@ -0,0 +1,11 @@ +[EVENT_ACTION] +#INITIAL_STATE_BY_POWERKEY_BOOTING +Enum=3000 +BootReason=powerkey +Action=start,normal + +[EVENT_ACTION] +#INITIAL_STATE_BY_CHARGER_BOOTING +Enum=3001 +BootReason=charger +Action=start,sleep diff --git a/packaging/deviced.spec b/packaging/deviced.spec index e32051c..e45ed0c 100644 --- a/packaging/deviced.spec +++ b/packaging/deviced.spec @@ -268,6 +268,7 @@ mv %{_libdir}/iot-headless-battery.so %{_libdir}/deviced/battery.so %endif %config %{_sysconfdir}/dbus-1/system.d/org.tizen.system.deviced.conf %config %{_sysconfdir}/deviced/power.conf +%config %{_sysconfdir}/deviced/init.conf %if %{?battery_module} == on %config %{_sysconfdir}/deviced/battery.conf %endif diff --git a/plugins/iot-headless/battery/battery-plugin.c b/plugins/iot-headless/battery/battery-plugin.c index e0b2bbd..1e867f8 100644 --- a/plugins/iot-headless/battery/battery-plugin.c +++ b/plugins/iot-headless/battery/battery-plugin.c @@ -32,20 +32,6 @@ static void parse_device_notifier(struct battery_event_handler *handler, const c } } -static enum psm_state convert_action_string_to_psm_state(char *str) -{ - if (MATCH(str, "sleep")) - return PSM_SLEEP; - else if (MATCH(str, "normal")) - return PSM_NORMAL; - else if (MATCH(str, "poweroff")) - return PSM_POWEROFF; - - _W("Invalid psm_state=%s", str); - - return PSM_MAX; -} - static void add_action_transition_info(struct battery_event_handler *handler, char *curr, char *next) { struct trans_info *ti = NULL; diff --git a/plugins/iot-headless/input/input-config.c b/plugins/iot-headless/input/input-config.c index ce798cd..7e193ff 100644 --- a/plugins/iot-headless/input/input-config.c +++ b/plugins/iot-headless/input/input-config.c @@ -70,20 +70,6 @@ static void parse_trigger_type(struct input_event_unit *ieu, const char *type) } -static enum psm_state convert_action_string_to_psm_state(char *str) -{ - if (MATCH(str, "sleep")) - return PSM_SLEEP; - else if (MATCH(str, "normal")) - return PSM_NORMAL; - else if (MATCH(str, "poweroff")) - return PSM_POWEROFF; - - _W("Invalid psm_state=%s", str); - - return PSM_MAX; -} - static void add_action_transition_info(struct input_event_unit *ieu, char *curr, char *next) { struct trans_info *ti = NULL; diff --git a/plugins/iot-headless/power/power-config-parse.c b/plugins/iot-headless/power/power-config-parse.c new file mode 100644 index 0000000..94ccb6c --- /dev/null +++ b/plugins/iot-headless/power/power-config-parse.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include + +#include "power-state-manager.h" + +#define INIT_CONF_PATH "/etc/deviced/init.conf" + +static struct trans_info initial_transition_info = { + .reason = -1, + .curr = PSM_START, + .next = PSM_NORMAL, +}; + +static void parse_transition_info(const char *action) +{ + char curr[16] = { 0, }; + char next[16] = { 0, }; + + if (sscanf(action, "%15[^,],%15s", curr, next) == 2) { + initial_transition_info.curr = convert_action_string_to_psm_state(curr); + initial_transition_info.next = convert_action_string_to_psm_state(next); + } +} + +static void parse_initial_transition_info(const struct parse_result *result) +{ + GList *elem; + struct section_property *prop; + + SYS_G_LIST_FOREACH(result->props, elem, prop) { + if (MATCH(prop->key, "Enum")) + initial_transition_info.reason = atoi(prop->value); + else if (MATCH(prop->key, "Action")) + parse_transition_info(prop->value); + } +} + +static int parse_matching_bootreason(const struct parse_result *result, void *data) +{ + GList *elem; + struct section_property *prop; + char *bootreason = (char *) data; + + if (!MATCH(result->section, "EVENT_ACTION")) + return 0; + + SYS_G_LIST_FOREACH(result->props, elem, prop) { + if (MATCH(prop->key, "BootReason") && MATCH(prop->value, bootreason)) + parse_initial_transition_info(result); + } + + return 0; +} + +void parse_initial_transition(void *data) +{ + int retval; + char bootreason[64] = "Unknown"; + GList **head = (GList **) data; + + if (!head) + return; + + retval = hal_device_board_get_boot_reason(bootreason, sizeof(bootreason)); + if (retval == 0) + libsys_config_parse_by_section(INIT_CONF_PATH, parse_matching_bootreason, bootreason); + + CRITICAL_LOG("BootReason=%s", bootreason); + + *head = g_list_append(*head, &initial_transition_info); +} diff --git a/plugins/iot-headless/power/power-config-parse.h b/plugins/iot-headless/power/power-config-parse.h new file mode 100644 index 0000000..efcdc12 --- /dev/null +++ b/plugins/iot-headless/power/power-config-parse.h @@ -0,0 +1,6 @@ +#ifndef __POWER_CONFIG_PARSE_H__ +#define __POWER_CONFIG_PARSE_H__ + +void parse_initial_transition(void *data); + +#endif //__POWER_CONFIG_PARSE_H__ diff --git a/plugins/iot-headless/power/power-state-manager.c b/plugins/iot-headless/power/power-state-manager.c index b50fd78..cbc24d2 100644 --- a/plugins/iot-headless/power/power-state-manager.c +++ b/plugins/iot-headless/power/power-state-manager.c @@ -12,11 +12,13 @@ #include "power-dbus.h" #include "power-state-wait.h" #include "power-event-lock.h" +#include "power-config-parse.h" #define EVENT_TYPE_SLEEP 0 #define EVENT_TYPE_WAKEUP 1 char *psm_name[PSM_MAX] = { + [PSM_START] = "PSM_START", [PSM_NORMAL] = "PSM_NORMAL", [PSM_SLEEP] = "PSM_SLEEP", [PSM_POWEROFF] = "PSM_POWEROFF", @@ -24,7 +26,7 @@ char *psm_name[PSM_MAX] = { }; static guint64 state_transition_counter = 0; -static enum psm_state current; +static enum psm_state current = PSM_START; static void psm_wake_unlock(void) { @@ -55,6 +57,7 @@ static void broadcast_transition_info(const struct trans_info *ti) { // mapping deviced state to capi signame static const char *capi_signame[PSM_MAX] = { + [PSM_START] = SIGNAME_CHANGE_STATE_TO_START, [PSM_NORMAL] = SIGNAME_CHANGE_STATE_TO_NORMAL, [PSM_SLEEP] = SIGNAME_CHANGE_STATE_TO_SLEEP, [PSM_POWEROFF] = SIGNAME_CHANGE_STATE_TO_POWEROFF, @@ -63,6 +66,7 @@ static void broadcast_transition_info(const struct trans_info *ti) // mapping deviced state to capi state static const guint64 capi_state[PSM_MAX] = { + [PSM_START] = POWER_STATE_START, [PSM_NORMAL] = POWER_STATE_NORMAL, [PSM_SLEEP] = POWER_STATE_SLEEP, [PSM_POWEROFF] = POWER_STATE_POWEROFF, @@ -73,6 +77,31 @@ static void broadcast_transition_info(const struct trans_info *ti) g_variant_new("(ttti)", capi_state[ti->curr], capi_state[ti->next], state_transition_counter, ti->reason)); } +static void psm_transition_start_to_normal(const struct trans_info *ti) +{ + current = PSM_NORMAL; + + device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL); + broadcast_transition_info(ti); +} + +static void psm_transition_start_to_sleep(const struct trans_info *ti) +{ + int waiting; + + current = PSM_SLEEP; + + device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL); + broadcast_transition_info(ti); + waiting = update_change_state_wait(state_transition_counter, ti, psm_wake_unlock); + if (waiting > 0) { + _D("Defer wake unlock"); + return; + } + + psm_wake_unlock(); +} + static void psm_transition_normal_to_normal(const struct trans_info *ti) { broadcast_transition_info(ti); @@ -99,8 +128,8 @@ static void psm_transition_sleep_to_normal(const struct trans_info *ti) { current = PSM_NORMAL; - broadcast_transition_info(ti); device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL); + broadcast_transition_info(ti); update_change_state_wait(state_transition_counter, ti, NULL); } @@ -108,8 +137,8 @@ static void psm_transition_sleep_to_sleep(const struct trans_info *ti) { int waiting; - broadcast_transition_info(ti); device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL); + broadcast_transition_info(ti); waiting = update_change_state_wait(state_transition_counter, ti, psm_wake_unlock); if (waiting > 0) { _D("Defer wake unlock"); @@ -162,7 +191,12 @@ static int psm_transition_state_cb(void *data) /* transition */ ++state_transition_counter; - if (current == PSM_NORMAL) { + if (current == PSM_START) { + if (next == PSM_NORMAL) + psm_transition_start_to_normal(ti); + else if (next == PSM_SLEEP) + psm_transition_start_to_sleep(ti); + } else if (current == PSM_NORMAL) { if (next == PSM_NORMAL) psm_transition_normal_to_normal(ti); else if (next == PSM_SLEEP) @@ -179,17 +213,29 @@ static int psm_transition_state_cb(void *data) return 0; } -void power_state_manager_init(void *data) +static int defer_autosleep_enable(void *data) { - /* initialize state */ - current = PSM_NORMAL; + /* Deferred autosleep enable, + * This prevents system go suspend during booting */ device_notify(DEVICE_NOTIFIER_REQUEST_ENABLE_AUTOSLEEP, NULL); - device_notify(DEVICE_NOTIFIER_REQUEST_WAKE_LOCK, NULL); + return 0; +} + +void power_state_manager_init(void *data) +{ + GList *initial_ti = NULL; + + register_notifier(DEVICE_NOTIFIER_DELAYED_INIT, defer_autosleep_enable); register_notifier(DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE, psm_transition_state_cb); power_plugin_dbus_init(NULL); power_event_lock_init(); + + /* initialize the power state */ + parse_initial_transition(&initial_ti); + psm_transition_state_cb(initial_ti); + g_list_free(initial_ti); } static const struct device_ops power_state_manager_device_ops = { diff --git a/plugins/iot-headless/power/power-state-manager.h b/plugins/iot-headless/power/power-state-manager.h index 9da0859..3d5c0d2 100644 --- a/plugins/iot-headless/power/power-state-manager.h +++ b/plugins/iot-headless/power/power-state-manager.h @@ -2,8 +2,12 @@ #define __POWER_STATE_MANAGER_H__ #include +#include + +#include "shared/log.h" enum psm_state { + PSM_START, PSM_NORMAL, PSM_SLEEP, PSM_POWEROFF, @@ -21,4 +25,20 @@ struct trans_info { typedef void (*psm_transfunc) (const struct trans_info *info); void power_state_manager_init(void *data); +static inline enum psm_state convert_action_string_to_psm_state(const char *str) +{ + if (MATCH(str, "start")) + return PSM_START; + else if (MATCH(str, "sleep")) + return PSM_SLEEP; + else if (MATCH(str, "normal")) + return PSM_NORMAL; + else if (MATCH(str, "poweroff")) + return PSM_POWEROFF; + + _W("Invalid psm_state=%s", str); + + return PSM_MAX; +} + #endif //__POWER_STATE_MANAGER_H__ -- 2.7.4 From 0eb89db286a456f07390625888e7cfaed4345e44 Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Tue, 11 Jan 2022 23:01:04 -0800 Subject: [PATCH 15/16] power: make change state wait timeout configurable Change-Id: I808f29e3518c643a295189accf919cd163f75e7e Signed-off-by: Youngjae Cho --- conf/power.conf | 3 +++ plugins/iot-headless/power/power-state-manager.c | 1 + plugins/iot-headless/power/power-state-wait.c | 21 ++++++++++++++++++++- plugins/iot-headless/power/power-state-wait.h | 1 + 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/conf/power.conf b/conf/power.conf index 52abf4a..60a66cc 100644 --- a/conf/power.conf +++ b/conf/power.conf @@ -7,3 +7,6 @@ Option=silent [Sleep] TimeoutSleepSupport=yes + +[PowerState] +ChangeStateMaxWaitSecond=10 diff --git a/plugins/iot-headless/power/power-state-manager.c b/plugins/iot-headless/power/power-state-manager.c index cbc24d2..6f9bf09 100644 --- a/plugins/iot-headless/power/power-state-manager.c +++ b/plugins/iot-headless/power/power-state-manager.c @@ -231,6 +231,7 @@ void power_state_manager_init(void *data) power_plugin_dbus_init(NULL); power_event_lock_init(); + power_state_wait_init(); /* initialize the power state */ parse_initial_transition(&initial_ti); diff --git a/plugins/iot-headless/power/power-state-wait.c b/plugins/iot-headless/power/power-state-wait.c index bdd7152..bfa430a 100644 --- a/plugins/iot-headless/power/power-state-wait.c +++ b/plugins/iot-headless/power/power-state-wait.c @@ -11,8 +11,11 @@ #include "power-state-wait.h" #include "power-state-manager.h" +#define POWER_CONF_FILE "/etc/deviced/power.conf" #define MAX_WAIT_SECOND 5 /* second */ +static int max_wait_timeout = 5; /* second */ + struct proc_info { pid_t pid; char comm[128]; @@ -213,7 +216,23 @@ int update_change_state_wait(guint64 id, const struct trans_info *ti, change_sta __change_state_wait_done = callback; _D("Expected number of wait confirm=%d", n_waiting); - max_wait_timer = g_timeout_add_seconds(MAX_WAIT_SECOND, max_wait_expired_cb, NULL); + max_wait_timer = g_timeout_add_seconds(max_wait_timeout, max_wait_expired_cb, NULL); return n_waiting; } + +static int load_max_wait_timeout(struct parse_result *result, void *user_data) +{ + if (MATCH(result->section, "PowerState") + && MATCH(result->name, "ChangeStateMaxWaitSecond")) + max_wait_timeout = atoi(result->value); + + return 0; +} + +void power_state_wait_init(void) +{ + config_parse(POWER_CONF_FILE, load_max_wait_timeout, NULL); + + CRITICAL_LOG("Change state max wait timeout=%ds", max_wait_timeout); +} diff --git a/plugins/iot-headless/power/power-state-wait.h b/plugins/iot-headless/power/power-state-wait.h index 45544cd..622575f 100644 --- a/plugins/iot-headless/power/power-state-wait.h +++ b/plugins/iot-headless/power/power-state-wait.h @@ -10,5 +10,6 @@ int add_change_state_wait(pid_t pid, guint64 state); void remove_change_state_wait(pid_t pid, guint64 state); int confirm_change_state_wait(pid_t pid, guint64 id); int update_change_state_wait(guint64 id, const struct trans_info *ti, change_state_wait_done_cb cb); +void power_state_wait_init(void); #endif //__POWER_STATE_WAIT_H__ -- 2.7.4 From 768987ae674708586bbd287d424728e5991868cb Mon Sep 17 00:00:00 2001 From: Youngjae Cho Date: Tue, 11 Jan 2022 21:55:31 -0800 Subject: [PATCH 16/16] input: add ConditionVconf property for conditional action [EVENT_ACTION] of input.conf can now have property ConditionVconf - ConditionVconf=key,type,value which set the condition for an event, so that it will trigger action only when the given vconf meet. Change-Id: I3dbd4484718cc3ba3b9b241ec670b28963d45f3d Signed-off-by: Youngjae Cho --- conf/iot-headless-input.conf | 1 + plugins/iot-headless/input/input-config.c | 103 +++++++++++++++++++++++++++++ plugins/iot-headless/input/input-config.h | 16 +++++ plugins/iot-headless/input/input-handler.c | 12 +++- 4 files changed, 129 insertions(+), 3 deletions(-) diff --git a/conf/iot-headless-input.conf b/conf/iot-headless-input.conf index 404bb55..3d4a658 100644 --- a/conf/iot-headless-input.conf +++ b/conf/iot-headless-input.conf @@ -54,4 +54,5 @@ Enum=1004 Keycode=power Duration=7000,-1 TriggerType=edge +ConditionVconf=memory/sysman/charger_status,int,0 Action=normal,poweroff diff --git a/plugins/iot-headless/input/input-config.c b/plugins/iot-headless/input/input-config.c index 7e193ff..69bd8ac 100644 --- a/plugins/iot-headless/input/input-config.c +++ b/plugins/iot-headless/input/input-config.c @@ -70,6 +70,40 @@ static void parse_trigger_type(struct input_event_unit *ieu, const char *type) } +static void parse_condition_vconf(struct input_event_unit *ieu, const char *str) +{ + int retval; + + char vconfkey[128] = { 0, }; + char vconftype[16] = { 0, }; + char vconfvalue[64] = { 0, }; + + retval = sscanf(str, "%127[^,],%15[^,],%63s", vconfkey, vconftype, vconfvalue); + if (retval != 3) + return; + + _D("Condition vconf: key=%s, type=%s, value=%s", vconfkey, vconftype, vconfvalue); + + if (!strncasecmp(vconftype, "bool", sizeof("bool"))) { + ieu->cv.type = VCONF_TYPE_BOOL; + sscanf(vconfvalue, "%d", &ieu->cv.b); + } else if (!strncasecmp(vconftype, "int", sizeof("int"))) { + ieu->cv.type = VCONF_TYPE_INT; + sscanf(vconfvalue, "%d", &ieu->cv.i); + } else if (!strncasecmp(vconftype, "double", sizeof("double"))) { + ieu->cv.type = VCONF_TYPE_DOUBLE; + sscanf(vconfvalue, "%lf", &ieu->cv.d); + } else if (!strncasecmp(vconftype, "string", sizeof("string"))) { + ieu->cv.type = VCONF_TYPE_STRING; + ieu->cv.s = strndup(vconfvalue, 128); + } else { + _E("Invalid condition vconf type"); + return; + } + + ieu->cv.keyname = strndup(vconfkey, 128); +} + static void add_action_transition_info(struct input_event_unit *ieu, char *curr, char *next) { struct trans_info *ti = NULL; @@ -126,6 +160,8 @@ static void parse_event_action_property(gpointer data, gpointer user_data) parse_duration(ieu, prop->value); } else if (MATCH(prop->key, "TriggerType")) { parse_trigger_type(ieu, prop->value); + } else if (MATCH(prop->key, "ConditionVconf")) { + parse_condition_vconf(ieu, prop->value); } else if (MATCH(prop->key, "Action")) { parse_action(ieu, prop->value); } @@ -163,6 +199,73 @@ static int parse_event_action(const struct parse_result *result, void *data) return 0; } +/* return 1 if the condition met, otherwise return 0 */ +int check_input_event_condition(const struct input_event_unit *ieu) +{ + char *keyname; + int retval, ret; + char buffer[256] = { 0, }; + + int b; + int i; + double d; + char *s; + + if (!ieu) + return 0; + + if (!ieu->cv.keyname) + return 1; + + keyname = ieu->cv.keyname; + + switch (ieu->cv.type) { + case VCONF_TYPE_BOOL: + retval = vconf_get_bool(keyname, &b); + if (retval < 0) { + _E("Failed to get vconf=%s", keyname); + return 0; + } + snprintf(buffer, sizeof(buffer), "expected=%d, current=%d", ieu->cv.b, b); + ret = (b == ieu->cv.b); + break; + case VCONF_TYPE_INT: + retval = vconf_get_int(keyname, &i); + if (retval < 0) { + _E("Failed to get vconf=%s", keyname); + return 0; + } + snprintf(buffer, sizeof(buffer), "expected=%d, current=%d", ieu->cv.i, i); + ret = (i == ieu->cv.i); + break; + case VCONF_TYPE_DOUBLE: + retval = vconf_get_dbl(keyname, &d); + if (retval < 0) { + _E("Failed to get vconf=%s", keyname); + return 0; + } + snprintf(buffer, sizeof(buffer), "expected=%lf, current=%lf", ieu->cv.d, d); + ret = (d == ieu->cv.d); + break; + case VCONF_TYPE_STRING: + s = vconf_get_str(keyname); + if (!s) { + _E("Failed to get vconf=%s", keyname); + return 0; + } + snprintf(buffer, sizeof(buffer), "expected=%s, current=%s", ieu->cv.s, s); + ret = (strncmp(s, ieu->cv.s, 128) == 0); + free(s); + break; + default: + return 0; + } + + _D("Check condition vconf=%s(%s)", keyname, buffer); + + return ret; +} + void init_input_config(void) { libsys_config_parse_by_section(INPUT_CONF_PATH, parse_event_action, NULL); diff --git a/plugins/iot-headless/input/input-config.h b/plugins/iot-headless/input/input-config.h index 1fe1e75..7638298 100644 --- a/plugins/iot-headless/input/input-config.h +++ b/plugins/iot-headless/input/input-config.h @@ -1,6 +1,7 @@ #ifndef __INPUT_CONFIG_H__ #define __INPUT_CONFIG_H__ +#include #include "shared/device-notifier.h" enum trigger_type { @@ -8,6 +9,17 @@ enum trigger_type { TRIGGER_TYPE_EDGE, /* trigger event if a key is released within a specific time interval */ }; +struct condition_vconf { + char *keyname; + enum vconf_t type; + union { + int b; + int i; + double d; + char *s; + }; +}; + struct input_event_unit { char *name; int id; @@ -17,6 +29,9 @@ struct input_event_unit { enum trigger_type type; unsigned long interval[2]; + /* condition for triggering action */ + struct condition_vconf cv; + /* which action to do on receiving an event */ enum device_notifier_type notifier; void *user_data; @@ -34,5 +49,6 @@ struct input_config { void init_input_config(void); struct input_config *find_input_config(int keycode); +int check_input_event_condition(const struct input_event_unit *ieu); #endif //__INPUT_CONFIG_H__ diff --git a/plugins/iot-headless/input/input-handler.c b/plugins/iot-headless/input/input-handler.c index 4b69c04..dd989ad 100644 --- a/plugins/iot-headless/input/input-handler.c +++ b/plugins/iot-headless/input/input-handler.c @@ -38,9 +38,11 @@ static gboolean level_triggered(gpointer data) ieu->timer = 0; - if (ieu->notifier > 0) { + if (check_input_event_condition(ieu)) { _D("Trigger(level) event=%s(%d), action=%d", ieu->name, ieu->id, ieu->notifier); device_notify(ieu->notifier, ieu->user_data); + } else { + _D("Skip(level) event=%s(%d), condition=%s isn't meet", ieu->name, ieu->id, ieu->cv.keyname); } return G_SOURCE_REMOVE; @@ -48,8 +50,12 @@ static gboolean level_triggered(gpointer data) static void edge_triggered(struct input_event_unit *ieu) { - _D("Trigger(edge) event=%s(%d), action=%d", ieu->name, ieu->id, ieu->notifier); - device_notify(ieu->notifier, ieu->user_data); + if (check_input_event_condition(ieu)) { + _D("Trigger(edge) event=%s(%d), action=%d", ieu->name, ieu->id, ieu->notifier); + device_notify(ieu->notifier, ieu->user_data); + } else { + _D("Skip(edge) event=%s(%d), condition=%s isn't meet", ieu->name, ieu->id, ieu->cv.keyname); + } } static void start_event_timer(struct input_config *ic) -- 2.7.4