Initialize Tizen 2.3
[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/data.h"
30 #include "core/common.h"
31 #include "core/devices.h"
32
33 #define PMON_PERMANENT_DIR      "/tmp/permanent"
34
35 static Ecore_Fd_Handler *pmon_efd = NULL;
36
37 static int __pmon_start(struct main_data *ad);
38 static int __pmon_stop(int fd);
39 static int replace_char(int size, char *t)
40 {
41         while (size > 0) {
42                 if (*t == 0)
43                         *t = ' ';
44                 size--;
45                 t++;
46         }
47         return 0;
48 }
49
50 static char *pmon_get_permanent_pname(int pid)
51 {
52         int fd;
53         int ret;
54         char buf[PATH_MAX];
55         struct stat st;
56         char *cmdline = NULL;
57
58         snprintf(buf, sizeof(buf), "%s/%d", PMON_PERMANENT_DIR, pid);
59         fd = open(buf, O_RDONLY);
60         if (fd == -1) {
61                 _E("file open error");
62                 return NULL;
63         }
64
65         if (fstat(fd, &st) < 0) {
66                 _E("fstat error");
67                 close(fd);
68                 return NULL;
69         }
70         _D("size = %d", (int)st.st_size);
71
72         cmdline = malloc(st.st_size + 1);
73         if (cmdline == NULL) {
74                 _E("Not enough memory");
75                 close(fd);
76                 return NULL;
77         }
78         memset(cmdline, 0, st.st_size + 1);
79
80         ret = read(fd, cmdline, st.st_size);
81         if (ret >= 0 && ret < st.st_size) {
82                 /* TODO - must change more smarter */
83                 replace_char(st.st_size - 1, cmdline);
84         }
85         close(fd);
86
87         return cmdline;
88 }
89
90 static void print_pmon_state(unsigned int dead_pid)
91 {
92         _D("[Process MON] %d killed", dead_pid);
93 }
94
95 static int pmon_process(int pid, void *ad)
96 {
97         char *cmdline;
98         int new_pid;
99         char old_file[PATH_MAX];
100         int fd;
101         int r;
102
103         if (is_vip(pid)) {
104                 _I("=======================================");
105                 _I("[Process MON] VIP process dead.");
106                 _I("=======================================");
107         }
108         /* If there is NOT a .hibernation_start file, run following codes 
109          * On hibernation processing, just ignore relaunching */
110         else if (access("/tmp/.hibernation_start", R_OK) != 0) {
111                 cmdline = pmon_get_permanent_pname(pid);
112                 if (cmdline != NULL) {
113                         _I("[Process MON] %s relaunch", cmdline);
114                         new_pid = launch_evenif_exist(cmdline, "");
115                         free(cmdline);
116                         if (new_pid > 0) {
117                                 /* TODO - set oom */
118                                 char buf[PATH_MAX];
119                                 char filepath[PATH_MAX];
120                                 int cnt;
121
122                                 if (access(PMON_PERMANENT_DIR, R_OK) < 0) {
123                                         _I("no predefined matrix dir = %s, so created", PMON_PERMANENT_DIR);
124                                         r = mkdir(PMON_PERMANENT_DIR, 0777);
125                                         if(r < 0) {
126                                                 _E("Make Directory is failed");
127                                                 return -1;
128                                         }
129                                 }
130
131                                 snprintf(filepath, sizeof(filepath), "%s/%d", PMON_PERMANENT_DIR, pid);
132                                 fd = open(filepath, O_RDONLY);
133                                 if (fd == -1) {
134                                         _E("Failed to open");
135                                         return -1;
136                                 }
137                                 cnt = read(fd, buf, PATH_MAX);
138                                 close(fd);
139
140                                 if (cnt <= 0) {
141                                         _E("Failed to read");
142                                         return -1;
143                                 }
144
145                                 snprintf(filepath, sizeof(filepath), "%s/%d", PMON_PERMANENT_DIR, new_pid);
146
147                                 fd = open(filepath, O_CREAT | O_WRONLY, 0644);
148                                 if (fd == -1) {
149                                         _E("Failed to open");
150                                         return -1;
151                                 }
152                                 if (write(fd, buf, cnt) == -1) {
153                                         _E("Failed to write");
154                                         close(fd);
155                                         return -1;
156                                 }
157                                 close(fd);
158                                 if ( device_set_property(DEVICE_TYPE_PROCESS, PROP_PROCESS_MP_PNP, new_pid) < 0) {
159                                         _E("Write new pid failed");
160                                 }
161                                 _I("[Process MON] %d ", new_pid);
162
163                                 FILE *fp;
164
165                                 _I("[Process MON] OOMADJ_SET : pid %d, new_oomadj %d",
166                                      new_pid, (-17));
167
168                                 fp = open_proc_oom_score_adj_file(new_pid, "w");
169                                 if (fp == NULL)
170                                         return -1;
171                                 fprintf(fp, "%d",0);
172                                 fclose(fp);
173
174                                 snprintf(old_file, sizeof(old_file), "%s/%d",
175                                          PMON_PERMANENT_DIR, pid);
176                                 unlink(old_file);
177                         } else {
178                                 _I("[Process MON] failed relaunching");
179                         }
180                 }
181         }
182         return 0;
183 }
184 /*
185 static unsigned int pmon_read(int fd)
186 {
187         unsigned int pid;
188         read(fd, &pid, sizeof(pid));
189         return pid;
190 }
191 */
192
193 static Eina_Bool pmon_cb(void *data, Ecore_Fd_Handler * fd_handler)
194 {
195         int fd;
196         struct main_data *ad = (struct main_data *)data;
197         int dead_pid;
198         char pid_str[PATH_MAX];
199         int ret;
200
201         if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) {
202                 _E("ecore_main_fd_handler_active_get error , return");
203                 goto out;
204         }
205
206         fd = ecore_main_fd_handler_fd_get(fd_handler);
207
208         if (fd < 0) {
209                 _E("ecore_main_fd_handler_fd_get error , return");
210                 goto out;
211         }
212
213         ret = read(fd, pid_str, PATH_MAX);
214
215         if (ret < 0 || ret >= PATH_MAX) {
216                 __pmon_stop(fd);
217                 _E("Reading DEAD_PID failed, restart ecore fd");
218                 __pmon_start(ad);
219                 goto out;
220         }
221
222         pid_str[ret] = '\0';
223         dead_pid = strtoul(pid_str, NULL, 10);
224         print_pmon_state(dead_pid);
225         pmon_process(dead_pid, ad);
226 out:
227         return EINA_TRUE;
228 }
229
230 static int __pmon_start(struct main_data *ad)
231 {
232         int pmon_fd = -1;
233         char pmon_dev_node[PATH_MAX];
234         if (device_get_property(DEVICE_TYPE_PROCESS, PROP_PROCESS_NODE,
235                 (int *)pmon_dev_node) < 0) {
236                 _E("ss_pmon_init get dev node path failed");
237                 return -1;
238         }
239
240         pmon_fd = open(pmon_dev_node, O_RDONLY);
241         if (pmon_fd < 0) {
242                 _E("ss_pmon_init fd open failed");
243                 return -1;
244         }
245         pmon_efd = ecore_main_fd_handler_add(pmon_fd, ECORE_FD_READ, pmon_cb, ad, NULL, NULL);
246         if (!pmon_efd) {
247                 _E("error ecore_main_fd_handler_add");
248                 return -1;
249         }
250         return 0;
251 }
252 static int __pmon_stop(int fd)
253 {
254         if (pmon_efd) {
255                 ecore_main_fd_handler_del(pmon_efd);
256                 pmon_efd = NULL;
257         }
258         if (fd >=0) {
259                 close(fd);
260                 fd = -1;
261         }
262         return 0;
263 }
264
265 static void pmon_init(void *data)
266 {
267         struct main_data *ad = (struct main_data*)data;
268         int ret = -1;
269
270         if (pmon_efd) {
271                 ecore_main_fd_handler_del(pmon_efd);
272                 pmon_efd = NULL;
273         }
274         if (__pmon_start(ad) == -1) {
275                 _E("fail pmon control fd init");
276         }
277 }
278
279 static const struct device_ops pmon_device_ops = {
280         .priority = DEVICE_PRIORITY_NORMAL,
281         .name     = "pmon",
282         .init     = pmon_init,
283 };
284
285 DEVICE_OPS_REGISTER(&pmon_device_ops)