tizen 2.3 release
[framework/system/deviced.git] / src / cool-down / cool-down.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2014 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 <stdio.h>
21 #include <stdbool.h>
22 #include <unistd.h>
23 #include <dirent.h>
24 #include <sys/types.h>
25 #include <device-node.h>
26 #include <sys/un.h>
27 #include <stdarg.h>
28 #include <errno.h>
29 #include <vconf.h>
30 #include <vconf-keys.h>
31 #include <fcntl.h>
32
33 #include "core/log.h"
34 #include "core/common.h"
35 #include "core/devices.h"
36 #include "core/device-notifier.h"
37 #include "core/edbus-handler.h"
38 #include "core/udev.h"
39 #include "hall/hall-handler.h"
40
41 #define COOL_DOWN_DBUS_INTERFACE "org.tizen.trm.siop"
42 #define COOL_DOWN_DBUS_PATH "/Org/Tizen/Trm/Siop"
43 #define COOL_DOWN_DBUS_SIGNAL "ChangedCooldownMode"
44
45 #define COOL_DOWN_POPUP_NAME            "cooldown-syspopup"
46
47 #define SIGNAL_COOL_DOWN_SHUT_DOWN      "ShutDown"
48 #define SIGNAL_COOL_DOWN_NOTIFICATION   "Notification"
49 #define SIGNAL_COOL_DOWN_LIMIT_ACTION   "LimitAction"
50 #define SIGNAL_COOL_DOWN_RELEASE        "Release"
51
52 #define METHOD_COOL_DOWN_STATUS         "GetCoolDownStatus"
53 #define METHOD_COOL_DOWN_CHANGED        "CoolDownChanged"
54
55 #define SIGNAL_STRING_MAX_LEN   30
56
57 #define COOL_DOWN_LIMIT_ACTION_WAIT     60
58 #define COOL_DOWN_SHUTDOWN_POPUP_WAIT   60
59 #define COOL_DOWN_SHUTDOWN_FORCE_WAIT   30
60 #define SYSTEMD_STOP_POWER_OFF          4
61
62 #define VCONFKEY_SYSMAN_COOL_DOWN_MODE "db/private/sysman/cool_down_mode"
63
64 enum cool_down_status_type {
65         COOL_DOWN_RELEASE       = 0,
66         COOL_DOWN_NOTIFICATION  = 1,
67         COOL_DOWN_SHUT_DOWN     = 2,
68 };
69
70 enum cool_down_timer_type {
71         COOL_DOWN_LIMIT_ACTION_TIMER    = 1,
72         COOL_DOWN_POPUP_TIMER           = 2,
73         COOL_DOWN_SHUT_DOWN_TIMER       = 3,
74 };
75
76 enum cool_down_timer_status {
77         COOL_DOWN_TIMER_DELETED_ALREADY = 0,
78         COOL_DOWN_TIMER_DELETED_NOW             = 1,
79 };
80
81 struct popup_data {
82         char *name;
83         char *key;
84 };
85
86 static int cool_down_level = 0;
87 static const char *cool_down_status = NULL;
88 static Ecore_Timer *app_limit_timer = NULL;
89 static Ecore_Timer *shut_down_timer = NULL;
90 static const struct device_ops *hall_ic = NULL;
91
92 static void cool_down_timer_start(int type);
93 static int cool_down_timer_stop(int type);
94
95 static int hall_ic_status(void)
96 {
97         int ret;
98
99         ret = device_get_status(hall_ic);
100         if (ret < 0)
101                 return HALL_IC_OPENED;
102         return ret;
103 }
104
105 static int cool_down_popup(char *type)
106 {
107         struct popup_data *params;
108         static const struct device_ops *apps = NULL;
109         int val;
110
111         val = hall_ic_status();
112         if (val == HALL_IC_CLOSED) {
113                 _I("cover is closed");
114                 return 0;
115         }
116
117         FIND_DEVICE_INT(apps, "apps");
118
119         params = malloc(sizeof(struct popup_data));
120         if (params == NULL) {
121                 _E("Malloc failed");
122                 return -1;
123         }
124         params->name = COOL_DOWN_POPUP_NAME;
125         params->key = type;
126         apps->init((void *)params);
127         free(params);
128         return 0;
129 }
130
131 static Eina_Bool broadcast_cool_down_limit_action(void *data)
132 {
133         char buf[SIGNAL_STRING_MAX_LEN];
134         char *param[1];
135
136         cool_down_timer_stop(COOL_DOWN_LIMIT_ACTION_TIMER);
137
138         cool_down_status = SIGNAL_COOL_DOWN_LIMIT_ACTION;
139         snprintf(buf, SIGNAL_STRING_MAX_LEN, "%s", cool_down_status);
140         param[0] = buf;
141
142         broadcast_edbus_signal(DEVICED_PATH_SYSNOTI, DEVICED_INTERFACE_SYSNOTI,
143                 METHOD_COOL_DOWN_CHANGED, "s", param);
144         _I("%s", SIGNAL_COOL_DOWN_LIMIT_ACTION);
145         return EINA_FALSE;
146 }
147
148 static Eina_Bool cool_down_shutdown_popup(void *data)
149 {
150         cool_down_popup(SIGNAL_COOL_DOWN_SHUT_DOWN);
151         cool_down_timer_start(COOL_DOWN_SHUT_DOWN_TIMER);
152         return EINA_FALSE;
153 }
154
155 static Eina_Bool cool_down_shutdown_force(void *data)
156 {
157         cool_down_timer_stop(COOL_DOWN_SHUT_DOWN_TIMER);
158         vconf_set_int(VCONFKEY_SYSMAN_COOL_DOWN_MODE, COOL_DOWN_SHUT_DOWN);
159         vconf_set_int(VCONFKEY_SYSMAN_POWER_OFF_STATUS, SYSTEMD_STOP_POWER_OFF);
160         return EINA_FALSE;
161 }
162
163 static int cool_down_timer_stop(int type)
164 {
165         if (type == COOL_DOWN_NOTIFICATION) {
166                 if (!app_limit_timer)
167                         return COOL_DOWN_TIMER_DELETED_ALREADY;
168                 ecore_timer_del(app_limit_timer);
169                 app_limit_timer = NULL;
170         } else if (type == COOL_DOWN_POPUP_TIMER ||
171             type == COOL_DOWN_SHUT_DOWN_TIMER) {
172                 if (!shut_down_timer)
173                         return COOL_DOWN_TIMER_DELETED_ALREADY;
174                 ecore_timer_del(shut_down_timer);
175                 shut_down_timer = NULL;
176         }
177         _D("stop %d", type);
178         return COOL_DOWN_TIMER_DELETED_NOW;
179 }
180
181 static void cool_down_timer_start(int type)
182 {
183         cool_down_timer_stop(type);
184         if (type == COOL_DOWN_LIMIT_ACTION_TIMER) {
185                 app_limit_timer = ecore_timer_add(COOL_DOWN_LIMIT_ACTION_WAIT,
186                                 broadcast_cool_down_limit_action, NULL);
187                 if (!app_limit_timer)
188                         _E("fail to add timer");
189         } else if (type == COOL_DOWN_POPUP_TIMER) {
190                 shut_down_timer = ecore_timer_add(COOL_DOWN_SHUTDOWN_POPUP_WAIT,
191                                 cool_down_shutdown_popup, NULL);
192                 if (!shut_down_timer)
193                         _E("fail to add timer");
194         } else if (type == COOL_DOWN_SHUT_DOWN_TIMER) {
195                 shut_down_timer = ecore_timer_add(COOL_DOWN_SHUTDOWN_FORCE_WAIT,
196                                 cool_down_shutdown_force, NULL);
197                 if (!shut_down_timer)
198                         _E("fail to add timer");
199         }
200         _D("start %d", type);
201 }
202
203 static void broadcast_cool_down_status(int status)
204 {
205         int ret;
206         char buf[SIGNAL_STRING_MAX_LEN];
207         char *param[1];
208
209         switch(status)
210         {
211         case COOL_DOWN_RELEASE:
212                 cool_down_status = SIGNAL_COOL_DOWN_RELEASE;
213                 cool_down_timer_stop(COOL_DOWN_SHUT_DOWN_TIMER);
214                 cool_down_timer_stop(COOL_DOWN_POPUP_TIMER);
215                 cool_down_timer_stop(COOL_DOWN_LIMIT_ACTION_TIMER);
216                 break;
217         case COOL_DOWN_NOTIFICATION:
218                 cool_down_status = SIGNAL_COOL_DOWN_NOTIFICATION;
219                 cool_down_timer_stop(COOL_DOWN_SHUT_DOWN_TIMER);
220                 cool_down_timer_stop(COOL_DOWN_POPUP_TIMER);
221                 cool_down_timer_start(COOL_DOWN_LIMIT_ACTION_TIMER);
222                 break;
223         case COOL_DOWN_SHUT_DOWN:
224                 ret = cool_down_timer_stop(COOL_DOWN_LIMIT_ACTION_TIMER);
225                 if (ret == COOL_DOWN_TIMER_DELETED_NOW)
226                         broadcast_cool_down_limit_action(NULL);
227                 cool_down_status = SIGNAL_COOL_DOWN_SHUT_DOWN;
228                 cool_down_timer_start(COOL_DOWN_POPUP_TIMER);
229                 break;
230         default:
231                 _E("abnormal value %d", status);
232                 return;
233         }
234
235         snprintf(buf, SIGNAL_STRING_MAX_LEN, "%s", cool_down_status);
236         param[0] = buf;
237
238         broadcast_edbus_signal(DEVICED_PATH_SYSNOTI, DEVICED_INTERFACE_SYSNOTI,
239                 METHOD_COOL_DOWN_CHANGED, "s", param);
240         device_notify(DEVICE_NOTIFIER_COOL_DOWN, (void *)status);
241         _I("%s", cool_down_status);
242 }
243
244 static int cool_down_booting_done(void *data)
245 {
246         static int done = 0;
247         int mode;
248         int ret;
249
250         if (data == NULL)
251                 goto out;
252
253         done = (int)data;
254         if (cool_down_level) {
255                 if (cool_down_level == COOL_DOWN_SHUT_DOWN) {
256                         broadcast_cool_down_status(COOL_DOWN_NOTIFICATION);
257                         broadcast_cool_down_limit_action(NULL);
258                         cool_down_timer_start(COOL_DOWN_POPUP_TIMER);
259                         goto out;
260                 }
261                 broadcast_cool_down_status(cool_down_level);
262                 goto out;
263         }
264         ret = vconf_get_int(VCONFKEY_SYSMAN_COOL_DOWN_MODE, &mode);
265         vconf_set_int(VCONFKEY_SYSMAN_COOL_DOWN_MODE, cool_down_level);
266         if (ret == 0 && mode == COOL_DOWN_SHUT_DOWN)
267                 cool_down_popup(SIGNAL_COOL_DOWN_RELEASE);
268 out:
269         return done;
270 }
271
272 static int cool_down_execute(void *data)
273 {
274         int booting_done;
275         static int old = COOL_DOWN_RELEASE;
276
277         cool_down_level = *(int *)data;
278         if (old == cool_down_level)
279                 return 0;
280         _I("status %d", cool_down_level);
281
282         booting_done = cool_down_booting_done(NULL);
283         if (!booting_done)
284                 return 0;
285
286         if (old == COOL_DOWN_RELEASE &&
287             cool_down_level == COOL_DOWN_SHUT_DOWN) {
288                 old = cool_down_level;
289                 broadcast_cool_down_status(COOL_DOWN_NOTIFICATION);
290                 broadcast_cool_down_limit_action(NULL);
291                 cool_down_timer_start(COOL_DOWN_POPUP_TIMER);
292                 return 0;
293         }
294         old = cool_down_level;
295         broadcast_cool_down_status(cool_down_level);
296         return 0;
297 }
298
299 static int changed_device(int level)
300 {
301         int *state = NULL;
302         int status = level;
303
304         state = &status;
305         cool_down_execute((void *)state);
306 out:
307         return 0;
308 }
309
310 static void cool_down_edbus_signal_handler(void *data, DBusMessage *msg)
311 {
312         DBusError err;
313         int val = 0;
314
315         if (dbus_message_is_signal(msg, COOL_DOWN_DBUS_INTERFACE, COOL_DOWN_DBUS_SIGNAL) == 0) {
316                 _E("there is no cool down signal");
317                 return;
318         }
319
320         dbus_error_init(&err);
321
322         if (dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &val, DBUS_TYPE_INVALID) == 0) {
323                 _E("there is no message");
324                 return;
325         }
326         changed_device(val);
327 }
328
329 static DBusMessage *dbus_get_status(E_DBus_Object *obj, DBusMessage *msg)
330 {
331         DBusMessageIter iter;
332         DBusMessage *reply;
333         char buf[SIGNAL_STRING_MAX_LEN];
334         char *param = buf;
335
336         snprintf(buf, SIGNAL_STRING_MAX_LEN, "%s", cool_down_status);
337         reply = dbus_message_new_method_return(msg);
338         dbus_message_iter_init_append(reply, &iter);
339         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &param);
340         return reply;
341 }
342
343 static DBusMessage *dbus_device_handler(E_DBus_Object *obj, DBusMessage *msg)
344 {
345         DBusError err;
346         DBusMessageIter iter;
347         DBusMessage *reply;
348         pid_t pid;
349         int ret;
350         int val;
351         int argc;
352         char *type_str;
353         char *argv[2];
354
355         dbus_error_init(&err);
356
357         if (!dbus_message_get_args(msg, &err,
358                     DBUS_TYPE_STRING, &type_str,
359                     DBUS_TYPE_INT32, &argc,
360                     DBUS_TYPE_STRING, &argv[0],
361                     DBUS_TYPE_STRING, &argv[1], DBUS_TYPE_INVALID)) {
362                 _E("there is no message");
363                 ret = -EINVAL;
364                 goto out;
365         }
366
367         if (argc < 0 || !argv[0] || !argv[1]){
368                 _E("message is invalid!");
369                 ret = -EINVAL;
370                 goto out;
371         }
372
373         pid = get_edbus_sender_pid(msg);
374         if (kill(pid, 0) == -1) {
375                 _E("%d process does not exist, dbus ignored!", pid);
376                 ret = -ESRCH;
377                 goto out;
378         }
379
380         val = atoi(argv[1]);
381         changed_device(val);
382
383 out:
384         reply = dbus_message_new_method_return(msg);
385         dbus_message_iter_init_append(reply, &iter);
386         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &ret);
387
388         return reply;
389 }
390
391 static const struct edbus_method edbus_methods[] = {
392         { METHOD_COOL_DOWN_STATUS,      NULL,   "s", dbus_get_status },
393         { METHOD_COOL_DOWN_CHANGED,     "siss", "i", dbus_device_handler },
394 };
395
396 static void cool_down_init(void *data)
397 {
398         int ret;
399
400         ret = register_edbus_method(DEVICED_PATH_SYSNOTI, edbus_methods, ARRAY_SIZE(edbus_methods));
401         if (ret < 0)
402                 _E("fail to init edbus method(%d)", ret);
403         register_edbus_signal_handler(COOL_DOWN_DBUS_PATH, COOL_DOWN_DBUS_INTERFACE,
404                         COOL_DOWN_DBUS_SIGNAL,
405                     cool_down_edbus_signal_handler);
406         register_notifier(DEVICE_NOTIFIER_BOOTING_DONE, cool_down_booting_done);
407         hall_ic = find_device(HALL_IC_NAME);
408 }
409
410 static const struct device_ops cool_down_device_ops = {
411         .priority = DEVICE_PRIORITY_NORMAL,
412         .name     = "cool-down",
413         .init     = cool_down_init,
414         .execute  = cool_down_execute,
415 };
416
417 DEVICE_OPS_REGISTER(&cool_down_device_ops)