tizen 2.3 release
[kernel/api/system-resource.git] / src / proc-stat / proc-monitor.c
index 799054b..5ae3008 100644 (file)
 #include "trace.h"
 #include "edbus-handler.h"
 #include "proc-process.h"
+#include "lowmem-handler.h"
+#include "notifier.h"
+
+#include <journal/system.h>
 
 #define WATCHDOG_LAUNCHING_PARAM "WatchdogPopupLaunch"
 #define WATCHDOG_KEY1                  "_SYSPOPUP_CONTENT_"
 #define SIGNAL_PROC_WATCHDOG_RESULT    "WatchdogResult"
 #define SIGNAL_PROC_ACTIVE             "Active"
 #define SIGNAL_PROC_EXCLUDE            "ProcExclude"
+#define SIGNAL_PROC_PRELAUNCH          "ProcPrelaunch"
 #define SIGNAL_PROC_STATUS             "ProcStatus"
+#define SIGNAL_PROC_SWEEP              "ProcSweep"
+#define SIGNAL_PROC_WATCHDOG           "ProcWatchdog"
+#define SIGNAL_PROC_GROUP              "ProcGroup"
+#define TIZEN_DEBUG_MODE_FILE   "/opt/etc/.debugmode"
+
+
+#define INIT_PID       1
+#define INIT_PROC_VAL  -1
 
 static int proc_watchdog_state;
 static int proc_dbus_proc_state;
+int current_lcd_state;
+
+static Ecore_Timer *watchdog_check_timer = NULL;
+#define WATCHDOG_TIMER_INTERVAL                90
 
 /*
  * Callback function executed by edbus 'Signal' method call. Extracts
@@ -80,6 +97,14 @@ enum proc_status_type { /** cgroup command type **/
        PROC_STATUS_BACKGRD,
 };
 
+static int check_debugenable(void)
+{
+       if (access(TIZEN_DEBUG_MODE_FILE, F_OK) == 0)
+               return 1;
+       else
+               return 0;
+}
+
 void proc_set_watchdog_state(int state)
 {
        proc_watchdog_state = state;
@@ -97,7 +122,6 @@ static void proc_dbus_active_signal_handler(void *data, DBusMessage *msg)
        char *str;
        pid_t pid;
 
-       _D("call dbus_proc_active_signal_handler");
        ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_ACTIVE);
        if (ret == 0) {
                _D("there is no active signal");
@@ -117,7 +141,7 @@ static void proc_dbus_active_signal_handler(void *data, DBusMessage *msg)
                type = PROC_CGROUP_SET_INACTIVE;
        else
                return;
-       resourced_proc_status_change(type, pid, NULL);
+       resourced_proc_status_change(type, pid, NULL, NULL);
 }
 
 int proc_get_dbus_proc_state(void)
@@ -171,8 +195,8 @@ static void proc_dbus_proc_signal_handler(void *data, DBusMessage *msg)
        default:
                return;
        }
-       _D("call dbus_proc_active_signal_handler : pid = %d, type = %d", pid, convert);
-       resourced_proc_status_change(convert, pid, NULL);
+       _D("call proc_dbus_proc_signal_handler : pid = %d, type = %d", pid, convert);
+       resourced_proc_status_change(convert, pid, NULL, NULL);
 }
 
 static void proc_dbus_exclude_signal_handler(void *data, DBusMessage *msg)
@@ -182,7 +206,6 @@ static void proc_dbus_exclude_signal_handler(void *data, DBusMessage *msg)
        char *str;
        pid_t pid;
 
-       _D("call dbus_proc_active_signal_handler");
        ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_EXCLUDE);
        if (ret == 0) {
                _D("there is no active signal");
@@ -196,7 +219,71 @@ static void proc_dbus_exclude_signal_handler(void *data, DBusMessage *msg)
                return;
        }
 
-       return;
+       _D("call proc_dbus_exclude_signal_handler : pid = %d, str = %s", pid, str);
+       if (!strcmp(str, "exclude"))
+               proc_set_runtime_exclude_list(pid, PROC_EXCLUDE);
+       else if (!strcmp(str, "include"))
+               proc_set_runtime_exclude_list(pid, PROC_INCLUDE);
+       else
+               return;
+}
+
+static void proc_dbus_prelaunch_signal_handler(void *data, DBusMessage *msg)
+{
+       DBusError err;
+       int ret;
+       char *appid;
+       char *pkgid;
+       int flags;
+
+       ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS,
+               SIGNAL_PROC_PRELAUNCH);
+       if (ret == 0) {
+               _D("there is no prelaunch signal");
+               return;
+       }
+
+       dbus_error_init(&err);
+
+       if (dbus_message_get_args(msg, &err,
+               DBUS_TYPE_STRING, &appid,
+               DBUS_TYPE_STRING, &pkgid,
+               DBUS_TYPE_INT32, &flags, DBUS_TYPE_INVALID) == 0) {
+               _D("there is no message");
+               return;
+       }
+
+       _D("call proc_dbus_prelaunch_handler: appid = %s, pkgid = %s, flags = %d",
+               appid, pkgid, flags);
+
+       if (flags & PROC_LARGE_HEAP) {
+               proc_set_apptype(appid, pkgid, PROC_LARGE_HEAP);
+               lowmem_dynamic_process_killer(DYNAMIC_KILL_LARGEHEAP);
+       }
+}
+
+static void proc_dbus_sweep_signal_handler(void *data, DBusMessage *msg)
+{
+       DBusError err;
+       int ret;
+
+       ret = dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS,
+               SIGNAL_PROC_SWEEP);
+
+       if (ret == 0) {
+               _D("there is no sweep signal");
+               return;
+       }
+
+       dbus_error_init(&err);
+       proc_sweep_memory(PROC_SWEEP_INCLUDE_ACTIVE, INIT_PID);
+}
+
+static Eina_Bool check_watchdog_cb(void *data)
+{
+       ecore_timer_del(watchdog_check_timer);
+       watchdog_check_timer = NULL;
+       return ECORE_CALLBACK_CANCEL;
 }
 
 static void proc_dbus_watchdog_result(void *data, DBusMessage *msg)
@@ -217,8 +304,13 @@ static void proc_dbus_watchdog_result(void *data, DBusMessage *msg)
        }
 
        if (type == 1) {
-               if (proc_watchdog.signum == SIGTERM || proc_watchdog.signum == SIGKILL)
+               if (proc_watchdog.signum == SIGTERM || proc_watchdog.signum == SIGKILL) {
                        kill(proc_watchdog.pid, SIGABRT);
+                       if (watchdog_check_timer == NULL) {
+                               watchdog_check_timer =
+                                       ecore_timer_add(WATCHDOG_TIMER_INTERVAL, check_watchdog_cb, (void *)NULL);
+                       }
+               }
                else
                        _E("ERROR: Unsupported signal type!");
        }
@@ -268,6 +360,95 @@ static int proc_dbus_show_popup(const char *value)
        return ret_val;
 }
 
+static void proc_dbus_watchdog_handler(void *data, DBusMessage *msg)
+{
+       DBusError err;
+       int pid, command, ret;
+       char appname[PROC_NAME_MAX];
+
+       if (dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_WATCHDOG) == 0) {
+               _D("there is no watchdog result signal");
+               return;
+       }
+
+       dbus_error_init(&err);
+
+       ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INT32,
+               &command, DBUS_TYPE_INVALID);
+
+       if (ret == 0) {
+               _D("there is no message");
+               return;
+       }
+
+       ret = proc_get_cmdline(pid, appname);
+       if (ret != RESOURCED_ERROR_NONE) {
+               _E("ERROR : invalid pid(%d)", pid);
+               return;
+       }
+
+       if (proc_watchdog.pid != INIT_PROC_VAL) {
+               _E("pid %d(%s) has already received watchdog siganl", pid, appname);
+               return;
+       }
+       ret = resourced_proc_excluded(appname);
+       if (ret == RESOURCED_ERROR_NONMONITOR)
+               return;
+
+       if (current_lcd_state == LCD_STATE_OFF) {
+               _E("Receive watchdog signal to pid: %d(%s) but don't show ANR popup in LCD off state\n", pid, appname);
+               return;
+       }
+
+       _E("Receive watchdog signal to pid: %d(%s)\n", pid, appname);
+       journal_system_anr(appname);
+       if (watchdog_check_timer) {
+               _E("current killing watchdog process. so skipped kill %d(%s)\n", pid, appname);
+               return;
+       }
+
+       if (check_debugenable()) {
+               _E("just kill watchdog process when debug enabled pid: %d(%s)\n", pid, appname);
+               kill(pid, SIGABRT);
+               if (watchdog_check_timer == NULL) {
+                       watchdog_check_timer =
+                               ecore_timer_add(WATCHDOG_TIMER_INTERVAL, check_watchdog_cb, (void *)NULL);
+       }
+       }
+       else {
+               ret = proc_dbus_show_popup(appname);
+               if (ret < 0)
+                       _E("ERROR : request_to_launch_by_dbus()failed : %d", ret);
+               else {
+                       proc_watchdog.pid = pid;
+                       proc_watchdog.signum = command;
+               }
+       }
+}
+
+static void proc_dbus_grouping_handler(void *data, DBusMessage *msg)
+{
+       DBusError err;
+       int pid, childpid, ret;
+
+       if (dbus_message_is_signal(msg, RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_GROUP) == 0) {
+               _D("there is no watchdog result signal");
+               return;
+       }
+
+       dbus_error_init(&err);
+
+       ret = dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INT32,
+               &childpid, DBUS_TYPE_INVALID);
+
+       if (ret == 0) {
+               _D("there is no message");
+               return;
+       }
+
+       proc_set_group(pid, childpid);
+}
+
 static DBusMessage *edbus_signal_trigger(E_DBus_Object *obj, DBusMessage *msg)
 {
        DBusMessage *reply;
@@ -304,26 +485,80 @@ static DBusMessage *edbus_signal_trigger(E_DBus_Object *obj, DBusMessage *msg)
        return reply;
 }
 
+static void proc_dbus_lcd_on(void *data, DBusMessage *msg)
+{
+       DBusError err;
+       dbus_error_init(&err);
+
+       if (dbus_message_is_signal(msg, DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_ON) == 0) {
+               _D("there is no lcd on signal");
+               return;
+       }
+       dbus_error_free(&err);
+       current_lcd_state = LCD_STATE_ON;
+       resourced_notify(RESOURCED_NOTIFIER_LCD_ON, NULL);
+       /* nothing */
+}
+
+static void proc_dbus_lcd_off(void *data, DBusMessage *msg)
+{
+       DBusError err;
+
+       dbus_error_init(&err);
+       if (dbus_message_is_signal(msg, DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_OFF) == 0) {
+               _D("there is no lcd on signal");
+               return;
+       }
+
+       dbus_error_free(&err);
+       current_lcd_state = LCD_STATE_OFF;
+       resourced_notify(RESOURCED_NOTIFIER_LCD_OFF, NULL);
+}
+
+
 static resourced_ret_c proc_dbus_init(void)
 {
-       int ret;
        register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
                        SIGNAL_PROC_WATCHDOG_RESULT,
                    proc_dbus_watchdog_result);
 
-       ret = register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
+       register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
                        SIGNAL_PROC_ACTIVE,
                    proc_dbus_active_signal_handler);
 
-       ret = register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
+       register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
                        SIGNAL_PROC_EXCLUDE,
                    proc_dbus_exclude_signal_handler);
 
-       ret = register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
+       register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
+                       SIGNAL_PROC_PRELAUNCH,
+                   proc_dbus_prelaunch_signal_handler);
+
+       register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
                        SIGNAL_PROC_STATUS,
                    proc_dbus_proc_signal_handler);
 
-       _D("register_edbus_signal_handler: %d\n", ret);
+       register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
+                       SIGNAL_PROC_SWEEP,
+                   proc_dbus_sweep_signal_handler);
+
+       register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
+                       SIGNAL_PROC_WATCHDOG,
+                   proc_dbus_watchdog_handler);
+
+       register_edbus_signal_handler(RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
+                       SIGNAL_PROC_WATCHDOG,
+                   proc_dbus_grouping_handler);
+
+       register_edbus_signal_handler(DEVICED_PATH_DISPLAY,
+                   DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_ON, proc_dbus_lcd_on);
+
+       register_edbus_signal_handler(DEVICED_PATH_DISPLAY,
+                   DEVICED_INTERFACE_DISPLAY, SIGNAL_LCD_OFF, proc_dbus_lcd_off);
+
+       /* start watchdog check timer for preveting ANR during booting */
+       watchdog_check_timer =
+               ecore_timer_add(WATCHDOG_TIMER_INTERVAL, check_watchdog_cb, (void *)NULL);
 
        return edbus_add_methods(RESOURCED_PATH_PROCESS, edbus_methods,
                          ARRAY_SIZE(edbus_methods));