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