#process
SET(PROCESS_SOURCE_DIR ${SOURCE_DIR}/process)
-SET(VIP_SOURCE_DIR ${PROCESS_SOURCE_DIR}/vip)
SET(BLOCK_SOURCE_DIR ${PROCESS_SOURCE_DIR}/block)
SET(WATCHDOG_SOURCE_DIR ${PROCESS_SOURCE_DIR}/watchdog)
SET(PRIORITY_SOURCE_DIR ${PROCESS_SOURCE_DIR}/priority)
[APPUSAGE]
APPUSAGE=ON
-[WATCHDOG_EXCLUDED_PROCESSES]
+[WatchdogExcludedApps]
PREDEFINE=indicator-win
PREDEFINE=lockscreen
PREDEFINE=quickpanel
# Notice : to use freezer module, you should install system-freezer plugin
%define cpu_module ON
%define memory_module ON
-%define vip_agent_module ON
+%define watchdog_module ON
%define compaction_module ON
%define confdir %{_sysconfdir}/resourced
Requires: %{_sbindir}/mkswap
Requires: %{_bindir}/dd
-%if %{?vip_agent_module} == ON
-Requires: %{name}-vip-release-agent = %{version}-%{release}
+%if %{?watchdog_module} == ON
+Requires: %{name}-watchdog-handler = %{version}-%{release}
%endif
Requires: %{name}-bin = %{version}-%{release}
Summary: Resourced light binary
Requires: %{name}-bin = %{version}-%{release}
Requires: %{name}-config = %{version}-%{release}
-%if %{?vip_agent_module} == ON
-Requires: %{name}-vip-release-agent = %{version}-%{release}
+%if %{?watchdog_module} == ON
+Requires: %{name}-watchdog-handler = %{version}-%{release}
%endif
%description light
Requires: %{name}-bin
%description tests
-%if %{?vip_agent_module} == ON
-%package vip-release-agent
-Summary: vip-release-agent module for resourced
-%description vip-release-agent
+%if %{?watchdog_module} == ON
+%package watchdog-handler
+Summary: watchdog module for resourced
+%description watchdog-handler
%endif
%prep
-DCPU_MODULE=%{cpu_module} \
-DMEMORY_MODULE=%{memory_module} \
-DCOMPACTION_MODULE=%{compaction_module} \
- -DVIP_AGENT=%{vip_agent_module} \
+ -DPROC_WATCHDOG=%{watchdog_module} \
-DRD_SYS_ETC=%{TZ_SYS_ETC} \
-DRD_SYS_DATA=%{TZ_SYS_GLOBALUSER_DATA} \
-DRD_SYS_DB=%{TZ_SYS_GLOBALUSER_DB} \
%manifest resourced.manifest
%{confdir}/configs/config-limiter-profile-iot-headless.conf
-%if %{?vip_agent_module} == ON
-%files vip-release-agent
+%if %{?watchdog_module} == ON
+%files watchdog-handler
%license LICENSE
%manifest resourced.manifest
-%attr(700,root, root) %{_bindir}/vip-release-agent
+%attr(700,root, root) %{_bindir}/resourced-watchdog-handler
%endif
%files light
kernel doesn't have any SMACK label on its own,
such processes get the default SMACK label which
doesn't confer the needed privilege. -->
- <filesystem path="/usr/bin/vip-release-agent" label="System" exec_label="System"/>
+ <filesystem path="/usr/bin/resourced-watchdog-handler" label="System" exec_label="System"/>
</assign>
</manifest>
FILE(GLOB FILES "${PRIORITY_SOURCE_DIR}/*.c")
SET(RESOURCED_SHARED_SOURCES ${RESOURCED_SHARED_SOURCES} ${FILES})
-FILE(GLOB FILES "${VIP_SOURCE_DIR}/*.c")
-SET(RESOURCED_SHARED_SOURCES ${RESOURCED_SHARED_SOURCES} ${FILES})
-
FILE(GLOB FILES "${COMMON_SOURCE_DIR}/*.c")
SET(RESOURCED_SHARED_SOURCES ${RESOURCED_SHARED_SOURCES} ${FILES})
ENDFOREACH()
ENDIF()
-IF("${VIP_AGENT}" STREQUAL "ON")
+IF("${PROC_WATCHDOG}" STREQUAL "ON")
SET(SOURCES ${SOURCES}
- ${VIP_SOURCE_DIR}/vip-process.c
+ ${WATCHDOG_SOURCE_DIR}/proc-watchdog.c
)
ENDIF()
INSTALL(FILES ${CONF_DIR}/limiter-profile-iot-headless.conf DESTINATION ${RD_CONFIG_PATH})
ENDIF()
-IF("${VIP_AGENT}" STREQUAL "ON")
+IF("${PROC_WATCHDOG}" STREQUAL "ON")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall -fPIE")
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie")
- ADD_EXECUTABLE(vip-release-agent ${VIP_SOURCE_DIR}/vip-release-agent.c)
- TARGET_LINK_LIBRARIES(vip-release-agent resourced-private-api dlog)
- INSTALL(TARGETS vip-release-agent DESTINATION bin)
+ ADD_EXECUTABLE(resourced-watchdog-handler ${WATCHDOG_SOURCE_DIR}/proc-watchdog-handler.c)
+ TARGET_LINK_LIBRARIES(resourced-watchdog-handler resourced-private-api dlog)
+ INSTALL(TARGETS resourced-watchdog-handler DESTINATION bin)
ENDIF()
INSTALL(FILES ${CONF_DIR}/process.conf
#include "cgroup.h"
#include "memory-cgroup.h"
+#include "watchdog-cgroup.h"
#include "const.h"
#include "macro.h"
#include "util.h"
#include <unistd.h>
#include <sys/mount.h>
-#define RELEASE_AGENT "release_agent"
-#define NOTIFY_ON_RELEASE "notify_on_release"
-
-
#define MAKE_NAME(name) CGROUP_##name##_NAME
#define cgroup_name_cpy(dst, src, length) \
do { \
*
*/
+/*
+ * Cgroup creation interface
+ */
+
+#ifndef _CGROUP_LIBRARY_CGROUP_H_
+#define _CGROUP_LIBRARY_CGROUP_H_
+
#include <assert.h>
#include <string.h>
#include <resourced.h>
#include "const.h"
#include "macro.h"
-/*
- * Cgroup creation interface
- */
-
-#ifndef _CGROUP_LIBRARY_CGROUP_H_
-#define _CGROUP_LIBRARY_CGROUP_H_
-
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern "C" {
#endif /* __cplusplus */
-#define CPUCG_PATH CGROUP_PATH "/cpu"
+#define CPUCG_NAME "cpu"
+#define CPUCG_PATH CGROUP_PATH "/" CPUCG_NAME
#define CPUCG_VIP_PATH CPUCG_PATH "/" CGROUP_VIP_NAME
#define CPUCG_HIGH_PATH CPUCG_PATH "/" CGROUP_VIP_NAME "/" CGROUP_HIGH_NAME
#define CPUCG_MEDIUM_PATH CPUCG_PATH "/" CGROUP_VIP_NAME "/" CGROUP_HIGH_NAME "/" CGROUP_MEDIUM_NAME
#define MEMCG_MEDIUM_RATIO 0.96
#define MEMCG_FOREGROUND_LEAVE_RATIO 0.25
-#define MEMCG_PATH CGROUP_PATH "/memory"
+#define MEMCG_NAME "memory"
+#define MEMCG_PATH CGROUP_PATH "/" MEMCG_NAME
#define MEMCG_VIP_PATH MEMCG_PATH "/" CGROUP_VIP_NAME
#define MEMCG_HIGH_PATH MEMCG_PATH "/" CGROUP_VIP_NAME "/" CGROUP_HIGH_NAME
#define MEMCG_MEDIUM_PATH MEMCG_PATH "/" CGROUP_VIP_NAME "/" CGROUP_HIGH_NAME "/" CGROUP_MEDIUM_NAME
--- /dev/null
+#ifndef __WATCHDOG_CGROUP_H__
+#define __WATCHDOG_CGROUP_H__
+
+#include "cgroup.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define RELEASE_AGENT "release_agent"
+#define NOTIFY_ON_RELEASE "notify_on_release"
+#define CHECK_RELEASE_PROGRESS "/tmp/.release_ongoing"
+
+#define PROC_WATCHDOG_HANDLER_PATH "/usr/bin/resourced-watchdog-handler"
+#define PROC_WATCHDOGCG_NAME "watchdog"
+#define PROC_WATCHDOGCG_PATH CGROUP_PATH "/" PROC_WATCHDOGCG_NAME
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*__WATCHDOG_CGROUP_H__*/
extern "C" {
#endif /* __cplusplus */
+#define PER_PROCESS_CONF "PerProcess"
+
#define MATCH(a, b) (!strncmp(a, b, strlen(a) + 1) ? 1 : 0)
#define SET_CONF(a, b) (a = (b > 0.0 ? b : a))
#define SIGNAL_PROC_EXCLUDE "ProcExclude"
#define SIGNAL_PROC_PRELAUNCH "ProcPrelaunch"
#define SIGNAL_PROC_SWEEP "ProcSweep"
-#define SIGNAL_PROC_WATCHDOG "ProcWatchdog"
+#define SIGNAL_APP_WATCHDOG "AppWatchdog"
#define SIGNAL_PROC_SYSTEMSERVICE "SystemService"
#define SIGNAL_PROC_EXCLUDEAPPID "ProcExcludeByAppid"
#define SIGNAL_PROC_SET_PRIORITY "ProcSetPriority"
PROC_WEBAPP = 0x04u, /* for checking webapp */
PROC_DOWNLOADAPP = 0x08u, /* for monitoring disk usage about downloadable app */
PROC_SERVICEAPP = 0x10u, /* for distinguishing service app and ui app */
- PROC_VIP_ATTRIBUTE = 0x20u, /* for giving VIP attribute about MDM app */
+ PROC_CGROUP_HIGH_ATTRIBUTE = 0x20u, /* for providing High level about MDM app */
PROC_BGALLOW = 0x100u, /* for allowing background application */
PROC_BGCTRL_PLATFORM = 0x200u, /* for controlling background application by appfw */
PROC_BGCTRL_APP = 0x400u, /* for checking old version application */
char *appid;
pid_t main_pid;
pid_list childs;
- int watchdog_exclude;
+ int app_watchdog_exclude;
int runtime_exclude;
int flags;
int lru_state;
#endif
#endif
-#define WATCHDOG_EXCLUDE_CONF_FILE RD_CONFIG_FILE(process)
-#define WATCHDOG_EXCLUDE_CONF_SECTION "WATCHDOG_EXCLUDED_PROCESSES"
+#define APP_WATCHDOG_EXCLUDE_CONF_FILE RD_CONFIG_FILE(process)
+#define APP_WATCHDOG_EXCLUDE_CONF_SECTION "WatchdogExcludedApps"
-static GHashTable *watchdog_exclude_list;
+static GHashTable *app_watchdog_exclude_list;
static const struct module_ops *freezer;
static GSList *proc_module; /* proc sub-module list */
int oom_score_adj = 0;
if (pai) {
- if (CHECK_BIT(pai->flags, PROC_VIP_ATTRIBUTE))
+ if (CHECK_BIT(pai->flags, PROC_CGROUP_HIGH_ATTRIBUTE))
oom_score_adj = OOMADJ_SU;
else {
retval = proc_get_oom_score_adj(pai->main_pid, &oom_score_adj);
pai->appid = pai->ai->appid;
- pai->watchdog_exclude = resourced_watchdog_excluded(appid);
+ pai->app_watchdog_exclude = resourced_app_watchdog_excluded(appid);
pai->type = type;
pai->state = state;
continue;
LOG_DUMP(fp, "index : %d, type : %d, pkgname : %s, appid : %s\n"
- "\t lru : %d, watchdog_exclude : %d, runtime_exclude : %d, flags : %X, "
+ "\t lru : %d, app watchdog_exclude : %d, runtime_exclude : %d, flags : %X, "
"state : %d\n", index, pai->type, pai->ai->pkgname, pai->ai->appid,
- pai->lru_state, pai->watchdog_exclude, pai->runtime_exclude,
+ pai->lru_state, pai->app_watchdog_exclude, pai->runtime_exclude,
pai->flags, pai->state);
if (proc_get_mem_usage(pai->main_pid, &size))
}
}
-static void proc_free_watchdog_exclude_key(gpointer data)
+static void proc_free_app_watchdog_exclude_key(gpointer data)
{
if (data)
free(data);
return pai->appid;
}
-int resourced_watchdog_excluded(const char *app_name)
+int resourced_app_watchdog_excluded(const char *app_name)
{
gboolean ret = 0;
- if (watchdog_exclude_list)
- ret = g_hash_table_contains(watchdog_exclude_list, (gpointer)app_name);
+ if (app_watchdog_exclude_list)
+ ret = g_hash_table_contains(app_watchdog_exclude_list, (gpointer)app_name);
return ret ? RESOURCED_ERROR_NONMONITOR : RESOURCED_ERROR_NONE;
}
-static int load_watchdog_exclude_config(struct parse_result *result, void *user_data)
+static int load_app_watchdog_exclude_config(struct parse_result *result, void *user_data)
{
(void) user_data;
if (!result)
return RESOURCED_ERROR_INVALID_PARAMETER;
- if (!strncmp(result->section, WATCHDOG_EXCLUDE_CONF_SECTION, strlen(WATCHDOG_EXCLUDE_CONF_SECTION) + 1) &&
+ if (!strncmp(result->section, APP_WATCHDOG_EXCLUDE_CONF_SECTION,
+ strlen(APP_WATCHDOG_EXCLUDE_CONF_SECTION) + 1) &&
!strncmp(result->name, "PREDEFINE", 10)) {
- g_hash_table_insert(watchdog_exclude_list,
+ _I("[WATCHDOG] app (%s) is excluded from the watchdog list", result->value);
+ g_hash_table_insert(app_watchdog_exclude_list,
g_strndup(result->value, strlen(result->value)),
GINT_TO_POINTER(1));
}
return RESOURCED_ERROR_NONE;
}
-static void watchdog_exclude_init(void)
+static void app_watchdog_exclude_init(void)
{
- watchdog_exclude_list = g_hash_table_new_full(
+ app_watchdog_exclude_list = g_hash_table_new_full(
g_str_hash,
g_str_equal,
- proc_free_watchdog_exclude_key,
+ proc_free_app_watchdog_exclude_key,
NULL);
- if (watchdog_exclude_list == NULL) {
- _E("Can't initialize exclude_list!");
+ if (app_watchdog_exclude_list == NULL) {
+ _E("[WATCHDOG] Can't initialize exclude_list!");
return;
}
- config_parse(WATCHDOG_EXCLUDE_CONF_FILE, load_watchdog_exclude_config, NULL);
+ config_parse(APP_WATCHDOG_EXCLUDE_CONF_FILE, load_app_watchdog_exclude_config, NULL);
}
void proc_module_add(const struct proc_module_ops *ops)
gslist_for_each_item(iter, proc_module) {
module = (struct proc_module_ops *)iter->data;
- _D("Initialize [%s] module\n", module->name);
+ _D("[WATCHDOG] Initialize [%s] module\n", module->name);
if (module->init)
ret = module->init(data);
if (ret != RESOURCED_ERROR_NONE)
return RESOURCED_ERROR_FAIL;
}
- watchdog_exclude_init();
+ app_watchdog_exclude_init();
proc_module_init(data);
return RESOURCED_ERROR_NONE;
}
if (prelaunch)
free(prelaunch);
proc_delete_all_lists();
- g_hash_table_destroy(watchdog_exclude_list);
+ g_hash_table_destroy(app_watchdog_exclude_list);
proc_module_exit(data);
return RESOURCED_ERROR_NONE;
}
else
proc_set_oom_score_adj(pid, OOMADJ_INIT, ps.pai);
- if (CHECK_BIT(ps.pai->flags, PROC_VIP_ATTRIBUTE))
+ if (CHECK_BIT(ps.pai->flags, PROC_CGROUP_HIGH_ATTRIBUTE))
proc_set_oom_score_adj(pid, OOMADJ_SU, ps.pai);
if (ps.pai->categories)
static struct module_ops proc_modules_ops = {
.priority = MODULE_PRIORITY_HIGH,
- .name = "PROC",
+ .name = "proc",
.init = resourced_proc_init,
.exit = resourced_proc_exit,
.restore = resourced_proc_restore,
*/
int resourced_proc_action(int type, int argnum, char **arg);
-int resourced_watchdog_excluded(const char *app_name);
+int resourced_app_watchdog_excluded(const char *app_name);
int resourced_proc_status_change(int status, pid_t pid, char* app_name, char* pkg_name, int apptype);
#include "module.h"
#include "util.h"
#include "file-helper.h"
+#include "watchdog-cgroup.h"
#define WATCHDOG_LAUNCHING_PARAM "PopupLaunch"
#define WATCHDOG_KEY1 "_SYSPOPUP_CONTENT_"
static int current_lcd_state;
-static GSource *watchdog_check_timer;
-#define WATCHDOG_TIMER_INTERVAL 10
+static GSource *app_watchdog_check_timer;
+#define APP_WATCHDOG_TIMER_INTERVAL 10
-static struct proc_watchdog_info {
+static struct app_watchdog_info {
pid_t pid;
int signum;
-} proc_watchdog = { -1, -1 };
+} app_watchdog = { -1, -1 };
static void dbus_get_meminfo(GDBusMethodInvocation *invocation, GVariant *params)
{
g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ok ? RESOURCED_ERROR_NONE : RESOURCED_ERROR_FAIL));
}
-static void turn_off_vip_handler()
+static void turn_off_proc_watchdog_handler()
{
/* Set the agent to something harmless. This destroys the previous
* state by losing information about the previous agent, though it's
* way of doing this (iterate over all subdirectories and set their
* `notify_on_release` to 0) is bound to be slower than this. */
static const char AGENT_REPLACEMENT_PATH[] = "/bin/true";
- if (fwrite_str("/sys/fs/cgroup/vip/release_agent", AGENT_REPLACEMENT_PATH) == RESOURCED_ERROR_NONE) {
- _I("disabled VIP release agent by setting to %s", AGENT_REPLACEMENT_PATH);
+ if (fwrite_str(PROC_WATCHDOGCG_PATH "/" RELEASE_AGENT, AGENT_REPLACEMENT_PATH) == RESOURCED_ERROR_NONE) {
+ _I("[DEBUG] disabled release agent by setting to %s", AGENT_REPLACEMENT_PATH);
return;
}
* as now the program does something else than expected but the
* system is shutting down and nobody else should use the agent
* anyway so there isn't much opportunity to cause any surprises. */
- static const char VIP_RELEASE_AGENT_PATH[] = "/usr/bin/vip-release-agent";
- if (!mount(AGENT_REPLACEMENT_PATH, VIP_RELEASE_AGENT_PATH, NULL, MS_BIND | MS_RDONLY, NULL)) {
- _I("disabled VIP release agent by bind mounting %s to %s", AGENT_REPLACEMENT_PATH, VIP_RELEASE_AGENT_PATH);
+ if (!mount(AGENT_REPLACEMENT_PATH, PROC_WATCHDOG_HANDLER_PATH, NULL, MS_BIND | MS_RDONLY, NULL)) {
+ _I("[DEBUG] disabled release agent by bind mounting %s to %s", AGENT_REPLACEMENT_PATH, PROC_WATCHDOG_HANDLER_PATH);
return;
}
- _E("disabling VIP release agent by bind mounting %s to %s failed; VIP release agent is potentially still alive", AGENT_REPLACEMENT_PATH, VIP_RELEASE_AGENT_PATH);
+ _E("[DEBUG] disabling release agent by bind mounting %s to %s failed; release agent is potentially still alive", AGENT_REPLACEMENT_PATH, PROC_WATCHDOG_HANDLER_PATH);
}
-static void turn_off_vip()
+static void turn_off_proc_watchdog()
{
- /* Turn off the "reboot on VIP death" behaviour.
- * It is normal for VIPs to die throughout a poweroff, while it
+ /* Turn off the "reboot on death" behaviour.
+ * It is normal for processes to die throughout a poweroff, while it
* is undesirable for the poweroff to be replaced by a reboot. */
- turn_off_vip_handler();
+ turn_off_proc_watchdog_handler();
- /* Unmounting the VIP cgroup does not make the above redundant because
+ /* Unmounting the release cgroup does not make the above redundant because
* the unmounting can be done lazily and is not guaranteed to take place
* immediately. */
- umount2("/sys/fs/cgroup/vip", MNT_FORCE | MNT_DETACH);
- _I("disabled VIP by unmounting VIP cgroup");
+ umount2(PROC_WATCHDOGCG_PATH, MNT_FORCE | MNT_DETACH);
+ _I("[DEBUG] disabled process by unmounting release cgroup");
}
static void proc_poweroff()
proc_sweep_memory(PROC_SWEEP_EXCLUDE_ACTIVE, INIT_PID);
resourced_notify(RESOURCED_NOTIFIER_POWER_OFF, NULL);
- turn_off_vip();
+ turn_off_proc_watchdog();
}
static void dbus_pre_poweroff(GDBusMethodInvocation *invocation, GVariant *params)
}
appid = pai->appid;
- if (pai->watchdog_exclude || pai->runtime_exclude) {
+ if (pai->app_watchdog_exclude || pai->runtime_exclude) {
_E("application (%d, %s) used %s lock longly but it is excluded", pid, appid, type);
goto response;
}
proc_sweep_memory(PROC_SWEEP_INCLUDE_ACTIVE, INIT_PID);
}
-static gboolean check_watchdog_cb(gpointer data)
+static gboolean check_app_watchdog_cb(gpointer data)
{
int oom_score_adj = 0, ret;
- pid_t pid = proc_watchdog.pid;
+ pid_t pid = app_watchdog.pid;
ret = proc_get_oom_score_adj(pid, &oom_score_adj);
if (!ret) {
- _E("watchdog pid %d not terminated, kill again\n", pid);
+ _E("app watchdog pid %d not terminated, kill again\n", pid);
safe_kill(pid, SIGKILL);
}
- watchdog_check_timer = NULL;
- proc_watchdog.pid = -1;
- proc_watchdog.signum = -1;
+ app_watchdog_check_timer = NULL;
+ app_watchdog.pid = -1;
+ app_watchdog.signum = -1;
return false;
}
return ret_val;
}
-static void proc_dbus_watchdog_handler(GVariant *params)
+static void proc_dbus_app_watchdog_handler(GVariant *params)
{
int ret;
int pid = -1;
do_expr_unless_g_variant_get_typechecked(return, params, "(ii)", &pid, &command);
if (pid < 0 || command < 0) {
- _D("there is no message");
+ _D("[WATCHDOG] there is no message");
return;
}
ret = proc_get_cmdline(pid, appname, sizeof appname);
if (ret != RESOURCED_ERROR_NONE) {
- _E("[DEBUG] ERROR : invalid pid(%d)", pid);
+ _E("[WATCHDOG] ERROR : invalid pid(%d)", pid);
return;
}
- ret = resourced_watchdog_excluded(appname);
- if (ret == RESOURCED_ERROR_NONMONITOR)
+ ret = resourced_app_watchdog_excluded(appname);
+ if (ret == RESOURCED_ERROR_NONMONITOR) {
+ _I("[WATCHDOG] appname (%s), pid (%d) is watchdog excluded app", appname, pid);
return;
+ }
if (current_lcd_state == LCD_STATE_OFF) {
- _E("[DEBUG] Receive watchdog signal to pid: %d(%s) but don't show ANR popup in LCD off state\n", pid, appname);
+ _E("[WATCHDOG] Receive watchdog signal to pid: %d(%s) but don't show ANR popup in LCD off state\n", pid, appname);
return;
}
- _E("[DEBUG] Receive watchdog signal to app %s, pid %d\n", appname, pid);
+ _E("[WATCHDOG] Receive watchdog signal to app %s, pid %d\n", appname, pid);
ps.pai = find_app_info(pid);
ps.pid = pid;
resourced_notify(RESOURCED_NOTIFIER_APP_ANR, &ps);
if (proc_dbus_show_popup(appname) < 0)
- _E("Failed to show ANR popup");
+ _E("[WATCHDOG] Failed to show ANR popup");
- if (watchdog_check_timer) {
- if (proc_watchdog.pid == pid) {
- _E("app %s, pid %d has already received watchdog siganl but not terminated", appname, pid);
+ if (app_watchdog_check_timer) {
+ if (app_watchdog.pid == pid) {
+ _E("[WATCHDOG] app %s, pid %d has already received watchdog siganl but not terminated", appname, pid);
safe_kill(pid, SIGKILL);
- proc_watchdog.pid = -1;
- proc_watchdog.signum = -1;
+ app_watchdog.pid = -1;
+ app_watchdog.signum = -1;
return;
}
}
resourced_proc_status_change(PROC_CGROUP_SET_TERMINATE_REQUEST,
pid, NULL, NULL, PROC_TYPE_NONE);
safe_kill(pid, SIGABRT);
- if (!watchdog_check_timer) {
- watchdog_check_timer = g_timeout_source_new_seconds(WATCHDOG_TIMER_INTERVAL);
- g_source_set_callback(watchdog_check_timer, check_watchdog_cb, NULL, NULL);
- g_source_attach(watchdog_check_timer, NULL);
+ if (!app_watchdog_check_timer) {
+ app_watchdog_check_timer = g_timeout_source_new_seconds(APP_WATCHDOG_TIMER_INTERVAL);
+ g_source_set_callback(app_watchdog_check_timer, check_app_watchdog_cb, NULL, NULL);
+ g_source_attach(app_watchdog_check_timer, NULL);
- proc_watchdog.pid = pid;
- proc_watchdog.signum = command;
+ app_watchdog.pid = pid;
+ app_watchdog.signum = command;
}
}
{RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
SIGNAL_PROC_SWEEP, proc_dbus_sweep_signal_handler, NULL},
{RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
- SIGNAL_PROC_WATCHDOG, proc_dbus_watchdog_handler, NULL},
+ SIGNAL_APP_WATCHDOG, proc_dbus_app_watchdog_handler, NULL},
{RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
SIGNAL_PROC_SYSTEMSERVICE, proc_dbus_systemservice_handler, NULL},
{RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS,
resourced_ret_c ret;
/* start watchdog check timer for preveting ANR during booting */
- watchdog_check_timer = g_timeout_source_new_seconds(WATCHDOG_TIMER_INTERVAL);
- g_source_set_callback(watchdog_check_timer, check_watchdog_cb, NULL, NULL);
- g_source_attach(watchdog_check_timer, NULL);
+ app_watchdog_check_timer = g_timeout_source_new_seconds(APP_WATCHDOG_TIMER_INTERVAL);
+ g_source_set_callback(app_watchdog_check_timer, check_app_watchdog_cb, NULL, NULL);
+ g_source_attach(app_watchdog_check_timer, NULL);
ret = d_bus_register_signals(dbus_signals, ARRAY_SIZE(dbus_signals));
if (ret != RESOURCED_ERROR_NONE)
static int proc_dbus_exit(void *data)
{
- if (watchdog_check_timer)
- g_source_destroy(watchdog_check_timer);
+ if (app_watchdog_check_timer)
+ g_source_destroy(app_watchdog_check_timer);
return RESOURCED_ERROR_NONE;
}
+++ /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.
- *
-*/
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <dirent.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <libsyscommon/list.h>
-
-#include "const.h"
-#include "resourced.h"
-#include "trace.h"
-#include "cgroup.h"
-#include "procfs.h"
-#include "macro.h"
-#include "util.h"
-#include "config-parser.h"
-#include "file-helper.h"
-#include "storage-helper.h"
-#include "notifier.h"
-#include "module.h"
-#include "module-data.h"
-#include "vip-process.h"
-#include "dbus-handler.h"
-
-#define VIP_CONF_DIR "/etc/resourced/vip-process.d"
-#define VIP_CONF_SUFFIX ".conf"
-
-#define SYSTEMD_DBUS_DEST "org.freedesktop.systemd1"
-#define SYSTEMD_DBUS_UNIT_PATH "/org/freedesktop/systemd1/unit/"
-#define SYSTEMD_DBUS_SERVICE_IFACE SYSTEMD_DBUS_DEST".Service"
-#define DBUS_IFACE_DBUS_PROPERTIES "org.freedesktop.DBus.Properties"
-
-#define SYSTEMD_UNIT_ESCAPE_CHAR ".-"
-
-#define BOOT_PARAM_VIP_DISABLED "tizen.vip_reboot_disable"
-
-struct vip_group {
- char name[64];
- GList *service;
- GList *process;
-
- /* options */
- int reboot_on_failure;
-};
-
-static GList *vip_group_list;
-
-/* print log on console */
-static void vip_print_console(const char *format, ...)
-{
- FILE *fp = NULL;
- char buffer[256] = {0, };
- va_list ap;
-
- va_start(ap, format);
- vsnprintf(buffer, sizeof(buffer), format, ap);
- va_end(ap);
-
- fp = fopen("/dev/console", "a");
- if (!fp) {
- _E("%s(failed to print log on console, %m)", buffer);
- return;
- }
-
- _D("%s", buffer);
- fprintf(fp, "%s\n", buffer);
-
- fclose(fp);
-}
-
-static bool vip_boot_param_reboot_disabled(void)
-{
- char cmdline[1024];
- int retval;
-
- retval = proc_get_cmdline(0, cmdline, sizeof(cmdline));
- if (retval != RESOURCED_ERROR_NONE)
- return false;
-
- return (strstr(cmdline, BOOT_PARAM_VIP_DISABLED) != NULL);
-}
-
-/* copy of libsyscommon/libsystemd.c: systemd_get_unit_dbus_path() */
-static int vip_get_escaped_name(const char *unit, char **escaped)
-{
- char *path = NULL;
- int i;
- size_t p, k, prefix_len, unit_len;
- size_t path_len, len, escape;
-
- if (!unit) {
- _E("Invalid parameter.");
- return -EINVAL;
- }
- unit_len = strlen(unit);
-
- for (escape = 0, p = 0; p < unit_len; escape++) {
- k = strcspn(unit + p, SYSTEMD_UNIT_ESCAPE_CHAR);
- if (p + k >= unit_len)
- break;
- p += k+1;
- }
-
- prefix_len = strlen(SYSTEMD_DBUS_UNIT_PATH);
- /* assume we try to get object path of foo-bar.service then
- * the object path will be
- * "/org/freedesktop/systemd1/unit/foo_2dbar_2eservice\n". In
- * this case we can find two escape characters, one of escape
- * char('-') is changed to three of char("_2d"). So the total
- * length will be: */
- /* (PREFIX) + (unit - escape + 3*escape) + NULL */
- path_len = prefix_len + (unit_len - escape)
- + (escape * 3 * sizeof(char)) + 1;
- path = (char *)calloc(path_len, sizeof(char));
- if (!path) {
- _E("Not enough memory.");
- return -ENOMEM;
- }
-
- *escaped = path;
-
- strncpy(path, SYSTEMD_DBUS_UNIT_PATH, prefix_len + 1);
- for (i = 0, p = 0; i <= escape; i++) {
- k = strcspn(unit + p, SYSTEMD_UNIT_ESCAPE_CHAR);
- strncpy(path + prefix_len, unit + p, k);
- if (k < strlen(unit + p)) {
- len = path_len - (prefix_len + k);
- snprintf(path + prefix_len + k, len,
- "_%x", *(unit + p + k) & 0xff);
- prefix_len += k + 3;
- p += k+1;
- }
- }
-
- return 0;
-}
-
-/* get MainPID of a service. */
-static int vip_get_service_mainpid(const char *service, int *pid)
-{
- char *escaped;
- int ret = 0;
- GVariant *reply = NULL;
- GVariant *inner_reply = NULL;
-
- if (!service)
- return -EINVAL;
-
- ret = vip_get_escaped_name(service, &escaped);
- if (ret < 0) {
- _E("Failed to makeup escaped service name.");
- return ret;
- }
-
- ret = d_bus_call_method_sync_gvariant_with_reply(SYSTEMD_DBUS_DEST,
- escaped,
- DBUS_IFACE_DBUS_PROPERTIES,
- "Get",
- g_variant_new("(ss)", SYSTEMD_DBUS_SERVICE_IFACE, "ExecMainPID"),
- &reply);
-
- free(escaped);
-
- if (!reply || ret < 0) {
- _E("Failed to get pid of service=%s", service);
- if (reply)
- g_variant_unref(reply);
- return -ECOMM;
- }
-
- do_expr_unless_g_variant_consume_typechecked(return -EINVAL, reply, "(v)", &inner_reply);
- do_expr_unless_g_variant_consume_typechecked(return -EINVAL, inner_reply, "u", pid);
-
- return 0;
-}
-
-static bool vip_check_all(void)
-{
- int pid;
- int ret_val;
- bool ret = true;
- char *process;
- char *service;
- GList *elem1, *elem2;
- struct vip_group *vg;
-
- SYS_G_LIST_FOREACH(vip_group_list, elem1, vg) {
- if (!vg->reboot_on_failure)
- continue;
-
- SYS_G_LIST_FOREACH(vg->process, elem2, process) {
- pid = find_pid_from_cmdline(process);
- if (pid < 0) {
- vip_print_console("[VIP FAILED] %s is not running", process);
- ret = false;
- }
- }
-
- SYS_G_LIST_FOREACH(vg->service, elem2, service) {
- ret_val = vip_get_service_mainpid(service, &pid);
- if (ret_val < 0) {
- _E("Failed to get MainPID of service=%s", service);
- continue;
- }
-
- /* The property MainPID can return a positive MainPID
- * as a pid of inactive(dead) service if the service had once
- * been active before. Therefore, it is necessary to check
- * whether it is still alive. */
- if (pid == 0 || kill(pid, 0) != 0) {
- vip_print_console("[VIP FAILED] %s is not running", service);
- ret = false;
- }
- }
- }
-
- return ret;
-}
-
-static void vip_force_reboot(void)
-{
- vip_print_console("[VIP FAILED] Force reboot");
- execl("/usr/bin/vip-release-agent", "/usr/bin/vip-release-agent", NULL);
-
- _E("Failed to execute vip-release-agent");
-}
-
-static int vip_load_config(struct parse_result *result, void *user_data)
-{
- char vgname[64] = {0, };
- struct vip_group *vg;
- GList *elem;
-
- if (!user_data)
- return -1;
-
- if (!strstr(result->section, "VIP_GROUP"))
- return -1;
-
- snprintf(vgname, sizeof(vgname), "%s:%s", (char *)user_data, result->section);
-
- SYS_G_LIST_FOREACH(vip_group_list, elem, vg) {
- if (!strncmp(vg->name, vgname, sizeof(vg->name)))
- break;
- }
-
- if (!vg) {
- vg = calloc(1, sizeof(struct vip_group));
- if (!vg)
- return -1;
- strncpy(vg->name, vgname, sizeof(vg->name));
- SYS_G_LIST_APPEND(vip_group_list, vg);
- }
-
- if (!strncmp(result->name, "PROCESS", sizeof("PROCESS"))) {
- SYS_G_LIST_APPEND(vg->process, strndup(result->value, PATH_MAX));
- } else if (!strncmp(result->name, "SERVICE", sizeof("SERVICE"))) {
- SYS_G_LIST_APPEND(vg->service, strndup(result->value, PATH_MAX));
- } else if (!strncmp(result->name, "ACTION_ON_FAILURE", sizeof("ACTION_ON_FAILURE"))) {
- if (!strncmp(result->value, "reboot", sizeof("reboot")))
- vg->reboot_on_failure = 1;
- else
- vg->reboot_on_failure = 0;
- }
-
- return 0;
-}
-
-static int vip_create_sub_cgroup(const char *name, pid_t pid)
-{
- _cleanup_free_ char *cgroup_name = NULL;
- bool already;
- int r;
-
- assert(name);
- assert(pid);
-
- r = cgroup_make_subdir(VIP_CGROUP, name, &already);
- if (r < 0) {
- _E("failed to create vip sub dir");
- return r;
- }
-
- if (already) {
- _D("PID(%d) is already registered as VIP sub cgroup(%s)",
- pid, name);
- return 0;
- }
-
- r = asprintf(&cgroup_name, "%s/%s", VIP_CGROUP, name);
- if (r < 0) {
- _E("failed to allocate memory");
- return -ENOMEM;
- }
-
- cgroup_write_tid_fullpath(cgroup_name, pid);
-/* r = cgroup_write_node_uint32(cgroup_name, TASK_FILE_NAME, pid);
- if (r < 0) {
- _E("failed to write pid '%d' to '%s': %m",
- pid, cgroup_name);
- return r;
- }*/
-
- _D("PID(%d) is registered as VIP sub cgroup(%s)", pid, name);
-
- return 0;
-}
-
-static void vip_create_proc_name_groups(void)
-{
- GList *elem1, *elem2;
- struct vip_group *vg;
- char *process;
- int r;
-
- SYS_G_LIST_FOREACH(vip_group_list, elem1, vg) {
- if (!vg->reboot_on_failure)
- continue;
-
- SYS_G_LIST_FOREACH(vg->process, elem2, process) {
- pid_t pid = 0;
-
- pid = find_pid_from_cmdline(process);
- if (pid > 0) {
- r = vip_create_sub_cgroup(process, pid);
- if (r < 0)
- _E("failed to create sub cgroup of '%s', ignoring", process);
- } else {
- _D("failed to find pid of name: %s", process);
- }
- }
- }
-}
-
-static void vip_create_systemd_service_groups(void)
-{
- GList *elem1, *elem2;
- struct vip_group *vg;
- char *service;
-
- SYS_G_LIST_FOREACH(vip_group_list, elem1, vg) {
- if (!vg->reboot_on_failure)
- continue;
-
- SYS_G_LIST_FOREACH(vg->service, elem2, service) {
- int ret_val;
- pid_t pid;
-
- ret_val = vip_get_service_mainpid(service, &pid);
- if (ret_val == -ECOMM)
- continue;
-
- if (pid > 0) {
- ret_val = vip_create_sub_cgroup(service, pid);
- if (ret_val < 0)
- _E("failed to create sub cgroup of '%s', ignoring", service);
- }
- }
- }
-}
-
-static int vip_booting_done(void *data)
-{
- vip_create_proc_name_groups();
- vip_create_systemd_service_groups();
-
- if (vip_check_all() == false)
- vip_force_reboot();
-
- return 0;
-}
-
-static int vip_process_disable(void *data)
-{
- _cleanup_close_ int checkfd = -1;
-
- /* make tmp file */
- checkfd = creat(CHECK_RELEASE_PROGRESS, 0640);
- if (checkfd < 0)
- _E("Unable to disable vip release agent - can't make file %s (%m)", CHECK_RELEASE_PROGRESS);
-
- return 0;
-}
-
-static void vip_load_configs(void)
-{
- int count;
- int idx;
- struct dirent **namelist;
-
- if ((count = scandir(VIP_CONF_DIR, &namelist, NULL, alphasort)) == -1) {
- _W("[DEBUG] failed to opendir (%s)", VIP_CONF_DIR);
- return;
- }
-
- for (idx = 0; idx < count; idx++) {
- char path[PATH_MAX] = {0, };
-
- if (!strstr(namelist[idx]->d_name, VIP_CONF_SUFFIX))
- continue;
-
- snprintf(path, sizeof(path), "%s/%s", VIP_CONF_DIR, namelist[idx]->d_name);
- config_parse(path, vip_load_config, (void *)namelist[idx]->d_name);
- free(namelist[idx]);
- }
-
- free(namelist);
-
- /* print result */
- GList *elem1, *elem2;
- struct vip_group *vg;
- char *name;
-
- SYS_G_LIST_FOREACH(vip_group_list, elem1, vg) {
- _D("%s", vg->name);
- _D(" reboot on failure=%d", vg->reboot_on_failure);
- SYS_G_LIST_FOREACH(vg->process, elem2, name)
- _D(" vip process: %s", name);
- SYS_G_LIST_FOREACH(vg->service, elem2, name)
- _D(" vip service: %s", name);
- }
-}
-
-static int resourced_vip_process_init(void *data)
-{
- _cleanup_close_ int checkfd = -1;
- int r;
-
- if (vip_boot_param_reboot_disabled()) {
- vip_print_console("[VIP] Reboot has been disabled, boot param: %s", BOOT_PARAM_VIP_DISABLED);
- return RESOURCED_ERROR_NONE;
- }
-
- r = access(CHECK_RELEASE_PROGRESS, F_OK);
- if (r == 0) {
- r = unlink(CHECK_RELEASE_PROGRESS);
- if (r < 0)
- _E("failed to remove %s: %m", CHECK_RELEASE_PROGRESS);
- }
-
- vip_load_configs();
-
- if (!is_mounted(VIP_CGROUP)) {
- r = cgroup_make_subdir(CGROUP_PATH, "vip", NULL);
- if (r < 0) {
- _E("failed to make vip cgroup");
- return RESOURCED_ERROR_FAIL;
- }
-
- r = cgroup_mount_subsystem("vip_cgroup", VIP_CGROUP,
- "none,name=vip_cgroup");
- if (r < 0) {
- _E("failed to mount vip cgroup: %m");
- return RESOURCED_ERROR_FAIL;
- }
-
- r = cgroup_set_release_agent("vip", "/usr/bin/vip-release-agent");
- if (r < 0) {
- _E("failed to set vip release agent: %m");
- return RESOURCED_ERROR_FAIL;
- }
- }
-
- vip_create_proc_name_groups();
- vip_create_systemd_service_groups();
-
- register_notifier(RESOURCED_NOTIFIER_POWER_OFF,
- vip_process_disable);
-
- r = register_notifier(RESOURCED_NOTIFIER_BOOTING_DONE,
- vip_booting_done);
- if (r < 0) {
- _E("failed to register notifier BootingDone");
- return RESOURCED_ERROR_FAIL;
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-static int resourced_vip_process_finalize(void *data)
-{
- GList *elem1, *elem1_n, *elem2, *elem2_n;
- struct vip_group *vg;
- char *process, *service;
-
- if (vip_boot_param_reboot_disabled())
- return RESOURCED_ERROR_NONE;
-
- SYS_G_LIST_FOREACH_SAFE(vip_group_list, elem1, elem1_n, vg) {
- SYS_G_LIST_FOREACH_SAFE(vg->process, elem2, elem2_n, process) {
- SYS_G_LIST_REMOVE(vg->process, process);
- free(process);
- }
-
- SYS_G_LIST_FOREACH_SAFE(vg->service, elem2, elem2_n, service) {
- SYS_G_LIST_REMOVE(vg->service, service);
- free(service);
- }
-
- SYS_G_LIST_REMOVE(vip_group_list, vg);
- free(vg);
- }
-
- vip_process_disable(NULL);
- unregister_notifier(RESOURCED_NOTIFIER_BOOTING_DONE, vip_booting_done);
- unregister_notifier(RESOURCED_NOTIFIER_POWER_OFF, vip_process_disable);
-
- return RESOURCED_ERROR_NONE;
-}
-
-static struct module_ops vip_modules_ops = {
- .priority = MODULE_PRIORITY_NORMAL,
- .name = "vip-process",
- .init = resourced_vip_process_init,
- .exit = resourced_vip_process_finalize,
-};
-
-MODULE_REGISTER(&vip_modules_ops)
+++ /dev/null
-/*
- * resourced
- *
- * Copyright (c) 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.h
- * @desc proc monitor
- **/
-
-#ifndef __RESOURCED_VIP_PROCESS_H__
-#define __RESOURCED_VIP_PROCESS_H__
-
-#define CHECK_RELEASE_PROGRESS "/tmp/.release_ongoing"
-#define VIP_CGROUP "/sys/fs/cgroup/vip"
-
-#endif /* __RESOURCED_VIP_PROCESS_H__ */
-
--- /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"
+#include "safe-kill.h"
+
+enum app_watchdog_control_type {
+ SET_FOREGRD,
+ SET_BACKGRD,
+};
+
+static GSList *app_watchdog_list;
+
+struct app_watchdog_info {
+ pid_t pid;
+ unsigned int watchdog_timeout;
+ GSource *watchdog_timer;
+};
+
+struct app_watchdog_info *find_app_watchdog_info(const pid_t pid)
+{
+ GSList *iter = NULL;
+ struct app_watchdog_info *wai = NULL;
+
+ if (!app_watchdog_list)
+ return NULL;
+
+ gslist_for_each_item(iter, app_watchdog_list) {
+ wai = (struct app_watchdog_info *)iter->data;
+ if (wai->pid == pid)
+ return wai;
+ }
+ return NULL;
+}
+
+static gboolean app_watchdog_cb(gpointer data)
+{
+ struct app_watchdog_info *wai = (struct app_watchdog_info *)data;
+ GDBusConnection *conn;
+ GError *err = NULL;
+
+ if (!app_watchdog_list || !wai)
+ return false;
+
+ if (!g_slist_find(app_watchdog_list, wai))
+ return false;
+
+ if (safe_kill(wai->pid, 0) == -1) {
+ _I("[WATCHDOG] %d process doesn't exit, remove watchdog handler", wai->pid);
+ app_watchdog_list = g_slist_remove(app_watchdog_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("[WATCHDOG] detect app 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_APP_WATCHDOG,
+ g_variant_new("(ii)", wai->pid, SIGKILL), &err);
+
+ return false;
+}
+
+static void app_update_watchdog(struct app_watchdog_info *wai, unsigned int timeout)
+{
+ if (wai->watchdog_timer) {
+ g_source_destroy(wai->watchdog_timer);
+ wai->watchdog_timer = NULL;
+ _D("[WATCHDOG] 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, app_watchdog_cb, (gpointer)wai, NULL);
+ g_source_attach(wai->watchdog_timer, NULL);
+ _D("[WATCHDOG] restart app watchdog timer for pid %d with timeout %u", wai->pid, timeout);
+ }
+}
+
+static void app_argos_watchdog_handler(GDBusMethodInvocation *invocation, GVariant *params)
+{
+ int pid = -1;
+ unsigned int timeout = 0;
+ struct app_watchdog_info *wai;
+
+ _D("[WATCHDOG] receive app watchdog dbus");
+
+ do_expr_unless_g_variant_get_typechecked(goto finish, params, "(iu)", &pid, &timeout);
+
+ wai = find_app_watchdog_info(pid);
+ if (!wai) {
+ wai = calloc(sizeof(struct app_watchdog_info), 1);
+ if (!wai) {
+ g_dbus_method_invocation_return_error(invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NO_MEMORY,
+ "Out of memory");
+ return;
+ }
+
+ wai->pid = pid;
+ app_watchdog_list = g_slist_prepend(app_watchdog_list, wai);
+ _D("[WATCHDOG] create new app watchdog handler for pid %d", pid);
+ }
+
+ app_update_watchdog(wai, timeout);
+
+finish:
+ D_BUS_REPLY_ERR(invocation);
+}
+
+static void app_watchdog_wakeup(GVariant *params)
+{
+ GSList *iter = NULL;
+ struct app_watchdog_info *wai = NULL;
+
+ if (!app_watchdog_list)
+ return;
+
+ _I("[WATCHDOG] app watchdog wakeup");
+ gslist_for_each_item(iter, app_watchdog_list) {
+ wai = (struct app_watchdog_info *)iter->data;
+ app_update_watchdog(wai, wai->watchdog_timeout);
+ }
+}
+
+static void app_watchdog_freeze(GVariant *params)
+{
+ int pid = -1, type = -1;
+ unsigned int timeout = 0;
+ struct app_watchdog_info *wai;
+
+ do_expr_unless_g_variant_get_typechecked(return, params, "(ii)", &type, &pid);
+
+ wai = find_app_watchdog_info(pid);
+ if (!wai)
+ return;
+
+ _I("[WATCHDOG] app watchdog pid (%d) freeze with timeout (%u)", pid, timeout);
+ timeout = (type == SET_BACKGRD) ? 0 : wai->watchdog_timeout;
+ app_update_watchdog(wai, timeout);
+}
+
+static void app_watchdog_suspend(GVariant *params)
+{
+ GSList *iter = NULL;
+ struct app_watchdog_info *wai = NULL;
+
+ if (!app_watchdog_list)
+ return;
+
+ _I("[WATCHDOG] app watchdog suspend");
+ gslist_for_each_item(iter, app_watchdog_list) {
+ wai = (struct app_watchdog_info *)iter->data;
+ app_update_watchdog(wai, 0);
+ }
+}
+
+static int app_watchdog_terminated_cb(void *data)
+{
+ struct proc_status *ps = (struct proc_status *)data;
+ struct app_watchdog_info *wai;
+
+ if (!ps || !ps->pid)
+ return RESOURCED_ERROR_FAIL;
+
+ wai = find_app_watchdog_info(ps->pid);
+ if (!wai)
+ return RESOURCED_ERROR_NO_DATA;
+
+ app_update_watchdog(wai, 0);
+ app_watchdog_list = g_slist_remove(app_watchdog_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", app_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, app_watchdog_wakeup, NULL},
+ {DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
+ SIGNAL_DEVICED_SUSPEND, app_watchdog_suspend, NULL},
+ {RESOURCED_PATH_FREEZER, RESOURCED_INTERFACE_FREEZER,
+ SIGNAL_FREEZER_STATE, app_watchdog_freeze, NULL},
+};
+
+static int app_watchdog_init(void *data)
+{
+ _I("[WATCHDOG] app watchdog init");
+
+ register_notifier(RESOURCED_NOTIFIER_APP_TERMINATED,
+ app_watchdog_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 app_watchdog_exit(void *data)
+{
+ unregister_notifier(RESOURCED_NOTIFIER_APP_TERMINATED,
+ app_watchdog_terminated_cb);
+ return RESOURCED_ERROR_NONE;
+}
+
+static const struct proc_module_ops app_watchdog_ops = {
+ .name = "APP_WATCHDOG",
+ .init = app_watchdog_init,
+ .exit = app_watchdog_exit,
+};
+PROC_MODULE_REGISTER(&app_watchdog_ops)
+
#include <fcntl.h>
#include <dirent.h>
#include "trace.h"
-#include "vip-process.h"
+#include "watchdog-cgroup.h"
#include "safe-kill.h"
#define TIZEN_DEBUG_MODE_FILE RD_SYS_ETC"/.debugmode"
if (pid == 0) {
setpgid(0, 0);
if (execv(argv[0], argv) == -1) {
- _E("Error execv: %m.\n");
+ _E("[WATCHDOG] Error execv: %m.\n");
_exit(-1);
}
_exit(1);
sleep(WAIT_TIMEOUT);
times++;
} else {
- _D("timeout!!, kill child process(%s)\n",
+ _D("[WATCHDOG] timeout!!, kill child process(%s)\n",
argv[0]);
safe_kill(pid, SIGKILL);
}
char *rebootargv[4] = {REBOOT_PATH, "silent", NULL, NULL};
DIR *dir = 0;
- _I("Starting vip-release-agent: [%d:%s]", argc, argv[1]);
+ _I("[WATCHDOG] Starting process watchdog handler: [%d:%s]", argc, argv[1]);
- dir = opendir(VIP_CGROUP);
+ dir = opendir(PROC_WATCHDOGCG_PATH);
if (!dir) {
- _E("doesn't support cgroup release agent: %m");
+ _E("[WATCHDOG] doesn't support %s cgroup: %m", PROC_WATCHDOGCG_NAME);
return 0;
}
closedir(dir);
if (access(CHECK_RELEASE_PROGRESS, F_OK) == 0)
return 0;
- _D("No other vip-release-agent is running.");
+ _D("[WATCHDOG] No other release_agent is running.");
/* make tmp file */
checkfd = creat(CHECK_RELEASE_PROGRESS, 0640);
if (checkfd < 0) {
- _E("fail to make %s file\n", CHECK_RELEASE_PROGRESS);
+ _E("[WATCHDOG] fail to make %s file\n", CHECK_RELEASE_PROGRESS);
checkfd = 0;
}
- /* unmount cgroup for preventing launching another release-agent */
- _E("unmounting /sys/fs/cgroup");
- umount2("/sys/fs/cgroup", MNT_FORCE |MNT_DETACH);
+ /* unmount cgroup for preventing launching another release_agent */
+ _E("[WATCHDOG] unmounting %s", CGROUP_PATH);
+ umount2(CGROUP_PATH, MNT_FORCE |MNT_DETACH);
/* check debug level */
if (check_debugenable())
/* clear tmp file */
if (checkfd) {
if (unlink(CHECK_RELEASE_PROGRESS) < 0)
- _E("fail to remove %s file\n", CHECK_RELEASE_PROGRESS);
+ _E("[WATCHDOG] fail to remove %s file\n", CHECK_RELEASE_PROGRESS);
close(checkfd);
}
sync();
- _E("rebooting");
+ _E("[WATCHDOG] rebooting");
run_exec(rebootargv);
return 0;
}
/*
-
* resourced
*
* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
* 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 <ctype.h>
+#include <stdio.h>
+#include <stdbool.h>
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libsyscommon/list.h>
-#include "proc-main.h"
+#include "const.h"
#include "resourced.h"
-#include "macro.h"
#include "trace.h"
-#include "dbus-handler.h"
-#include "freezer.h"
+#include "cgroup.h"
+#include "watchdog-cgroup.h"
+#include "procfs.h"
+#include "macro.h"
+#include "util.h"
+#include "config-parser.h"
+#include "file-helper.h"
+#include "storage-helper.h"
#include "notifier.h"
-#include "safe-kill.h"
+#include "module.h"
+#include "module-data.h"
+#include "dbus-handler.h"
-enum watchdog_control_type {
- SET_FOREGRD,
- SET_BACKGRD,
-};
+#define PROC_CONF_DIR "/etc/resourced/process.conf.d"
+#define PROC_CONF_SUFFIX ".conf"
-static GSList *watchdog_app_list;
+#define SYSTEMD_DBUS_DEST "org.freedesktop.systemd1"
+#define SYSTEMD_DBUS_UNIT_PATH "/org/freedesktop/systemd1/unit/"
+#define SYSTEMD_DBUS_SERVICE_IFACE SYSTEMD_DBUS_DEST".Service"
+#define DBUS_IFACE_DBUS_PROPERTIES "org.freedesktop.DBus.Properties"
-struct watchdog_app_info {
- pid_t pid;
- unsigned int watchdog_timeout;
- GSource *watchdog_timer;
+#define SYSTEMD_UNIT_ESCAPE_CHAR ".-"
+
+#define BOOT_PARAM_PROC_WATCHDOG_REBOOT_DISABLED "tizen.watchdog_reboot_disable"
+
+struct proc_watchdog_group {
+ char name[64];
+ GList *service;
+ GList *process;
+
+ /* options */
+ int reboot_on_failure;
};
-struct watchdog_app_info *find_watchdog_info(const pid_t pid)
+static GList *proc_watchdog_group_list;
+
+/* print log on console */
+static void proc_watchdog_print_console(const char *format, ...)
{
- GSList *iter = NULL;
- struct watchdog_app_info *wai = NULL;
+ FILE *fp = NULL;
+ char buffer[256] = {0, };
+ va_list ap;
- if (!watchdog_app_list)
- return NULL;
+ va_start(ap, format);
+ vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
- gslist_for_each_item(iter, watchdog_app_list) {
- wai = (struct watchdog_app_info *)iter->data;
- if (wai->pid == pid)
- return wai;
+ fp = fopen("/dev/console", "a");
+ if (!fp) {
+ _E("[WATCHDOG] %s(failed to print log on console, %m)", buffer);
+ return;
}
- return NULL;
+
+ _D("[WATCHDOG] %s", buffer);
+ fprintf(fp, "%s\n", buffer);
+
+ fclose(fp);
}
-static gboolean watchdog_cb(gpointer data)
+static bool proc_watchdog_boot_param_reboot_disabled(void)
{
- struct watchdog_app_info *wai = (struct watchdog_app_info *)data;
- GDBusConnection *conn;
- GError *err = NULL;
+ char cmdline[1024];
+ int retval;
- if (!watchdog_app_list || !wai)
+ retval = proc_get_cmdline(0, cmdline, sizeof(cmdline));
+ if (retval != RESOURCED_ERROR_NONE)
return false;
- if (!g_slist_find(watchdog_app_list, wai))
- return false;
+ return (strstr(cmdline, BOOT_PARAM_PROC_WATCHDOG_REBOOT_DISABLED) != NULL);
+}
- if (safe_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;
+/* copy of libsyscommon/libsystemd.c: systemd_get_unit_dbus_path() */
+static int proc_watchdog_get_escaped_name(const char *unit, char **escaped)
+{
+ char *path = NULL;
+ int i;
+ size_t p, k, prefix_len, unit_len;
+ size_t path_len, len, escape;
+
+ if (!unit) {
+ _E("[WATCHDOG] Invalid parameter.");
+ return -EINVAL;
}
+ unit_len = strlen(unit);
- wai->watchdog_timer = NULL;
- conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
- if (!conn)
- return false;
+ for (escape = 0, p = 0; p < unit_len; escape++) {
+ k = strcspn(unit + p, SYSTEMD_UNIT_ESCAPE_CHAR);
+ if (p + k >= unit_len)
+ break;
+ p += k+1;
+ }
- _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);
+ prefix_len = strlen(SYSTEMD_DBUS_UNIT_PATH);
+ /* assume we try to get object path of foo-bar.service then
+ * the object path will be
+ * "/org/freedesktop/systemd1/unit/foo_2dbar_2eservice\n". In
+ * this case we can find two escape characters, one of escape
+ * char('-') is changed to three of char("_2d"). So the total
+ * length will be: */
+ /* (PREFIX) + (unit - escape + 3*escape) + NULL */
+ path_len = prefix_len + (unit_len - escape)
+ + (escape * 3 * sizeof(char)) + 1;
+ path = (char *)calloc(path_len, sizeof(char));
+ if (!path) {
+ _E("[WATCHDOG] Not enough memory.");
+ return -ENOMEM;
+ }
+
+ *escaped = path;
+
+ strncpy(path, SYSTEMD_DBUS_UNIT_PATH, prefix_len + 1);
+ for (i = 0, p = 0; i <= escape; i++) {
+ k = strcspn(unit + p, SYSTEMD_UNIT_ESCAPE_CHAR);
+ strncpy(path + prefix_len, unit + p, k);
+ if (k < strlen(unit + p)) {
+ len = path_len - (prefix_len + k);
+ snprintf(path + prefix_len + k, len,
+ "_%x", *(unit + p + k) & 0xff);
+ prefix_len += k + 3;
+ p += k+1;
+ }
+ }
- return false;
+ return 0;
}
-static void proc_update_watchdog(struct watchdog_app_info *wai, unsigned int timeout)
+/* get MainPID of a service. */
+static int proc_watchdog_get_service_mainpid(const char *service, int *pid)
{
- if (wai->watchdog_timer) {
- g_source_destroy(wai->watchdog_timer);
- wai->watchdog_timer = NULL;
- _D("delete previous watchdog timer for pid %d", wai->pid);
+ char *escaped;
+ int ret = 0;
+ GVariant *reply = NULL;
+ GVariant *inner_reply = NULL;
+
+ if (!service)
+ return -EINVAL;
+
+ ret = proc_watchdog_get_escaped_name(service, &escaped);
+ if (ret < 0) {
+ _E("[WATCHDOG] Failed to makeup escaped service name.");
+ return ret;
}
- 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);
+ ret = d_bus_call_method_sync_gvariant_with_reply(SYSTEMD_DBUS_DEST,
+ escaped,
+ DBUS_IFACE_DBUS_PROPERTIES,
+ "Get",
+ g_variant_new("(ss)", SYSTEMD_DBUS_SERVICE_IFACE, "ExecMainPID"),
+ &reply);
+
+ free(escaped);
+
+ if (!reply || ret < 0) {
+ _E("[WATCHDOG] Failed to get pid of service=%s", service);
+ if (reply)
+ g_variant_unref(reply);
+ return -ECOMM;
}
+
+ do_expr_unless_g_variant_consume_typechecked(return -EINVAL, reply, "(v)", &inner_reply);
+ do_expr_unless_g_variant_consume_typechecked(return -EINVAL, inner_reply, "u", pid);
+
+ return 0;
}
-static void proc_argos_watchdog_handler(GDBusMethodInvocation *invocation, GVariant *params)
+static bool proc_watchdog_check_all(void)
{
- int pid = -1;
- unsigned int timeout = 0;
- struct watchdog_app_info *wai;
-
- _D("receive watchdog dbus");
-
- do_expr_unless_g_variant_get_typechecked(goto finish, params, "(iu)", &pid, &timeout);
-
- wai = find_watchdog_info(pid);
- if (!wai) {
- wai = calloc(sizeof(struct watchdog_app_info), 1);
- if (!wai) {
- g_dbus_method_invocation_return_error(invocation,
- G_DBUS_ERROR,
- G_DBUS_ERROR_NO_MEMORY,
- "Out of memory");
- return;
+ int pid;
+ int ret_val;
+ bool ret = true;
+ char *process;
+ char *service;
+ GList *elem1, *elem2;
+ struct proc_watchdog_group *vg;
+
+ SYS_G_LIST_FOREACH(proc_watchdog_group_list, elem1, vg) {
+ if (!vg->reboot_on_failure)
+ continue;
+
+ SYS_G_LIST_FOREACH(vg->process, elem2, process) {
+ pid = find_pid_from_cmdline(process);
+ if (pid < 0) {
+ proc_watchdog_print_console("%s is not running", process);
+ ret = false;
+ }
}
- wai->pid = pid;
- watchdog_app_list = g_slist_prepend(watchdog_app_list, wai);
- _D("create new watchdog handler for pid %d", pid);
+ SYS_G_LIST_FOREACH(vg->service, elem2, service) {
+ ret_val = proc_watchdog_get_service_mainpid(service, &pid);
+ if (ret_val < 0) {
+ _E("[WATCHDOG] Failed to get MainPID of service=%s", service);
+ continue;
+ }
+
+ /* The property MainPID can return a positive MainPID
+ * as a pid of inactive(dead) service if the service had once
+ * been active before. Therefore, it is necessary to check
+ * whether it is still alive. */
+ if (pid == 0 || kill(pid, 0) != 0) {
+ proc_watchdog_print_console("%s is not running", service);
+ ret = false;
+ }
+ }
}
- proc_update_watchdog(wai, timeout);
+ return ret;
+}
-finish:
- D_BUS_REPLY_ERR(invocation);
+static void proc_watchdog_force_reboot(void)
+{
+ proc_watchdog_print_console("Force reboot");
+ execl("PROC_WATCHDOG_HANDLER_PATH", "PROC_WATCHDOG_HANDLER_PATH", NULL);
+
+ _E("[WATCHDOG] Failed to execute %s", PROC_WATCHDOG_HANDLER_PATH);
}
-static void proc_watchdog_wakeup(GVariant *params)
+static int proc_watchdog_load_config(struct parse_result *result, void *user_data)
{
- GSList *iter = NULL;
- struct watchdog_app_info *wai = NULL;
+ char vgname[64] = {0, };
+ struct proc_watchdog_group *vg;
+ GList *elem;
- if (!watchdog_app_list)
- return;
+ if (!user_data)
+ return -1;
+
+ if (!strstr(result->section, PER_PROCESS_CONF))
+ return -1;
- gslist_for_each_item(iter, watchdog_app_list) {
- wai = (struct watchdog_app_info *)iter->data;
- proc_update_watchdog(wai, wai->watchdog_timeout);
+ snprintf(vgname, sizeof(vgname), "%s:%s", (char *)user_data, result->section);
+
+ SYS_G_LIST_FOREACH(proc_watchdog_group_list, elem, vg) {
+ if (!strncmp(vg->name, vgname, sizeof(vg->name)))
+ break;
+ }
+
+ if (!vg) {
+ vg = calloc(1, sizeof(struct proc_watchdog_group));
+ if (!vg)
+ return -1;
+ strncpy(vg->name, vgname, sizeof(vg->name));
+ SYS_G_LIST_APPEND(proc_watchdog_group_list, vg);
}
+
+ if (!strncmp(result->name, "Process", sizeof("Process"))) {
+ SYS_G_LIST_APPEND(vg->process, strndup(result->value, PATH_MAX));
+ } else if (!strncmp(result->name, "Service", sizeof("Service"))) {
+ SYS_G_LIST_APPEND(vg->service, strndup(result->value, PATH_MAX));
+ } else if (!strncmp(result->name, "ActionOnFailure", sizeof("ActionOnFailure"))) {
+ if (!strncmp(result->value, "reboot", sizeof("reboot")))
+ vg->reboot_on_failure = 1;
+ else
+ vg->reboot_on_failure = 0;
+ }
+
+ return 0;
}
-static void proc_watchdog_freeze(GVariant *params)
+static int proc_watchdog_create_sub_cgroup(const char *name, pid_t pid)
{
- int pid = -1, type = -1;
- unsigned int timeout = 0;
- struct watchdog_app_info *wai;
+ _cleanup_free_ char *cgroup_name = NULL;
+ bool already;
+ int r;
- do_expr_unless_g_variant_get_typechecked(return, params, "(ii)", &type, &pid);
+ assert(name);
+ assert(pid);
- wai = find_watchdog_info(pid);
- if (!wai)
- return;
+ r = cgroup_make_subdir(PROC_WATCHDOGCG_PATH, name, &already);
+ if (r < 0) {
+ _E("[WATCHDOG] failed to create %s sub dir", PROC_WATCHDOGCG_PATH);
+ return r;
+ }
+
+ if (already) {
+ _D("[WATCHDOG] PID(%d) is already registered as %s sub cgroup(%s)",
+ pid, PROC_WATCHDOGCG_NAME, name);
+ return 0;
+ }
+
+ r = asprintf(&cgroup_name, "%s/%s", PROC_WATCHDOGCG_PATH, name);
+ if (r < 0) {
+ _E("[WATCHDOG] failed to allocate memory");
+ return -ENOMEM;
+ }
+
+ cgroup_write_tid_fullpath(cgroup_name, pid);
+/* r = cgroup_write_node_uint32(cgroup_name, TASK_FILE_NAME, pid);
+ if (r < 0) {
+ _E("[WATCHDOG] failed to write pid '%d' to '%s': %m",
+ pid, cgroup_name);
+ return r;
+ }*/
- timeout = (type == SET_BACKGRD) ? 0 : wai->watchdog_timeout;
- proc_update_watchdog(wai, timeout);
+ _D("[WATCHDOG] PID(%d) is registered as %s sub cgroup(%s)", pid, PROC_WATCHDOGCG_NAME, name);
+
+ return 0;
}
-static void proc_watchdog_suspend(GVariant *params)
+static void proc_watchdog_create_proc_name_groups(void)
{
- GSList *iter = NULL;
- struct watchdog_app_info *wai = NULL;
-
- if (!watchdog_app_list)
- return;
+ GList *elem1, *elem2;
+ struct proc_watchdog_group *vg;
+ char *process;
+ int r;
+
+ SYS_G_LIST_FOREACH(proc_watchdog_group_list, elem1, vg) {
+ if (!vg->reboot_on_failure)
+ continue;
+
+ SYS_G_LIST_FOREACH(vg->process, elem2, process) {
+ pid_t pid = 0;
+
+ pid = find_pid_from_cmdline(process);
+ if (pid > 0) {
+ r = proc_watchdog_create_sub_cgroup(process, pid);
+ if (r < 0)
+ _E("[WATCHDOG] failed to create sub cgroup of '%s', ignoring", process);
+ } else {
+ _D("[WATCHDOG] failed to find pid of name: %s", process);
+ }
+ }
+ }
+}
- gslist_for_each_item(iter, watchdog_app_list) {
- wai = (struct watchdog_app_info *)iter->data;
- proc_update_watchdog(wai, 0);
+static void proc_watchdog_create_systemd_service_groups(void)
+{
+ GList *elem1, *elem2;
+ struct proc_watchdog_group *vg;
+ char *service;
+
+ SYS_G_LIST_FOREACH(proc_watchdog_group_list, elem1, vg) {
+ if (!vg->reboot_on_failure)
+ continue;
+
+ SYS_G_LIST_FOREACH(vg->service, elem2, service) {
+ int ret_val;
+ pid_t pid;
+
+ ret_val = proc_watchdog_get_service_mainpid(service, &pid);
+ if (ret_val == -ECOMM)
+ continue;
+
+ if (pid > 0) {
+ ret_val = proc_watchdog_create_sub_cgroup(service, pid);
+ if (ret_val < 0)
+ _E("[WATCHDOG] failed to create sub cgroup of '%s', ignoring", service);
+ }
+ }
}
}
-static int watchdog_app_terminated_cb(void *data)
+static int proc_watchdog_booting_done(void *data)
{
- struct proc_status *ps = (struct proc_status *)data;
- struct watchdog_app_info *wai;
+ proc_watchdog_create_proc_name_groups();
+ proc_watchdog_create_systemd_service_groups();
- if (!ps || !ps->pid)
- return RESOURCED_ERROR_FAIL;
+ if (proc_watchdog_check_all() == false)
+ proc_watchdog_force_reboot();
- wai = find_watchdog_info(ps->pid);
- if (!wai)
- return RESOURCED_ERROR_NO_DATA;
+ return 0;
+}
- proc_update_watchdog(wai, 0);
- watchdog_app_list = g_slist_remove(watchdog_app_list, wai);
- free(wai);
+static int proc_watchdog_process_disable(void *data)
+{
+ _cleanup_close_ int checkfd = -1;
- return RESOURCED_ERROR_NONE;
+ /* make tmp file */
+ checkfd = creat(CHECK_RELEASE_PROGRESS, 0640);
+ if (checkfd < 0)
+ _E("[WATCHDOG] Unable to disable cgroup release_agent - can't make file %s (%m)", CHECK_RELEASE_PROGRESS);
+
+ return 0;
}
-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 void proc_watchdog_load_configs(void)
+{
+ int count;
+ int idx;
+ struct dirent **namelist;
-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},
-};
+ if ((count = scandir(PROC_CONF_DIR, &namelist, NULL, alphasort)) == -1) {
+ _W("[WATCHDOG] failed to opendir (%s)", PROC_CONF_DIR);
+ return;
+ }
+
+ for (idx = 0; idx < count; idx++) {
+ char path[PATH_MAX] = {0, };
+
+ if (!strstr(namelist[idx]->d_name, PROC_CONF_SUFFIX))
+ continue;
+
+ snprintf(path, sizeof(path), "%s/%s", PROC_CONF_DIR, namelist[idx]->d_name);
+ config_parse(path, proc_watchdog_load_config, (void *)namelist[idx]->d_name);
+ free(namelist[idx]);
+ }
+
+ free(namelist);
+
+ /* print result */
+ GList *elem1, *elem2;
+ struct proc_watchdog_group *vg;
+ char *name;
+
+ SYS_G_LIST_FOREACH(proc_watchdog_group_list, elem1, vg) {
+ _D("[WATCHDOG] %s", vg->name);
+ _D("[WATCHDOG] reboot on failure=%d", vg->reboot_on_failure);
+ SYS_G_LIST_FOREACH(vg->process, elem2, name)
+ _D("[WATCHDOG] proc watchdog process: %s", name);
+ SYS_G_LIST_FOREACH(vg->service, elem2, name)
+ _D("[WATCHDOG] proc watchdog service: %s", name);
+ }
+}
-static int proc_watchdog_init(void *data)
+static int resourced_proc_watchdog_process_init(void *data)
{
- register_notifier(RESOURCED_NOTIFIER_APP_TERMINATED,
- watchdog_app_terminated_cb);
+ _cleanup_close_ int checkfd = -1;
+ int r;
- 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));
+ if (proc_watchdog_boot_param_reboot_disabled()) {
+ proc_watchdog_print_console("Reboot has been disabled, boot param: %s", BOOT_PARAM_PROC_WATCHDOG_REBOOT_DISABLED);
+ return RESOURCED_ERROR_NONE;
+ }
+
+ r = access(CHECK_RELEASE_PROGRESS, F_OK);
+ if (r == 0) {
+ r = unlink(CHECK_RELEASE_PROGRESS);
+ if (r < 0)
+ _E("[WATCHDOG] failed to remove %s: %m", CHECK_RELEASE_PROGRESS);
+ }
+
+ proc_watchdog_load_configs();
+
+ if (!is_mounted(PROC_WATCHDOGCG_PATH)) {
+ r = cgroup_make_subdir(CGROUP_PATH, PROC_WATCHDOGCG_NAME, NULL);
+ if (r < 0) {
+ _E("[WATCHDOG] failed to make %s cgroup", PROC_WATCHDOGCG_PATH);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ r = cgroup_mount_subsystem("cgroup", PROC_WATCHDOGCG_PATH,
+ "none,name=watchdog");
+ if (r < 0) {
+ _E("[WATCHDOG] failed to mount %s cgroup: %m", PROC_WATCHDOGCG_PATH);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ r = cgroup_set_release_agent(PROC_WATCHDOGCG_NAME, PROC_WATCHDOG_HANDLER_PATH);
+ if (r < 0) {
+ _E("[WATCHDOG] failed to set cgroup release_agent: %m");
+ return RESOURCED_ERROR_FAIL;
+ }
+ }
+
+ proc_watchdog_create_proc_name_groups();
+ proc_watchdog_create_systemd_service_groups();
+
+ register_notifier(RESOURCED_NOTIFIER_POWER_OFF,
+ proc_watchdog_process_disable);
+
+ r = register_notifier(RESOURCED_NOTIFIER_BOOTING_DONE,
+ proc_watchdog_booting_done);
+ if (r < 0) {
+ _E("[WATCHDOG] failed to register notifier BootingDone");
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ return RESOURCED_ERROR_NONE;
}
-static int proc_watchdog_exit(void *data)
+static int resourced_proc_watchdog_process_finalize(void *data)
{
- unregister_notifier(RESOURCED_NOTIFIER_APP_TERMINATED,
- watchdog_app_terminated_cb);
+ GList *elem1, *elem1_n, *elem2, *elem2_n;
+ struct proc_watchdog_group *vg;
+ char *process, *service;
+
+ if (proc_watchdog_boot_param_reboot_disabled())
+ return RESOURCED_ERROR_NONE;
+
+ SYS_G_LIST_FOREACH_SAFE(proc_watchdog_group_list, elem1, elem1_n, vg) {
+ SYS_G_LIST_FOREACH_SAFE(vg->process, elem2, elem2_n, process) {
+ SYS_G_LIST_REMOVE(vg->process, process);
+ free(process);
+ }
+
+ SYS_G_LIST_FOREACH_SAFE(vg->service, elem2, elem2_n, service) {
+ SYS_G_LIST_REMOVE(vg->service, service);
+ free(service);
+ }
+
+ SYS_G_LIST_REMOVE(proc_watchdog_group_list, vg);
+ free(vg);
+ }
+
+ proc_watchdog_process_disable(NULL);
+ unregister_notifier(RESOURCED_NOTIFIER_BOOTING_DONE, proc_watchdog_booting_done);
+ unregister_notifier(RESOURCED_NOTIFIER_POWER_OFF, proc_watchdog_process_disable);
+
return RESOURCED_ERROR_NONE;
}
-static const struct proc_module_ops proc_watchdog_ops = {
- .name = "PROC_WATCHDOG",
- .init = proc_watchdog_init,
- .exit = proc_watchdog_exit,
+static struct module_ops proc_watchdog_modules_ops = {
+ .priority = MODULE_PRIORITY_NORMAL,
+ .name = "proc-watchdog",
+ .init = resourced_proc_watchdog_process_init,
+ .exit = resourced_proc_watchdog_process_finalize,
};
-PROC_MODULE_REGISTER(&proc_watchdog_ops)
+MODULE_REGISTER(&proc_watchdog_modules_ops)
error = proc_get_oom_score_adj(pid, &oom_score_adj);
if (error) {
- _E("[DEBUG] Cannot get oom_score_adj of pid (%d)", pid);
+ _E("Cannot get oom_score_adj of pid (%d)", pid);
return RESOURCED_ERROR_FAIL;
}
return RESOURCED_ERROR_NONE;
}
- _E("[DEBUG] pthread_mutex_trylock fail: %d, errno: %d", ret, errno);
+ _E("pthread_mutex_trylock fail: %d, errno: %d", ret, errno);
return RESOURCED_ERROR_FAIL;
}
memcpy(&(bundle->msg), data, sizeof(struct swap_status_msg));
if (bundle->msg.type <= CGROUP_HIGH) {
- _E("[DEBUG] swap op should be done on CGROUP Medium or Lowest");
+ _E("swap op should be done on CGROUP Medium or Lowest");
return RESOURCED_ERROR_FAIL;
}
ret = swap_communicate_thread(bundle);
r = config_parse_new(SWAP_CONF_FILE, (void*) items);
if (r < 0) {
- _E("[DEBUG] Failed to parse configuration file: %m");
+ _E("Failed to parse configuration file: %m");
return r;
}
if (algorithm)
strncpy(zram_control.comp_algorithm, algorithm, MAX_TYPE_LENGTH - 1);
- _I("[DEBUG] algorithm=%s, ratio=%f", algorithm, zram_control.ratio);
+ _I("algorithm=%s, ratio=%f", algorithm, zram_control.ratio);
return 0;
}
SET(UNIT_TESTS_CFLAGS "${UNIT_TESTS_CFLAGS} -I${MEMORY_LIMITER_SOURCE_DIR}")
SET(UNIT_TESTS_CFLAGS "${UNIT_TESTS_CFLAGS} -I${PROCESS_SOURCE_DIR}")
SET(UNIT_TESTS_CFLAGS "${UNIT_TESTS_CFLAGS} -I${RESOURCED_SOURCE_DIR}")
-SET(UNIT_TESTS_CFLAGS "${UNIT_TESTS_CFLAGS} -I${VIP_SOURCE_DIR}")
+SET(UNIT_TESTS_CFLAGS "${UNIT_TESTS_CFLAGS} -I${WATCHDOG_SOURCE_DIR}")
SET(UNIT_TESTS_CFLAGS "${UNIT_TESTS_CFLAGS} -Wno-psabi")
function(ADD_TESTS name flags wraps sources)
ADD_SKIP_TEST(test-block "-O0" test-block.c)
ADD_SKIP_TEST(test-block-monitor "-O0" test-block-monitor.c)
ADD_SKIP_TEST(test-common-procfs "-O0" test-common-procfs.c)
-ADD_SKIP_TEST(test-vip-agent "-O0" test-vip-agent.c)
+ADD_SKIP_TEST(test-proc-watchdog-handler "-O0" test-proc-watchdog-handler.c)
function(ADD_MEMORY_TESTS name libs wraps sources)
ADD_EXECUTABLE(${name} ${sources} ${ARGN})