watchdog ,hang_detect分析

作用:
用于监控,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, &param);

    //无限循环开始监控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);
        ......
    }
}

 

---------------------  

原文:https://blog.csdn.net/xiaolli/article/details/62039795  
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值