efc491b275f6a2ef9ad68eaa9f43fae008609fb6
[framework/system/deviced.git] / src / power / power-handler.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
20 #include <unistd.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 <limits.h>
28 #include <vconf.h>
29 #include <fcntl.h>
30 #include <sys/reboot.h>
31 #include <sys/time.h>
32 #include <mntent.h>
33 #include <sys/mount.h>
34 #include <device-node.h>
35 #include <journal/system.h>
36 #include "dd-deviced.h"
37 #include "core/log.h"
38 #include "core/launch.h"
39 #include "core/device-handler.h"
40 #include "core/device-notifier.h"
41 #include "core/common.h"
42 #include "core/devices.h"
43 #include "proc/proc-handler.h"
44 #include "display/poll.h"
45 #include "display/setting.h"
46 #include "core/edbus-handler.h"
47 #include "display/core.h"
48 #include "power-handler.h"
49 #include "hall/hall-handler.h"
50
51 #define SIGNAL_NAME_POWEROFF_POPUP      "poweroffpopup"
52 #define SIGNAL_BOOTING_DONE             "BootingDone"
53
54 #define POWEROFF_NOTI_NAME              "power_off_start"
55 #define POWEROFF_DURATION               2
56 #define MAX_RETRY                       2
57
58 #define SYSTEMD_STOP_POWER_OFF                          4
59
60 #define SIGNAL_POWEROFF_STATE   "ChangeState"
61
62 #define POWEROFF_POPUP_NAME     "poweroff-syspopup"
63 #define UMOUNT_RW_PATH "/opt/usr"
64
65 static void poweroff_control_cb(keynode_t *in_key, void *data);
66
67 struct popup_data {
68         char *name;
69         char *key;
70 };
71
72 static struct timeval tv_start_poweroff;
73
74 static int power_off = 0;
75 static const struct device_ops *telephony = NULL;
76 static const struct device_ops *hall_ic = NULL;
77
78 static void telephony_init(void)
79 {
80         FIND_DEVICE_VOID(telephony, "telephony");
81         _I("telephony (%d)", telephony);
82 }
83
84 static void telephony_start(void)
85 {
86         telephony_init();
87         device_start(telephony);
88 }
89
90 static void telephony_stop(void)
91 {
92         device_stop(telephony);
93 }
94
95 static int telephony_exit(void *data)
96 {
97         int ret;
98
99         ret = device_exit(telephony, data);
100         return ret;
101 }
102
103 static int systemd_manager_object(const char *opt, char **param)
104 {
105         return dbus_method_async("org.freedesktop.systemd1",
106                                  "/org/freedesktop/systemd1",
107                                  "org.freedesktop.systemd1.Manager",
108                                  opt,
109                                  "ss", param);
110 }
111
112 static int systemd_manager_object_start_unit(char **param)
113 {
114         return systemd_manager_object("StartUnit", param);
115 }
116
117 static int systemd_manager_object_stop_unit(char **param)
118 {
119         return systemd_manager_object("StopUnit", param);
120 }
121
122 static int stop_systemd_journald(void)
123 {
124         char *journal_socket[2]  = { "systemd-journald.socket",    "replace" };
125         char *journal_service[2] = { "systemd-journald.service",   "replace" };
126
127         int ret = 0;
128
129         ret = systemd_manager_object_stop_unit(journal_socket);
130         if (ret < 0) {
131                 _E("failed to stop 'systemd-journald.socket'");
132                 return ret;
133         }
134         ret |= systemd_manager_object_stop_unit(journal_service);
135         if (ret < 0) {
136                 _E("failed to stop 'systemd-journald.service'");
137                 return ret;
138         }
139
140         return 0;
141 }
142
143 static int hall_ic_status(void)
144 {
145         int ret;
146
147         ret = device_get_status(hall_ic);
148         if (ret < 0)
149                 return HALL_IC_OPENED;
150         return ret;
151 }
152
153 static void poweroff_start_animation(void)
154 {
155         char params[128];
156         snprintf(params, sizeof(params), "/usr/bin/boot-animation --stop --clear");
157         launch_app_cmd_with_nice(params, -20);
158         launch_evenif_exist("/usr/bin/sound_server", "--poweroff");
159         device_notify(DEVICE_NOTIFIER_POWEROFF_HAPTIC, NULL);
160 }
161
162 int previous_poweroff(void)
163 {
164         int ret;
165         static const struct device_ops *display_device_ops = NULL;
166
167         telephony_start();
168
169         FIND_DEVICE_INT(display_device_ops, "display");
170
171         display_device_ops->exit(NULL);
172         sync();
173
174         gettimeofday(&tv_start_poweroff, NULL);
175
176         ret = telephony_exit(POWER_POWEROFF);
177
178         if (ret < 0) {
179                 powerdown_ap(NULL);
180                 return 0;
181         }
182         return ret;
183 }
184
185 static int poweroff(void)
186 {
187         int retry_count = 0;
188         poweroff_start_animation();
189         while (retry_count < MAX_RETRY) {
190                 if (previous_poweroff() < 0) {
191                         _E("failed to request poweroff to deviced");
192                         retry_count++;
193                         continue;
194                 }
195                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, (void*)poweroff_control_cb);
196                 return 0;
197         }
198         return -1;
199 }
200
201 static int pwroff_popup(void)
202 {
203         struct popup_data *params;
204         static const struct device_ops *apps = NULL;
205         int val;
206
207         val = hall_ic_status();
208         if (val == HALL_IC_CLOSED) {
209                 _I("cover is closed");
210                 return 0;
211         }
212
213         FIND_DEVICE_INT(apps, "apps");
214
215         params = malloc(sizeof(struct popup_data));
216         if (params == NULL) {
217                 _E("Malloc failed");
218                 return -1;
219         }
220         params->name = POWEROFF_POPUP_NAME;
221         apps->init((void *)params);
222         free(params);
223         return 0;
224 }
225
226 static int power_reboot(int type)
227 {
228         int ret;
229
230         const struct device_ops *display_device_ops = NULL;
231         poweroff_start_animation();
232         telephony_start();
233
234         FIND_DEVICE_INT(display_device_ops, "display");
235
236         pm_change_internal(getpid(), LCD_NORMAL);
237         display_device_ops->exit(NULL);
238         sync();
239
240         gettimeofday(&tv_start_poweroff, NULL);
241
242         if (type == SYSTEMD_STOP_POWER_RESTART_RECOVERY)
243                 ret = telephony_exit(POWER_RECOVERY);
244         else if (type == SYSTEMD_STOP_POWER_RESTART_FOTA)
245                 ret = telephony_exit(POWER_FOTA);
246         else
247                 ret = telephony_exit(POWER_REBOOT);
248
249         if (ret < 0) {
250                 restart_ap((void *)type);
251                 return 0;
252         }
253         return ret;
254 }
255
256 static int power_execute(void *data)
257 {
258         int ret = 0;
259
260         if (strncmp(POWER_POWEROFF, (char *)data, POWER_POWEROFF_LEN) == 0)
261                 ret = poweroff();
262         else if (strncmp(PWROFF_POPUP, (char *)data, PWROFF_POPUP_LEN) == 0)
263                 ret = pwroff_popup();
264         else if (strncmp(POWER_REBOOT, (char *)data, POWER_REBOOT_LEN) == 0)
265                 ret = power_reboot(VCONFKEY_SYSMAN_POWER_OFF_RESTART);
266         else if (strncmp(POWER_RECOVERY, (char *)data, POWER_RECOVERY_LEN) == 0)
267                 ret = power_reboot(SYSTEMD_STOP_POWER_RESTART_RECOVERY);
268         else if (strncmp(POWER_FOTA, (char *)data, POWER_FOTA_LEN) == 0)
269                 ret = power_reboot(SYSTEMD_STOP_POWER_RESTART_FOTA);
270         else if (strncmp(INTERNAL_PWROFF, (char *)data, INTERNAL_PWROFF_LEN) == 0)
271                 ret = previous_poweroff();
272
273         return ret;
274 }
275
276 static void poweroff_popup_edbus_signal_handler(void *data, DBusMessage *msg)
277 {
278         DBusError err;
279         char *str;
280         int val = 0;
281
282         if (dbus_message_is_signal(msg, DEVICED_INTERFACE_NAME, SIGNAL_NAME_POWEROFF_POPUP) == 0) {
283                 _E("there is no power off popup signal");
284                 return;
285         }
286
287         dbus_error_init(&err);
288
289         if (dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID) == 0) {
290                 _E("there is no message");
291                 return;
292         }
293
294         if (!strncmp(str, PWROFF_POPUP, PWROFF_POPUP_LEN))
295                 val = VCONFKEY_SYSMAN_POWER_OFF_POPUP;
296         else if (!strncmp(str, POWER_POWEROFF, POWER_POWEROFF_LEN))
297                 val = SYSTEMD_STOP_POWER_OFF;
298         else if (!strncmp(str, POWER_REBOOT, POWER_REBOOT_LEN))
299                 val = SYSTEMD_STOP_POWER_RESTART;
300         else if (!strncmp(str, POWER_FOTA, POWER_FOTA_LEN))
301                 val = SYSTEMD_STOP_POWER_RESTART_FOTA;
302         if (val == 0) {
303                 _E("not supported message : %s", str);
304                 return;
305         }
306         vconf_set_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, val);
307 }
308
309 static int booting_done(void *data)
310 {
311         static int done = 0;
312
313         if (data == NULL)
314                 goto out;
315
316         done = (int)data;
317         telephony_init();
318 out:
319         return done;
320 }
321
322 static void booting_done_edbus_signal_handler(void *data, DBusMessage *msg)
323 {
324         int done;
325
326         if (!dbus_message_is_signal(msg, DEVICED_INTERFACE_CORE, SIGNAL_BOOTING_DONE)) {
327                 _E("there is no bootingdone signal");
328                 return;
329         }
330         done = booting_done(NULL);
331         if (done)
332                 return;
333
334         _I("signal booting done");
335         device_notify(DEVICE_NOTIFIER_BOOTING_DONE, (void *)TRUE);
336 }
337
338 static void poweroff_send_broadcast(int status)
339 {
340         static int old = 0;
341         char *arr[1];
342         char str_status[32];
343
344         if (old == status)
345                 return;
346
347         _D("broadcast poweroff %d", status);
348
349         old = status;
350         snprintf(str_status, sizeof(str_status), "%d", status);
351         arr[0] = str_status;
352
353         broadcast_edbus_signal(DEVICED_PATH_POWEROFF, DEVICED_INTERFACE_POWEROFF,
354                         SIGNAL_POWEROFF_STATE, "i", arr);
355 }
356
357 static void poweroff_stop_systemd_service(void)
358 {
359         char buf[256];
360         _D("systemd service stop");
361         umount2("/sys/fs/cgroup", MNT_FORCE |MNT_DETACH);
362 }
363
364 static void poweroff_control_cb(keynode_t *in_key, void *data)
365 {
366         int val;
367         int ret;
368         int recovery;
369
370         telephony_start();
371
372         if (vconf_get_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, &val) != 0)
373                 return;
374
375         recovery = val;
376
377         if (val == SYSTEMD_STOP_POWER_OFF ||
378             val == SYSTEMD_STOP_POWER_RESTART ||
379             val == SYSTEMD_STOP_POWER_RESTART_RECOVERY ||
380             val == SYSTEMD_STOP_POWER_RESTART_FOTA) {
381                 pm_lock_internal(INTERNAL_LOCK_POWEROFF, LCD_OFF, STAY_CUR_STATE, 0);
382                 poweroff_stop_systemd_service();
383                 if (val == SYSTEMD_STOP_POWER_OFF)
384                         val = VCONFKEY_SYSMAN_POWER_OFF_DIRECT;
385                 else
386                         val = VCONFKEY_SYSMAN_POWER_OFF_RESTART;
387                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, (void*)poweroff_control_cb);
388                 vconf_set_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, val);
389         }
390
391         if (val == VCONFKEY_SYSMAN_POWER_OFF_DIRECT || val == VCONFKEY_SYSMAN_POWER_OFF_RESTART)
392                 poweroff_send_broadcast(val);
393
394         switch (val) {
395         case VCONFKEY_SYSMAN_POWER_OFF_DIRECT:
396                 device_notify(DEVICE_NOTIFIER_POWEROFF, (void *)val);
397                 poweroff();
398                 break;
399         case VCONFKEY_SYSMAN_POWER_OFF_POPUP:
400                 pwroff_popup();
401                 break;
402         case VCONFKEY_SYSMAN_POWER_OFF_RESTART:
403                 device_notify(DEVICE_NOTIFIER_POWEROFF, (void *)val);
404                 power_reboot(recovery);
405                 break;
406         }
407
408         if (update_pm_setting)
409                 update_pm_setting(SETTING_POWEROFF, val);
410 }
411
412 /* umount usr data partition */
413 static void unmount_rw_partition()
414 {
415         int retry = 0;
416         sync();
417 #ifdef MICRO_DD
418         if (!mount_check(UMOUNT_RW_PATH))
419                 return;
420 #endif
421         while (1) {
422                 switch (retry++) {
423                 case 0:
424                         /* Second, kill app with SIGTERM */
425                         _I("Kill app with SIGTERM");
426                         terminate_process(UMOUNT_RW_PATH, false);
427                         sleep(3);
428                         break;
429                 case 1:
430                         /* Last time, kill app with SIGKILL */
431                         _I("Kill app with SIGKILL");
432                         terminate_process(UMOUNT_RW_PATH, true);
433                         sleep(1);
434                         break;
435                 default:
436                         if (umount2(UMOUNT_RW_PATH, 0) != 0) {
437                                 _I("Failed to unmount %s", UMOUNT_RW_PATH);
438                                 return;
439                         }
440                         _I("%s unmounted successfully", UMOUNT_RW_PATH);
441                         return;
442                 }
443                 if (umount2(UMOUNT_RW_PATH, 0) == 0) {
444                         _I("%s unmounted successfully", UMOUNT_RW_PATH);
445                         return;
446                 }
447         }
448 }
449
450 static void powerdown(void)
451 {
452         static int wait = 0;
453         struct timeval now;
454         int poweroff_duration = POWEROFF_DURATION;
455         int check_duration = 0;
456         char *buf;
457
458         if (power_off == 1) {
459                 _E("during power off");
460                 return;
461         }
462         journal_system_shutdown();
463         /* if this fails, that's OK */
464         stop_systemd_journald();
465         telephony_stop();
466         vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, (void*)poweroff_control_cb);
467         power_off = 1;
468         sync();
469
470         buf = getenv("PWROFF_DUR");
471         if (buf != NULL && strlen(buf) < 1024)
472                 poweroff_duration = atoi(buf);
473         if (poweroff_duration < 0 || poweroff_duration > 60)
474                 poweroff_duration = POWEROFF_DURATION;
475         gettimeofday(&now, NULL);
476         check_duration = now.tv_sec - tv_start_poweroff.tv_sec;
477         while (check_duration < poweroff_duration) {
478                 if (wait == 0) {
479                         _I("wait poweroff %d %d", check_duration, poweroff_duration);
480                         wait = 1;
481                 }
482                 usleep(100000);
483                 gettimeofday(&now, NULL);
484                 check_duration = now.tv_sec - tv_start_poweroff.tv_sec;
485                 if (check_duration < 0)
486                         break;
487         }
488 #ifndef EMULATOR
489         unmount_rw_partition();
490 #endif
491 }
492
493 static void restart_by_mode(int mode)
494 {
495         if (mode == SYSTEMD_STOP_POWER_RESTART_RECOVERY)
496                 launch_evenif_exist("/usr/sbin/reboot", "recovery");
497         else if (mode == SYSTEMD_STOP_POWER_RESTART_FOTA)
498                 launch_evenif_exist("/usr/sbin/reboot", "fota");
499         else
500                 reboot(RB_AUTOBOOT);
501 }
502
503 int reset_resetkey_disable(char *name, enum watch_id id)
504 {
505         _D("force reset power resetkey disable to zero");
506         return device_set_property(DEVICE_TYPE_POWER, PROP_POWER_RESETKEY_DISABLE, 0);
507 }
508
509 static DBusMessage *edbus_resetkeydisable(E_DBus_Object *obj, DBusMessage *msg)
510 {
511         DBusMessageIter iter;
512         DBusMessage *reply;
513         int val, ret;
514
515         ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &val,
516                         DBUS_TYPE_INVALID);
517         if (!ret) {
518                 _E("there is no message");
519                 ret = -EINVAL;
520                 goto error;
521         }
522
523         ret = device_set_property(DEVICE_TYPE_POWER, PROP_POWER_RESETKEY_DISABLE, val);
524         if (ret < 0)
525                 goto error;
526
527         if (val)
528                 register_edbus_watch(msg, WATCH_POWER_RESETKEY_DISABLE, reset_resetkey_disable);
529         else
530                 unregister_edbus_watch(msg, WATCH_POWER_RESETKEY_DISABLE);
531
532         _D("get power resetkey disable %d, %d", val, ret);
533
534 error:
535         reply = dbus_message_new_method_return(msg);
536         dbus_message_iter_init_append(reply, &iter);
537         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
538         return reply;
539 }
540
541 static int reset_wakeupkey(char *name, enum watch_id id)
542 {
543         _D("force reset wakeupkey to zero");
544         return device_set_property(DEVICE_TYPE_POWER, PROP_POWER_WAKEUP_KEY, 0);
545 }
546
547 static DBusMessage *edbus_set_wakeup_key(E_DBus_Object *obj, DBusMessage *msg)
548 {
549         DBusMessageIter iter;
550         DBusMessage *reply;
551         int val, ret;
552
553         ret = dbus_message_get_args(msg, NULL,
554                         DBUS_TYPE_INT32, &val,
555                         DBUS_TYPE_INVALID);
556         if (!ret) {
557                 _E("there is no message");
558                 ret = -EINVAL;
559                 goto error;
560         }
561
562         ret = device_set_property(DEVICE_TYPE_POWER, PROP_POWER_WAKEUP_KEY, val);
563         if (ret < 0)
564                 goto error;
565
566         if (val)
567                 register_edbus_watch(msg, WATCH_POWER_WAKEUPKEY, reset_wakeupkey);
568         else
569                 unregister_edbus_watch(msg, WATCH_POWER_WAKEUPKEY);
570
571         _D("set power wakeup key %d %d", val, ret);
572
573 error:
574         reply = dbus_message_new_method_return(msg);
575         dbus_message_iter_init_append(reply, &iter);
576         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
577         return reply;
578 }
579
580 static DBusMessage *dbus_power_handler(E_DBus_Object *obj, DBusMessage *msg)
581 {
582         DBusError err;
583         DBusMessageIter iter;
584         DBusMessage *reply;
585         pid_t pid;
586         int ret;
587         int argc;
588         char *type_str;
589
590         dbus_error_init(&err);
591
592         if (!dbus_message_get_args(msg, &err,
593                     DBUS_TYPE_STRING, &type_str,
594                     DBUS_TYPE_INT32, &argc, DBUS_TYPE_INVALID)) {
595                 _E("there is no message");
596                 ret = -EINVAL;
597                 goto out;
598         }
599
600         if (argc < 0) {
601                 _E("message is invalid!");
602                 ret = -EINVAL;
603                 goto out;
604         }
605
606         pid = get_edbus_sender_pid(msg);
607         if (kill(pid, 0) == -1) {
608                 _E("%d process does not exist, dbus ignored!", pid);
609                 ret = -ESRCH;
610                 goto out;
611         }
612
613         telephony_start();
614
615         if(!strncmp(type_str, POWER_REBOOT, POWER_REBOOT_LEN))
616                 ret = power_reboot(VCONFKEY_SYSMAN_POWER_OFF_RESTART);
617         else if(!strncmp(type_str, POWER_RECOVERY, POWER_RECOVERY_LEN))
618                 ret = power_reboot(SYSTEMD_STOP_POWER_RESTART_RECOVERY);
619         else if(!strncmp(type_str, PWROFF_POPUP, PWROFF_POPUP_LEN))
620                 ret = pwroff_popup();
621
622 out:
623         reply = dbus_message_new_method_return(msg);
624         dbus_message_iter_init_append(reply, &iter);
625         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
626
627         return reply;
628 }
629
630 void powerdown_ap(void *data)
631 {
632         _I("Power off");
633         powerdown();
634         reboot(RB_POWER_OFF);
635 }
636
637 void restart_ap(void *data)
638 {
639         _I("Restart %d", (int)data);
640         journal_system_device_reboot((int)data);
641         powerdown();
642         restart_by_mode((int)data);
643 }
644
645 static const struct edbus_method edbus_methods[] = {
646         { "setresetkeydisable",   "i",   "i", edbus_resetkeydisable },
647         { "SetWakeupKey", "i", "i", edbus_set_wakeup_key },
648         { POWER_REBOOT, "si", "i", dbus_power_handler },
649         { POWER_RECOVERY, "si", "i", dbus_power_handler },
650         { PWROFF_POPUP, "si", "i", dbus_power_handler },
651         /* Add methods here */
652 };
653
654 static void power_init(void *data)
655 {
656         int bTelReady = 0;
657         int ret;
658
659         /* init dbus interface */
660         ret = register_edbus_method(DEVICED_PATH_POWER, edbus_methods, ARRAY_SIZE(edbus_methods));
661         if (ret < 0)
662                 _E("fail to init edbus method(%d)", ret);
663
664         if (vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, (void *)poweroff_control_cb, NULL) < 0) {
665                 _E("Vconf notify key chaneged failed: KEY(%s)", VCONFKEY_SYSMAN_POWER_OFF_STATUS);
666         }
667
668         register_edbus_signal_handler(DEVICED_OBJECT_PATH, DEVICED_INTERFACE_NAME,
669                         SIGNAL_NAME_POWEROFF_POPUP,
670                     poweroff_popup_edbus_signal_handler);
671         register_edbus_signal_handler(DEVICED_PATH_CORE,
672                     DEVICED_INTERFACE_CORE,
673                     SIGNAL_BOOTING_DONE,
674                     booting_done_edbus_signal_handler);
675         register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, booting_done);
676
677         hall_ic = find_device(HALL_IC_NAME);
678 }
679
680 static const struct device_ops power_device_ops = {
681         .priority = DEVICE_PRIORITY_NORMAL,
682         .name     = POWER_OPS_NAME,
683         .init     = power_init,
684         .execute  = power_execute,
685 };
686
687 DEVICE_OPS_REGISTER(&power_device_ops)