4 * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * @file proc-monitor.c
23 * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
27 #include <sys/types.h>
32 #include "proc-main.h"
33 #include "proc-monitor.h"
34 #include "resourced.h"
37 #include "edbus-handler.h"
38 #include "proc-process.h"
39 #include "lowmem-handler.h"
42 #include <journal/system.h>
44 #define WATCHDOG_LAUNCHING_PARAM "WatchdogPopupLaunch"
45 #define WATCHDOG_KEY1 "_SYSPOPUP_CONTENT_"
46 #define WATCHDOG_KEY2 "_APP_NAME_"
47 #define WATCHDOG_VALUE_1 "watchdog"
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"
61 #define INIT_PROC_VAL -1
63 static int proc_watchdog_state;
64 static int proc_dbus_proc_state;
65 int current_lcd_state;
67 static Ecore_Timer *watchdog_check_timer = NULL;
68 #define WATCHDOG_TIMER_INTERVAL 90
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.
75 static DBusMessage *edbus_signal_trigger(E_DBus_Object *obj, DBusMessage *msg);
77 static struct proc_watchdog_info {
80 } proc_watchdog = { -1, -1 };
83 * Adds function callbacks to edbus interface.
85 static resourced_ret_c proc_dbus_init(void);
87 static const struct edbus_method edbus_methods[] = {
88 { "Signal", "ii", NULL, edbus_signal_trigger },
89 /* Add methods here */
92 enum proc_status_type { /** cgroup command type **/
95 PROC_STATUS_TERMINATE,
100 static int check_debugenable(void)
102 if (access(TIZEN_DEBUG_MODE_FILE, F_OK) == 0)
108 void proc_set_watchdog_state(int state)
110 proc_watchdog_state = state;
113 static int proc_get_watchdog_state(void)
115 return proc_watchdog_state;
118 static void proc_dbus_active_signal_handler(void *data, DBusMessage *msg)
125 ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_ACTIVE);
127 _D("there is no active signal");
131 dbus_error_init(&err);
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");
138 if (!strcmp(str, "active"))
139 type = PROC_CGROUP_SET_ACTIVE;
140 else if (!strcmp(str, "inactive"))
141 type = PROC_CGROUP_SET_INACTIVE;
144 resourced_proc_status_change(type, pid, NULL, NULL);
147 int proc_get_dbus_proc_state(void)
149 return proc_dbus_proc_state;
152 static void proc_set_dbus_proc_state(int state)
154 proc_dbus_proc_state = state;
157 static void proc_dbus_proc_signal_handler(void *data, DBusMessage *msg)
160 int ret, type, convert = 0;
163 ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_STATUS);
165 _D("there is no active signal");
169 dbus_error_init(&err);
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");
176 if (!proc_dbus_proc_state)
177 proc_set_dbus_proc_state(PROC_DBUS_ENABLE);
180 case PROC_STATUS_LAUNCH:
181 convert = PROC_CGROUP_SET_LAUNCH_REQUEST;
183 case PROC_STATUS_RESUME:
184 convert = PROC_CGROUP_SET_RESUME_REQUEST;
186 case PROC_STATUS_TERMINATE:
187 convert = PROC_CGROUP_SET_TERMINATE_REQUEST;
189 case PROC_STATUS_FOREGRD:
190 convert = PROC_CGROUP_SET_FOREGRD;
192 case PROC_STATUS_BACKGRD:
193 convert = PROC_CGROUP_SET_BACKGRD;
198 _D("call proc_dbus_proc_signal_handler : pid = %d, type = %d", pid, convert);
199 resourced_proc_status_change(convert, pid, NULL, NULL);
202 static void proc_dbus_exclude_signal_handler(void *data, DBusMessage *msg)
209 ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_EXCLUDE);
211 _D("there is no active signal");
215 dbus_error_init(&err);
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");
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);
231 static void proc_dbus_prelaunch_signal_handler(void *data, DBusMessage *msg)
239 ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS,
240 SIGNAL_PROC_PRELAUNCH);
242 _D("there is no prelaunch signal");
246 dbus_error_init(&err);
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");
256 _D("call proc_dbus_prelaunch_handler: appid = %s, pkgid = %s, flags = %d",
257 appid, pkgid, flags);
259 if (flags & PROC_LARGE_HEAP) {
260 proc_set_apptype(appid, pkgid, PROC_LARGE_HEAP);
261 lowmem_dynamic_process_killer(DYNAMIC_KILL_LARGEHEAP);
265 static void proc_dbus_sweep_signal_handler(void *data, DBusMessage *msg)
270 ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS,
274 _D("there is no sweep signal");
278 dbus_error_init(&err);
279 proc_sweep_memory(PROC_SWEEP_INCLUDE_ACTIVE, INIT_PID);
282 static Eina_Bool check_watchdog_cb(void *data)
284 ecore_timer_del(watchdog_check_timer);
285 watchdog_check_timer = NULL;
286 return ECORE_CALLBACK_CANCEL;
289 static void proc_dbus_watchdog_result(void *data, DBusMessage *msg)
294 if (dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_WATCHDOG_RESULT) == 0) {
295 _D("there is no watchdog result signal");
299 dbus_error_init(&err);
301 if (dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &type, DBUS_TYPE_INVALID) == 0) {
302 _D("there is no message");
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);
315 _E("ERROR: Unsupported signal type!");
317 proc_watchdog.pid = -1;
318 proc_watchdog.signum = -1;
321 static int proc_dbus_show_popup(const char *value)
329 snprintf(str_val, sizeof(str_val), "%s", value);
331 pa[0] = WATCHDOG_KEY1;
332 pa[1] = WATCHDOG_VALUE_1;
333 pa[2] = WATCHDOG_KEY2;
338 msg = dbus_method_sync(SYSTEM_POPUP_BUS_NAME, SYSTEM_POPUP_PATH_WATCHDOG, SYSTEM_POPUP_IFACE_WATCHDOG, WATCHDOG_LAUNCHING_PARAM, "ssss", pa);
341 _E("Re-try to sync DBUS message, err_count : %d", i);
342 } while (i++ < RETRY_MAX);
345 _E("Failed to sync DBUS message.");
349 dbus_error_init(&err);
351 ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &ret_val, DBUS_TYPE_INVALID);
353 _E("no message : [%s:%s]\n", err.name, err.message);
357 dbus_message_unref(msg);
358 dbus_error_free(&err);
363 static void proc_dbus_watchdog_handler(void *data, DBusMessage *msg)
366 int pid, command, ret;
367 char appname[PROC_NAME_MAX];
369 if (dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_WATCHDOG) == 0) {
370 _D("there is no watchdog result signal");
374 dbus_error_init(&err);
376 ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INT32,
377 &command, DBUS_TYPE_INVALID);
380 _D("there is no message");
384 ret = proc_get_cmdline(pid, appname);
385 if (ret != RESOURCED_ERROR_NONE) {
386 _E("ERROR : invalid pid(%d)", pid);
390 if (proc_watchdog.pid != INIT_PROC_VAL) {
391 _E("pid %d(%s) has already received watchdog siganl", pid, appname);
394 ret = resourced_proc_excluded(appname);
395 if (ret == RESOURCED_ERROR_NONMONITOR)
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);
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);
410 if (check_debugenable()) {
411 _E("just kill watchdog process when debug enabled pid: %d(%s)\n", pid, appname);
413 if (watchdog_check_timer == NULL) {
414 watchdog_check_timer =
415 ecore_timer_add(WATCHDOG_TIMER_INTERVAL, check_watchdog_cb, (void *)NULL);
419 ret = proc_dbus_show_popup(appname);
421 _E("ERROR : request_to_launch_by_dbus()failed : %d", ret);
423 proc_watchdog.pid = pid;
424 proc_watchdog.signum = command;
429 static void proc_dbus_grouping_handler(void *data, DBusMessage *msg)
432 int pid, childpid, ret;
434 if (dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_GROUP) == 0) {
435 _D("there is no watchdog result signal");
439 dbus_error_init(&err);
441 ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INT32,
442 &childpid, DBUS_TYPE_INVALID);
445 _D("there is no message");
449 proc_set_group(pid, childpid);
452 static DBusMessage *edbus_signal_trigger(E_DBus_Object *obj, DBusMessage *msg)
456 int pid, command, ret_val;
457 char appname[PROC_NAME_MAX];
459 ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INT32,
460 &command, DBUS_TYPE_INVALID);
463 ret_val = proc_get_cmdline(pid, appname);
464 if (ret_val != RESOURCED_ERROR_NONE)
465 _E("ERROR : invalid pid(%d)", pid);
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);
473 _E("ERROR : request_to_launch_by_dbus()failed : %d", ret_val);
475 proc_watchdog.pid = pid;
476 proc_watchdog.signum = command;
482 _E("ERROR: Wrong message arguments!");
484 reply = dbus_message_new_method_return(msg);
488 static void proc_dbus_lcd_on(void *data, DBusMessage *msg)
491 dbus_error_init(&err);
493 if (dbus_message_is_signal(msg, DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_ON) == 0) {
494 _D("there is no lcd on signal");
497 dbus_error_free(&err);
498 current_lcd_state = LCD_STATE_ON;
499 resourced_notify(RESOURCED_NOTIFIER_LCD_ON, NULL);
503 static void proc_dbus_lcd_off(void *data, DBusMessage *msg)
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");
513 dbus_error_free(&err);
514 current_lcd_state = LCD_STATE_OFF;
515 resourced_notify(RESOURCED_NOTIFIER_LCD_OFF, NULL);
519 static resourced_ret_c proc_dbus_init(void)
521 register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
522 SIGNAL_PROC_WATCHDOG_RESULT,
523 proc_dbus_watchdog_result);
525 register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
527 proc_dbus_active_signal_handler);
529 register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
531 proc_dbus_exclude_signal_handler);
533 register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
534 SIGNAL_PROC_PRELAUNCH,
535 proc_dbus_prelaunch_signal_handler);
537 register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
539 proc_dbus_proc_signal_handler);
541 register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
543 proc_dbus_sweep_signal_handler);
545 register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
546 SIGNAL_PROC_WATCHDOG,
547 proc_dbus_watchdog_handler);
549 register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
550 SIGNAL_PROC_WATCHDOG,
551 proc_dbus_grouping_handler);
553 register_edbus_signal_handler(DEVICED_PATH_DISPLAY,
554 DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_ON, proc_dbus_lcd_on);
556 register_edbus_signal_handler(DEVICED_PATH_DISPLAY,
557 DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_OFF, proc_dbus_lcd_off);
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);
563 return edbus_add_methods(RESOURCED_PATH_PROCESS, edbus_methods,
564 ARRAY_SIZE(edbus_methods));
567 resourced_ret_c proc_monitor_init(void)
569 return proc_dbus_init();