--- /dev/null
+/*
+
+ * resourced
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * @file proc-monitor.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <stdlib.h>
+
+#include "proc-main.h"
+#include "resourced.h"
+#include "macro.h"
+#include "trace.h"
+#include "dbus-handler.h"
+#include "freezer.h"
+#include "notifier.h"
+
+enum watchdog_control_type {
+ SET_FOREGRD,
+ SET_BACKGRD,
+};
+
+static GSList *watchdog_app_list;
+
+struct watchdog_app_info {
+ pid_t pid;
+ unsigned int watchdog_timeout;
+ GSource *watchdog_timer;
+};
+
+struct watchdog_app_info *find_watchdog_info(const pid_t pid)
+{
+ GSList *iter = NULL;
+ struct watchdog_app_info *wai = NULL;
+
+ if (!watchdog_app_list)
+ return NULL;
+
+ gslist_for_each_item(iter, watchdog_app_list) {
+ wai = (struct watchdog_app_info *)iter->data;
+ if (wai->pid == pid)
+ return wai;
+ }
+ return NULL;
+}
+
+static gboolean watchdog_cb(gpointer data)
+{
+ struct watchdog_app_info *wai = (struct watchdog_app_info *)data;
+ GDBusConnection *conn;
+ GError *err = NULL;
+
+ if (!watchdog_app_list || !wai)
+ return false;
+
+ if (!g_slist_find(watchdog_app_list, wai))
+ return false;
+
+ if (kill(wai->pid, 0) == -1) {
+ _I("%d process doesn't exit, remove watchdog handler", wai->pid);
+ watchdog_app_list = g_slist_remove(watchdog_app_list, wai);
+ free(wai);
+ return false;
+ }
+
+ wai->watchdog_timer = NULL;
+ conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+ if (!conn)
+ return false;
+
+ _I("detect watchdog for pid %d with timeout %u", wai->pid, wai->watchdog_timeout);
+ g_dbus_connection_emit_signal(conn, NULL, RESOURCED_PATH_PROCESS,
+ RESOURCED_INTERFACE_PROCESS, SIGNAL_PROC_WATCHDOG,
+ g_variant_new("(ii)", wai->pid, SIGKILL), &err);
+
+ return false;
+}
+
+static void proc_update_watchdog(struct watchdog_app_info *wai, unsigned int timeout)
+{
+ if (wai->watchdog_timer) {
+ g_source_destroy(wai->watchdog_timer);
+ wai->watchdog_timer = NULL;
+ _D("delete previous watchdog timer for pid %d", wai->pid);
+ }
+
+ if (timeout) {
+ wai->watchdog_timeout = timeout;
+ wai->watchdog_timer = g_timeout_source_new_seconds(wai->watchdog_timeout);
+ g_source_set_callback(wai->watchdog_timer, watchdog_cb, (gpointer)wai, NULL);
+ g_source_attach(wai->watchdog_timer, NULL);
+ _D("restart watchdog timer for pid %d with timeout %u", wai->pid, timeout);
+ }
+}
+
+static void proc_argos_watchdog_handler(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int pid = -1;
+ unsigned int timeout = 0;
+ struct watchdog_app_info *wai;
+
+ _D("receive watchdog dbus");
+ g_variant_get(params, "(iu)", &pid, &timeout);
+ if (pid < 0) {
+ _E("there is no message");
+ return;
+ }
+
+ wai = find_watchdog_info(pid);
+ if (!wai) {
+ wai = calloc(sizeof(struct watchdog_app_info), 1);
+ if (!wai)
+ return;
+
+ wai->pid = pid;
+ watchdog_app_list = g_slist_prepend(watchdog_app_list, wai);
+ _D("create new watchdog handler for pid %d", pid);
+ }
+
+ proc_update_watchdog(wai, timeout);
+}
+
+static void proc_watchdog_wakeup(GVariant *params)
+{
+ GSList *iter = NULL;
+ struct watchdog_app_info *wai = NULL;
+
+ if (!watchdog_app_list)
+ return;
+
+ gslist_for_each_item(iter, watchdog_app_list) {
+ wai = (struct watchdog_app_info *)iter->data;
+ proc_update_watchdog(wai, wai->watchdog_timeout);
+ }
+}
+
+static void proc_watchdog_suspend(GVariant *params)
+{
+ int pid = -1, type = -1;
+ unsigned int timeout = 0;
+ struct watchdog_app_info *wai;
+
+ g_variant_get(params, "(ii)", &type, &pid);
+ if (pid < 0 || type < 0)
+ return;
+
+ wai = find_watchdog_info(pid);
+ if (!wai)
+ return;
+
+ timeout = (type == SET_BACKGRD) ? 0 : wai->watchdog_timeout;
+ proc_update_watchdog(wai, timeout);
+}
+
+static void proc_watchdog_freeze(GVariant *params)
+{
+ GSList *iter = NULL;
+ struct watchdog_app_info *wai = NULL;
+
+ if (!watchdog_app_list)
+ return;
+
+ gslist_for_each_item(iter, watchdog_app_list) {
+ wai = (struct watchdog_app_info *)iter->data;
+ proc_update_watchdog(wai, 0);
+ }
+}
+
+static int watchdog_app_terminated_cb(void *data)
+{
+ struct proc_status *ps = (struct proc_status *)data;
+ struct watchdog_app_info *wai;
+
+ if (!ps || !ps->pid)
+ return RESOURCED_ERROR_FAIL;
+
+ wai = find_watchdog_info(ps->pid);
+ if (!wai)
+ return RESOURCED_ERROR_NO_DATA;
+
+ proc_update_watchdog(wai, 0);
+ watchdog_app_list = g_slist_remove(watchdog_app_list, wai);
+ free(wai);
+
+ return RESOURCED_ERROR_NONE;
+}
+
+static const char dbus_methods_xml[] =
+"<node>"
+" <interface name='"RESOURCED_INTERFACE_WATCHDOG"'>"
+" <method name='Start'>"
+" <arg type='i' name='Pid' direction='in'/>"
+" <arg type='u' name='Timeout' direction='in'/>"
+" </method>"
+" </interface>"
+"</node>";
+
+static struct d_bus_method dbus_methods[] = {
+ { "Start", proc_argos_watchdog_handler },
+ /* Add methods here */
+};
+
+static const struct d_bus_signal dbus_signals[] = {
+ /* RESOURCED DBUS */
+ {DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ SIGNAL_DEVICED_WAKEUP, proc_watchdog_wakeup, NULL},
+ {DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ SIGNAL_DEVICED_SUSPEND, proc_watchdog_suspend, NULL},
+ {RESOURCED_PATH_FREEZER, RESOURCED_INTERFACE_FREEZER,
+ SIGNAL_FREEZER_STATE, proc_watchdog_freeze, NULL},
+};
+
+static int proc_watchdog_init(void *data)
+{
+ register_notifier(RESOURCED_NOTIFIER_APP_TERMINATED,
+ watchdog_app_terminated_cb);
+
+ d_bus_register_signals(dbus_signals, ARRAY_SIZE(dbus_signals));
+ return d_bus_register_methods(RESOURCED_PATH_WATCHDOG, dbus_methods_xml,
+ dbus_methods, ARRAY_SIZE(dbus_methods));
+}
+
+static int proc_watchdog_exit(void *data)
+{
+ unregister_notifier(RESOURCED_NOTIFIER_APP_TERMINATED,
+ watchdog_app_terminated_cb);
+ return RESOURCED_ERROR_NONE;
+}
+
+static const struct proc_module_ops proc_watchdog_ops = {
+ .name = "PROC_WATCHDOG",
+ .init = proc_watchdog_init,
+ .exit = proc_watchdog_exit,
+};
+PROC_MODULE_REGISTER(&proc_watchdog_ops)
+