tizen 2.3 release
[kernel/api/system-resource.git] / src / proc-stat / proc-monitor.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
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 /*
21  * @file proc-monitor.c
22  *
23  * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
24  *
25  */
26
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <Ecore.h>
30 #include <E_DBus.h>
31
32 #include "proc-main.h"
33 #include "proc-monitor.h"
34 #include "resourced.h"
35 #include "macro.h"
36 #include "trace.h"
37 #include "edbus-handler.h"
38 #include "proc-process.h"
39 #include "lowmem-handler.h"
40 #include "notifier.h"
41
42 #include <journal/system.h>
43
44 #define WATCHDOG_LAUNCHING_PARAM "WatchdogPopupLaunch"
45 #define WATCHDOG_KEY1                   "_SYSPOPUP_CONTENT_"
46 #define WATCHDOG_KEY2                   "_APP_NAME_"
47 #define WATCHDOG_VALUE_1                        "watchdog"
48
49 #define SIGNAL_PROC_WATCHDOG_RESULT     "WatchdogResult"
50 #define SIGNAL_PROC_ACTIVE              "Active"
51 #define SIGNAL_PROC_EXCLUDE             "ProcExclude"
52 #define SIGNAL_PROC_PRELAUNCH           "ProcPrelaunch"
53 #define SIGNAL_PROC_STATUS              "ProcStatus"
54 #define SIGNAL_PROC_SWEEP               "ProcSweep"
55 #define SIGNAL_PROC_WATCHDOG            "ProcWatchdog"
56 #define SIGNAL_PROC_GROUP               "ProcGroup"
57 #define TIZEN_DEBUG_MODE_FILE   "/opt/etc/.debugmode"
58
59
60 #define INIT_PID        1
61 #define INIT_PROC_VAL   -1
62
63 static int proc_watchdog_state;
64 static int proc_dbus_proc_state;
65 int current_lcd_state;
66
67 static Ecore_Timer *watchdog_check_timer = NULL;
68 #define WATCHDOG_TIMER_INTERVAL         90
69
70 /*
71  * Callback function executed by edbus 'Signal' method call. Extracts
72  * process pid and signal type from message body and uses it to send a specific
73  * signal to the process.
74  */
75 static DBusMessage *edbus_signal_trigger(E_DBus_Object *obj, DBusMessage *msg);
76
77 static struct proc_watchdog_info {
78         pid_t pid;
79         int signum;
80 } proc_watchdog = { -1, -1 };
81
82 /*
83  * Adds function callbacks to edbus interface.
84  */
85 static resourced_ret_c proc_dbus_init(void);
86
87 static const struct edbus_method edbus_methods[] = {
88         { "Signal", "ii", NULL, edbus_signal_trigger },
89         /* Add methods here */
90 };
91
92 enum proc_status_type { /** cgroup command type **/
93         PROC_STATUS_LAUNCH,
94         PROC_STATUS_RESUME,
95         PROC_STATUS_TERMINATE,
96         PROC_STATUS_FOREGRD,
97         PROC_STATUS_BACKGRD,
98 };
99
100 static int check_debugenable(void)
101 {
102         if (access(TIZEN_DEBUG_MODE_FILE, F_OK) == 0)
103                 return 1;
104         else
105                 return 0;
106 }
107
108 void proc_set_watchdog_state(int state)
109 {
110         proc_watchdog_state = state;
111 }
112
113 static int proc_get_watchdog_state(void)
114 {
115         return proc_watchdog_state;
116 }
117
118 static void proc_dbus_active_signal_handler(void *data, DBusMessage *msg)
119 {
120         DBusError err;
121         int ret, type;
122         char *str;
123         pid_t pid;
124
125         ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_ACTIVE);
126         if (ret == 0) {
127                 _D("there is no active signal");
128                 return;
129         }
130
131         dbus_error_init(&err);
132
133         if (dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &str, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID) == 0) {
134                 _D("there is no message");
135                 return;
136         }
137
138         if (!strcmp(str, "active"))
139                 type = PROC_CGROUP_SET_ACTIVE;
140         else if (!strcmp(str, "inactive"))
141                 type = PROC_CGROUP_SET_INACTIVE;
142         else
143                 return;
144         resourced_proc_status_change(type, pid, NULL, NULL);
145 }
146
147 int proc_get_dbus_proc_state(void)
148 {
149         return proc_dbus_proc_state;
150 }
151
152 static void proc_set_dbus_proc_state(int state)
153 {
154         proc_dbus_proc_state = state;
155 }
156
157 static void proc_dbus_proc_signal_handler(void *data, DBusMessage *msg)
158 {
159         DBusError err;
160         int ret, type, convert = 0;
161         pid_t pid;
162
163         ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_STATUS);
164         if (ret == 0) {
165                 _D("there is no active signal");
166                 return;
167         }
168
169         dbus_error_init(&err);
170
171         if (dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &type, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID) == 0) {
172                 _D("there is no message");
173                 return;
174         }
175
176         if (!proc_dbus_proc_state)
177                 proc_set_dbus_proc_state(PROC_DBUS_ENABLE);
178
179         switch (type) {
180         case PROC_STATUS_LAUNCH:
181                 convert = PROC_CGROUP_SET_LAUNCH_REQUEST;
182                 break;
183         case PROC_STATUS_RESUME:
184                 convert = PROC_CGROUP_SET_RESUME_REQUEST;
185                 break;
186         case PROC_STATUS_TERMINATE:
187                 convert = PROC_CGROUP_SET_TERMINATE_REQUEST;
188                 break;
189         case PROC_STATUS_FOREGRD:
190                 convert = PROC_CGROUP_SET_FOREGRD;
191                 break;
192         case PROC_STATUS_BACKGRD:
193                 convert = PROC_CGROUP_SET_BACKGRD;
194                 break;
195         default:
196                 return;
197         }
198         _D("call proc_dbus_proc_signal_handler : pid = %d, type = %d", pid, convert);
199         resourced_proc_status_change(convert, pid, NULL, NULL);
200 }
201
202 static void proc_dbus_exclude_signal_handler(void *data, DBusMessage *msg)
203 {
204         DBusError err;
205         int ret;
206         char *str;
207         pid_t pid;
208
209         ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_EXCLUDE);
210         if (ret == 0) {
211                 _D("there is no active signal");
212                 return;
213         }
214
215         dbus_error_init(&err);
216
217         if (dbus_message_get_args(msg, &err, DBUS_TYPE_STRING, &str, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID) == 0) {
218                 _D("there is no message");
219                 return;
220         }
221
222         _D("call proc_dbus_exclude_signal_handler : pid = %d, str = %s", pid, str);
223         if (!strcmp(str, "exclude"))
224                 proc_set_runtime_exclude_list(pid, PROC_EXCLUDE);
225         else if (!strcmp(str, "include"))
226                 proc_set_runtime_exclude_list(pid, PROC_INCLUDE);
227         else
228                 return;
229 }
230
231 static void proc_dbus_prelaunch_signal_handler(void *data, DBusMessage *msg)
232 {
233         DBusError err;
234         int ret;
235         char *appid;
236         char *pkgid;
237         int flags;
238
239         ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS,
240                 SIGNAL_PROC_PRELAUNCH);
241         if (ret == 0) {
242                 _D("there is no prelaunch signal");
243                 return;
244         }
245
246         dbus_error_init(&err);
247
248         if (dbus_message_get_args(msg, &err,
249                 DBUS_TYPE_STRING, &appid,
250                 DBUS_TYPE_STRING, &pkgid,
251                 DBUS_TYPE_INT32, &flags, DBUS_TYPE_INVALID) == 0) {
252                 _D("there is no message");
253                 return;
254         }
255
256         _D("call proc_dbus_prelaunch_handler: appid = %s, pkgid = %s, flags = %d",
257                 appid, pkgid, flags);
258
259         if (flags & PROC_LARGE_HEAP) {
260                 proc_set_apptype(appid, pkgid, PROC_LARGE_HEAP);
261                 lowmem_dynamic_process_killer(DYNAMIC_KILL_LARGEHEAP);
262         }
263 }
264
265 static void proc_dbus_sweep_signal_handler(void *data, DBusMessage *msg)
266 {
267         DBusError err;
268         int ret;
269
270         ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS,
271                 SIGNAL_PROC_SWEEP);
272
273         if (ret == 0) {
274                 _D("there is no sweep signal");
275                 return;
276         }
277
278         dbus_error_init(&err);
279         proc_sweep_memory(PROC_SWEEP_INCLUDE_ACTIVE, INIT_PID);
280 }
281
282 static Eina_Bool check_watchdog_cb(void *data)
283 {
284         ecore_timer_del(watchdog_check_timer);
285         watchdog_check_timer = NULL;
286         return ECORE_CALLBACK_CANCEL;
287 }
288
289 static void proc_dbus_watchdog_result(void *data, DBusMessage *msg)
290 {
291         DBusError err;
292         int type;
293
294         if (dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_WATCHDOG_RESULT) == 0) {
295                 _D("there is no watchdog result signal");
296                 return;
297         }
298
299         dbus_error_init(&err);
300
301         if (dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &type, DBUS_TYPE_INVALID) == 0) {
302                 _D("there is no message");
303                 return;
304         }
305
306         if (type == 1) {
307                 if (proc_watchdog.signum == SIGTERM || proc_watchdog.signum == SIGKILL) {
308                         kill(proc_watchdog.pid, SIGABRT);
309                         if (watchdog_check_timer == NULL) {
310                                 watchdog_check_timer =
311                                         ecore_timer_add(WATCHDOG_TIMER_INTERVAL, check_watchdog_cb, (void *)NULL);
312                         }
313                 }
314                 else
315                         _E("ERROR: Unsupported signal type!");
316         }
317         proc_watchdog.pid = -1;
318         proc_watchdog.signum = -1;
319 }
320
321 static int proc_dbus_show_popup(const char *value)
322 {
323         DBusError err;
324         DBusMessage *msg;
325         char str_val[32];
326         char *pa[4];
327         int i, ret, ret_val;
328
329         snprintf(str_val, sizeof(str_val), "%s", value);
330
331         pa[0] = WATCHDOG_KEY1;
332         pa[1] = WATCHDOG_VALUE_1;
333         pa[2] = WATCHDOG_KEY2;
334         pa[3] = str_val;
335         i = 0;
336
337         do {
338                 msg = dbus_method_sync(SYSTEM_POPUP_BUS_NAME, SYSTEM_POPUP_PATH_WATCHDOG, SYSTEM_POPUP_IFACE_WATCHDOG, WATCHDOG_LAUNCHING_PARAM, "ssss", pa);
339                 if (msg)
340                         break;
341                 _E("Re-try to sync DBUS message, err_count : %d", i);
342         } while (i++ < RETRY_MAX);
343
344         if (!msg) {
345                 _E("Failed to sync DBUS message.");
346                 return -EBADMSG;
347         }
348
349         dbus_error_init(&err);
350
351         ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &ret_val, DBUS_TYPE_INVALID);
352         if (!ret) {
353                 _E("no message : [%s:%s]\n", err.name, err.message);
354                 ret_val = -EBADMSG;
355         }
356
357         dbus_message_unref(msg);
358         dbus_error_free(&err);
359
360         return ret_val;
361 }
362
363 static void proc_dbus_watchdog_handler(void *data, DBusMessage *msg)
364 {
365         DBusError err;
366         int pid, command, ret;
367         char appname[PROC_NAME_MAX];
368
369         if (dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_WATCHDOG) == 0) {
370                 _D("there is no watchdog result signal");
371                 return;
372         }
373
374         dbus_error_init(&err);
375
376         ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INT32,
377                 &command, DBUS_TYPE_INVALID);
378
379         if (ret == 0) {
380                 _D("there is no message");
381                 return;
382         }
383
384         ret = proc_get_cmdline(pid, appname);
385         if (ret != RESOURCED_ERROR_NONE) {
386                 _E("ERROR : invalid pid(%d)", pid);
387                 return;
388         }
389
390         if (proc_watchdog.pid != INIT_PROC_VAL) {
391                 _E("pid %d(%s) has already received watchdog siganl", pid, appname);
392                 return;
393         }
394         ret = resourced_proc_excluded(appname);
395         if (ret == RESOURCED_ERROR_NONMONITOR)
396                 return;
397
398         if (current_lcd_state == LCD_STATE_OFF) {
399                 _E("Receive watchdog signal to pid: %d(%s) but don't show ANR popup in LCD off state\n", pid, appname);
400                 return;
401         }
402
403         _E("Receive watchdog signal to pid: %d(%s)\n", pid, appname);
404         journal_system_anr(appname);
405         if (watchdog_check_timer) {
406                 _E("current killing watchdog process. so skipped kill %d(%s)\n", pid, appname);
407                 return;
408         }
409
410         if (check_debugenable()) {
411                 _E("just kill watchdog process when debug enabled pid: %d(%s)\n", pid, appname);
412                 kill(pid, SIGABRT);
413                 if (watchdog_check_timer == NULL) {
414                         watchdog_check_timer =
415                                 ecore_timer_add(WATCHDOG_TIMER_INTERVAL, check_watchdog_cb, (void *)NULL);
416         }
417         }
418         else {
419                 ret = proc_dbus_show_popup(appname);
420                 if (ret < 0)
421                         _E("ERROR : request_to_launch_by_dbus()failed : %d", ret);
422                 else {
423                         proc_watchdog.pid = pid;
424                         proc_watchdog.signum = command;
425                 }
426         }
427 }
428
429 static void proc_dbus_grouping_handler(void *data, DBusMessage *msg)
430 {
431         DBusError err;
432         int pid, childpid, ret;
433
434         if (dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_GROUP) == 0) {
435                 _D("there is no watchdog result signal");
436                 return;
437         }
438
439         dbus_error_init(&err);
440
441         ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INT32,
442                 &childpid, DBUS_TYPE_INVALID);
443
444         if (ret == 0) {
445                 _D("there is no message");
446                 return;
447         }
448
449         proc_set_group(pid, childpid);
450 }
451
452 static DBusMessage *edbus_signal_trigger(E_DBus_Object *obj, DBusMessage *msg)
453 {
454         DBusMessage *reply;
455         dbus_bool_t ret;
456         int pid, command, ret_val;
457         char appname[PROC_NAME_MAX];
458
459         ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INT32,
460                 &command, DBUS_TYPE_INVALID);
461
462         if (ret == TRUE) {
463                 ret_val = proc_get_cmdline(pid, appname);
464                 if (ret_val != RESOURCED_ERROR_NONE)
465                         _E("ERROR : invalid pid(%d)", pid);
466                 else {
467                         _E("Receive watchdog signal to pid: %d(%s)\n", pid, appname);
468                         if (proc_get_watchdog_state() == PROC_WATCHDOG_ENABLE  &&  proc_watchdog.pid == -1) {
469                                 ret_val = resourced_proc_excluded(appname);
470                                 if (ret_val == RESOURCED_ERROR_NONE) {
471                                         ret_val = proc_dbus_show_popup(appname);
472                                         if (ret_val < 0)
473                                                 _E("ERROR : request_to_launch_by_dbus()failed : %d", ret_val);
474                                         else {
475                                                 proc_watchdog.pid = pid;
476                                                 proc_watchdog.signum = command;
477                                         }
478                                 }
479                         }
480                 }       
481         } else
482                 _E("ERROR: Wrong message arguments!");
483
484         reply = dbus_message_new_method_return(msg);
485         return reply;
486 }
487
488 static void proc_dbus_lcd_on(void *data, DBusMessage *msg)
489 {
490         DBusError err;
491         dbus_error_init(&err);
492
493         if (dbus_message_is_signal(msg, DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_ON) == 0) {
494                 _D("there is no lcd on signal");
495                 return;
496         }
497         dbus_error_free(&err);
498         current_lcd_state = LCD_STATE_ON;
499         resourced_notify(RESOURCED_NOTIFIER_LCD_ON, NULL);
500         /* nothing */
501 }
502
503 static void proc_dbus_lcd_off(void *data, DBusMessage *msg)
504 {
505         DBusError err;
506
507         dbus_error_init(&err);
508         if (dbus_message_is_signal(msg, DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_OFF) == 0) {
509                 _D("there is no lcd on signal");
510                 return;
511         }
512
513         dbus_error_free(&err);
514         current_lcd_state = LCD_STATE_OFF;
515         resourced_notify(RESOURCED_NOTIFIER_LCD_OFF, NULL);
516 }
517
518
519 static resourced_ret_c proc_dbus_init(void)
520 {
521         register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
522                         SIGNAL_PROC_WATCHDOG_RESULT,
523                     proc_dbus_watchdog_result);
524
525         register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
526                         SIGNAL_PROC_ACTIVE,
527                     proc_dbus_active_signal_handler);
528
529         register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
530                         SIGNAL_PROC_EXCLUDE,
531                     proc_dbus_exclude_signal_handler);
532
533         register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
534                         SIGNAL_PROC_PRELAUNCH,
535                     proc_dbus_prelaunch_signal_handler);
536
537         register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
538                         SIGNAL_PROC_STATUS,
539                     proc_dbus_proc_signal_handler);
540
541         register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
542                         SIGNAL_PROC_SWEEP,
543                     proc_dbus_sweep_signal_handler);
544
545         register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
546                         SIGNAL_PROC_WATCHDOG,
547                     proc_dbus_watchdog_handler);
548
549         register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
550                         SIGNAL_PROC_WATCHDOG,
551                     proc_dbus_grouping_handler);
552
553         register_edbus_signal_handler(DEVICED_PATH_DISPLAY,
554                     DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_ON, proc_dbus_lcd_on);
555
556         register_edbus_signal_handler(DEVICED_PATH_DISPLAY,
557                     DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_OFF, proc_dbus_lcd_off);
558
559         /* start watchdog check timer for preveting ANR during booting */
560         watchdog_check_timer =
561                 ecore_timer_add(WATCHDOG_TIMER_INTERVAL, check_watchdog_cb, (void *)NULL);
562
563         return edbus_add_methods(RESOURCED_PATH_PROCESS, edbus_methods,
564                           ARRAY_SIZE(edbus_methods));
565 }
566
567 resourced_ret_c proc_monitor_init(void)
568 {
569         return proc_dbus_init();
570 }