tizen 2.3 release
[framework/system/deviced.git] / src / proc / pmon-handler.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 #include <fcntl.h>
21 #include <assert.h>
22 #include <limits.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <device-node.h>
26
27 #include "core/log.h"
28 #include "core/launch.h"
29 #include "core/common.h"
30 #include "core/devices.h"
31
32 #define PMON_PERMANENT_DIR      "/tmp/permanent"
33
34 static Ecore_Fd_Handler *pmon_efd = NULL;
35
36 static int __pmon_start(void);
37 static int __pmon_stop(int fd);
38 static int replace_char(int size, char *t)
39 {
40         while (size > 0) {
41                 if (*t == 0)
42                         *t = ' ';
43                 size--;
44                 t++;
45         }
46         return 0;
47 }
48
49 static char *pmon_get_permanent_pname(int pid)
50 {
51         int fd;
52         int ret;
53         char buf[PATH_MAX];
54         struct stat st;
55         char *cmdline = NULL;
56
57         snprintf(buf, sizeof(buf), "%s/%d", PMON_PERMANENT_DIR, pid);
58         fd = open(buf, O_RDONLY);
59         if (fd == -1) {
60                 _E("file open error");
61                 return NULL;
62         }
63
64         if (fstat(fd, &st) < 0) {
65                 _E("fstat error");
66                 close(fd);
67                 return NULL;
68         }
69         _D("size = %d", (int)st.st_size);
70
71         cmdline = malloc(st.st_size + 1);
72         if (cmdline == NULL) {
73                 _E("Not enough memory");
74                 close(fd);
75                 return NULL;
76         }
77         memset(cmdline, 0, st.st_size + 1);
78
79         ret = read(fd, cmdline, st.st_size);
80         if (ret >= 0 && ret < st.st_size) {
81                 /* TODO - must change more smarter */
82                 replace_char(st.st_size - 1, cmdline);
83         }
84         close(fd);
85
86         return cmdline;
87 }
88
89 static void print_pmon_state(unsigned int dead_pid)
90 {
91         _D("[Process MON] %d killed", dead_pid);
92 }
93
94 static int pmon_process(int pid)
95 {
96         char *cmdline;
97         int new_pid;
98         char old_file[PATH_MAX];
99         int fd;
100         int r;
101
102         if (is_vip(pid)) {
103                 _I("=======================================");
104                 _I("[Process MON] VIP process dead.");
105                 _I("=======================================");
106         }
107         /* If there is NOT a .hibernation_start file, run following codes 
108          * On hibernation processing, just ignore relaunching */
109         else if (access("/tmp/.hibernation_start", R_OK) != 0) {
110                 cmdline = pmon_get_permanent_pname(pid);
111                 if (cmdline != NULL) {
112                         _I("[Process MON] %s relaunch", cmdline);
113                         new_pid = launch_evenif_exist(cmdline, "");
114                         free(cmdline);
115                         if (new_pid > 0) {
116                                 /* TODO - set oom */
117                                 char buf[PATH_MAX];
118                                 char filepath[PATH_MAX];
119                                 int cnt;
120
121                                 if (access(PMON_PERMANENT_DIR, R_OK) < 0) {
122                                         _I("no predefined matrix dir = %s, so created", PMON_PERMANENT_DIR);
123                                         r = mkdir(PMON_PERMANENT_DIR, 0777);
124                                         if(r < 0) {
125                                                 _E("Make Directory is failed");
126                                                 return -1;
127                                         }
128                                 }
129
130                                 snprintf(filepath, sizeof(filepath), "%s/%d", PMON_PERMANENT_DIR, pid);
131                                 fd = open(filepath, O_RDONLY);
132                                 if (fd == -1) {
133                                         _E("Failed to open");
134                                         return -1;
135                                 }
136                                 cnt = read(fd, buf, PATH_MAX);
137                                 close(fd);
138
139                                 if (cnt <= 0) {
140                                         _E("Failed to read");
141                                         return -1;
142                                 }
143
144                                 snprintf(filepath, sizeof(filepath), "%s/%d", PMON_PERMANENT_DIR, new_pid);
145
146                                 fd = open(filepath, O_CREAT | O_WRONLY, 0644);
147                                 if (fd == -1) {
148                                         _E("Failed to open");
149                                         return -1;
150                                 }
151                                 if (write(fd, buf, cnt) == -1) {
152                                         _E("Failed to write");
153                                         close(fd);
154                                         return -1;
155                                 }
156                                 close(fd);
157                                 if ( device_set_property(DEVICE_TYPE_PROCESS, PROP_PROCESS_MP_PNP, new_pid) < 0) {
158                                         _E("Write new pid failed");
159                                 }
160                                 _I("[Process MON] %d ", new_pid);
161
162                                 FILE *fp;
163
164                                 _I("[Process MON] OOMADJ_SET : pid %d, new_oomadj %d",
165                                      new_pid, (-17));
166
167                                 fp = open_proc_oom_score_adj_file(new_pid, "w");
168                                 if (fp == NULL)
169                                         return -1;
170                                 fprintf(fp, "%d",0);
171                                 fclose(fp);
172
173                                 snprintf(old_file, sizeof(old_file), "%s/%d",
174                                          PMON_PERMANENT_DIR, pid);
175                                 unlink(old_file);
176                         } else {
177                                 _I("[Process MON] failed relaunching");
178                         }
179                 }
180         }
181         return 0;
182 }
183 /*
184 static unsigned int pmon_read(int fd)
185 {
186         unsigned int pid;
187         read(fd, &pid, sizeof(pid));
188         return pid;
189 }
190 */
191
192 static Eina_Bool pmon_cb(void *data, Ecore_Fd_Handler * fd_handler)
193 {
194         int fd;
195         int dead_pid;
196         char pid_str[PATH_MAX];
197         int ret;
198
199         if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) {
200                 _E("ecore_main_fd_handler_active_get error , return");
201                 goto out;
202         }
203
204         fd = ecore_main_fd_handler_fd_get(fd_handler);
205
206         if (fd < 0) {
207                 _E("ecore_main_fd_handler_fd_get error , return");
208                 goto out;
209         }
210
211         ret = read(fd, pid_str, PATH_MAX);
212
213         if (ret < 0 || ret >= PATH_MAX) {
214                 __pmon_stop(fd);
215                 _E("Reading DEAD_PID failed, restart ecore fd");
216                 __pmon_start();
217                 goto out;
218         }
219
220         pid_str[ret] = '\0';
221         dead_pid = strtoul(pid_str, NULL, 10);
222         print_pmon_state(dead_pid);
223         pmon_process(dead_pid);
224 out:
225         return EINA_TRUE;
226 }
227
228 static int __pmon_start(void)
229 {
230         int pmon_fd = -1;
231         char pmon_dev_node[PATH_MAX];
232         if (device_get_property(DEVICE_TYPE_PROCESS, PROP_PROCESS_NODE,
233                 (int *)pmon_dev_node) < 0) {
234                 _E("ss_pmon_init get dev node path failed");
235                 return -1;
236         }
237
238         pmon_fd = open(pmon_dev_node, O_RDONLY);
239         if (pmon_fd < 0) {
240                 _E("ss_pmon_init fd open failed");
241                 return -1;
242         }
243         pmon_efd = ecore_main_fd_handler_add(pmon_fd, ECORE_FD_READ, pmon_cb, ad, NULL, NULL);
244         if (!pmon_efd) {
245                 _E("error ecore_main_fd_handler_add");
246                 return -1;
247         }
248         return 0;
249 }
250 static int __pmon_stop(int fd)
251 {
252         if (pmon_efd) {
253                 ecore_main_fd_handler_del(pmon_efd);
254                 pmon_efd = NULL;
255         }
256         if (fd >=0) {
257                 close(fd);
258                 fd = -1;
259         }
260         return 0;
261 }
262
263 static void pmon_init(void *data)
264 {
265         int ret = -1;
266
267         if (pmon_efd) {
268                 ecore_main_fd_handler_del(pmon_efd);
269                 pmon_efd = NULL;
270         }
271         if (__pmon_start() == -1) {
272                 _E("fail pmon control fd init");
273         }
274 }
275
276 static const struct device_ops pmon_device_ops = {
277         .priority = DEVICE_PRIORITY_NORMAL,
278         .name     = "pmon",
279         .init     = pmon_init,
280 };
281
282 DEVICE_OPS_REGISTER(&pmon_device_ops)