Initialize Tizen 2.3
[framework/system/deviced.git] / src / power / systemd-power.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 <fcntl.h>
23 #include <dirent.h>
24 #include <vconf.h>
25 #include <assert.h>
26 #include <limits.h>
27 #include <sys/reboot.h>
28 #include <sys/time.h>
29 #include <mntent.h>
30 #include <sys/mount.h>
31 #include <device-node.h>
32 #include "core/common.h"
33 #include "core/data.h"
34 #include "core/device-handler.h"
35 #include "core/device-notifier.h"
36 #include "core/devices.h"
37 #include "core/edbus-handler.h"
38 #include "core/launch.h"
39 #include "core/log.h"
40 #include "core/predefine.h"
41 #include "core/queue.h"
42 #include "dd-deviced.h"
43 #include "display/poll.h"
44 #include "display/setting.h"
45 #include "hall/hall-handler.h"
46 #include "power-handler.h"
47 #include "proc/proc-handler.h"
48
49 #define SIGNAL_BOOTING_DONE             "BootingDone"
50 #define PREDEF_PWROFF_POPUP             "pwroff-popup"
51 #define POWEROFF_POPUP_NAME             "poweroff-syspopup"
52 #define RECOVERY_POWER_OFF              "reboot recovery"
53
54 #define SYSTEMD_STOP_POWER_OFF          4
55 #define SYSTEMD_STOP_POWER_RESTART      5
56 #define SYSTEMD_STOP_POWER_RESTART_RECOVERY     6
57 #define SYSTEMD_CHECK_POWER_OFF         15
58
59 struct popup_data {
60         char *name;
61         char *key;
62 };
63
64 static const struct device_ops *hall_ic = NULL;
65 static Ecore_Timer *systemd_poweroff_timer = NULL;
66
67 static Eina_Bool systemd_force_shutdown_cb(void *arg)
68 {
69         char params[128];
70         if (systemd_poweroff_timer) {
71                 ecore_timer_del(systemd_poweroff_timer);
72                 systemd_poweroff_timer = NULL;
73         }
74         snprintf(params, sizeof(params), "%s -f", (char*)arg);
75         launch_evenif_exist("/usr/bin/systemctl", params);
76         return EINA_TRUE;
77 }
78
79 static void start_boot_animation(void)
80 {
81         char params[128];
82         snprintf(params, sizeof(params), "--stop --clear");
83         launch_evenif_exist("/usr/bin/boot-animation", params);
84 }
85
86 static int systemd_shutdown(const char *arg)
87 {
88         assert(arg);
89         systemd_poweroff_timer = ecore_timer_add(SYSTEMD_CHECK_POWER_OFF,
90                             systemd_force_shutdown_cb, (void *)arg);
91         start_boot_animation();
92         device_notify(DEVICE_NOTIFIER_POWEROFF_HAPTIC, NULL);
93         return launch_evenif_exist("/usr/bin/systemctl", arg);
94 }
95
96 int do_poweroff(int argc, char **argv)
97 {
98         return vconf_set_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS,
99                              VCONFKEY_SYSMAN_POWER_OFF_DIRECT);
100 }
101
102 static void poweroff_control_cb(keynode_t *in_key, struct main_data *ad)
103 {
104         int val;
105         int ret;
106
107         if (vconf_get_int(in_key->keyname, &val) != 0)
108                 return;
109
110         if (val == SYSTEMD_STOP_POWER_OFF
111             || val == SYSTEMD_STOP_POWER_RESTART
112             || val == SYSTEMD_STOP_POWER_RESTART_RECOVERY) {
113                 vconf_ignore_key_changed(in_key->keyname,
114                                          (void*)poweroff_control_cb);
115                 vconf_set_int(in_key->keyname, val);
116         }
117
118         device_notify(DEVICE_NOTIFIER_PMQOS_POWEROFF, (void*)1);
119
120         switch (val) {
121         case SYSTEMD_STOP_POWER_OFF:
122         case VCONFKEY_SYSMAN_POWER_OFF_DIRECT:
123                 device_notify(DEVICE_NOTIFIER_POWEROFF,
124                               (void *)VCONFKEY_SYSMAN_POWER_OFF_DIRECT);
125                 ret = systemd_shutdown(PREDEF_POWEROFF);
126                 if (ret < 0)
127                         _E("fail to do (%s)", PREDEF_POWEROFF);
128                 break;
129         case SYSTEMD_STOP_POWER_RESTART:
130         case VCONFKEY_SYSMAN_POWER_OFF_RESTART:
131                 device_notify(DEVICE_NOTIFIER_POWEROFF,
132                               (void *)VCONFKEY_SYSMAN_POWER_OFF_RESTART);
133                 ret = systemd_shutdown(PREDEF_REBOOT);
134                 if (ret < 0)
135                         _E("fail to do (%s)", PREDEF_REBOOT);
136                 break;
137         case SYSTEMD_STOP_POWER_RESTART_RECOVERY:
138                 device_notify(DEVICE_NOTIFIER_POWEROFF,
139                               (void *)VCONFKEY_SYSMAN_POWER_OFF_RESTART);
140                 ret = systemd_shutdown(RECOVERY_POWER_OFF);
141                 if (ret < 0)
142                         _E("fail to do (%s)", RECOVERY_POWER_OFF);
143                 break;
144         case VCONFKEY_SYSMAN_POWER_OFF_POPUP:
145                 notify_action(PREDEF_PWROFF_POPUP, 0);
146                 break;
147         }
148
149         if (update_pm_setting)
150                 update_pm_setting(SETTING_POWEROFF, val);
151 }
152
153 static void booting_done_edbus_signal_handler(void *data, DBusMessage *msg)
154 {
155         if (!dbus_message_is_signal(msg,
156                                     DEVICED_INTERFACE_CORE,
157                                     SIGNAL_BOOTING_DONE)) {
158                 _E("there is no bootingdone signal");
159                 return;
160         }
161
162         device_notify(DEVICE_NOTIFIER_BOOTING_DONE, (void *)TRUE);
163 }
164
165 static int hall_ic_status(void)
166 {
167         if (!hall_ic)
168                 return HALL_IC_OPENED;
169         return hall_ic->status();
170 }
171
172 int reset_resetkey_disable(char *name, enum watch_id id)
173 {
174         _D("force reset power resetkey disable to zero");
175         return device_set_property(DEVICE_TYPE_POWER,
176                                    PROP_POWER_RESETKEY_DISABLE,
177                                    0);
178 }
179
180 static DBusMessage *edbus_resetkeydisable(E_DBus_Object *obj, DBusMessage *msg)
181 {
182         DBusMessageIter iter;
183         DBusMessage *reply;
184         int val, ret;
185
186         ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &val,
187                                     DBUS_TYPE_INVALID);
188         if (!ret) {
189                 _E("there is no message");
190                 ret = -EINVAL;
191                 goto error;
192         }
193
194         ret = device_set_property(DEVICE_TYPE_POWER,
195                                   PROP_POWER_RESETKEY_DISABLE,
196                                   val);
197         if (ret < 0)
198                 goto error;
199
200         if (val)
201                 register_edbus_watch(msg,
202                                      WATCH_POWER_RESETKEY_DISABLE,
203                                      reset_resetkey_disable);
204         else
205                 unregister_edbus_watch(msg,
206                                        WATCH_POWER_RESETKEY_DISABLE);
207
208         _D("get power resetkey disable %d, %d", val, ret);
209
210 error:
211         reply = dbus_message_new_method_return(msg);
212         dbus_message_iter_init_append(reply, &iter);
213         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
214         return reply;
215 }
216
217 static int reset_wakeupkey(char *name, enum watch_id id)
218 {
219         _D("force reset wakeupkey to zero");
220         return device_set_property(DEVICE_TYPE_POWER, PROP_POWER_WAKEUP_KEY, 0);
221 }
222
223 static DBusMessage *edbus_set_wakeup_key(E_DBus_Object *obj, DBusMessage *msg)
224 {
225         DBusMessageIter iter;
226         DBusMessage *reply;
227         int val, ret;
228
229         ret = dbus_message_get_args(msg, NULL,
230                                     DBUS_TYPE_INT32, &val,
231                                     DBUS_TYPE_INVALID);
232         if (!ret) {
233                 _E("there is no message");
234                 ret = -EINVAL;
235                 goto error;
236         }
237
238         ret = device_set_property(DEVICE_TYPE_POWER, PROP_POWER_WAKEUP_KEY, val);
239         if (ret < 0)
240                 goto error;
241
242         if (val)
243                 register_edbus_watch(msg, WATCH_POWER_WAKEUPKEY, reset_wakeupkey);
244         else
245                 unregister_edbus_watch(msg, WATCH_POWER_WAKEUPKEY);
246
247         _D("set power wakeup key %d %d", val, ret);
248
249 error:
250         reply = dbus_message_new_method_return(msg);
251         dbus_message_iter_init_append(reply, &iter);
252         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
253         return reply;
254 }
255
256 static const struct edbus_method edbus_methods[] = {
257         { "setresetkeydisable", "i",    "i",    edbus_resetkeydisable   },
258         { "SetWakeupKey",       "i",    "i",    edbus_set_wakeup_key    },
259         /* Add methods here */
260 };
261
262 int launching_predefine_action(int argc, char **argv)
263 {
264         struct popup_data *params;
265         static const struct device_ops *apps = NULL;
266         int val;
267
268         val = hall_ic_status();
269         if (val == HALL_IC_CLOSED) {
270                 _I("cover is closed");
271                 return 0;
272         }
273         if (apps == NULL) {
274                 apps = find_device("apps");
275                 if (apps == NULL)
276                         return 0;
277         }
278         params = malloc(sizeof(struct popup_data));
279         if (params == NULL) {
280                 _E("Malloc failed");
281                 return -1;
282         }
283         params->name = POWEROFF_POPUP_NAME;
284         apps->init((void *)params);
285         free(params);
286         return 0;
287 }
288
289 static void power_init(void *data)
290 {
291         int bTelReady = 0;
292         int ret;
293
294         /* init dbus interface */
295         ret = register_edbus_method(DEVICED_PATH_POWER,
296                                     edbus_methods,
297                                     ARRAY_SIZE(edbus_methods));
298         if (ret < 0)
299                 _E("fail to init edbus method(%d)", ret);
300
301         ret = register_edbus_signal_handler(DEVICED_PATH_CORE,
302                                             DEVICED_INTERFACE_CORE,
303                                             SIGNAL_BOOTING_DONE,
304                                             booting_done_edbus_signal_handler);
305         if (ret < 0)
306                 _E("fail to register handler for signal: %s",
307                    SIGNAL_BOOTING_DONE);
308
309         register_action(PREDEF_POWEROFF,
310                         do_poweroff, NULL, NULL);
311         register_action(PREDEF_PWROFF_POPUP,
312                         launching_predefine_action, NULL, NULL);
313
314         ret = vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS,
315                                        (void *)poweroff_control_cb,
316                                        NULL);
317         if (ret < 0)
318                 _E("Vconf notify key chaneged failed: KEY(%s)",
319                    VCONFKEY_SYSMAN_POWER_OFF_STATUS);
320         hall_ic = find_device(HALL_IC_NAME);
321 }
322
323 static const struct device_ops power_device_ops = {
324         .priority = DEVICE_PRIORITY_NORMAL,
325         .name     = "systemd-power",
326         .init     = power_init,
327 };
328
329 DEVICE_OPS_REGISTER(&power_device_ops)