proc: introduce watchdog handler 02/197702/2
authorByungSoo Kim <bs1770.kim@samsung.com>
Mon, 6 Aug 2018 11:01:10 +0000 (20:01 +0900)
committerŁukasz Stelmach <l.stelmach@samsung.com>
Thu, 24 Jan 2019 15:55:21 +0000 (16:55 +0100)
It is new management to trigger watchdog.
Anyone sends dbus signal to register, start and stop the watchdog.
Resourced will make the watchdog timer with gslist.
And it also considers freezer, device suspend and application lifecycle.

Change-Id: Ib9bae3e02e7d156505e10835b8bb7ce3a3932f9a
Signed-off-by: ByungSoo Kim <bs1770.kim@samsung.com>
Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
resourced.conf
src/CMakeLists.txt
src/common/dbus-handler.h
src/proc-stat/proc-watchdog.c [new file with mode: 0644]

index 6f9901f..ba4c2e0 100644 (file)
@@ -30,5 +30,9 @@
                send_interface="org.tizen.resourced.process"
                send_member="ProcSweep"
                privilege="http://tizen.org/privilege/systemsettings.admin"/>
+        <check send_destination="org.tizen.resourced"
+               send_interface="org.tizen.resourced.watchdog"
+               send_member="Start"
+               privilege="http://tizen.org/privilege/systemmonitor"/>
     </policy>
 </busconfig>
index c1a01aa..b933d91 100644 (file)
@@ -45,6 +45,7 @@ SET(SOURCES
   ${PROC-STAT_SOURCE_DIR}/proc-usage-stats-helper.c
   ${PROC-STAT_SOURCE_DIR}/proc-appusage.c
   ${PROC-STAT_SOURCE_DIR}/proc-priority.c
+  ${PROC-STAT_SOURCE_DIR}/proc-watchdog.c
   ${RESOURCED_SOURCE_DIR}/init.c
   ${RESOURCED_SOURCE_DIR}/main.c
   ${COMMON_SOURCE_DIR}/procfs.c
index 0af7cc8..1c507a7 100644 (file)
@@ -105,6 +105,9 @@ struct d_bus_signal {
 #define RESOURCED_PATH_DBUS             RESOURCED_DBUS_OBJECT_PATH"/DBus"
 #define RESOURCED_INTERFACE_DBUS        RESOURCED_DBUS_INTERFACE_NAME".dbus"
 
+#define RESOURCED_PATH_WATCHDOG         RESOURCED_DBUS_OBJECT_PATH"/Watchdog"
+#define RESOURCED_INTERFACE_WATCHDOG    RESOURCED_DBUS_INTERFACE_NAME".watchdog"
+
 #define SIGNAL_PROC_WATCHDOG_RESULT     "WatchdogResult"
 #define SIGNAL_PROC_ACTIVE              "Active"
 #define SIGNAL_PROC_EXCLUDE             "ProcExclude"
@@ -176,6 +179,8 @@ struct d_bus_signal {
 #define SIGNAL_DEVICED_SYSTEMTIME_CHANGED  "SystemTimeChanged"
 #define SIGNAL_DEVICED_LOW_BATTERY                "BatteryStatusLow"
 #define SIGNAL_DEVICED_EARLY_BOOTING_DONE  "EarlyBootingDone"
+#define SIGNAL_DEVICED_SUSPEND             "sleep"
+#define SIGNAL_DEVICED_WAKEUP              "wakeup"
 
 /*
  * dump service
diff --git a/src/proc-stat/proc-watchdog.c b/src/proc-stat/proc-watchdog.c
new file mode 100644 (file)
index 0000000..b30d9ae
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+
+ * 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)
+