2cf17c6ce2af190df3edd11cd9c0ec03f372c56c
[platform/core/system/deviced.git] / src / power / power-off.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19 #include <unistd.h>
20 #include <string.h>
21 #include <time.h>
22 #include <limits.h>
23 #include <fcntl.h>
24 #include <dirent.h>
25 #include <vconf.h>
26 #include <assert.h>
27 #include <sys/syscall.h>
28 #include <linux/reboot.h>
29 #include <sys/time.h>
30 #include <mntent.h>
31 #include <sys/mount.h>
32 #include <bundle.h>
33 #include <eventsystem.h>
34 #include <stdbool.h>
35 #include <signal.h>
36 #include <systemd/sd-daemon.h>
37 #include <libsyscommon/libgdbus.h>
38 #include <libsyscommon/libsystemd.h>
39 #include <libsyscommon/ini-parser.h>
40
41 #include "dd-deviced.h"
42 #include "core/log.h"
43 #include "shared/device-notifier.h"
44 #include "shared/common.h"
45 #include "shared/devices.h"
46 #include "display/poll.h"
47 #include "display/setting.h"
48 #include "display/core.h"
49 #include "display/display-ops.h"
50 #include "power-off.h"
51 #include "power.h"
52 #include "power-boot.h"
53 #include "shared/plugin.h"
54
55 #define POWEROFF_WAIT_RESOURCED     (0.5*1000) /* 0.5 seconds */
56 #define POWEROFF_WAIT_MAX           10 /* 10 seconds */
57 #define POWEROFF_WAIT_SYSTEMD_MS    (30 * 1000/*ms*/) /* 30 seconds */
58 #define SIGNAL_POWEROFF_STATE       "ChangeState"
59 #define POWER_CONF_FILE             "/etc/deviced/power.conf"
60
61 static struct timeval tv_start_poweroff;
62 static int poweroff_delay_second = 0;
63
64 static void poweroff_start_animation(void)
65 {
66         int ret_val;
67
68         ret_val = systemd_start_unit_async("shutdown-animation.service", NULL);
69         if (ret_val < 0)
70                 _E("Failed to start shutdown animation.");
71
72         gettimeofday(&tv_start_poweroff, NULL);
73 }
74
75 static void poweroff_notify_resourced(void)
76 {
77         _I("Request to stop systemd service to resourced.");
78         gdbus_call_sync_with_reply_timeout(RESOURCED_BUS_NAME,
79                                 RESOURCED_PATH_PROCESS,
80                                 RESOURCED_INTERFACE_PROCESS,
81                                 "PrePoweroff",
82                                 NULL,
83                                 NULL,
84                                 POWEROFF_WAIT_RESOURCED);
85 }
86
87 static void disable_display(void)
88 {
89         const struct device_ops *display_device_ops = NULL;
90         FIND_DEVICE_VOID(display_device_ops, "display");
91         if (display_device_ops->stop)
92                 display_device_ops->stop(NORMAL_MODE);
93 }
94
95 static int disable_systemd_journald(void)
96 {
97         int ret_val;
98
99         ret_val = systemd_stop_unit_async("systemd-journald.socket", NULL);
100         if (ret_val < 0) {
101                 _E("Failed to stop 'systemd-journald.socket'.");
102                 return ret_val;
103         }
104
105         ret_val = systemd_stop_unit_async("systemd-journald.service", NULL);
106         if (ret_val < 0) {
107                 _E("Failed to stop 'systemd-journald.service'.");
108                 return ret_val;
109         }
110         return 0;
111 }
112
113 /* processes might start to fail abnormally after we kill them via
114  * umount_partition_by_kill. Failing services can trigger coredump
115  * handler, which might have trouble handling core in inconsistent
116  * system state (eg. lack of /opt).  Due to this we disable the
117  * coredump handler for the shutdown period.
118  */
119 static bool disable_coredump_handler(void)
120 {
121         int ret_val = 0;
122         int fd = open("/proc/sys/kernel/core_pattern", O_WRONLY);
123         if (fd >= 0) {
124                 ret_val = write(fd, "/dev/null", sizeof("/dev/null") - 1);
125                 close(fd);
126         }
127
128         bool is_ok = ret_val > 0;
129         _I("Disabling core dumps %s.", is_ok  ? "succeeded" : "failed");
130
131         return is_ok;
132 }
133
134 void poweroff_request_shutdown(int state)
135 {
136         const char *systemd_method = "PowerOff";
137
138         if (!is_poweroff_state(state))
139                 return;
140
141         if (state == POWER_STATE_POWEROFF)
142                 systemd_method = "PowerOff";
143         else if (state == POWER_STATE_REBOOT)
144                 systemd_method = "Reboot";
145         else if (state == POWER_STATE_EXIT)
146                 systemd_method = "Exit";
147
148         CRITICAL_LOG("Requested %s via systemd.", systemd_method);
149         gdbus_call_sync_with_reply_timeout(SYSTEMD_DBUS_DEST,
150                                         SYSTEMD_DBUS_PATH,
151                                         SYSTEMD_DBUS_IFACE_MANAGER,
152                                         systemd_method,
153                                         NULL,
154                                         NULL,
155                                         POWEROFF_WAIT_SYSTEMD_MS);
156
157         raise(SIGUSR1);
158 }
159
160 static void poweroff_delay_for_seconds(void)
161 {
162         static int wait;
163         struct timeval now;
164         int check_duration = 0;
165
166         if (poweroff_delay_second == 0)
167                 return;
168
169         watchdog_notify();
170
171         gettimeofday(&now, NULL);
172         check_duration = now.tv_sec - tv_start_poweroff.tv_sec;
173
174         while (check_duration < poweroff_delay_second) {
175                 if (wait == 0) {
176                         _I("Wait poweroff %d %d.", check_duration, poweroff_delay_second);
177                         wait = 1;
178                 }
179                 usleep(100000);
180
181                 gettimeofday(&now, NULL);
182                 check_duration = now.tv_sec - tv_start_poweroff.tv_sec;
183
184                 if (check_duration < 0)
185                         break;
186         }
187
188         watchdog_notify();
189 }
190
191 int poweroff_check_revived(void)
192 {
193         if (access(POWEROFF_OPTPATH_POWEROFF, F_OK) == 0) {
194                 return POWER_STATE_POWEROFF;
195         }
196
197         if (access(POWEROFF_OPTPATH_REBOOT, F_OK) == 0) {
198                 return POWER_STATE_REBOOT;
199         }
200
201         if (access(POWEROFF_OPTPATH_EXIT, F_OK) == 0) {
202                 return POWER_STATE_EXIT;
203         }
204
205         return POWER_STATE_NORMAL;
206 }
207
208 static void mark_poweroff_option(uint64_t state, const char *option)
209 {
210         int fd;
211         ssize_t len;
212         const char *optpath;
213
214         if (state == POWER_STATE_POWEROFF)
215                 optpath = POWEROFF_OPTPATH_POWEROFF;
216         else if (state == POWER_STATE_REBOOT)
217                 optpath = POWEROFF_OPTPATH_REBOOT;
218         else if (state == POWER_STATE_EXIT)
219                 optpath = POWEROFF_OPTPATH_EXIT;
220         else
221                 return;
222
223         fd = open(optpath, O_RDWR|O_CREAT, S_IRUSR | S_IWUSR);
224         if (fd < 0) {
225                 _E("Failed to create '%s'.", optpath);
226                 return;
227         }
228
229         len = option ? write(fd, option, strlen(option)) : 0;
230         if (len < 0)
231                 _E("Failed to store option: %zd", len < 0 ? errno : len);
232
233         close(fd);
234 }
235
236 static gboolean __poweroff_main(gpointer data)
237 {
238         int state = (int)(intptr_t) data;
239
240         CRITICAL_LOG("Starting poweroff sequence");
241
242         // Watchdog timeout 90 -> 30 sec to reduce delay from unexpected poweroff failure.
243         sd_notifyf(0, "WATCHDOG_USEC=%llu", (unsigned long long)POWEROFF_WAIT_SYSTEMD_MS*1000);
244
245         poweroff_notify_resourced();
246         disable_systemd_journald();
247         disable_coredump_handler();
248         poweroff_delay_for_seconds();
249         disable_display();
250
251         /* Below functions follow after notifying DEVICE_NOTIFIER_POWEROFF
252            1. pmlock
253            - pmlock_detector_poweroff_cb()
254            - cleanup_pmlock_statistics()
255            - do_copy_force()
256            - save_display_log()
257            2. tzip
258            - tzip_poweroff()
259            - tzip_server_exit()
260            3. udev
261            - device_change_poweroff()
262            - uevent_control_stop()
263         */
264         device_notify_once(DEVICE_NOTIFIER_POWEROFF, data);
265
266         poweroff_request_shutdown(state);
267
268         return G_SOURCE_REMOVE;
269 }
270
271 void poweroff_main(void *udata)
272 {
273         static guint poweroff_id = 0;
274
275         if (poweroff_id > 0)
276                 return;
277
278         /* Terminate this subroutine at this point. The procedure returns to the caller, therefore
279          * the RemovePowerOffWait caller would not be blocked, if they invoked method synchronously.
280          * And the deviced enter poweroff_main on the next gmainloop iteration. */
281         poweroff_id = g_idle_add(__poweroff_main, udata);
282 }
283
284 static void system_shutdown_send_system_event(void)
285 {
286         bundle *b;
287
288         b = bundle_create();
289         bundle_add_str(b, EVT_KEY_SYSTEM_SHUTDOWN, EVT_VAL_SYSTEM_SHUTDOWN_TRUE);
290         eventsystem_send_system_event(SYS_EVENT_SYSTEM_SHUTDOWN, b);
291         bundle_free(b);
292 }
293
294 void poweroff_prepare(uint64_t state, void *option)
295 {
296         int vconf = VCONFKEY_SYSMAN_POWER_OFF_NONE;
297
298         if (!is_poweroff_state(state))
299                 return;
300
301         mark_poweroff_option(state, option);
302
303         if (state == POWER_STATE_POWEROFF)
304                 vconf = VCONFKEY_SYSMAN_POWER_OFF_DIRECT;
305         else if (state == POWER_STATE_REBOOT)
306                 vconf = VCONFKEY_SYSMAN_POWER_OFF_RESTART;
307         vconf_set_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, vconf);
308
309         power_disable_autosleep();
310         device_notify_once(DEVICE_NOTIFIER_POWEROFF_TRIGGERED, (void *)(intptr_t) vconf);
311
312         /* Poweroff event broadcasting */
313         system_shutdown_send_system_event();
314
315         /* Skip running animation if it is silent reboot */
316         if (option && strncmp(option, "silent", sizeof("silent")) == 0)
317                 return;
318
319         poweroff_start_animation();
320 }
321
322 static int check_sender_process(GDBusConnection *conn, const char *sender)
323 {
324         pid_t pid;
325
326         if (sender == NULL || g_dbus_is_name(sender) == FALSE) {
327                 _E("Invalid sender");
328                 return -EINVAL;
329         }
330
331         pid = gdbus_connection_get_sender_pid(conn, sender);
332         if (pid == -1 || kill(pid, 0) == -1) {
333                 _E("Process(%d) does not exist, dbus ignored.", pid);
334                 return -ESRCH;
335         }
336
337         return pid;
338 }
339
340 static GVariant *dbus_poweroff_handler(GDBusConnection *conn,
341         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
342         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
343 {
344         int ret;
345         char comm[128] = "Unknown";
346         char *type;
347         int next;
348
349         g_variant_get(param, "(s)", &type);
350
351         ret = check_sender_process(conn, sender);
352         if (ret < 0)
353                 goto out;
354
355         get_command(ret, comm, sizeof(comm));
356
357         if (strncmp(type, "poweroff", sizeof("poweroff")) == 0)
358                 next = POWER_STATE_POWEROFF;
359         else if (strncmp(type, "reboot", sizeof("reboot")) == 0)
360                 next = POWER_STATE_REBOOT;
361         else if (strncmp(type, "exit", sizeof("exit")) == 0)
362                 next = POWER_STATE_EXIT;
363         else {
364                 ret = -EINVAL;
365                 goto out;
366         }
367
368         CRITICAL_LOG("Poweroff pid=%d(%s) requests %s.", ret, comm, type);
369         power_request_change_state_strict(POWER_STATE_ALL, next, 9000, NULL);
370
371 out:
372         g_free(type);
373         return g_variant_new("(i)", ret);
374 }
375
376 static GVariant *dbus_poweroff_option_handler(GDBusConnection *conn,
377         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
378         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
379 {
380         int ret;
381         char comm[128] = "Unknown";
382         char *type, *option;
383         int next;
384
385         g_variant_get(param, "(ss)", &type, &option);
386
387         ret = check_sender_process(conn, sender);
388         if (ret < 0)
389                 goto out;
390
391         get_command(ret, comm, sizeof(comm));
392
393         if (strncmp(type, "poweroff", sizeof("poweroff")) == 0)
394                 next = POWER_STATE_POWEROFF;
395         else if (strncmp(type, "reboot", sizeof("reboot")) == 0)
396                 next = POWER_STATE_REBOOT;
397         else if (strncmp(type, "exit", sizeof("exit")) == 0)
398                 next = POWER_STATE_EXIT;
399         else {
400                 ret = -EINVAL;
401                 goto out;
402         }
403
404         CRITICAL_LOG("Poweroff pid=%d(%s) requests type=%s option=%s.", ret, comm, type, option);
405         power_request_change_state_strict(POWER_STATE_ALL, next, 9000, option);
406
407 out:
408         g_free(type);
409         g_free(option);
410         return g_variant_new("(i)", ret);
411 }
412
413 static GVariant *add_poweroff_time(GDBusConnection *conn,
414         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
415         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
416 {
417         return g_variant_new("(i)", 0);
418 }
419
420 static GVariant *remove_poweroff_time(GDBusConnection *conn,
421         const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
422         GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
423 {
424         return g_variant_new("(i)", 0);
425 }
426
427 static const dbus_method_s dbus_methods[] = {
428         { "PowerOff"          , "s" , "i", dbus_poweroff_handler },
429         { "PowerOffWithOption", "ss", "i", dbus_poweroff_option_handler },
430         /* Public API device_power_reboot() calls this dbus method. */
431         { "AddPowerOffWait"   , NULL, "i", add_poweroff_time }, /* deprecated */
432         { "RemovePowerOffWait", NULL, "i", remove_poweroff_time }, /* deprecated */
433         /* Add methods here */
434 };
435
436 static const dbus_interface_u dbus_interface = {
437         .oh = NULL,
438         .name = DEVICED_INTERFACE_POWEROFF,
439         .methods = dbus_methods,
440         .nr_methods = ARRAY_SIZE(dbus_methods),
441 };
442
443 static int load_config(struct parse_result *result, void *user_data)
444 {
445         if (MATCH(result->section, "PowerState") && MATCH(result->name, "PowerOffDelaySecond")) {
446                 sscanf(result->value, "%d", &poweroff_delay_second);
447         }
448
449         return 0;
450 }
451
452 static int delayed_init_done(void *data)
453 {
454         static int done;
455
456         if (data == NULL)
457                 goto out;
458
459         done = *(int *)data;
460 out:
461         return done;
462 }
463
464 void power_off_init(void)
465 {
466         int ret_val;
467
468         /* init dbus interface */
469         ret_val = gdbus_add_object(NULL, DEVICED_PATH_POWEROFF, &dbus_interface);
470         if (ret_val < 0)
471                 _E("Failed to init dbus method: %d", ret_val);
472
473         add_delayed_init_done_handler(NULL);
474
475         register_notifier(DEVICE_NOTIFIER_DELAYED_INIT, delayed_init_done);
476
477         ret_val = config_parse(POWER_CONF_FILE, load_config, NULL);
478         if (ret_val < 0)
479                 _E("Failed to load power off config: %d", ret_val);
480 }