Remove initscripts and add PIDFile to service file
[platform/core/system/power-manager.git] / pm_core.c
1 /*
2  * power-manager
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16 */
17
18
19 /**
20  * @file        pm_core.c
21  * @version     0.2
22  * @brief       Power manager main loop.
23  *
24  * This file includes Main loop, the FSM, signal processing.
25  */
26 #include <signal.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <limits.h>
31 #include <glib.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <stdbool.h>
35 #include <time.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <heynoti.h>
40 #include <sysman.h>
41 #include <aul.h>
42 #include <vconf-keys.h>
43 #include <device-node.h>
44
45 #include "pm_core.h"
46 #include "pm_battery.h"
47
48 #define USB_CON_PIDFILE                 "/var/run/.system_server.pid"
49 #define PM_STATE_LOG_FILE               "/var/log/pm_state.log"
50 #define PM_WAKEUP_NOTI_NAME             "system_wakeup"
51 #define PM_EVENT_NOTI_NAME      "pm_event"
52 #define PM_EVENT_NOTI_PATH      "/opt/share/noti/"PM_EVENT_NOTI_NAME
53
54 /**
55  * @addtogroup POWER_MANAGER
56  * @{
57  */
58
59 #define LOCKSTATUS_TIMEOUT              3
60 #define TELEPHONY_SIGNAL_TIMEOUT        10
61
62 #define SET_BRIGHTNESS_IN_BOOTLOADER "/usr/bin/save_blenv SLP_LCD_BRIGHT"
63
64 /* default transition, action fuctions */
65 static int default_trans(int evt);
66 static int default_action(int timeout);
67 static int default_check(int next);
68
69 unsigned int status_flag;
70
71 static void (*power_saving_func) (int onoff);
72 static void reset_timeout(int timeout);
73
74 int cur_state;
75 int old_state;
76 static GMainLoop *mainloop;
77 guint timeout_src_id;
78 static time_t last_t;
79 static int pre_suspend_flag = false;
80 int system_wakeup_flag = false;
81
82 struct state states[S_END] = {
83         {S_START, default_trans, default_action, default_check,},
84         {S_NORMAL, default_trans, default_action, default_check,},
85         {S_LCDDIM, default_trans, default_action, default_check,},
86         {S_LCDOFF, default_trans, default_action, default_check,},
87         {S_SLEEP, default_trans, default_action, default_check,}
88 };
89
90 int (*pm_init_extention) (void *data);
91 void (*pm_exit_extention) (void);
92
93 static char state_string[5][10] =
94     { "S_START", "S_NORMAL", "S_LCDDIM", "S_LCDOFF", "S_SLEEP" };
95
96 static int trans_table[S_END][EVENT_END] = {
97         /* Timeout , Input */
98         {S_START, S_START},     /* S_START */
99         {S_LCDDIM, S_NORMAL},   /* S_NORMAL */
100         {S_LCDOFF, S_NORMAL},   /* S_LCDDIM */
101         {S_SLEEP, S_NORMAL},    /* S_LCDOFF */
102         {S_LCDOFF, S_NORMAL},   /* S_SLEEP, When wake up by devices, go lcd_off state  */
103 };
104
105 #define SHIFT_UNLOCK            4
106 #define MASK_RESET_TIMEOUT      0x8     /* 1000 */
107 #define MASK_MARGIN_TIMEOUT     (0x1 << 8)
108 #define SHIFT_CHANGE_STATE      7
109 #define CHANGE_STATE_BIT        0xF00   /* 1111 0000 0000 */
110 #define LOCK_SCREEN_TIMEOUT     5
111 #define SHIFT_HOLD_KEY_BLOCK    16
112
113 #define DEFAULT_NORMAL_TIMEOUT  30
114 #define DEFAULT_DIM_TIMEOUT             5
115 #define DEFAULT_OFF_TIMEOUT             5
116 #define GET_HOLDKEY_BLOCK_STATE(x) ((x >> SHIFT_HOLD_KEY_BLOCK) & 0x1)
117
118 static int received_sleep_cmd = 0;
119
120 typedef struct _node {
121         pid_t pid;
122         int timeout_id;
123         gboolean holdkey_block;
124         struct _node *next;
125 } Node;
126
127 static Node *cond_head[S_END];
128
129 static int refresh_app_cond()
130 {
131         trans_condition = 0;
132
133         if (cond_head[S_LCDDIM] != NULL)
134                 trans_condition = trans_condition | MASK_DIM;
135         if (cond_head[S_LCDOFF] != NULL)
136                 trans_condition = trans_condition | MASK_OFF;
137         if (cond_head[S_SLEEP] != NULL)
138                 trans_condition = trans_condition | MASK_SLP;
139
140         return 0;
141 }
142
143 static Node *find_node(enum state_t s_index, pid_t pid)
144 {
145         Node *t = cond_head[s_index];
146
147         while (t != NULL) {
148                 if (t->pid == pid)
149                         break;
150                 t = t->next;
151         }
152         return t;
153 }
154
155 static Node *add_node(enum state_t s_index, pid_t pid, int timeout_id,
156                 gboolean holdkey_block)
157 {
158         Node *n;
159
160         n = (Node *) malloc(sizeof(Node));
161         if (n == NULL) {
162                 LOGERR("Not enough memory, add cond. fail");
163                 return NULL;
164         }
165
166         n->pid = pid;
167         n->timeout_id = timeout_id;
168         n->holdkey_block = holdkey_block;
169         n->next = cond_head[s_index];
170         cond_head[s_index] = n;
171
172         refresh_app_cond();
173         return n;
174 }
175
176 static int del_node(enum state_t s_index, Node *n)
177 {
178         Node *t;
179         Node *prev;
180
181         if (n == NULL)
182                 return 0;
183
184         t = cond_head[s_index];
185         prev = NULL;
186         while (t != NULL) {
187                 if (t == n) {
188                         if (prev != NULL)
189                                 prev->next = t->next;
190                         else
191                                 cond_head[s_index] = cond_head[s_index]->next;
192                         free(t);
193                         break;
194                 }
195                 prev = t;
196                 t = t->next;
197         }
198         refresh_app_cond();
199         return 0;
200 }
201
202 static gboolean del_dim_cond(gpointer data)
203 {
204         Node *tmp = NULL;
205         LOGINFO("delete prohibit dim condition by timeout\n");
206
207         tmp = find_node(S_LCDDIM, (pid_t) data);
208         del_node(S_LCDDIM, tmp);
209
210         if (timeout_src_id == 0)
211                 states[cur_state].trans(EVENT_TIMEOUT);
212
213         return FALSE;
214 }
215
216 static gboolean del_off_cond(gpointer data)
217 {
218         Node *tmp = NULL;
219         LOGINFO("delete prohibit off condition by timeout\n");
220
221         tmp = find_node(S_LCDOFF, (pid_t) data);
222         del_node(S_LCDOFF, tmp);
223
224         if (timeout_src_id == 0)
225                 states[cur_state].trans(EVENT_TIMEOUT);
226
227         return FALSE;
228 }
229
230 static gboolean del_sleep_cond(gpointer data)
231 {
232         Node *tmp = NULL;
233         LOGINFO("delete prohibit sleep condition by timeout\n");
234
235         tmp = find_node(S_SLEEP, (pid_t) data);
236         del_node(S_SLEEP, tmp);
237
238         if (timeout_src_id == 0)
239                 states[cur_state].trans(EVENT_TIMEOUT);
240
241         sysman_inform_inactive((pid_t) data);
242         return FALSE;
243 }
244
245 /* update transition condition for application requrements */
246 static int proc_condition(PMMsg *data)
247 {
248         Node *tmp = NULL;
249         unsigned int val = data->cond;
250         pid_t pid = data->pid;
251         int cond_timeout_id = -1;
252         gboolean holdkey_block = 0;
253
254         if (val == 0)
255                 return 0;
256         /* for debug */
257         char pname[PATH_MAX];
258         char buf[PATH_MAX];
259         int fd_cmdline;
260         snprintf(buf, PATH_MAX, "/proc/%d/cmdline", pid);
261         fd_cmdline = open(buf, O_RDONLY);
262         if (fd_cmdline < 0) {
263                 snprintf(pname, PATH_MAX,
264                                 "does not exist now(may be dead without unlock)");
265         } else {
266                 read(fd_cmdline, pname, PATH_MAX);
267                 close(fd_cmdline);
268         }
269
270         if (val & MASK_DIM) {
271                 if (data->timeout > 0) {
272                         cond_timeout_id =
273                                 g_timeout_add_full(G_PRIORITY_DEFAULT,
274                                                 data->timeout,
275                                                 (GSourceFunc) del_dim_cond,
276                                                 (gpointer) pid, NULL);
277                 }
278                 holdkey_block = GET_HOLDKEY_BLOCK_STATE(val);
279                 tmp = find_node(S_LCDDIM, pid);
280                 if (tmp == NULL)
281                         add_node(S_LCDDIM, pid, cond_timeout_id, holdkey_block);
282                 else if (tmp->timeout_id > 0) {
283                         g_source_remove(tmp->timeout_id);
284                         tmp->timeout_id = cond_timeout_id;
285                         tmp->holdkey_block = holdkey_block;
286                 }
287                 /* for debug */
288                 LOGINFO("[%s] locked by pid %d - process %s\n", "S_NORMAL", pid,
289                                 pname);
290         }
291         if (val & MASK_OFF) {
292                 if (data->timeout > 0) {
293                         cond_timeout_id =
294                                 g_timeout_add_full(G_PRIORITY_DEFAULT,
295                                                 data->timeout,
296                                                 (GSourceFunc) del_off_cond,
297                                                 (gpointer) pid, NULL);
298                 }
299                 holdkey_block = GET_HOLDKEY_BLOCK_STATE(val);
300                 tmp = find_node(S_LCDOFF, pid);
301                 if (tmp == NULL)
302                         add_node(S_LCDOFF, pid, cond_timeout_id, holdkey_block);
303                 else if (tmp->timeout_id > 0) {
304                         g_source_remove(tmp->timeout_id);
305                         tmp->timeout_id = cond_timeout_id;
306                         tmp->holdkey_block = holdkey_block;
307                 }
308                 /* for debug */
309                 LOGINFO("[%s] locked by pid %d - process %s\n", "S_LCDDIM", pid,
310                                 pname);
311         }
312         if (val & MASK_SLP) {
313                 if (data->timeout > 0) {
314                         cond_timeout_id =
315                                 g_timeout_add_full(G_PRIORITY_DEFAULT,
316                                                 data->timeout,
317                                                 (GSourceFunc) del_sleep_cond,
318                                                 (gpointer) pid, NULL);
319                 }
320                 tmp = find_node(S_SLEEP, pid);
321                 if (tmp == NULL)
322                         add_node(S_SLEEP, pid, cond_timeout_id, 0);
323                 else if (tmp->timeout_id > 0) {
324                         g_source_remove(tmp->timeout_id);
325                         tmp->timeout_id = cond_timeout_id;
326                         tmp->holdkey_block = 0;
327                 }
328                 sysman_inform_active(pid);
329                 /* for debug */
330                 LOGINFO("[%s] locked by pid %d - process %s\n", "S_LCDOFF", pid,
331                                 pname);
332         }
333
334         /* UNLOCK(GRANT) condition processing */
335         val = val >> SHIFT_UNLOCK;
336         if (val & MASK_DIM) {
337                 tmp = find_node(S_LCDDIM, pid);
338                 del_node(S_LCDDIM, tmp);
339                 LOGINFO("[%s] unlocked by pid %d - process %s\n", "S_LORMAL",
340                                 pid, pname);
341         }
342         if (val & MASK_OFF) {
343                 tmp = find_node(S_LCDOFF, pid);
344                 del_node(S_LCDOFF, tmp);
345                 LOGINFO("[%s] unlocked by pid %d - process %s\n", "S_LCDDIM",
346                                 pid, pname);
347         }
348         if (val & MASK_SLP) {
349                 tmp = find_node(S_SLEEP, pid);
350                 del_node(S_SLEEP, tmp);
351                 sysman_inform_inactive(pid);
352                 LOGINFO("[%s] unlocked by pid %d - process %s\n", "S_LCDOFF",
353                                 pid, pname);
354         }
355         val = val >> 8;
356         if (val != 0) {
357                 if ((val & 0x1)) {
358                         reset_timeout(states[cur_state].timeout);
359                         LOGINFO("reset timeout\n", "S_LCDOFF", pid, pname);
360                 }
361         } else {
362                 /* guard time for suspend */
363                 if (cur_state == S_LCDOFF) {
364                         reset_timeout(5);
365                         LOGINFO("margin timeout (5 seconds)\n");
366                 }
367         }
368
369         if (timeout_src_id == 0)
370                 states[cur_state].trans(EVENT_TIMEOUT);
371
372         return 0;
373 }
374
375 static int proc_change_state(unsigned int cond)
376 {
377         int next_state = 0;
378         struct state *st;
379         int i;
380
381         for (i = S_NORMAL; i < S_END; i++) {
382                 if ((cond >> (SHIFT_CHANGE_STATE + i)) & 0x1) {
383                         next_state = i;
384                         break;
385                 }
386         }
387         LOGINFO("Change State to %s", state_string[next_state]);
388
389         switch (next_state) {
390                 case S_NORMAL:
391                 case S_LCDDIM:
392                 case S_LCDOFF:
393                         /* state transition */
394                         old_state = cur_state;
395                         cur_state = next_state;
396                         st = &states[cur_state];
397
398                         /* enter action */
399                         if (st->action) {
400                                 st->action(st->timeout);
401                         }
402                         break;
403                 case S_SLEEP:
404                         LOGINFO("Dangerous requests.");
405                         /* at first LCD_OFF and then goto sleep */
406                         /* state transition */
407                         old_state = cur_state;
408                         cur_state = S_LCDOFF;
409                         st = &states[cur_state];
410                         if (st->action) {
411                                 st->action(0);
412                         }
413                         old_state = cur_state;
414                         cur_state = S_SLEEP;
415                         st = &states[cur_state];
416                         if (st->action) {
417                                 st->action(0);
418                         }
419                         break;
420
421                 default:
422                         return -1;
423         }
424
425         return 0;
426 }
427
428 /* If some changed, return 1 */
429 int check_processes(enum state_t prohibit_state)
430 {
431         Node *t = cond_head[prohibit_state];
432         Node *tmp = NULL;
433         int ret = 0;
434
435         while (t != NULL) {
436                 if (kill(t->pid, 0) == -1) {
437                         LOGERR
438                                 ("%d process does not exist, delete the REQ - prohibit state %d ",
439                                  t->pid, prohibit_state);
440                         tmp = t;
441                         ret = 1;
442                 }
443                 t = t->next;
444
445                 if (tmp != NULL) {
446                         del_node(prohibit_state, tmp);
447                         tmp = NULL;
448                 }
449         }
450
451         return ret;
452 }
453
454 int check_holdkey_block(enum state_t state)
455 {
456         Node *t = cond_head[state];
457         int ret = 0;
458
459         LOGINFO("check holdkey block : state of %s", state_string[state]);
460
461         while(t != NULL) {
462                 if(t->holdkey_block == true) {
463                         ret = 1;
464                         LOGINFO("Hold key blocked by pid(%d)!", t->pid);
465                         break;
466                 }
467                 t = t->next;
468         }
469
470         return ret;
471 }
472
473 int delete_condition(enum state_t state)
474 {
475         Node *t = cond_head[state];
476         int ret = 0;
477         Node *tmp = NULL;
478
479         LOGINFO("delete condition : state of %s", state_string[state]);
480
481         while(t != NULL) {
482                 if(t->timeout_id > 0) {
483                         g_source_remove(t->timeout_id);
484                 }
485                 tmp = t;
486                 t = t->next;
487                 LOGINFO("delete node of pid(%d)", tmp->pid);
488                 del_node(state, tmp);
489         }
490
491         return 0;
492 }
493
494 /* SIGINT, SIGTERM, SIGQUIT signal handler */
495 static void sig_quit(int signo)
496 {
497         LOGINFO("received %d signal : stops a main loop", signo);
498         if (mainloop)
499                 g_main_loop_quit(mainloop);
500 }
501
502 void print_info(int fd)
503 {
504         int s_index = 0;
505         char buf[255];
506         int i = 1, ret;
507
508         if (fd < 0)
509                 return;
510
511         snprintf(buf, sizeof(buf), 
512                         "\n======================================================================\n");
513         write(fd, buf, strlen(buf));
514         snprintf(buf, sizeof(buf),"Timeout Info: Run[%d] Dim[%d] Off[%d]\n",
515                         states[S_NORMAL].timeout,
516                         states[S_LCDDIM].timeout, states[S_LCDOFF].timeout);
517         write(fd, buf, strlen(buf));
518
519         snprintf(buf, sizeof(buf), "Tran. Locked : %s %s %s\n",
520                         (trans_condition & MASK_DIM) ? state_string[S_NORMAL] : "-",
521                         (trans_condition & MASK_OFF) ? state_string[S_LCDDIM] : "-",
522                         (trans_condition & MASK_SLP) ? state_string[S_LCDOFF] : "-");
523         write(fd, buf, strlen(buf));
524
525         snprintf(buf, sizeof(buf), "Current State: %s\n", state_string[cur_state]);
526         write(fd, buf, strlen(buf));
527
528         snprintf(buf, sizeof(buf), "Current Lock Conditions: \n");
529         write(fd, buf, strlen(buf));
530
531         for (s_index = S_NORMAL; s_index < S_END; s_index++) {
532                 Node *t;
533                 char pname[PATH_MAX];
534                 int fd_cmdline;
535                 t = cond_head[s_index];
536
537                 while (t != NULL) {
538                         snprintf(buf, sizeof(buf), "/proc/%d/cmdline", t->pid);
539                         fd_cmdline = open(buf, O_RDONLY);
540                         if (fd_cmdline < 0) {
541                                 snprintf(pname, PATH_MAX,
542                                                 "does not exist now(may be dead without unlock)");
543                         } else {
544                                 read(fd_cmdline, pname, PATH_MAX);
545                                 close(fd_cmdline);
546                         }
547                         snprintf(buf, sizeof(buf),
548                                         " %d: [%s] locked by pid %d - process %s\n",
549                                         i++, state_string[s_index - 1], t->pid, pname);
550                         write(fd, buf, strlen(buf));
551                         t = t->next;
552                 }
553         }
554 }
555
556 /* SIGHUP signal handler 
557  * For debug... print info to syslog
558  */
559 static void sig_hup(int signo)
560 {
561         int fd;
562         char buf[255];
563         time_t now_time;
564
565         time(&now_time);
566
567         fd = open(PM_STATE_LOG_FILE, O_CREAT | O_WRONLY, 0644);
568         if (fd != -1) {
569                 snprintf(buf, sizeof(buf), "\npm_state_log now-time : %d (s)\n\n",
570                                 (int)now_time);
571                 write(fd, buf, strlen(buf));
572
573                 snprintf(buf, sizeof(buf), "status_flag: %x\n", status_flag);
574                 write(fd, buf, strlen(buf));
575
576                 snprintf(buf, sizeof(buf), "received sleep cmd count : %d\n",
577                                 received_sleep_cmd);
578                 write(fd, buf, strlen(buf));
579
580                 print_info(fd);
581                 close(fd);
582         }
583
584         fd = open("/dev/console", O_WRONLY);
585         if (fd != -1) {
586                 print_info(fd);
587                 close(fd);
588         }
589 }
590
591 /* timeout handler  */
592 gboolean timeout_handler(gpointer data)
593 {
594         LOGINFO("Time out state %s\n", state_string[cur_state]);
595
596         if (timeout_src_id != 0) {
597                 g_source_remove(timeout_src_id);
598                 timeout_src_id = 0;
599         }
600
601         if ((status_flag & VCALL_FLAG)
602                         && (cur_state == S_LCDOFF || cur_state == S_SLEEP)) {
603                 status_flag &= ~(VCALL_FLAG);
604                 reset_timeout(TELEPHONY_SIGNAL_TIMEOUT);
605                 return FALSE;
606         }
607         states[cur_state].trans(EVENT_TIMEOUT);
608         return FALSE;
609 }
610
611 static void reset_timeout(int timeout)
612 {
613         if (timeout_src_id != 0) {
614                 g_source_remove(timeout_src_id);
615                 timeout_src_id = 0;
616         }
617         if (timeout > 0) {
618                 timeout_src_id = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
619                                 timeout,
620                                 (GSourceFunc)
621                                 timeout_handler,
622                                 NULL, NULL);
623         }
624 }
625
626 static void sig_usr(int signo)
627 {
628         status_flag |= VCALL_FLAG;
629 }
630
631 static void sig_break_block(int signo)
632 {
633         LOGINFO("We got signal to break that pending checking in kernel\n");
634 }
635
636 /* 
637  * default transition function
638  *   1. call check 
639  *   2. transition 
640  *   3. call enter action function
641  */
642 static int default_trans(int evt)
643 {
644         struct state *st = &states[cur_state];
645         int next_state;
646
647         if(cur_state == S_NORMAL && st->timeout == 0) {
648                 LOGINFO("LCD always on enabled!");
649                 return 0;
650         }
651
652         next_state = (enum state_t)trans_table[cur_state][evt];
653
654         /* check conditions */
655         while (st->check && !st->check(next_state)) {
656                 /* There is a condition. */
657                 LOGINFO("%s -> %s : check fail", state_string[cur_state],
658                        state_string[next_state]);
659                 if (!check_processes(next_state)) {
660                         /* this is valid condition - the application that sent the condition is running now. */
661                         return -1;
662                 }
663         }
664
665         /* state transition */
666         old_state = cur_state;
667         cur_state = next_state;
668         st = &states[cur_state];
669
670         /* enter action */
671         if (st->action) {
672                 st->action(st->timeout);
673         }
674
675         return 0;
676 }
677
678 /* default enter action function */
679 static int default_action(int timeout)
680 {
681         int ret;
682         int wakeup_count = -1;
683         char buf[NAME_MAX];
684         char *pkgname = NULL;
685         int i = 0;
686         int lock_state = -1;
687         struct itimerval val;
688
689         if (cur_state != old_state && cur_state != S_SLEEP)
690                 set_setting_pmstate(cur_state);
691
692         switch (cur_state) {
693                 case S_NORMAL:
694                         /* normal state : backlight on and restore the previous brightness */
695                         if (old_state == S_LCDOFF || old_state == S_SLEEP) {
696                                 if (pre_suspend_flag == true) {
697                                         system_post_resume();
698                                         pre_suspend_flag = false;
699                                 }
700                                 for (i = 0; i < 14; i++) {
701                                 vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock_state);
702                                 LOGERR("Idle lock check : %d, vonf : %d", i, lock_state);
703                                         if (lock_state)
704                                                 break;
705                                         usleep(50000);
706                                 }
707 #ifndef X86 /* Different with ARM FB driver, IA gfx driver is sensitive to the order. */
708                                 backlight_restore();
709                                 backlight_on();
710 #else
711                                 backlight_on();
712                                 backlight_restore();
713 #endif
714                         } else if (old_state == S_LCDDIM)
715                                 backlight_restore();
716                         break;
717
718                 case S_LCDDIM:
719                         if (old_state == S_LCDOFF || old_state == S_SLEEP) {
720                                 backlight_on();
721                         }
722                         /* lcd dim state : dim the brightness */
723                         backlight_dim();
724                         break;
725
726                 case S_LCDOFF:
727                         if (old_state != S_SLEEP && old_state != S_LCDOFF) {
728                                 /* lcd off state : turn off the backlight */
729                                 backlight_off();
730                                 if (pre_suspend_flag == false) {
731                                         pre_suspend_flag = true;
732                                         system_pre_suspend();
733                                 }
734                         }
735                         break;
736
737                 case S_SLEEP:
738                         /*
739                          * We can not always be blocked here because of that
740                          * in-progress checking in kernel for wakeup count,
741                          * if we cannot get the result within some time, then
742                          * just give it up and then retry it in the next time,
743                          * this method would not break that original expected
744                          * 'aggresive suspend' idea, but at the same time make
745                          * the system is 'always' responsible to some keypress
746                          * actions like power button press.
747                          */
748                         val.it_value.tv_sec = TOLERANCE_SLOT;
749                         val.it_value.tv_usec = 0;
750                         val.it_interval.tv_sec = val.it_interval.tv_usec = 0;
751                         setitimer(ITIMER_REAL, &val, NULL);
752
753                         /* sleep state : set system mode to SUSPEND */
754                         if (0 > device_get_property(DEVICE_TYPE_POWER, PROP_POWER_WAKEUP_COUNT, &wakeup_count))
755                                 LOGERR("wakeup count read error");
756
757                         if (wakeup_count < 0) {
758                                 LOGINFO("Wakup Event! Can not enter suspend mode.");
759                                 goto go_lcd_off;
760                         }
761
762                         if (0 > device_set_property(DEVICE_TYPE_POWER, PROP_POWER_WAKEUP_COUNT, wakeup_count)) {
763                                 LOGERR("wakeup count write error");
764                                 goto go_lcd_off;
765                         }
766
767                         goto go_suspend;
768         }
769
770         /* set timer with current state timeout */
771         reset_timeout(timeout);
772         LOGINFO("timout set: %s state %d sec", state_string[cur_state], timeout);
773
774         return 0;
775
776 go_suspend:
777         system_suspend();
778         LOGINFO("system wakeup!!");
779         system_wakeup_flag = true;
780         heynoti_publish(PM_WAKEUP_NOTI_NAME);
781         /* Resume !! */
782         if (check_wakeup_src() == EVENT_DEVICE)
783                 /* system waked up by devices */
784                 states[cur_state].trans(EVENT_DEVICE);
785         else
786                 /* system waked up by user input */
787                 states[cur_state].trans(EVENT_INPUT);
788         return 0;
789
790 go_lcd_off:
791         heynoti_publish(PM_WAKEUP_NOTI_NAME);
792         /* Resume !! */
793         states[cur_state].trans(EVENT_DEVICE);
794         return 0;
795 }
796
797 /* 
798  * default check function
799  *   return 
800  *    0 : can't transit, others : transitable
801  */
802 static int default_check(int next)
803 {
804         int trans_cond = trans_condition & MASK_BIT;
805         int lock_state = -1;
806
807         LOGINFO("trans_cond : %x", trans_cond);
808
809         vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock_state);
810         if(lock_state==VCONFKEY_IDLE_LOCK && next != S_SLEEP) {
811                 LOGINFO("default_check : LOCK STATE, it's transitable");
812                 return 1;
813         }
814
815         switch (next) {
816                 case S_LCDDIM:
817                         trans_cond = trans_cond & MASK_DIM;
818                         break;
819                 case S_LCDOFF:
820                         trans_cond = trans_cond & MASK_OFF;
821                         break;
822                 case S_SLEEP:
823                         trans_cond = trans_cond & MASK_SLP;
824                         break;
825                 default:                /* S_NORMAL is exceptional */
826                         trans_cond = 0;
827                         break;
828         }
829
830         if (trans_cond != 0)
831                 return 0;
832
833         return 1;               /* transitable */
834 }
835
836 /* get configurations from setting */
837 static int get_settings()
838 {
839         int i;
840         int val = 0;
841         int ret = -1;
842         char buf[255];
843
844         for (i = 0; i < S_END; i++) {
845                 switch (states[i].state) {
846                         case S_NORMAL:
847                                 ret = get_run_timeout(&val);
848                                 if (ret != 0) {
849                                         ret = get_env("PM_TO_NORMAL", buf, 255);
850                                         val = atoi(buf);
851                                 }
852                                 break;
853                         case S_LCDDIM:
854                                 ret = get_dim_timeout(&val);
855                                 break;
856                         case S_LCDOFF:
857                                 ret = get_off_timeout(&val);
858                                 break;
859                         default:
860                                 /* This state doesn't need to set time out. */
861                                 ret = -1;
862                                 break;
863                 }
864                 if (ret == 0 || val < 0) {
865                         states[i].timeout = val;
866                 } else {
867                         switch (states[i].state) {
868                                 case S_NORMAL:
869                                         states[i].timeout = DEFAULT_NORMAL_TIMEOUT;
870                                         break;
871                                 case S_LCDDIM:
872                                         states[i].timeout = DEFAULT_DIM_TIMEOUT;
873                                         break;
874                                 case S_LCDOFF:
875                                         states[i].timeout = DEFAULT_OFF_TIMEOUT;
876                                         break;
877                                 default:
878                                         states[i].timeout = 0;
879                                         break;
880                         }
881                 }
882                 LOGINFO("%s state : %d timeout", state_string[i], states[i].timeout);
883         }
884
885         return 0;
886 }
887
888 static void default_saving_mode(int onoff)
889 {
890         if (onoff) {
891                 status_flag |= PWRSV_FLAG;
892         } else {
893                 status_flag &= ~PWRSV_FLAG;
894         }
895         if (cur_state == S_NORMAL)
896                 backlight_restore();
897 }
898
899 static int poll_callback(int condition, PMMsg *data)
900 {
901         time_t now;
902
903         if (condition == INPUT_POLL_EVENT) {
904                 if (cur_state == S_LCDOFF || cur_state == S_SLEEP)
905                         LOGINFO("Power key input");
906                 time(&now);
907                 if (last_t != now) {
908                         states[cur_state].trans(EVENT_INPUT);
909                         last_t = now;
910                 }
911         } else if (condition == PM_CONTROL_EVENT) {
912                 LOGINFO("process pid(%d) pm_control condition : %x ", data->pid,
913                                 data->cond);
914
915                 if (data->cond & MASK_BIT
916                                 || (data->cond >> SHIFT_UNLOCK) & MASK_BIT)
917                         proc_condition(data);
918
919                 if (data->cond & CHANGE_STATE_BIT) {
920
921                         LOGINFO("Change state by pid(%d) request.", data->pid);
922                         proc_change_state(data->cond);
923                 }
924         }
925
926         return 0;
927 }
928
929 static int update_setting(int key_idx, int val)
930 {
931         char buf[PATH_MAX];
932         int ret = -1;
933         int dim_timeout = -1;
934         int run_timeout = -1;
935         int power_saving_stat = -1;
936         int power_saving_display_stat = -1;
937
938         switch (key_idx) {
939         case SETTING_TO_NORMAL:
940                 ret = get_dim_timeout(&dim_timeout);
941                 if(ret < 0 || dim_timeout < 0) {
942                         LOGERR("Can not get dim timeout. set default 5 seconds");
943                         dim_timeout = 5;
944                 }
945                 if(val < 0) {
946                         LOGERR("LCD timeout is wrong, set default 15 seconds");
947                         val = 15;
948                 }
949                 if(val == 0) {
950                         states[S_NORMAL].timeout = 0;
951                 } else if(val > dim_timeout) {
952                         states[S_NORMAL].timeout = val - dim_timeout;
953                 } else {
954                         states[S_NORMAL].timeout = 1;
955                 }
956                 states[cur_state].trans(EVENT_INPUT);
957                 break;
958         case SETTING_LOW_BATT:
959                 if (val < VCONFKEY_SYSMAN_BAT_WARNING_LOW) {
960                         if (!(status_flag & CHRGR_FLAG))
961                                 power_saving_func(true);
962                         status_flag |= LOWBT_FLAG;
963                 } else {
964                         if (status_flag & PWRSV_FLAG)
965                                 power_saving_func(false);
966                         status_flag &= ~LOWBT_FLAG;
967                         status_flag &= ~BRTCH_FLAG;
968                         vconf_set_bool(VCONFKEY_PM_BRIGHTNESS_CHANGED_IN_LPM,
969                             false);
970                 }
971                 break;
972         case SETTING_CHARGING:
973                 if (val) {
974                         if (status_flag & LOWBT_FLAG) {
975                                 power_saving_func(false);
976                                 status_flag &= ~LOWBT_FLAG;
977                         }
978                         status_flag |= CHRGR_FLAG;
979                 } else {
980                         int bat_state = VCONFKEY_SYSMAN_BAT_NORMAL;
981                         vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &bat_state);
982                         if(bat_state < VCONFKEY_SYSMAN_BAT_NORMAL) {
983                                 power_saving_func(true);
984                                 status_flag |= LOWBT_FLAG;
985                         }
986                         status_flag &= ~CHRGR_FLAG;
987                 }
988                 break;
989         case SETTING_BRT_LEVEL:
990                 if (status_flag & PWRSV_FLAG) {
991                         status_flag |= BRTCH_FLAG;
992                         vconf_set_bool(VCONFKEY_PM_BRIGHTNESS_CHANGED_IN_LPM,
993                             true);
994                         LOGINFO("brightness changed in low battery, escape dim state");
995                 }
996                 set_default_brt(val);
997                 snprintf(buf, sizeof(buf), "%s %d", SET_BRIGHTNESS_IN_BOOTLOADER, val);
998                 LOGINFO("Brightness set in bl : %d",val);
999                 system(buf);
1000                 break;
1001         case SETTING_LOCK_SCREEN:
1002                 if (val == VCONFKEY_IDLE_LOCK) {
1003                         states[S_NORMAL].timeout = LOCK_SCREEN_TIMEOUT;
1004                         LOGERR("LCD NORMAL timeout is set by %d seconds for lock screen", LOCK_SCREEN_TIMEOUT);
1005                 } else {
1006                         get_run_timeout(&run_timeout);
1007                         if(run_timeout < 0) {
1008                                 LOGERR("Can not get run timeout. set default 15 seconds(includes dim 5 seconds)");
1009                                 run_timeout = 10;
1010                         }
1011                         states[S_NORMAL].timeout = run_timeout;
1012                         LOGINFO("LCD NORMAL timeout is set by %d seconds because phone is unlocked", run_timeout);
1013                 }
1014                 if (cur_state == S_NORMAL) {
1015                         states[cur_state].trans(EVENT_INPUT);
1016                 }
1017                 break;
1018         case SETTING_POWER_SAVING:
1019                 if (val == 1)
1020                         vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_CUSTMODE_DISPLAY, &power_saving_display_stat);
1021                 if (power_saving_display_stat != 1)
1022                         power_saving_display_stat = 0;
1023                 device_set_property(DEVICE_TYPE_DISPLAY, PROP_DISPLAY_FRAME_RATE, power_saving_display_stat);
1024                 backlight_restore();
1025                 break;
1026         case SETTING_POWER_SAVING_DISPLAY:
1027                 vconf_get_bool(VCONFKEY_SETAPPL_PWRSV_SYSMODE_STATUS, &power_saving_stat);
1028                 if (power_saving_stat == 1) {
1029                         if (val == 1)
1030                                 power_saving_display_stat = 1;
1031                         else
1032                                 power_saving_display_stat = 0;
1033                         device_set_property(DEVICE_TYPE_DISPLAY, PROP_DISPLAY_FRAME_RATE, power_saving_display_stat);
1034                         backlight_restore();
1035                 }
1036                 break;
1037         default:
1038                 return -1;
1039         }
1040         return 0;
1041 }
1042
1043 static void check_seed_status(void)
1044 {
1045         int ret = -1;
1046         int tmp = 0;
1047         int bat_state = VCONFKEY_SYSMAN_BAT_NORMAL;
1048         int max_brt = 0;
1049         int brt = 0;
1050         int lock_state = -1;
1051
1052         /* Charging check */
1053         if ((get_charging_status(&tmp) == 0) && (tmp > 0)) {
1054                 status_flag |= CHRGR_FLAG;
1055         }
1056
1057         ret = get_setting_brightness(&tmp);
1058         if (ret != 0 || (tmp < PM_MIN_BRIGHTNESS || tmp > PM_MAX_BRIGHTNESS)) {
1059                 LOGINFO("fail to read vconf value for brightness");
1060                 brt = PM_DEFAULT_BRIGHTNESS;
1061                 if(tmp < PM_MIN_BRIGHTNESS || tmp > PM_MAX_BRIGHTNESS)
1062                         vconf_set_int(VCONFKEY_SETAPPL_LCD_BRIGHTNESS, brt);
1063                 tmp = brt;
1064         }
1065         LOGINFO("Set brightness from Setting App. %d", tmp);
1066         set_default_brt(tmp);
1067
1068         vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, &bat_state);
1069         if (bat_state < VCONFKEY_SYSMAN_BAT_NORMAL) {
1070                 if (!(status_flag & CHRGR_FLAG)) {
1071                         power_saving_func(true);
1072                         status_flag |= LOWBT_FLAG;
1073                 }
1074         }
1075         backlight_restore();
1076
1077         /* USB connection check
1078          * If connected, add sleep prohibit condition */
1079         if ((get_usb_status(&tmp) == 0) && (tmp > 0)) {
1080                 tmp = readpid(USB_CON_PIDFILE);
1081                 if (tmp != -1) {
1082                         add_node(S_SLEEP, tmp, -1, 0);
1083                 }
1084         }
1085
1086         /* lock screen check */
1087         ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &lock_state);
1088         if(lock_state == VCONFKEY_IDLE_LOCK) {
1089                 states[S_NORMAL].timeout = LOCK_SCREEN_TIMEOUT;
1090                 LOGERR("LCD NORMAL timeout is set by %d seconds for lock screen", LOCK_SCREEN_TIMEOUT);
1091         }
1092
1093         return;
1094 }
1095
1096 enum {
1097         INIT_SETTING = 0,
1098         INIT_INTERFACE,
1099         INIT_POLL,
1100         INIT_FIFO,
1101         INIT_END
1102 };
1103
1104 static char *errMSG[INIT_END] = {
1105         [INIT_SETTING] = "setting init error",
1106         [INIT_INTERFACE] = "lowlevel interface(sysfs or others) init error",
1107         [INIT_POLL] = "input devices poll init error",
1108         [INIT_FIFO] = "FIFO poll init error",
1109 };
1110
1111 /* logging indev_list for debug */
1112 void printglist()
1113 {
1114         int i;
1115         guint total=0;
1116         indev *tmp;
1117
1118         total=g_list_length(indev_list);
1119         LOGINFO("***** total list : %d *****",total);
1120         for(i=0;i<total;i++) {
1121                 tmp=(indev*)(g_list_nth(indev_list, i)->data);
1122                 LOGINFO("* %d | path:%s, gsource:%d, gfd:%d", i, tmp->dev_path, tmp->dev_src, tmp->dev_fd);
1123                 if(i==total-1 && g_list_nth(indev_list, i)->next==NULL)
1124                         LOGINFO("okokok");
1125         }
1126         LOGINFO("***************************\n");
1127 }
1128
1129 static GList *find_glist(GList *glist, char *path)
1130 {
1131         int i;
1132         guint total=0;
1133         indev *tmp;
1134
1135         total=g_list_length(indev_list);
1136         for(i=0;i<total;i++) {
1137                 tmp=(indev*)(g_list_nth(indev_list, i)->data);
1138                 if(!strcmp(tmp->dev_path, path)){
1139                         LOGINFO("nth : %d, path:%s, gsource:%d, gfd:%d", i, tmp->dev_path, tmp->dev_src, tmp->dev_fd);
1140                         return g_list_nth(indev_list, i);
1141                 }
1142         }
1143         return NULL;
1144 }
1145
1146 static void input_cb(void* data)
1147 {
1148         FILE *fp;
1149         char input_act[NAME_MAX], input_path[MAX_INPUT];
1150         char args[NAME_MAX + MAX_INPUT];
1151         int i, ret = -1;
1152         GList *glist = NULL;
1153
1154         fp = fopen((char *) data, "r");
1155         if (fp == NULL) {
1156                 LOGERR("input file open fail");
1157                 return ;
1158         }
1159
1160         while (fgets(args, NAME_MAX + MAX_INPUT, fp) != NULL){
1161                 if( args[strlen(args)-1] != '\n'){
1162                         LOGERR("input file must be terminated with new line character\n");
1163                         break;
1164                 }
1165                 args[strlen(args) - 1] = '\0';
1166                 for(i = 0; i< NAME_MAX + MAX_INPUT; i++){
1167                         if(args[i] == ' '){
1168                                 if( i >= NAME_MAX ){
1169                                         LOGERR("bsfile name is over the name_max(255)\n");
1170                                         break;
1171                                 }
1172                                 strncpy(input_act, args, i < NAME_MAX ? i : NAME_MAX);
1173                                 input_act[i]='\0';
1174                                 strncpy(input_path, args + i + 1, MAX_INPUT);
1175                                 input_path[MAX_INPUT - 1] = '\0';
1176
1177                                 if( !strcmp("add", input_act) ){
1178                                         LOGINFO("add input path:%s",input_path);
1179
1180                                         ret=init_pm_poll_input(poll_callback, input_path);
1181
1182                                 } else if ( !strcmp("remove", input_act) ){
1183                                         glist=find_glist(indev_list, input_path);
1184                                         if(glist != NULL){
1185                                                 LOGINFO("remove input dev");
1186                                                 g_source_remove_poll(((indev*)(glist->data))->dev_src, ((indev*)(glist->data))->dev_fd);
1187                                                 g_source_destroy(((indev*)(glist->data))->dev_src);
1188                                                 close(((indev*)(glist->data))->dev_fd->fd);
1189                                                 g_free(((indev*)(glist->data))->dev_fd);
1190                                                 free(((indev*)(glist->data))->dev_path);
1191                                                 indev_list=g_list_remove(indev_list, glist->data);
1192                                         }
1193                                         ret=0;
1194                                 }
1195                                 /* debug */
1196                                 printglist();
1197
1198                                 break;
1199                         }
1200                 }
1201                 if(ret<0)
1202                         break;
1203         }
1204         fclose(fp);
1205
1206         if ( ret != -1) {
1207                 fp = fopen((char *) data, "w");
1208                 if (fp == NULL) {
1209                         return ;
1210                 }
1211                 fclose(fp);
1212         }
1213
1214         return ;
1215 }
1216
1217 static int set_noti(int *noti_fd)
1218 {
1219         int fd;
1220         char buf[PATH_MAX];
1221
1222         fd = heynoti_init();
1223         if (fd < 0) {
1224                 LOGERR("heynoti_init error");
1225                 return -1;
1226         }
1227
1228         if (heynoti_subscribe(fd, PM_EVENT_NOTI_NAME, input_cb, PM_EVENT_NOTI_PATH) < 0) {
1229                 LOGERR("input file change noti add failed(%s). %s", buf, strerror(errno));
1230                 return -1;
1231         } else {
1232                 LOGERR("input file change noti add ok");
1233         }
1234
1235         if (heynoti_attach_handler(fd) < 0) {
1236                 LOGERR("heynoti_attach_handler error");
1237                 return -1;
1238         }
1239
1240         *noti_fd = fd;
1241         return 0;
1242 }
1243
1244 static int unset_noti(int noti_fd)
1245 {
1246         if (noti_fd < 0) {
1247                 LOGINFO("set noti already failed. nothing to do in unset");
1248                 return 0;
1249         }
1250
1251         if (heynoti_unsubscribe(noti_fd, PM_EVENT_NOTI_NAME, input_cb) < 0 || heynoti_detach_handler(noti_fd) < 0) {
1252                 LOGERR("heynoti unsubsribe or detach error");
1253                 return -1;
1254         }
1255         return 0;
1256 }
1257
1258 /**
1259  * Power manager Main loop
1260  *
1261  * @internal
1262  * @param[in] flags If the first bit of this is set, start managing without Start notification.
1263  *                                      If the second bit of ths is set, use unified device manager functions.
1264  */
1265 void start_main(unsigned int flags)
1266 {
1267         int ret, i;
1268
1269         LOGINFO("Start power manager daemon");
1270
1271         signal(SIGINT, sig_quit);
1272         signal(SIGTERM, sig_quit);
1273         signal(SIGQUIT, sig_quit);
1274         signal(SIGHUP, sig_hup);
1275         signal(SIGCHLD, SIG_IGN);
1276         signal(SIGUSR1, sig_usr);
1277         signal(SIGALRM, sig_break_block);
1278
1279         mainloop = g_main_loop_new(NULL, FALSE);
1280         power_saving_func = default_saving_mode;
1281
1282         /* noti init for new input device like bt mouse */
1283         int noti_fd = -1;
1284         indev_list=NULL;
1285         set_noti(&noti_fd);
1286
1287         for (i = INIT_SETTING; i < INIT_END; i++) {
1288                 switch (i) {
1289                         case INIT_SETTING:
1290                                 ret = init_setting(update_setting);
1291                                 break;
1292                         case INIT_INTERFACE:
1293                                 get_settings();
1294                                 ret = init_sysfs(flags);
1295                                 break;
1296                         case INIT_POLL:
1297                                 LOGINFO("poll init");
1298                                 ret = init_pm_poll(poll_callback);
1299                                 break;
1300                 }
1301                 if (ret != 0) {
1302                         LOGERR(errMSG[i]);
1303                         break;
1304                 }
1305         }
1306
1307         if (i == INIT_END) {
1308                 check_seed_status();
1309
1310                 if (pm_init_extention != NULL)
1311                         pm_init_extention(NULL);
1312
1313                 if (flags & WITHOUT_STARTNOTI) {        /* start without noti */
1314                         LOGINFO("Start Power managing without noti");
1315                         cur_state = S_NORMAL;
1316                         set_setting_pmstate(cur_state);
1317                         reset_timeout(states[S_NORMAL].timeout);
1318                 }
1319                 if (start_battinfo_gathering(BATTERY_POLLING_PERIOD) < 0)
1320                         LOGERR("Start Battery time info failed!");
1321
1322                 g_main_loop_run(mainloop);
1323                 g_main_loop_unref(mainloop);
1324         }
1325
1326         end_battinfo_gathering();
1327         for (i = i - 1; i >= INIT_SETTING; i--) {
1328                 switch (i) {
1329                         case INIT_SETTING:
1330                                 exit_setting();
1331                                 break;
1332                         case INIT_INTERFACE:
1333                                 exit_sysfs();
1334                                 break;
1335                         case INIT_POLL:
1336                                 unset_noti(noti_fd);
1337                                 exit_pm_poll();
1338                                 break;
1339                 }
1340         }
1341
1342         if (pm_exit_extention != NULL)
1343                 pm_exit_extention();
1344
1345         LOGINFO("Terminate power manager daemon");
1346 }
1347
1348 /**
1349  * @}
1350  */