#define SIGNAL_POWEROFF_STATE "ChangeState"
#define POWER_CONF_FILE "/etc/deviced/power.conf"
-static struct display_plugin *disp_plgn;
-
static struct timeval tv_start_poweroff;
-static GList *poweroff_options;
-static struct power_option poweroff_opt;
+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
void poweroff_request_shutdown(void)
{
- const char *method;
+ const char *systemd_poweroff_method = "Reboot";
- if (poweroff_opt.type == POWEROFF_TYPE_REBOOT)
- method = "Reboot";
- else if (poweroff_opt.type == POWEROFF_TYPE_POWEROFF)
- method = "PowerOff";
- else if (poweroff_opt.type == POWEROFF_TYPE_EXIT)
- method = "Exit";
- else {
- _E("Poweroff invalid type(%d).", poweroff_opt.type);
+ 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);
return;
}
- CRITICAL_LOG("Requested %s via systemd.", method);
+ CRITICAL_LOG("Requested %s via systemd.", systemd_poweroff_method);
gdbus_call_sync_with_reply_timeout(SYSTEMD_DBUS_DEST,
SYSTEMD_DBUS_PATH,
SYSTEMD_DBUS_IFACE_MANAGER,
- method,
+ systemd_poweroff_method,
NULL,
NULL,
POWEROFF_WAIT_SYSTEMD_MS);
void poweroff_prepare(void)
{
- int off = poweroff_opt.type;
-
- if (off == POWEROFF_TYPE_POWEROFF)
+ if (poweroff_type == POWEROFF_TYPE_POWEROFF)
CRITICAL_LOG("Prepare PowerOff.");
- else if (off == POWEROFF_TYPE_REBOOT)
+ 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
- device_change_poweroff()
- uevent_control_stop()
*/
- device_notify(DEVICE_NOTIFIER_POWEROFF, &off);
+ device_notify_once(DEVICE_NOTIFIER_POWEROFF, (void *)(intptr_t) poweroff_type);
}
int poweroff_check_revived(void)
{
- for (int i = 0; i < ARRAY_SIZE(poweroff_type_flagpaths); i++) {
- if (access(poweroff_type_flagpaths[i], F_OK) == 0) {
- poweroff_opt.type = i;
- poweroff_opt.option = NULL;
- return 1;
- }
+ if (access(POWER_FLAG_POWEROFF, F_OK) == 0) {
+ poweroff_type = POWEROFF_TYPE_POWEROFF;
+ return 1;
+ }
+
+ if (access(POWER_FLAG_REBOOT, F_OK) == 0) {
+ poweroff_type = POWEROFF_TYPE_REBOOT;
+ return 1;
+ }
+
+ if (access(POWER_FLAG_EXIT, F_OK) == 0) {
+ poweroff_type = POWEROFF_TYPE_EXIT;
+ return 1;
}
return 0;
}
-static void make_power_flag(enum poweroff_type type, const char *option)
+static void mark_poweroff_option(struct power_option *opt)
{
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))
return;
return 0;
}
-static gboolean poweroff_wait_timeout_cb(void *data)
+static gboolean __poweroff_main(gpointer data)
{
- char timeout[50] = {0,};
- pid_t pid = (pid_t)((intptr_t)data);
+ CRITICAL_LOG("Starting poweroff sequence.");
- poweroff_remove_handle(pid);
+ // 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);
- /* All other processes finished cleanup. Poweroff is now on standby */
- if (poweroff_stage == POWEROFF_WAIT_OTHERS && 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_prepare();
+ poweroff_request_shutdown();
- CRITICAL_LOG("Starting poweroff sequence.");
+ return G_SOURCE_REMOVE;
+}
+
+static void poweroff_main(void)
+{
+ static guint poweroff_id = 0;
- // Watchdog timeout 90 -> 30 sec to reduce delay from unexpected poweroff failure.
- snprintf(timeout, sizeof(timeout), "WATCHDOG_USEC=%llu", (unsigned long long)POWEROFF_WAIT_SYSTEMD_MS*1000);
- sd_notify(0, timeout);
+ if (poweroff_id > 0)
+ return;
- make_power_flag(poweroff_opt.type, poweroff_opt.option);
+ /* 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);
+}
- if (disp_plgn->pm_lock_internal)
- disp_plgn->pm_lock_internal(INTERNAL_LOCK_POWEROFF, LCD_OFF, STAY_CUR_STATE, 0);
+static gboolean poweroff_wait_timeout_cb(void *data)
+{
+ pid_t pid = (pid_t)((intptr_t)data);
+
+ poweroff_remove_handle(pid);
- poweroff_prepare();
- poweroff_request_shutdown();
+ 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);
}
static gboolean poweroff_start_timers(void *data)
{
struct poweroff_handle *handle = NULL;
- GList *l;
+ GList *l, *l_next;
bool timer_exist = false;
- int pid_alive = 0;
+ _D("POWEROFF_STAGE=WAIT_OTHERS");
poweroff_stage = POWEROFF_WAIT_OTHERS;
- SYS_G_LIST_FOREACH(poweroff_handles, l, handle) {
- pid_alive = kill(handle->pid, 0);
- if (pid_alive == -1) {
+ 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);
- handle->timeout = 0;
+ SYS_G_LIST_REMOVE(poweroff_handles, handle);
+ continue;
}
- _D("Run timer, pid=%d(%s) timeout=%d timeout_id=%d.", handle->pid, handle->comm, handle->timeout, handle->timeout_id);
+ _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,
timer_exist = true;
}
- if (timer_exist) {
+ if (timer_exist)
return G_SOURCE_REMOVE;
- } else {
- _D("Handle is NULL.");
-
- handle = (struct poweroff_handle *)malloc(sizeof(struct poweroff_handle));
- if (handle == NULL) {
- _E("Not enough memory.");
- return G_SOURCE_REMOVE;
- }
- handle->pid = getpid();
- handle->timeout = 0;
- handle->timeout_id = g_timeout_add_seconds(handle->timeout,
- poweroff_wait_timeout_cb,
- (void *)((intptr_t)(handle->pid)));
-
- if (!handle->timeout_id) {
- _E("Failed to timer_add.");
- free(handle);
- return G_SOURCE_REMOVE;
- }
-
- SYS_G_LIST_APPEND(poweroff_handles, handle);
- }
-
- _D("Last Timer: timer_id=%d pid=%d timeout=%d", handle->timeout_id, handle->pid, handle->timeout);
+ // No need to wait. Strat main poweroff procedure immediately.
+ poweroff_main();
return G_SOURCE_REMOVE;
}
bundle_free(b);
}
-static int poweroff_option_valid(enum poweroff_type type_e, const char *option)
-{
- GList *l;
- struct power_option *elem;
-
- SYS_G_LIST_FOREACH(poweroff_options, l, elem) {
- if (elem->type != type_e)
- continue;
-
- /* Do not match option
- if (option) {
- if (elem->option == NULL)
- continue;
- if (strncmp(elem->option, option, strlen(elem->option)))
- continue;
- } else {
- if (elem->option != NULL)
- continue;
- } */
- return 1;
- }
-
- return 0;
-}
-
static void poweroff_send_broadcast(int status)
{
static int old = 0;
static int __poweroff_trigger_poweroff(const char *typename, const char *option)
{
int ret_val;
+ GList *l;
+ struct power_option *opt = NULL;
if (poweroff_stage >= POWEROFF_TRIGGERED) {
_E("Duplicate poweroff request. Poweroff was already triggered.");
return -EINVAL;
}
- enum poweroff_type type_e = poweroff_name_to_type(typename);
- if (type_e == POWEROFF_TYPE_INVALID) {
- _E("Failed to get type enum value(%d).", type_e);
+ 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;
}
- if (poweroff_option_valid(type_e, option)) {
- poweroff_opt.type = type_e;
- free(poweroff_opt.option);
- poweroff_opt.option = NULL;
- if (option)
- poweroff_opt.option = strdup(option);
- } else {
- _E("Failed to find supported type(%s). option=%s", typename, (option ? option : "NULL"));
- 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, poweroff_opt.type);
+ 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;
- if (disp_plgn->update_pm_setting)
- disp_plgn->update_pm_setting(SETTING_POWEROFF, poweroff_opt.type);
+ power_disable_autosleep();
+ device_notify_once(DEVICE_NOTIFIER_POWEROFF_TRIGGERED, (void *)(intptr_t) type);
/* Poweroff event broadcasting */
system_shutdown_send_system_event();
- poweroff_send_broadcast(poweroff_opt.type);
+ poweroff_send_broadcast(type);
/* Skip running animation if option is silent */
- if (poweroff_opt.option != NULL && !strcmp(poweroff_opt.option, "silent"))
+ if (opt && strncmp(opt->option, "silent", sizeof("silent")) == 0)
_D("Skip running poweroff animation.");
else
poweroff_start_animation();
GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
{
struct poweroff_handle *handle;
- GList *l;
+ GList *l, *l_next;
int ret = 0;
pid_t pid;
pid = (pid_t)ret;
- SYS_G_LIST_FOREACH(poweroff_handles, l, handle) {
- if (handle->pid == pid)
+ 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 (handle) {
- if (handle->timeout_id)
- g_source_remove(handle->timeout_id);
- handle->timeout = 0;
- handle->timeout_id = g_timeout_add_seconds(handle->timeout,
- poweroff_wait_timeout_cb,
- (void *)((intptr_t)(handle->pid)));
- } else {
- _E("Invalid pid(%d).", pid);
- ret = -1;
- }
+ if (poweroff_stage == POWEROFF_WAIT_OTHERS && SYS_G_LIST_LENGTH(poweroff_handles) == 0)
+ poweroff_main();
out:
return g_variant_new("(i)", ret);
{ "PowerOffWithOption", "ss", "i", dbus_power_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 },
/* Add methods here */
};
}
opt->type = type;
- opt->option = (option ? strdup(option) : NULL);
+ if (option)
+ strncpy(opt->option, option, sizeof(opt->option) - 1);
- SYS_G_LIST_APPEND(poweroff_options, opt);
+ SYS_G_LIST_APPEND(poweroff_options_list, opt);
_D("Add %s option=%s", name, opt->option);
static int load_config(struct parse_result *result, void *user_data)
{
- enum poweroff_type type;
-
if (MATCH(result->section, "PowerOff") && MATCH(result->name, "Option")) {
- type = POWEROFF_TYPE_DIRECT;
- add_poweroff_option(type, result->value);
+ add_poweroff_option(POWEROFF_TYPE_POWEROFF, result->value);
} else if (MATCH(result->section, "Reboot") && MATCH(result->name, "Option")) {
- type = POWEROFF_TYPE_RESTART;
- add_poweroff_option(type, result->value);
+ add_poweroff_option(POWEROFF_TYPE_REBOOT, result->value);
} else if (MATCH(result->section, "PowerState") && MATCH(result->name, "PowerOffDelaySecond")) {
sscanf(result->value, "%d", &poweroff_delay_second);
}
poweroff_stage = POWEROFF_DEFAULT;
}
-
-static void __CONSTRUCTOR__ initialize(void)
-{
- disp_plgn = get_var_display_plugin();
- if (!disp_plgn)
- _E("Failed to get display plugin variable.");
-}