4 * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
27 #include <sys/syscall.h>
28 #include <linux/reboot.h>
31 #include <sys/mount.h>
33 #include <eventsystem.h>
36 #include <systemd/sd-daemon.h>
37 #include <libsyscommon/libgdbus.h>
38 #include <libsyscommon/libsystemd.h>
39 #include <libsyscommon/ini-parser.h>
40 #include <libsyscommon/proc.h>
42 #include "dd-deviced.h"
44 #include "shared/device-notifier.h"
45 #include "shared/common.h"
46 #include "shared/devices.h"
50 #include "display-ops.h"
51 #include "power-off.h"
53 #include "power-boot.h"
54 #include "shared/plugin.h"
56 #define POWEROFF_WAIT_RESOURCED (0.5*1000) /* 0.5 seconds */
57 #define POWEROFF_WAIT_MAX 10 /* 10 seconds */
58 #define POWEROFF_WAIT_SYSTEMD_MS (30 * 1000/*ms*/) /* 30 seconds */
59 #define SIGNAL_POWEROFF_STATE "ChangeState"
60 #define POWER_CONF_FILE "/etc/deviced/power.conf"
62 static struct timeval tv_start_poweroff;
63 static int poweroff_delay_second = 0;
64 static int silent_reboot = 0;
66 static void poweroff_start_animation(void)
70 ret_val = systemd_start_unit_async("shutdown-animation.service", NULL);
72 _E("Failed to start shutdown animation.");
74 gettimeofday(&tv_start_poweroff, NULL);
77 static void poweroff_notify_resourced(void)
79 _I("Request to stop systemd service to resourced.");
80 gdbus_call_sync_with_reply_timeout(RESOURCED_BUS_NAME,
81 RESOURCED_PATH_PROCESS,
82 RESOURCED_INTERFACE_PROCESS,
86 POWEROFF_WAIT_RESOURCED);
89 static void disable_display(void)
91 const struct device_ops *display_device_ops = NULL;
92 FIND_DEVICE_VOID(display_device_ops, "display");
93 if (display_device_ops->stop)
94 display_device_ops->stop(NORMAL_MODE);
97 static int disable_systemd_journald(void)
101 ret_val = systemd_stop_unit_async("systemd-journald.socket", NULL);
103 _E("Failed to stop 'systemd-journald.socket'.");
107 ret_val = systemd_stop_unit_async("systemd-journald.service", NULL);
109 _E("Failed to stop 'systemd-journald.service'.");
115 /* processes might start to fail abnormally after we kill them via
116 * umount_partition_by_kill. Failing services can trigger coredump
117 * handler, which might have trouble handling core in inconsistent
118 * system state (eg. lack of /opt). Due to this we disable the
119 * coredump handler for the shutdown period.
121 static bool disable_coredump_handler(void)
124 int fd = open("/proc/sys/kernel/core_pattern", O_WRONLY);
126 ret_val = write(fd, "/dev/null", sizeof("/dev/null") - 1);
130 bool is_ok = ret_val > 0;
131 _I("Disabling core dumps %s.", is_ok ? "succeeded" : "failed");
136 void poweroff_request_shutdown(int state)
138 const char *systemd_method = "PowerOff";
140 if (!is_poweroff_state(state))
143 if (state == DEVICED_POWER_STATE_POWEROFF)
144 systemd_method = "PowerOff";
145 else if (state == DEVICED_POWER_STATE_REBOOT)
146 systemd_method = "Reboot";
147 else if (state == DEVICED_POWER_STATE_EXIT)
148 systemd_method = "Exit";
150 CRITICAL_LOG("Requested %s via systemd.", systemd_method);
151 gdbus_call_sync_with_reply_timeout(SYSTEMD_DBUS_DEST,
153 SYSTEMD_DBUS_IFACE_MANAGER,
157 POWEROFF_WAIT_SYSTEMD_MS);
162 static void poweroff_delay_for_seconds(void)
166 int check_duration = 0;
168 if (poweroff_delay_second == 0)
173 gettimeofday(&now, NULL);
174 check_duration = now.tv_sec - tv_start_poweroff.tv_sec;
176 while (check_duration < poweroff_delay_second) {
178 _I("Wait poweroff %d %d.", check_duration, poweroff_delay_second);
183 gettimeofday(&now, NULL);
184 check_duration = now.tv_sec - tv_start_poweroff.tv_sec;
186 if (check_duration < 0)
193 int poweroff_check_revived(void)
195 if (access(POWEROFF_OPTPATH_POWEROFF, F_OK) == 0) {
196 return DEVICED_POWER_STATE_POWEROFF;
199 if (access(POWEROFF_OPTPATH_REBOOT, F_OK) == 0) {
200 return DEVICED_POWER_STATE_REBOOT;
203 if (access(POWEROFF_OPTPATH_EXIT, F_OK) == 0) {
204 return DEVICED_POWER_STATE_EXIT;
207 return DEVICED_POWER_STATE_NORMAL;
210 static void mark_poweroff_option(uint64_t state, const char *option)
216 if (state == DEVICED_POWER_STATE_POWEROFF)
217 optpath = POWEROFF_OPTPATH_POWEROFF;
218 else if (state == DEVICED_POWER_STATE_REBOOT)
219 optpath = POWEROFF_OPTPATH_REBOOT;
220 else if (state == DEVICED_POWER_STATE_EXIT)
221 optpath = POWEROFF_OPTPATH_EXIT;
225 if (option && strncmp(option, "silent", sizeof("silent")) == 0)
228 fd = open(optpath, O_RDWR|O_CREAT, S_IRUSR | S_IWUSR);
230 _E("Failed to create '%s'.", optpath);
234 len = option ? write(fd, option, strlen(option)) : 0;
236 _E("Failed to store option: %zd", len < 0 ? errno : len);
241 static gboolean __poweroff_main(gpointer data)
243 int state = (int)(intptr_t) data;
245 CRITICAL_LOG("Starting poweroff sequence");
247 // Watchdog timeout 90 -> 30 sec to reduce delay from unexpected poweroff failure.
248 sd_notifyf(0, "WATCHDOG_USEC=%llu", (unsigned long long)POWEROFF_WAIT_SYSTEMD_MS*1000);
250 poweroff_notify_resourced();
251 disable_systemd_journald();
252 disable_coredump_handler();
253 poweroff_delay_for_seconds();
256 /* Below functions follow after notifying DEVICED_NOTIFIER_POWEROFF
258 - pmlock_detector_poweroff_cb()
259 - cleanup_pmlock_statistics()
261 - display_misc_save_display_log()
266 - device_change_poweroff()
267 - uevent_control_stop()
269 syscommon_notifier_emit_notify_once(DEVICED_NOTIFIER_POWEROFF, data);
271 poweroff_request_shutdown(state);
273 return G_SOURCE_REMOVE;
276 void poweroff_main(void *udata)
278 static guint poweroff_id = 0;
283 /* Terminate this subroutine at this point. The procedure returns to the caller, therefore
284 * the RemovePowerOffWait caller would not be blocked, if they invoked method synchronously.
285 * And the deviced enter poweroff_main on the next gmainloop iteration. */
286 poweroff_id = g_idle_add(__poweroff_main, udata);
289 static void system_shutdown_send_system_event(void)
294 bundle_add_str(b, EVT_KEY_SYSTEM_SHUTDOWN, EVT_VAL_SYSTEM_SHUTDOWN_TRUE);
295 eventsystem_send_system_event(SYS_EVENT_SYSTEM_SHUTDOWN, b);
299 void poweroff_prepare(uint64_t state)
301 int vconf = VCONFKEY_SYSMAN_POWER_OFF_NONE;
304 if (!is_poweroff_state(state))
307 if (state == DEVICED_POWER_STATE_POWEROFF)
308 vconf = VCONFKEY_SYSMAN_POWER_OFF_DIRECT;
309 else if (state == DEVICED_POWER_STATE_REBOOT)
310 vconf = VCONFKEY_SYSMAN_POWER_OFF_RESTART;
311 ret = vconf_set_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, vconf);
313 _W("Failed to set vconf value for power off status: %d", vconf_get_ext_errno());
315 power_exit_autosleep();
316 syscommon_notifier_emit_notify_once(DEVICED_NOTIFIER_POWEROFF_TRIGGERED, (void *)(intptr_t) vconf);
318 /* Poweroff event broadcasting */
319 system_shutdown_send_system_event();
321 /* Skip running animation if it is silent reboot */
325 poweroff_start_animation();
328 static int check_sender_process(GDBusConnection *conn, const char *sender)
332 if (sender == NULL || g_dbus_is_name(sender) == FALSE) {
333 _E("Invalid sender");
337 pid = gdbus_connection_get_sender_pid(conn, sender);
338 if (pid == -1 || kill(pid, 0) == -1) {
339 _E("Process(%d) does not exist, dbus ignored.", pid);
346 static GVariant *dbus_poweroff_handler(GDBusConnection *conn,
347 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
348 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
351 char comm[128] = "Unknown";
355 g_variant_get(param, "(s)", &type);
357 ret = check_sender_process(conn, sender);
361 syscommon_proc_get_comm(ret, comm, sizeof(comm));
363 if (strncmp(type, "poweroff", sizeof("poweroff")) == 0)
364 next = DEVICED_POWER_STATE_POWEROFF;
365 else if (strncmp(type, "reboot", sizeof("reboot")) == 0)
366 next = DEVICED_POWER_STATE_REBOOT;
367 else if (strncmp(type, "exit", sizeof("exit")) == 0)
368 next = DEVICED_POWER_STATE_EXIT;
374 CRITICAL_LOG("Poweroff pid=%d(%s) requests %s.", ret, comm, type);
375 power_request_change_state_strict(DEVICED_POWER_STATE_ALL, next, 9000, NULL);
379 return g_variant_new("(i)", ret);
382 static GVariant *dbus_poweroff_option_handler(GDBusConnection *conn,
383 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
384 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
387 char comm[128] = "Unknown";
391 g_variant_get(param, "(ss)", &type, &option);
393 ret = check_sender_process(conn, sender);
397 syscommon_proc_get_comm(ret, comm, sizeof(comm));
399 if (strncmp(type, "poweroff", sizeof("poweroff")) == 0)
400 next = DEVICED_POWER_STATE_POWEROFF;
401 else if (strncmp(type, "reboot", sizeof("reboot")) == 0)
402 next = DEVICED_POWER_STATE_REBOOT;
403 else if (strncmp(type, "exit", sizeof("exit")) == 0)
404 next = DEVICED_POWER_STATE_EXIT;
410 mark_poweroff_option(next, option);
412 CRITICAL_LOG("Poweroff pid=%d(%s) requests type=%s option=%s.", ret, comm, type, option);
413 power_request_change_state_strict(DEVICED_POWER_STATE_ALL, next, 9000, NULL);
418 return g_variant_new("(i)", ret);
421 static GVariant *add_poweroff_time(GDBusConnection *conn,
422 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
423 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
425 return g_variant_new("(i)", 0);
428 static GVariant *remove_poweroff_time(GDBusConnection *conn,
429 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
430 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
432 return g_variant_new("(i)", 0);
435 static const dbus_method_s dbus_methods[] = {
436 { "PowerOff" , "s" , "i", dbus_poweroff_handler },
437 { "PowerOffWithOption", "ss", "i", dbus_poweroff_option_handler },
438 /* Public API device_power_reboot() calls this dbus method. */
439 { "AddPowerOffWait" , NULL, "i", add_poweroff_time }, /* deprecated */
440 { "RemovePowerOffWait", NULL, "i", remove_poweroff_time }, /* deprecated */
441 /* Add methods here */
444 static const dbus_interface_u dbus_interface = {
446 .name = DEVICED_INTERFACE_POWEROFF,
447 .methods = dbus_methods,
448 .nr_methods = ARRAY_SIZE(dbus_methods),
451 static int load_config(struct parse_result *result, void *user_data)
453 if (MATCH(result->section, "PowerState") && MATCH(result->name, "PowerOffDelaySecond")) {
454 sscanf(result->value, "%d", &poweroff_delay_second);
460 static int delayed_init_done(void *data)
472 void power_off_init(void)
476 /* init dbus interface */
477 ret_val = gdbus_add_object(NULL, DEVICED_PATH_POWEROFF, &dbus_interface);
479 _E("Failed to init dbus method: %d", ret_val);
481 add_delayed_init_done_handler(NULL);
483 syscommon_notifier_subscribe_notify(DEVICED_NOTIFIER_DELAYED_INIT, delayed_init_done);
485 ret_val = config_parse(POWER_CONF_FILE, load_config, NULL);
487 _E("Failed to load power off config: %d", ret_val);