watchdog ,hang_detect分析

来源:互联网 发布:淘宝客店铺做裂变 编辑:程序博客网 时间:2024/05/16 06:45

作用:
用于监控,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_detectstatic 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_detectint 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;}
//在新线程中运行此函数,去监控watchdogstatic 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@Overridepublic void run() {    while (true) {        if (exceptionHWT != null) {            exceptionHWT.WDTMatterJava(300);        }    }}
frameworks/base/core/java/com/mediatek/aee/ExceptionLog.javapublic 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.cppstatic 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

0 0