作用:
用于监控,system_server 中的watchdog 线程的行为是否异常。
实现:
mtk 在kernel 中专门注册了一个设备( /dev/RT_Monitor ),用于和上层通信监控 watchdog是否正常。
大概为:watchdog 向/dev/RT_Monitor 设置一个值,然后hang_detect根据此值,计算出一个时间,在此时间内,watchdog,必须再次通知一下hang_detect, 来表示并未超时。
代码流程:
kernel-3.18/drivers/misc/mediatek/aee/aed/monitor_hang.c
//定义/dev/RT_Monitor 设备。
static struct miscdevice aed_wdt_RT_Monitor_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "RT_Monitor",
.fops = &aed_wdt_RT_Monitor_fops,
};
//定义/dev/RT_Monitor 设备对应的操作函数。
static const struct file_operations aed_wdt_RT_Monitor_fops = {
.owner = THIS_MODULE,
.open = monitor_hang_open,
.release = monitor_hang_release,
.poll = monitor_hang_poll,
.read = monitor_hang_read,
.write = monitor_hang_write,
//watchdog 调用ioctl RT_Monitor驱动时,会调用 此方法monitor_hang_ioctl,来从新设置超时时间。
.unlocked_ioctl = monitor_hang_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = monitor_hang_ioctl,
#endif
}
//注册设备,并初始化 hang_detect
static int __init monitor_hang_init(void)
{
//注册一个字符设备,/dev/RT_Monitor
err = misc_register(&aed_wdt_RT_Monitor_dev);
//初始化hang_detect
hang_detect_init();
return err;
}
//启动一个新线程,初始化hang_detect
int hang_detect_init(void)
{
struct task_struct *hd_thread;
unsigned char *name = "hang_detect";
//创建monitor hang 线程,去监控 watchdog
//hang_detect_thread 新线程要运行的方法
//name 新线程的名字
hd_thread = kthread_create(hang_detect_thread, NULL, name);
//唤醒开始运行hd_thread,
wake_up_process(hd_thread);
return 0;
}
//在新线程中运行此函数,去监控watchdog
static int hang_detect_thread(void *arg)
{
struct sched_param param = {.sched_priority = 99 };
//设置调度策略
sched_setscheduler(current, SCHED_FIFO, ¶m);
//无限循环开始监控watchdog
while (!kthread_should_stop()) {
if ((1 == hd_detect_enabled) && (FindTaskByName("system_server") != -1)) {
if (hang_detect_counter <= 0)
ShowStatus();
if (hang_detect_counter == 0) {
//根据当前版本做不同的选择,
//如果是user版本,去通过aee_kernel_warning_api 抓取oops,并上报warning
if (aee_mode != AEE_MODE_CUSTOMER_USER) {
aee_kernel_warning_api
(__FILE__, __LINE__,
DB_OPT_NE_JBT_TRACES | DB_OPT_DISPLAY_HANG_DUMP,
"\nCRDISPATCH_KEY:SS Hang\n",
"we triger HWT ");
msleep(30 * 1000);
} else {
//如果不是user版本,向kernel上报bug,
BUG();
}
}
//如果本次循环没有问题,hang_detect_counter 减一,并休眠30s
//上层会通过ioctl RT_Monitor 设备,来重设 hang_detect_counter 的值
hang_detect_counter--;
} else {
//如果没有找到system_server线程,表示系统在重启,那么等待hang_detect_counter*30s
if (1 == hd_detect_enabled) {
hang_detect_counter = hd_timeout + 4;
hd_detect_enabled = 0;
}
}
//每次循环休眠30s
msleep((HD_INTER) * 1000);
}
return 0;
}
//如果是user版本:
kernel-3.18/drivers/misc/mediatek/aee/common/aee-common.c
void aee_kernel_warning_api(const char *file, const int line, const int db_opt, const char *module, const char *msg, ...)
{
char msgbuf[KERNEL_REPORT_LENGTH];
int offset = 0;
va_list args;
va_start(args, msg);
offset += snprintf(msgbuf, KERNEL_REPORT_LENGTH, "<%s:%d> ", file, line);
offset += vsnprintf(msgbuf + offset, KERNEL_REPORT_LENGTH - offset, msg, args);
if (g_aee_api && g_aee_api->kernel_reportAPI)
//如果g_aee_api存在且初始化成功,调用他的 kernel_reportAPI方法
g_aee_api->kernel_reportAPI(AE_DEFECT_WARNING, db_opt, module, msgbuf);
else
LOGE("AEE kernel warning: %s", msgbuf);
va_end(args);
}
EXPORT_SYMBOL(aee_kernel_warning_api);
//g_aee_api 的初始化为:
drivers/misc/mediatek/aee/aed/aed-main.c
module_init(aed_init);
static int __init aed_init(void)
{
......
aee_register_api(&kernel_api);
......
}
此kernel_api 是在本类中定义的,他的kernel_reportAPI 方法也是本类中的方法
static struct aee_kernel_api kernel_api = {
.kernel_reportAPI = kernel_reportAPI,
.md_exception = external_exception,
.md32_exception = external_exception,
.scp_exception = external_exception,
.combo_exception = external_exception
};
drivers/misc/mediatek/aee/common/aee-common.c
会在aee_register_api 方法中将kernel_api 赋值给g_aee_api
void aee_register_api(struct aee_kernel_api *aee_api)
{
if (!aee_api)
BUG();
g_aee_api = aee_api;
}
上层与底层通信是:
frameworks/base/services/core/java/com/android/server/Watchdog.java
@Override
public void run() {
while (true) {
if (exceptionHWT != null) {
exceptionHWT.WDTMatterJava(300);
}
}
}
frameworks/base/core/java/com/mediatek/aee/ExceptionLog.java
public void WDTMatterJava(long lParam) {
WDTMatter(lParam) ;
}
private static native void WDTMatter(long lParam) ;
frameworks/base/core/java/com/mediatek/aee/jni/com_mediatek_aee_exceptionlog.cpp
static void com_mediatek_exceptionlog_WDTMatter (JNIEnv* env, jobject clazz, jlong lParam){
//AE_WDT_DEVICE_PATH 即为设备 "/dev/RT_Monitor"
int fd = open(AE_WDT_DEVICE_PATH, O_RDONLY);
//通过ioctl 将 300 传入 RT_Monitor 驱动
if (ret = ioctl(fd, AEEIOCTL_RT_MON_Kick, (int)(lParam)))
......
close (fd) ;
return;
}
在之后会调用到monitor_hang 类的 monitor_hang_ioctl 方法(在注册此设备时,就已经指定,ioctl此设备,会调用此函数)
// 对 /dev/RT_Monitor 使用ioctl 操作时会调用此方法。
//cmd 为 AEEIOCTL_RT_MON_Kick
// arg 为 300
static long monitor_hang_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
......
//正常会走这里
if (cmd == AEEIOCTL_RT_MON_Kick) {
LOGE("AEEIOCTL_RT_MON_Kick ( %d)\n", (int)arg);
aee_kernel_RT_Monitor_api((int)arg);
return ret;
}
......
}
//在此方法中根据lParam(300),从新计算hang_detect_counter 的值
void aee_kernel_RT_Monitor_api(int lParam)
{
......
hd_detect_enabled = 1;
//HD_INTER 为 30
//300 对应的为 10,
//那么表示在10*30s内,watchdog 必须再次ioctl RT_monitor,否则认为watchdog 发生异常。
hang_detect_counter = hd_timeout = ((long)lParam + HD_INTER - 1) / (HD_INTER);
......
}
}
参考:
http://blog.csdn.net/ldinvicible/article/details/51042811