-[Reboot]
-Option=recovery
-Option=download
-Option=wdownload
-Option=debug
-Option=silent
-
[PowerState]
TimeoutSleepSupport=no
ChangeStateMaxWaitSecond=10
-[Reboot]
-Option=recovery
-Option=download
-Option=wdownload
-Option=debug
-Option=silent
-
[PowerState]
TimeoutSleepSupport=yes
ChangeStateMaxWaitSecond=10
-[Reboot]
-Option=recovery
-Option=download
-Option=wdownload
-Option=debug
-Option=silent
-
[PowerState]
TimeoutSleepSupport=yes
ChangeStateMaxWaitSecond=10
-[Reboot]
-Option=recovery
-Option=download
-Option=wdownload
-Option=debug
-Option=silent
-
[PowerState]
TimeoutSleepSupport=yes
ChangeStateMaxWaitSecond=10
-[Reboot]
-Option=recovery
-Option=download
-Option=wdownload
-Option=debug
-Option=silent
-
[PowerState]
TimeoutSleepSupport=yes
ChangeStateMaxWaitSecond=10
int val = (int)(intptr_t) udata;
switch (val) {
- case POWEROFF_TYPE_NONE:
+ case VCONFKEY_SYSMAN_POWER_OFF_NONE:
clear_pm_status_flag(PWROFF_FLAG);
break;
- case POWEROFF_TYPE_DIRECT:
- case POWEROFF_TYPE_RESTART:
+ case VCONFKEY_SYSMAN_POWER_OFF_DIRECT:
+ case VCONFKEY_SYSMAN_POWER_OFF_RESTART:
set_pm_status_flag(PWROFF_FLAG);
break;
}
#include "shared/log.h"
#include "battery/battery-ops.h"
-#include "power/power-state-manager.h"
+#include "power/power.h"
#define BATTERY_CONF_PATH "/etc/deviced/battery.conf"
* 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);
+ ti->curr = convert_action_string_to_power_state(curr);
+ ti->next = convert_action_string_to_power_state(next);
SYS_G_LIST_APPEND(*action_list, ti);
}
#include "shared/log.h"
#include "input-config.h"
-#include "power/power-state-manager.h"
+#include "power/power.h"
#define INPUT_CONF_PATH "/etc/deviced/input.conf"
* Otherwise, ieu->id won't be defined at this point.*/
ti->reason = ieu->id;
- ti->curr = convert_action_string_to_psm_state(curr);
- ti->next = convert_action_string_to_psm_state(next);
+ ti->curr = convert_action_string_to_power_state(curr);
+ ti->next = convert_action_string_to_power_state(next);
SYS_G_LIST_APPEND(*action_list, ti);
}
int val = (int)(intptr_t) udata;
switch (val) {
- case POWEROFF_TYPE_NONE:
+ case VCONFKEY_SYSMAN_POWER_OFF_NONE:
clear_pm_status_flag(PWROFF_FLAG);
break;
- case POWEROFF_TYPE_DIRECT:
- case POWEROFF_TYPE_RESTART:
+ case VCONFKEY_SYSMAN_POWER_OFF_DIRECT:
+ case VCONFKEY_SYSMAN_POWER_OFF_RESTART:
set_pm_status_flag(PWROFF_FLAG);
break;
}
int val = (int)(intptr_t) udata;
switch (val) {
- case POWEROFF_TYPE_NONE:
+ case VCONFKEY_SYSMAN_POWER_OFF_NONE:
clear_pm_status_flag(PWROFF_FLAG);
break;
- case POWEROFF_TYPE_DIRECT:
- case POWEROFF_TYPE_RESTART:
+ case VCONFKEY_SYSMAN_POWER_OFF_DIRECT:
+ case VCONFKEY_SYSMAN_POWER_OFF_RESTART:
set_pm_status_flag(PWROFF_FLAG);
break;
}
#include "shared/devices.h"
#include "display/display-ops.h"
#include "display/display-lock.h"
+#include "power/power.h"
#include "power/power-off.h"
#include "power/power-suspend.h"
#include "core.h"
static int poweroff_action(int timeout)
{
- static const struct device_ops *ops;
+ power_request_change_state(POWER_STATE_POWEROFF, 9000);
- FIND_DEVICE_INT(ops, "power-state-manager");
-
- return ops->execute(POWER_POWEROFF);
+ return 0;
}
static int poweroff_trans(int evt)
int val = (int)(intptr_t) udata;
switch (val) {
- case POWEROFF_TYPE_NONE:
+ case VCONFKEY_SYSMAN_POWER_OFF_NONE:
clear_pm_status_flag(PWROFF_FLAG);
break;
- case POWEROFF_TYPE_DIRECT:
- case POWEROFF_TYPE_RESTART:
+ case VCONFKEY_SYSMAN_POWER_OFF_DIRECT:
+ case VCONFKEY_SYSMAN_POWER_OFF_RESTART:
set_pm_status_flag(PWROFF_FLAG);
break;
}
#include "display/setting.h"
#include "display/poll.h"
#include "display/display-ops.h"
+#include "power/power.h"
#include "power/power-off.h"
#include "apps/apps.h"
#include "power-supply.h"
return 0;
}
-static int power_execute(void *data)
+static int power_execute(int state)
{
- static const struct device_ops *ops;
-
if (is_emulator()) {
CRITICAL_LOG("Poweroff by lowbattery is disabled at emulator.");
return 0;
}
- FIND_DEVICE_INT(ops, "power-state-manager");
+ power_request_change_state(state, LOWBAT_POWEROFF_REASON);
- return ops->execute(data);
+ return 0;
}
static int delayed_init_done(void *data)
if (launched_poweroff == 1) {
_I("Will be foreced power off.");
- power_execute(POWER_POWEROFF);
+ power_execute(POWER_STATE_POWEROFF);
return 0;
}
int battery_power_off_act(void *data)
{
CRITICAL_LOG("Low battery power off.");
- return power_execute(POWER_POWEROFF);
+ return power_execute(POWER_STATE_POWEROFF);
}
int battery_charge_err_cf_act(void *data)
#ifndef __LOWBAT_HANDLER_H__
#define __LOWBAT_HANDLER_H__
-#define RETRY_MAX 5
+#define RETRY_MAX 5
+#define LOWBAT_POWEROFF_REASON 2004
int lowbat_popup(int option);
void lowbat_enable_uevent_buffering(void);
#include "log.h"
#include "shared/common.h"
#include "shared/devices.h"
+#include "power/power.h"
#include "power/power-boot.h"
#include "power/power-off.h"
#include "shared/plugin.h"
mainloop = g_main_loop_new(NULL, FALSE);
ret = poweroff_check_revived();
- if (ret) {
+ if (is_poweroff_state(ret)) {
/* Restarted: deviced was terminated
* in middle of reboot/poweroff - resume procedure
*/
- poweroff_request_shutdown();
+ poweroff_request_shutdown(ret);
return 0;
}
#include "display/display-ops.h"
#include "shared/plugin.h"
#include "power-doze.h"
-#include "power-state-manager.h"
+#include "power.h"
#define SYSTEMD_DBUS_SIGNAL_SYSTEM_STARTUP_FINISHED "StartupFinished"
#define SYSTEMD_DBUS_SIGNAL_USER_STARTUP_FINISHED "UserSessionStartupFinished"
#define INIT_CONF_PATH "/etc/deviced/init.conf"
-static struct trans_info initial_transition_info = {
+static struct trans_info init_ti = {
.reason = -1,
- .curr = PSM_START,
- .next = PSM_NORMAL,
+ .curr = POWER_STATE_START,
+ .next = POWER_STATE_NORMAL,
};
static guint sig_id[2] = {0, 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);
+ init_ti.curr = convert_action_string_to_power_state(curr);
+ init_ti.next = convert_action_string_to_power_state(next);
}
}
-static void parse_initial_transition_info(const struct parse_result *result)
+static void parse_init_ti(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);
+ init_ti.reason = atoi(prop->value);
else if (MATCH(prop->key, "Action"))
parse_transition_info(prop->value);
}
SYS_G_LIST_FOREACH(result->props, elem, prop) {
if (MATCH(prop->key, "BootReason") && MATCH(prop->value, bootreason))
- parse_initial_transition_info(result);
+ parse_init_ti(result);
}
return 0;
}
-/* the initial transition by bootreason is defined in init.conf */
-void get_initial_transition_by_bootreason(void *data)
+void do_initial_transition_by_bootreason(void)
{
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);
+ power_request_change_state_strict(init_ti.curr, init_ti.next, init_ti.reason, NULL);
}
void add_delayed_init_done_handler(void *data);
void remove_delayed_init_done_handler(void *data);
-void get_initial_transition_by_bootreason(void *data);
+void do_initial_transition_by_bootreason(void);
extern int silent_boot;
#include "shared/device-notifier.h"
#include "power-suspend.h"
-#include "power-state-manager.h"
+#include "power.h"
#include "power-state-wait.h"
#ifndef PROCESS_CHECK_TIMEOUT
*/
#include <unistd.h>
+#include <string.h>
#include <time.h>
#include <limits.h>
#include <fcntl.h>
#include "display/core.h"
#include "display/display-ops.h"
#include "power-off.h"
+#include "power.h"
#include "apps/apps.h"
#include "power-boot.h"
#include "shared/plugin.h"
#define POWER_CONF_FILE "/etc/deviced/power.conf"
static struct timeval tv_start_poweroff;
-static GList *poweroff_options_list;
-static enum poweroff_type poweroff_type = POWEROFF_TYPE_REBOOT;
-static GList *poweroff_handles;
-
-static const char *poweroff_type_flagpaths[] = { // index denotes type
- [POWEROFF_TYPE_POWEROFF] = POWER_FLAG_POWEROFF,
- [POWEROFF_TYPE_REBOOT] = POWER_FLAG_REBOOT,
- [POWEROFF_TYPE_EXIT] = POWER_FLAG_EXIT,
-};
-
-static const char *poweroff_type_names[] = { // index denotes type
- [POWEROFF_TYPE_POWEROFF] = POWER_POWEROFF,
- [POWEROFF_TYPE_REBOOT] = POWER_REBOOT,
- [POWEROFF_TYPE_EXIT] = POWER_EXIT,
-};
-
-enum poweroff_stage {
- POWEROFF_DEFAULT, /* Default stage, poweroff has not been triggered */
- POWEROFF_TRIGGERED, /* Poweroff is triggered. Wait timer can be added up to this stage */
- POWEROFF_WAIT_OTHERS, /* Wait for other processes to clean up their resources */
-};
-
static int poweroff_delay_second = 0;
-static enum poweroff_stage poweroff_stage;
-
-static const char *poweroff_type_to_name(enum poweroff_type type)
-{
- if (type <= 0 || type >= ARRAY_SIZE(poweroff_type_names))
- return NULL;
-
- return poweroff_type_names[type];
-}
-
-static enum poweroff_type poweroff_name_to_type(const char *name)
-{
- if (!name)
- goto out;
-
- for (int i = 0; i < ARRAY_SIZE(poweroff_type_names); i++) {
- if (poweroff_type_names[i] && strcmp(poweroff_type_names[i], name) == 0)
- return i;
- }
-out:
- return POWEROFF_TYPE_INVALID;
-}
static void poweroff_start_animation(void)
{
return is_ok;
}
-void poweroff_request_shutdown(void)
+void poweroff_request_shutdown(int state)
{
- const char *systemd_poweroff_method = "Reboot";
-
- if (poweroff_type == POWEROFF_TYPE_REBOOT) {
- systemd_poweroff_method = "Reboot";
- } else if (poweroff_type == POWEROFF_TYPE_POWEROFF) {
- systemd_poweroff_method = "PowerOff";
- } else if (poweroff_type == POWEROFF_TYPE_EXIT) {
- systemd_poweroff_method = "Exit";
- } else {
- _E("Invalid poweroff type=%d", poweroff_type);
+ const char *systemd_method = "PowerOff";
+
+ if (!is_poweroff_state(state))
return;
- }
- CRITICAL_LOG("Requested %s via systemd.", systemd_poweroff_method);
+ if (state == POWER_STATE_POWEROFF)
+ systemd_method = "PowerOff";
+ else if (state == POWER_STATE_REBOOT)
+ systemd_method = "Reboot";
+ else if (state == POWER_STATE_EXIT)
+ systemd_method = "Exit";
+
+ CRITICAL_LOG("Requested %s via systemd.", systemd_method);
gdbus_call_sync_with_reply_timeout(SYSTEMD_DBUS_DEST,
SYSTEMD_DBUS_PATH,
SYSTEMD_DBUS_IFACE_MANAGER,
- systemd_poweroff_method,
+ systemd_method,
NULL,
NULL,
POWEROFF_WAIT_SYSTEMD_MS);
watchdog_notify();
}
-void poweroff_prepare(void)
-{
- if (poweroff_type == POWEROFF_TYPE_POWEROFF)
- CRITICAL_LOG("Prepare PowerOff.");
- else if (poweroff_type == POWEROFF_TYPE_REBOOT)
- CRITICAL_LOG("Prepare Reboot.");
-
- poweroff_notify_resourced();
- disable_systemd_journald();
- disable_coredump_handler();
- poweroff_delay_for_seconds();
- disable_display();
-
- /* Below functions follow after notifying DEVICE_NOTIFIER_POWEROFF
- 1. pmlock
- - pmlock_detector_poweroff_cb()
- - cleanup_pmlock_statistics()
- - do_copy_force()
- - save_display_log()
- 2. tzip
- - tzip_poweroff()
- - tzip_server_exit()
- 3. udev
- - device_change_poweroff()
- - uevent_control_stop()
- */
- device_notify_once(DEVICE_NOTIFIER_POWEROFF, (void *)(intptr_t) poweroff_type);
-}
-
int poweroff_check_revived(void)
{
- if (access(POWER_FLAG_POWEROFF, F_OK) == 0) {
- poweroff_type = POWEROFF_TYPE_POWEROFF;
- return 1;
+ if (access(POWEROFF_OPTPATH_POWEROFF, F_OK) == 0) {
+ return POWER_STATE_POWEROFF;
}
- if (access(POWER_FLAG_REBOOT, F_OK) == 0) {
- poweroff_type = POWEROFF_TYPE_REBOOT;
- return 1;
+ if (access(POWEROFF_OPTPATH_REBOOT, F_OK) == 0) {
+ return POWER_STATE_REBOOT;
}
- if (access(POWER_FLAG_EXIT, F_OK) == 0) {
- poweroff_type = POWEROFF_TYPE_EXIT;
- return 1;
+ if (access(POWEROFF_OPTPATH_EXIT, F_OK) == 0) {
+ return POWER_STATE_EXIT;
}
- return 0;
+ return POWER_STATE_NORMAL;
}
-static void mark_poweroff_option(struct power_option *opt)
+static void mark_poweroff_option(const struct trans_info *ti)
{
- const char *path;
int fd;
ssize_t len;
-
- if (!opt)
- return;
-
- enum poweroff_type type = opt->type;
- const char *option = opt->option;
-
- if (type <= 0 || type >= ARRAY_SIZE(poweroff_type_flagpaths))
+ const char *optpath;
+ const char *option;
+
+ if (ti->next == POWER_STATE_POWEROFF)
+ optpath = POWEROFF_OPTPATH_POWEROFF;
+ else if (ti->next == POWER_STATE_REBOOT)
+ optpath = POWEROFF_OPTPATH_REBOOT;
+ else if (ti->next == POWER_STATE_EXIT)
+ optpath = POWEROFF_OPTPATH_EXIT;
+ else
return;
- path = poweroff_type_flagpaths[type];
- if (!path)
- return;
+ option = (char *) ti->data;
- fd = open(path, O_RDWR|O_CREAT, S_IRUSR | S_IWUSR);
+ fd = open(optpath, O_RDWR|O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0) {
- _E("Failed to create '%s'.", path);
+ _E("Failed to create '%s'.", optpath);
return;
}
- if (option) {
- len = write(fd, option, strlen(option));
- if (len <= 0)
- _E("Failed to store option: %zd", len < 0 ? errno : len);
- }
+ len = option ? write(fd, option, strlen(option)) : 0;
+ if (len < 0)
+ _E("Failed to store option: %zd", len < 0 ? errno : len);
close(fd);
}
-static void poweroff_remove_handle(pid_t pid)
-{
- struct poweroff_handle *handle;
- GList *elem;
-
- SYS_G_LIST_FOREACH(poweroff_handles, elem, handle) {
- if (handle->pid == pid)
- break;
- }
-
- assert(handle);
-
- _D("Remove handle pid=%d(%s) timeout=%d timeout_id=%d.", handle->pid, handle->comm, handle->timeout, handle->timeout_id);
- SYS_G_LIST_REMOVE(poweroff_handles, handle);
-
- if (handle->timeout_id) {
- g_source_remove(handle->timeout_id);
- handle->timeout = 0;
- handle->timeout_id = 0;
- }
-
- free(handle);
-}
-
-static int poweroff_add_handle(pid_t pid)
-{
- struct poweroff_handle *handle;
- GList *l;
-
- SYS_G_LIST_FOREACH(poweroff_handles, l, handle) {
- if (handle->pid == pid)
- break;
- }
-
- if (handle)
- poweroff_remove_handle(pid);
-
- _D("Make a new handle.");
- handle = (struct poweroff_handle *)malloc(sizeof(struct poweroff_handle));
- if (handle == NULL) {
- _E("Not enough memory.");
- return -ENOMEM;
- }
-
- handle->pid = pid;
- handle->timeout_id = 0;
- handle->timeout = POWEROFF_WAIT_MAX;
- get_command(pid, handle->comm, sizeof(handle->comm));
-
- SYS_G_LIST_APPEND(poweroff_handles, handle);
- _D("Add a new poweroff timer. pid=%d(%s) timeout=%d", handle->pid, handle->comm, handle->timeout);
-
- return 0;
-}
-
static gboolean __poweroff_main(gpointer data)
{
- CRITICAL_LOG("Starting poweroff sequence.");
+ int state = (int)(intptr_t) data;
+
+ CRITICAL_LOG("Starting poweroff sequence");
// Watchdog timeout 90 -> 30 sec to reduce delay from unexpected poweroff failure.
sd_notifyf(0, "WATCHDOG_USEC=%llu", (unsigned long long)POWEROFF_WAIT_SYSTEMD_MS*1000);
- poweroff_prepare();
- poweroff_request_shutdown();
+ poweroff_notify_resourced();
+ disable_systemd_journald();
+ disable_coredump_handler();
+ poweroff_delay_for_seconds();
+ disable_display();
+
+ /* Below functions follow after notifying DEVICE_NOTIFIER_POWEROFF
+ 1. pmlock
+ - pmlock_detector_poweroff_cb()
+ - cleanup_pmlock_statistics()
+ - do_copy_force()
+ - save_display_log()
+ 2. tzip
+ - tzip_poweroff()
+ - tzip_server_exit()
+ 3. udev
+ - device_change_poweroff()
+ - uevent_control_stop()
+ */
+ device_notify_once(DEVICE_NOTIFIER_POWEROFF, data);
+
+ poweroff_request_shutdown(state);
return G_SOURCE_REMOVE;
}
-static void poweroff_main(void)
+void poweroff_main(void *udata)
{
static guint poweroff_id = 0;
/* Terminate this subroutine at this point. The procedure returns to the caller, therefore
* the RemovePowerOffWait caller would not be blocked, if they invoked method synchronously.
* And the deviced enter poweroff_main on the next gmainloop iteration. */
- poweroff_id = g_idle_add(__poweroff_main, NULL);
-}
-
-static gboolean poweroff_wait_timeout_cb(void *data)
-{
- pid_t pid = (pid_t)((intptr_t)data);
-
- poweroff_remove_handle(pid);
-
- if (poweroff_stage < POWEROFF_WAIT_OTHERS)
- return G_SOURCE_REMOVE;
-
- /* All other processes finished cleanup. Poweroff is now on standby */
- if (SYS_G_LIST_LENGTH(poweroff_handles) == 0) {
- _D("The last poweroff wait timer for pid %d is expired. Poweroff is now on standby.", pid);
- poweroff_main();
- } else {
- _D("Poweroff wait timer for pid %d is expired, but keep waiting for others...", pid);
- }
-
- return G_SOURCE_REMOVE;
-}
-
-static gboolean poweroff_start_timers(void *data)
-{
- struct poweroff_handle *handle = NULL;
- GList *l, *l_next;
- bool timer_exist = false;
-
- _D("POWEROFF_STAGE=WAIT_OTHERS");
- poweroff_stage = POWEROFF_WAIT_OTHERS;
-
- SYS_G_LIST_FOREACH_SAFE(poweroff_handles, l, l_next, handle) {
- if (kill(handle->pid, 0) == -1) {
- _D("Pid=%d(%s) is dead.", handle->pid, handle->comm);
- SYS_G_LIST_REMOVE(poweroff_handles, handle);
- continue;
- }
-
- _D("Run timer, pid=%d(%s) timeout=%d", handle->pid, handle->comm, handle->timeout);
-
- handle->timeout_id = g_timeout_add_seconds(handle->timeout,
- poweroff_wait_timeout_cb,
- (void *)((intptr_t)(handle->pid)));
-
- timer_exist = true;
- }
-
- if (timer_exist)
- return G_SOURCE_REMOVE;
-
- // No need to wait. Strat main poweroff procedure immediately.
- poweroff_main();
-
- return G_SOURCE_REMOVE;
+ poweroff_id = g_idle_add(__poweroff_main, udata);
}
static void system_shutdown_send_system_event(void)
bundle_free(b);
}
-static void poweroff_send_broadcast(int status)
+void poweroff_prepare(const struct trans_info *ti)
{
- static int old = 0;
- int ret_dbus;
+ int vconf = VCONFKEY_SYSMAN_POWER_OFF_NONE;
- if (old == status)
+ if (!is_poweroff_state(ti->next))
return;
- _D("Broadcast poweroff %d.", status);
-
- old = status;
+ mark_poweroff_option(ti);
- /* Need to notify to deviced-vibrator. deviced-vibrator receives ChangeState signal for POWEROFF_TYPE_DIRECT and POWEROFF_TYPE_RESTART */
- ret_dbus = gdbus_signal_emit(NULL,
- DEVICED_PATH_POWEROFF,
- DEVICED_INTERFACE_POWEROFF,
- SIGNAL_POWEROFF_STATE,
- g_variant_new("(i)", status));
- if (ret_dbus < 0)
- _E("Failed to send dbus signal(%s)", SIGNAL_POWEROFF_STATE);
-}
-
-static int __poweroff_trigger_poweroff(const char *typename, const char *option)
-{
- int ret_val;
- GList *l;
- struct power_option *opt = NULL;
+ if (ti->next == POWER_STATE_POWEROFF)
+ vconf = VCONFKEY_SYSMAN_POWER_OFF_DIRECT;
+ else if (ti->next == POWER_STATE_REBOOT)
+ vconf = VCONFKEY_SYSMAN_POWER_OFF_RESTART;
+ vconf_set_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, vconf);
- if (poweroff_stage >= POWEROFF_TRIGGERED) {
- _E("Duplicate poweroff request. Poweroff was already triggered.");
- return -EINVAL;
- }
-
- enum poweroff_type type = poweroff_name_to_type(typename);
- if (type == POWEROFF_TYPE_INVALID) {
- _E("Failed to get type enum value(%d).", type);
- return -EINVAL;
- }
-
- poweroff_type = type;
-
- if (option) {
- SYS_G_LIST_FOREACH(poweroff_options_list, l, opt) {
- if (opt->type == type && strncmp(opt->option, option, sizeof(opt->option)) == 0)
- break;
- }
-
- /* It writes option onto file /run/reboot.
- * The deviced shutdown binary, which is exec of systemd, refers the file. */
- if (opt)
- mark_poweroff_option(opt);
- }
-
- ret_val = vconf_set_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, type);
- if (ret_val < 0)
- _E("Failed to set vconf value for power off status: %d", vconf_get_ext_errno());
-
- _D("POWEROFF_STAGE=TRIGGERED");
- poweroff_stage = POWEROFF_TRIGGERED;
power_disable_autosleep();
- device_notify_once(DEVICE_NOTIFIER_POWEROFF_TRIGGERED, (void *)(intptr_t) type);
+ device_notify_once(DEVICE_NOTIFIER_POWEROFF_TRIGGERED, (void *)(intptr_t) vconf);
/* Poweroff event broadcasting */
system_shutdown_send_system_event();
- poweroff_send_broadcast(type);
-
- /* Skip running animation if option is silent */
- if (opt && strncmp(opt->option, "silent", sizeof("silent")) == 0)
- _D("Skip running poweroff animation.");
- else
- poweroff_start_animation();
-
- /* Spare time for AddPowerOffWait requests */
- g_timeout_add_seconds(1, poweroff_start_timers, NULL);
- return 0;
-}
+ /* Skip running animation if it is silent reboot */
+ if (ti->data && strncmp(ti->data, "silent", sizeof("silent")) == 0)
+ return;
-int poweroff_trigger_poweroff(void *data)
-{
- return __poweroff_trigger_poweroff((char *)data, NULL);
+ poweroff_start_animation();
}
static int check_sender_process(GDBusConnection *conn, const char *sender)
return pid;
}
-static GVariant *dbus_power_handler(GDBusConnection *conn,
+static GVariant *dbus_poweroff_handler(GDBusConnection *conn,
const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
{
int ret;
char comm[128] = "Unknown";
- char *type_str;
+ char *type;
+ int next;
- g_variant_get(param, "(s)", &type_str);
+ g_variant_get(param, "(s)", &type);
ret = check_sender_process(conn, sender);
if (ret < 0)
get_command(ret, comm, sizeof(comm));
- CRITICAL_LOG("Poweroff pid=%d(%s) requests %s.", ret, comm, type_str);
- ret = __poweroff_trigger_poweroff(type_str, NULL);
+ if (strncmp(type, "poweroff", sizeof("poweroff")) == 0)
+ next = POWER_STATE_POWEROFF;
+ else if (strncmp(type, "reboot", sizeof("reboot")) == 0)
+ next = POWER_STATE_REBOOT;
+ else if (strncmp(type, "exit", sizeof("exit")) == 0)
+ next = POWER_STATE_EXIT;
+ else {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ CRITICAL_LOG("Poweroff pid=%d(%s) requests %s.", ret, comm, type);
+ power_request_change_state_strict(POWER_STATE_ALL, next, 9000, NULL);
out:
- g_free(type_str);
+ g_free(type);
return g_variant_new("(i)", ret);
}
-static GVariant *dbus_power_option_handler(GDBusConnection *conn,
+static GVariant *dbus_poweroff_option_handler(GDBusConnection *conn,
const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
{
int ret;
char comm[128] = "Unknown";
char *type, *option;
+ int next;
g_variant_get(param, "(ss)", &type, &option);
get_command(ret, comm, sizeof(comm));
+ if (strncmp(type, "poweroff", sizeof("poweroff")) == 0)
+ next = POWER_STATE_POWEROFF;
+ else if (strncmp(type, "reboot", sizeof("reboot")) == 0)
+ next = POWER_STATE_REBOOT;
+ else if (strncmp(type, "exit", sizeof("exit")) == 0)
+ next = POWER_STATE_EXIT;
+ else {
+ ret = -EINVAL;
+ goto out;
+ }
+
CRITICAL_LOG("Poweroff pid=%d(%s) requests type=%s option=%s.", ret, comm, type, option);
- ret = __poweroff_trigger_poweroff(type, option);
+ power_request_change_state_strict(POWER_STATE_ALL, next, 9000, option);
out:
g_free(type);
return g_variant_new("(i)", ret);
}
-/* timer can be added before the stage POWEROFF_WAIT_OTHERS */
static GVariant *add_poweroff_time(GDBusConnection *conn,
const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
{
- int ret;
- pid_t pid;
-
- if (poweroff_stage >= POWEROFF_WAIT_OTHERS) {
- _E("It's too late. Poweroff is already in waiting stage.");
- ret = -1;
- goto out;
- }
-
- ret = check_sender_process(conn, sender);
- if (ret < 0)
- goto out;
-
- pid = (pid_t)ret;
- ret = poweroff_add_handle(pid);
-
-out:
- return g_variant_new("(i)", ret);
+ return g_variant_new("(i)", 0);
}
static GVariant *remove_poweroff_time(GDBusConnection *conn,
const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
{
- struct poweroff_handle *handle;
- GList *l, *l_next;
- int ret = 0;
- pid_t pid;
-
- ret = check_sender_process(conn, sender);
- if (ret < 0)
- goto out;
-
- pid = (pid_t)ret;
-
- SYS_G_LIST_FOREACH_SAFE(poweroff_handles, l, l_next, handle) {
- if (handle->pid == pid) {
- _D("Removed poweroff timer. pid=%d(%s)", handle->pid, handle->comm);
- SYS_G_LIST_REMOVE(poweroff_handles, handle);
- break;
- }
- }
-
- if (poweroff_stage == POWEROFF_WAIT_OTHERS && SYS_G_LIST_LENGTH(poweroff_handles) == 0)
- poweroff_main();
-
-out:
- return g_variant_new("(i)", ret);
+ return g_variant_new("(i)", 0);
}
static const dbus_method_s dbus_methods[] = {
- { "PowerOff" , "s" , "i", dbus_power_handler },
- { "PowerOffWithOption", "ss", "i", dbus_power_option_handler },
+ { "PowerOff" , "s" , "i", dbus_poweroff_handler },
+ { "PowerOffWithOption", "ss", "i", dbus_poweroff_option_handler },
/* Public API device_power_reboot() calls this dbus method. */
- { "AddPowerOffWait" , NULL, "i", add_poweroff_time },
- /* It is recommended to invoke RemovePowerOffWait by async as the invocation
- * could be the last removal of poweroff waitings. And if it is, the deviced
- * immediately fall into poweroff main sequence without returning to the caller. */
- { "RemovePowerOffWait", NULL, "i", remove_poweroff_time },
+ { "AddPowerOffWait" , NULL, "i", add_poweroff_time }, /* deprecated */
+ { "RemovePowerOffWait", NULL, "i", remove_poweroff_time }, /* deprecated */
/* Add methods here */
};
.nr_methods = ARRAY_SIZE(dbus_methods),
};
-static int add_poweroff_option(enum poweroff_type type, const char *option)
-{
- struct power_option *opt;
- const char *name;
-
- name = poweroff_type_to_name(type);
- if (!name) {
- _E("Invalid type(%d).", type);
- return -EINVAL;
- }
-
- opt = calloc(1, sizeof(struct power_option));
- if (!opt) {
- _E("Failed to calloc().");
- return -ENOMEM;
- }
-
- opt->type = type;
- if (option)
- strncpy(opt->option, option, sizeof(opt->option) - 1);
-
- SYS_G_LIST_APPEND(poweroff_options_list, opt);
-
- _D("Add %s option=%s", name, opt->option);
-
- return 0;
-}
-
-int poweroff_add_wait(pid_t pid)
-{
- return poweroff_add_handle(pid);
-}
-
-void poweroff_remove_wait(pid_t pid)
-{
- g_idle_add(poweroff_wait_timeout_cb, (void *)(intptr_t) pid);
-}
-
static int load_config(struct parse_result *result, void *user_data)
{
- if (MATCH(result->section, "PowerOff") && MATCH(result->name, "Option")) {
- add_poweroff_option(POWEROFF_TYPE_POWEROFF, result->value);
- } else if (MATCH(result->section, "Reboot") && MATCH(result->name, "Option")) {
- add_poweroff_option(POWEROFF_TYPE_REBOOT, result->value);
- } else if (MATCH(result->section, "PowerState") && MATCH(result->name, "PowerOffDelaySecond")) {
+ if (MATCH(result->section, "PowerState") && MATCH(result->name, "PowerOffDelaySecond")) {
sscanf(result->value, "%d", &poweroff_delay_second);
}
register_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
- add_poweroff_option(POWEROFF_TYPE_POWEROFF, NULL);
- add_poweroff_option(POWEROFF_TYPE_RESTART, NULL);
- add_poweroff_option(POWEROFF_TYPE_EXIT, NULL);
-
ret_val = config_parse(POWER_CONF_FILE, load_config, NULL);
if (ret_val < 0)
_E("Failed to load power off config: %d", ret_val);
-
- poweroff_stage = POWEROFF_DEFAULT;
}
#ifndef __DEVICED_POWER_OFF_H__
#define __DEVICED_POWER_OFF_H__
+#include "power.h"
#include <sys/types.h>
#define POWER_POWEROFF "poweroff"
#define POWER_OFF_POPUP "pwroff-popup"
#define POWER_EXIT "exit"
-#define POWER_FLAG_POWEROFF "/run/"POWER_POWEROFF
-#define POWER_FLAG_REBOOT "/run/"POWER_REBOOT
-#define POWER_FLAG_EXIT "/run/deviced-shutdown-exit"
-
-// 0: None
-// 1: Power Off Popup is launched (not supported since Tizen5.5)
-// 2: Poweroff
-// 3: Restart
-// 4: Exit
-enum poweroff_type {
- POWEROFF_TYPE_INVALID = 0,
- POWEROFF_TYPE_NONE = POWEROFF_TYPE_INVALID, // compat only
- POWEROFF_TYPE_POWEROFF = 2,
- POWEROFF_TYPE_DIRECT = POWEROFF_TYPE_POWEROFF, // compat only
- POWEROFF_TYPE_REBOOT,
- POWEROFF_TYPE_RESTART = POWEROFF_TYPE_REBOOT, // compat only
- POWEROFF_TYPE_EXIT,
-};
-
-struct power_option {
- enum poweroff_type type;
- char option[32];
-};
-
-struct poweroff_handle {
- pid_t pid;
- int timeout;
- char comm[128];
- guint timeout_id;
-};
+#define POWEROFF_OPTPATH_POWEROFF "/run/"POWER_POWEROFF
+#define POWEROFF_OPTPATH_REBOOT "/run/"POWER_REBOOT
+#define POWEROFF_OPTPATH_EXIT "/run/deviced-shutdown-exit"
void power_off_init(void);
-
-int poweroff_trigger_poweroff(void *data);
int poweroff_check_revived(void);
-void poweroff_request_shutdown(void);
-int poweroff_add_wait(pid_t pid);
-void poweroff_remove_wait(pid_t pid);
+void poweroff_request_shutdown(int state);
+void poweroff_prepare(const struct trans_info *ti);
+void poweroff_main(void *udata);
#endif /* __DEVICED_POWER_OFF_H__ */
+++ /dev/null
-/*
- * deviced
- *
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * 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 <stdio.h>
-#include <stdint.h>
-#include <linux/input.h>
-#include <libsyscommon/libgdbus.h>
-#include <libsyscommon/list.h>
-#include <device/power-internal.h>
-
-#include "shared/devices.h"
-#include "shared/device-notifier.h"
-#include "shared/log.h"
-#include "power-state-manager.h"
-#include "power-suspend.h"
-#include "power-dbus.h"
-#include "power-boot.h"
-#include "power-off.h"
-#include "power-state-wait.h"
-#include "power-event-lock.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",
- [PSM_REBOOT] = "PSM_REBOOT",
-};
-
-static int delayed_init_done = 0;
-static guint64 state_transition_counter = 0;
-static enum psm_state current = PSM_START;
-
-/* hold trans_info until delayed_init_done */
-static GList *deferred_transition_list;
-
-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;
- }
-
- power_release_wakelock();
-}
-
-static void psm_trigger_poweroff(void)
-{
- poweroff_trigger_poweroff("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_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,
- [PSM_REBOOT] = SIGNAME_CHANGE_STATE_TO_REBOOT,
- };
-
- // 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,
- [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_start_to_normal(const struct trans_info *ti)
-{
- current = PSM_NORMAL;
-
- power_acquire_wakelock();
- broadcast_transition_info(ti);
-}
-
-static void psm_transition_start_to_sleep(const struct trans_info *ti)
-{
- int waiting;
-
- current = PSM_SLEEP;
-
- power_acquire_wakelock();
- 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);
- update_change_state_wait(state_transition_counter, ti, NULL);
-}
-
-static void psm_transition_normal_to_sleep(const struct trans_info *ti)
-{
- int waiting;
-
- current = PSM_SLEEP;
-
- 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_sleep_to_normal(const struct trans_info *ti)
-{
- current = PSM_NORMAL;
-
- power_acquire_wakelock();
- broadcast_transition_info(ti);
- update_change_state_wait(state_transition_counter, ti, NULL);
-}
-
-static void psm_transition_sleep_to_sleep(const struct trans_info *ti)
-{
- int waiting;
-
- power_acquire_wakelock();
- 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_poweroff(const struct trans_info *ti)
-{
- int waiting;
-
- current = PSM_POWEROFF;
-
- broadcast_transition_info(ti);
- waiting = update_change_state_wait(state_transition_counter, ti, psm_trigger_poweroff);
- if (waiting > 0) {
- _D("Defer poweroff.");
- return;
- }
-
- psm_trigger_poweroff();
-}
-
-static void transition_state(const struct trans_info *ti)
-{
- enum psm_state next;
-
- next = ti->next;
-
- _D("Transition power state: %s -> %s, reason=%d",
- psm_name[current], psm_name[next], ti->reason);
-
- /* transition */
- ++state_transition_counter;
- 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)
- psm_transition_normal_to_sleep(ti);
- else if (next == PSM_POWEROFF)
- psm_transition_normal_to_poweroff(ti);
- } else if (current == PSM_SLEEP) {
- if (next == PSM_NORMAL)
- psm_transition_sleep_to_normal(ti);
- else if (next == PSM_SLEEP)
- psm_transition_sleep_to_sleep(ti);
- }
-}
-
-static void deferred_transition_state(gpointer data)
-{
- transition_state(data);
- free(data);
-}
-
-static int psm_transition_state_cb(void *data)
-{
- GList *action_list, *elem;
- const struct trans_info *ti = NULL;
-
- if (!data)
- return 0;
-
- action_list = (GList *) data;
-
- /* look for transition defined on the current state */
- SYS_G_LIST_FOREACH(action_list, elem, ti) {
- if (ti->curr == current)
- break;
- }
-
- if (!ti)
- return 0;
-
- /* defer state transition until delayed_init_done */
- if (!delayed_init_done) {
- struct trans_info *deferred_ti = calloc(1, sizeof(struct trans_info));
- if (!deferred_ti) {
- CRITICAL_LOG("Failed to defer transition.");
- return 0;
- }
-
- // Pseudo state transition.
- current = ti->next;
-
- // Reserve the trans_info.
- // Those are used on receiving delayed_init_done for real transitioning state.
- memcpy(deferred_ti, ti, sizeof(struct trans_info));
- deferred_transition_list = g_list_append(deferred_transition_list, deferred_ti);
- _D("Defer state transition %s->%s until delayed init done.", psm_name[ti->curr], psm_name[ti->next]);
-
- return 0;
- }
-
- transition_state(ti);
-
- return 0;
-}
-
-static int delayed_init_cb(void *data)
-{
- delayed_init_done = 1;
-
- _D("Start deferred state transition.");
-
- /* rewind current state to initial state and do the deferred transition */
- current = PSM_START;
- g_list_free_full(g_steal_pointer(&deferred_transition_list), deferred_transition_state);
-
- /* Enable autosleep at this point.
- * This prevents system go suspend(autosleep) before booting done */
- _D("Finished deferred state transition. Enable autosleep.");
- power_enable_autosleep();
-
- return 0;
-}
-
-void power_state_manager_init(void *data)
-{
- GList *initial_ti = NULL;
-
- register_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_cb);
- register_notifier(DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE, psm_transition_state_cb);
-
- power_dbus_init();
- power_off_init();
- power_suspend_init();
- power_event_lock_init();
- power_state_wait_init();
-
- /* Take the first transition from PSM_START.
- * It is determined by bootreason to which state to transition, PSM_NORMAL or PSM_SLEEP. */
- get_initial_transition_by_bootreason(&initial_ti);
- psm_transition_state_cb(initial_ti);
- g_list_free(initial_ti);
-}
-
-static const struct device_ops power_state_manager_device_ops = {
- DECLARE_NAME_LEN("power-state-manager"),
- .init = power_state_manager_init,
- /* It should be initilalized earlier than the almost other modules so that
- * it can receive and handle power request from the other modules. Therefore
- * give a high enough priority. */
- .priority = 990,
- .execute = poweroff_trigger_poweroff,
-};
-
-DEVICE_OPS_REGISTER(&power_state_manager_device_ops)
+++ /dev/null
-/*
- * deviced
- *
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * 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.
- */
-
-#ifndef __POWER_STATE_MANAGER_H__
-#define __POWER_STATE_MANAGER_H__
-
-#include <stdio.h>
-#include <libsyscommon/ini-parser.h>
-
-#include "shared/log.h"
-
-enum psm_state {
- PSM_START,
- PSM_NORMAL,
- PSM_SLEEP,
- PSM_POWEROFF,
- PSM_REBOOT,
- PSM_MAX,
-};
-extern char *psm_name[PSM_MAX];
-
-struct trans_info {
- int reason;
- enum psm_state curr;
- enum psm_state next;
-};
-
-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__
#include "shared/device-notifier.h"
#include "shared/common.h"
+#include "power.h"
#include "power-state-wait.h"
-#include "power-state-manager.h"
#define POWER_CONF_FILE "/etc/deviced/power.conf"
#define MAX_WAIT_SECOND 5 /* second */
struct change_state_wait {
struct proc_info *pi;
guint64 id;
- enum psm_state state;
+ int 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 *);
+static void *udata;
+static int waiting_state = POWER_STATE_START;
static void change_state_wait_done(void)
{
- _D("%s wait done", psm_name[waiting_state]);
+ _D("%s wait done", state_name(waiting_state));
if (max_wait_timer) {
g_source_remove(max_wait_timer);
}
if (__change_state_wait_done) {
- __change_state_wait_done();
+ __change_state_wait_done(udata);
}
}
if (kill(csw->pi->pid, 0) != 0)
csw->pi->killed = 1;
else
- _E("pid=%d(%s) hasn't confirmed id=%"PRIu64"(%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, state_name(csw->state));
waiting_list = g_list_remove_link(waiting_list, elem);
g_list_free(elem);
free(csw);
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=%"PRIu64"(%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, state_name(csw->state));
waiting_list = g_list_remove_link(waiting_list, elem);
g_list_free(elem);
free(csw);
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)
+int update_change_state_wait(guint64 id, const struct trans_info *ti, change_state_wait_done_cb callback, void *user_data)
{
struct proc_info *pi;
struct change_state_wait *csw;
GList *elem, *elem_next;
- int n_waiting;
+ static int n_waiting = 0;
// initialize timer
if (max_wait_timer) {
max_wait_timer = 0;
}
+ if (is_poweroff_state(waiting_state)) {
+ _W("No need to wait if poweroff had been triggered.");
+ return n_waiting;
+ }
+
// we are waiting for confirm of transition to the next state
waiting_state = ti->next;
- _D("%s wait is triggered, id=%"PRIu64, psm_name[waiting_state], id);
+
+ _D("%s wait is triggered, id=%"PRIu64, state_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) {
+ if ((csw->state & waiting_state) == 0) {
waiting_list = g_list_remove_link(waiting_list, elem);
g_list_free(elem);
- _D("Cancel waiting: pid=%d(%s) for id=%"PRIu64"(%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, state_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)) {
+ if (pi->state_bitmap & waiting_state) {
csw = calloc(1, sizeof(struct change_state_wait));
if (!csw)
continue;
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]);
+ _D("There were no csw requests for %s, skip waiting", state_name(waiting_state));
__change_state_wait_done = NULL;
return 0;
}
__change_state_wait_done = callback;
+ udata = user_data;
_D("The number of pending wait confirm=%d", n_waiting);
max_wait_timer = g_timeout_add_seconds(max_wait_timeout, max_wait_expired_cb, NULL);
#define __POWER_STATE_WAIT_H__
#include <unistd.h>
-#include "power-state-manager.h"
+#include "power.h"
-typedef void (*change_state_wait_done_cb) (void);
+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);
+int update_change_state_wait(guint64 id, const struct trans_info *ti, change_state_wait_done_cb cb, void *user_data);
void power_state_wait_init(void);
#endif //__POWER_STATE_WAIT_H__
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * 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 <stdio.h>
+#include <stdint.h>
+#include <linux/input.h>
+#include <libsyscommon/libgdbus.h>
+#include <libsyscommon/list.h>
+#include <device/power-internal.h>
+
+#include "shared/devices.h"
+#include "shared/device-notifier.h"
+#include "shared/log.h"
+#include "power.h"
+#include "power-suspend.h"
+#include "power-dbus.h"
+#include "power-boot.h"
+#include "power-off.h"
+#include "power-state-wait.h"
+#include "power-event-lock.h"
+
+#define EVENT_TYPE_SLEEP 0
+#define EVENT_TYPE_WAKEUP 1
+
+static int delayed_init_done = 0;
+static uint64_t state_transition_counter = 0;
+static uint64_t current = POWER_STATE_START;
+
+/* hold trans_info until delayed_init_done */
+static GList *deferred_transition_list;
+
+static int power_transition_state(void *data);
+
+static void power_wake_unlock(void *udata)
+{
+ /* for POWER_STATE_NORMAL, POWER_STATE_POWEROFF, do not wake unlock */
+ if (current != POWER_STATE_SLEEP) {
+ _E("Ignore sleep wait done, current=%s", state_name(current));
+ return;
+ }
+
+ power_release_wakelock();
+}
+
+static void broadcast_transition_info(const struct trans_info *ti)
+{
+ const char *signame;
+
+ if (ti->next == POWER_STATE_START)
+ signame = SIGNAME_CHANGE_STATE_TO_START;
+ else if (ti->next == POWER_STATE_NORMAL)
+ signame = SIGNAME_CHANGE_STATE_TO_NORMAL;
+ else if (ti->next == POWER_STATE_SLEEP)
+ signame = SIGNAME_CHANGE_STATE_TO_SLEEP;
+ else if (ti->next == POWER_STATE_POWEROFF)
+ signame = SIGNAME_CHANGE_STATE_TO_POWEROFF;
+ else if (ti->next == POWER_STATE_REBOOT)
+ signame = SIGNAME_CHANGE_STATE_TO_REBOOT;
+ else if (ti->next == POWER_STATE_EXIT)
+ signame = SIGNAME_CHANGE_STATE_TO_EXIT;
+ else
+ return;
+
+ gdbus_signal_emit(NULL, DEVICED_PATH_POWER, DEVICED_INTERFACE_POWER, signame,
+ g_variant_new("(ttti)", ti->curr, ti->next, state_transition_counter, ti->reason));
+}
+
+static void power_transition_start_to_normal(const struct trans_info *ti)
+{
+ current = POWER_STATE_NORMAL;
+
+ power_acquire_wakelock();
+ broadcast_transition_info(ti);
+}
+
+static void power_transition_start_to_sleep(const struct trans_info *ti)
+{
+ int waiting;
+
+ current = POWER_STATE_SLEEP;
+
+ power_acquire_wakelock();
+ broadcast_transition_info(ti);
+ waiting = update_change_state_wait(state_transition_counter, ti, power_wake_unlock, NULL);
+ if (waiting > 0) {
+ _D("Defer wake unlock.");
+ return;
+ }
+
+ power_wake_unlock(NULL);
+}
+
+static void power_transition_normal_to_normal(const struct trans_info *ti)
+{
+ broadcast_transition_info(ti);
+ update_change_state_wait(state_transition_counter, ti, NULL, NULL);
+}
+
+static void power_transition_normal_to_sleep(const struct trans_info *ti)
+{
+ int waiting;
+
+ current = POWER_STATE_SLEEP;
+
+ broadcast_transition_info(ti);
+ waiting = update_change_state_wait(state_transition_counter, ti, power_wake_unlock, NULL);
+ if (waiting > 0) {
+ _D("Defer wake unlock.");
+ return;
+ }
+
+ power_wake_unlock(NULL);
+}
+
+static void power_transition_sleep_to_normal(const struct trans_info *ti)
+{
+ current = POWER_STATE_NORMAL;
+
+ power_acquire_wakelock();
+ broadcast_transition_info(ti);
+ update_change_state_wait(state_transition_counter, ti, NULL, NULL);
+}
+
+static void power_transition_sleep_to_sleep(const struct trans_info *ti)
+{
+ int waiting;
+
+ power_acquire_wakelock();
+ broadcast_transition_info(ti);
+ waiting = update_change_state_wait(state_transition_counter, ti, power_wake_unlock, NULL);
+ if (waiting > 0) {
+ _D("Defer wake unlock.");
+ return;
+ }
+
+ power_wake_unlock(NULL);
+}
+
+static void power_transition_to_poweroff(const struct trans_info *ti)
+{
+ int waiting;
+
+ _D("Transition power state: %s -> %s, option=%s, reason=%d",
+ state_name(ti->curr), state_name(ti->next), (char *) ti->data, ti->reason);
+
+ current = ti->next;
+
+ // do not transition anymore after poweroff
+ unregister_notifier(DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE, power_transition_state);
+
+ poweroff_prepare(ti);
+ broadcast_transition_info(ti);
+ waiting = update_change_state_wait(state_transition_counter, ti, poweroff_main, (void *)(intptr_t) ti->next);
+ if (waiting > 0) {
+ _D("Defer poweroff.");
+ return;
+ }
+
+ poweroff_main((void *)(intptr_t) ti->next);
+}
+
+static void transition_state(const struct trans_info *ti)
+{
+ int next;
+ struct trans_info __ti = { 0, };
+
+ if (ti->curr == POWER_STATE_ALL) {
+ /* replace POWER_STATE_ALL to the current state */
+ memcpy(&__ti, ti, sizeof(struct trans_info));
+ __ti.curr = current;
+ ti = &__ti;
+ }
+
+ _D("Transition power state: %s -> %s, reason=%d",
+ state_name(ti->curr), state_name(ti->next), ti->reason);
+
+ next = ti->next;
+
+ /* transition */
+ ++state_transition_counter;
+ if (current == POWER_STATE_START) {
+ if (next == POWER_STATE_NORMAL)
+ power_transition_start_to_normal(ti);
+ else if (next == POWER_STATE_SLEEP)
+ power_transition_start_to_sleep(ti);
+ else if (is_poweroff_state(next))
+ power_transition_to_poweroff(ti);
+ } else if (current == POWER_STATE_NORMAL) {
+ if (next == POWER_STATE_NORMAL)
+ power_transition_normal_to_normal(ti);
+ else if (next == POWER_STATE_SLEEP)
+ power_transition_normal_to_sleep(ti);
+ else if (is_poweroff_state(next))
+ power_transition_to_poweroff(ti);
+ } else if (current == POWER_STATE_SLEEP) {
+ if (next == POWER_STATE_NORMAL)
+ power_transition_sleep_to_normal(ti);
+ else if (next == POWER_STATE_SLEEP)
+ power_transition_sleep_to_sleep(ti);
+ else if (is_poweroff_state(next))
+ power_transition_to_poweroff(ti);
+ }
+}
+
+static void deferred_transition_state(gpointer data)
+{
+ transition_state(data);
+ free(data);
+}
+
+static int power_transition_state(void *data)
+{
+ GList *ti_list, *elem;
+ const struct trans_info *ti = NULL;
+
+ if (!data)
+ return 0;
+
+ ti_list = (GList *) data;
+
+ // look for trans_info defined on the current state
+ SYS_G_LIST_FOREACH(ti_list, elem, ti) {
+ if (ti->curr & current)
+ break;
+ }
+
+ if (!ti)
+ return 0;
+
+ // defer state transition until delayed_init_done unless it is transition to poweroff.
+ // poweroff shall be handled immediately regardless of the delayed_init_done.
+ if (!delayed_init_done && !is_poweroff_state(ti->next)) {
+ struct trans_info *deferred_ti = calloc(1, sizeof(struct trans_info));
+ if (!deferred_ti) {
+ CRITICAL_LOG("Failed to defer transition.");
+ return 0;
+ }
+
+ // Pseudo state transition.
+ current = ti->next;
+
+ // Reserve the trans_info.
+ // Those are used on receiving delayed_init_done for real transitioning state.
+ memcpy(deferred_ti, ti, sizeof(struct trans_info));
+ deferred_transition_list = g_list_append(deferred_transition_list, deferred_ti);
+ _D("Defer state transition %s->%s until delayed init done.", state_name(ti->curr), state_name(ti->next));
+
+ return 0;
+ }
+
+ transition_state(ti);
+
+ return 0;
+}
+
+static int delayed_init_cb(void *data)
+{
+ delayed_init_done = 1;
+
+ _D("Start deferred state transition.");
+
+ /* rewind current state to initial state and do the deferred transition */
+ current = POWER_STATE_START;
+ g_list_free_full(g_steal_pointer(&deferred_transition_list), deferred_transition_state);
+
+ /* Enable autosleep at this point.
+ * This prevents system go suspend(autosleep) before booting done */
+ _D("Finished deferred state transition. Enable autosleep.");
+ power_enable_autosleep();
+
+ return 0;
+}
+
+void power_state_init(void *data)
+{
+ register_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_cb);
+ register_notifier(DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE, power_transition_state);
+
+ power_dbus_init();
+ power_off_init();
+ power_suspend_init();
+ power_event_lock_init();
+ power_state_wait_init();
+
+ /* Take the first transition.
+ *
+ * It is determined by bootreason to which state to transition, POWER_STATE_NORMAL or POWER_STATE_SLEEP.
+ * Normally, it will be transitioned to the POWER_STATE_NORMAL unless there is configuration for
+ * the initial state in init.conf. */
+ do_initial_transition_by_bootreason();
+}
+
+static const struct device_ops power_state_device_ops = {
+ DECLARE_NAME_LEN("power-state"),
+ .init = power_state_init,
+ /* It should be initilalized earlier than the almost other modules so that
+ * it can receive and handle power request from the other modules. Therefore
+ * give a high enough priority. */
+ .priority = 990,
+};
+
+DEVICE_OPS_REGISTER(&power_state_device_ops)
--- /dev/null
+/*
+ * deviced
+ *
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __POWER_STATE_MANAGER_H__
+#define __POWER_STATE_MANAGER_H__
+
+#include <stdio.h>
+#include <glib.h>
+#include <libsyscommon/ini-parser.h>
+#include <device/power-internal.h>
+
+#include "shared/log-macro.h"
+#include "shared/device-notifier.h"
+
+#define POWER_STATE_NONE 0
+
+struct trans_info {
+ uint64_t curr;
+ uint64_t next;
+ int reason;
+ void *data;
+};
+
+void power_state_manager_init(void *data);
+
+static inline uint64_t convert_action_string_to_power_state(const char *str)
+{
+ if (MATCH(str, "start"))
+ return POWER_STATE_START;
+ else if (MATCH(str, "sleep"))
+ return POWER_STATE_SLEEP;
+ else if (MATCH(str, "normal"))
+ return POWER_STATE_NORMAL;
+ else if (MATCH(str, "poweroff"))
+ return POWER_STATE_POWEROFF;
+ else if (MATCH(str, "reboot"))
+ return POWER_STATE_REBOOT;
+ else if (MATCH(str, "exit"))
+ return POWER_STATE_EXIT;
+ else if (MATCH(str, "current"))
+ return POWER_STATE_ALL;
+
+ _W("Invalid power state=%s", str);
+
+ return POWER_STATE_NONE;
+}
+
+static inline const char *state_name(uint64_t state)
+{
+ if (state == POWER_STATE_START)
+ return "POWER_STATE_START";
+ if (state == POWER_STATE_NORMAL)
+ return "POWER_STATE_NORMAL";
+ if (state == POWER_STATE_SLEEP)
+ return "POWER_STATE_SLEEP";
+ if (state == POWER_STATE_POWEROFF)
+ return "POWER_STATE_POWEROFF";
+ if (state == POWER_STATE_REBOOT)
+ return "POWER_STATE_REBOOT";
+ if (state == POWER_STATE_EXIT)
+ return "POWER_STATE_EXIT";
+ if (state == POWER_STATE_ALL)
+ return "POWER_STATE_ALL";
+
+ return "POWER_STATE_INVALID";
+}
+
+static inline int is_poweroff_state(uint64_t state)
+{
+ return !!(state & (POWER_STATE_POWEROFF | POWER_STATE_REBOOT | POWER_STATE_EXIT));
+}
+
+static inline void power_request_change_state_strict(uint64_t curr, uint64_t next, int reason, void *udata)
+{
+ struct trans_info ti = { curr, next, reason, udata };
+ GList l = { &ti, NULL, NULL };
+
+ device_notify(DEVICE_NOTIFIER_REQUEST_TRANSITION_STATE, &l);
+}
+
+static inline void power_request_change_state(uint64_t next, int reason)
+{
+ power_request_change_state_strict(POWER_STATE_ALL, next, reason, NULL);
+}
+
+#endif //__POWER_STATE_MANAGER_H__