Android 自己设计出的watchdog方案
一、一般情况下kernel层有问题的话,会有一套机制重启。我这里主要考虑是android上层有问题的时候,比如卡死的时候,不动用外部复位IC的情况下重启。
二、如何模拟android上层卡死呢?运行下面的命令,下面的命令会无限制的创建新的进程,耗尽内存,从而把android系统搞卡死,但是kernel层运行正常。
bomb(){ bomb|bomb & };bomb
三、设计思路很简单,在kernel搞一个定时器,因为上层卡死时候定时器还是在work的。开机运行giada_watchdog进行喂狗,设置persist.gwatchdog.enable和persist.gwatchdog.timeout的值来设置是否开启watchdog和时间,超时不喂狗就调用emergency_restart()紧急重启。
四、整个watchdong功能需要修改和添加的文件内容如下patch。
commit 003aeea086597bedbaed8838b382a6e1db1901a4
Author: weifanghai <weifanghai@giadatech.comgit@192.168.2.62:weifanghai/giadahdmiin.git>
Date: Sat Mar 13 14:42:21 2021 +0800
add giada watchdog function.
setprop persist.gwatchdog.enable 1 to enable watchdog,setprop persist.gwatchdog.enable 0 to disabled watchdog.
setprop persist.gwatchdog.timeout 15 to set watchdog timeout, the default value is 15s.
how to test watchdong----- adb shell ,then run "bomb(){ bomb|bomb & };bomb" to make the system crash.
diff --git a/device/rockchip/rk3288/device.mk b/device/rockchip/rk3288/device.mk
index c9ae574..cb51a5f 100755
--- a/device/rockchip/rk3288/device.mk
+++ b/device/rockchip/rk3288/device.mk
@@ -18,7 +18,8 @@ PRODUCT_PACKAGES += \
i2cdetect \
i2cget \
i2cdump \
- i2cset
+ i2cset \
+ giada_watchdog
PRODUCT_PACKAGES += \
memtrack.$(TARGET_BOARD_PLATFORM) \
diff --git a/device/rockchip/rk3288/init.rk3288.rc b/device/rockchip/rk3288/init.rk3288.rc
index 34e1a1b..c624b15 100755
--- a/device/rockchip/rk3288/init.rk3288.rc
+++ b/device/rockchip/rk3288/init.rk3288.rc
@@ -11,7 +11,8 @@ on property:sys.boot_completed=1
write /dev/video_state n
write /sys/module/rockchip_pwm_remotectl/parameters/red_green_led 1
start rootservice
-
+ start gwdtservice
+
on boot
# update foreground cpuset now that processors are up
# reserve CPU 3 for the top app
@@ -56,3 +57,11 @@ service rootservice /system/bin/rootandwakelock.sh
disabled
oneshot
seclabel u:r:init:s0
+
+service gwdtservice /system/bin/giada_watchdog
+ user root
+ group root
+ disabled
+ oneshot
+ seclabel u:r:init:s0
+
diff --git a/hardware/rockchip/giada_watchdog/Android.mk b/hardware/rockchip/giada_watchdog/Android.mk
new file mode 100755
index 0000000..0e5b9d4
--- /dev/null
+++ b/hardware/rockchip/giada_watchdog/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE:=giada_watchdog
+LOCAL_SHARED_LIBRARIES:=liblog libc libcutils
+LOCAL_SRC_FILES := $(call all-subdir-c-files)
+LOCAL_LDLIBS := -llog
+include $(BUILD_EXECUTABLE)
\ No newline at end of file
diff --git a/hardware/rockchip/giada_watchdog/giada_watchdog.c b/hardware/rockchip/giada_watchdog/giada_watchdog.c
new file mode 100755
index 0000000..bc08a1c
--- /dev/null
+++ b/hardware/rockchip/giada_watchdog/giada_watchdog.c
@@ -0,0 +1,94 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <errno.h>
+#include <utils/Log.h>
+#include <stdbool.h>
+
+#define LOG_TAG "GIADAWATCHDOG"
+#define DEBUG false
+#define GIADA_WATCHDOG_CONTROL_POINT "/sys/module/act8865_regulator/parameters/giada_watchdog_control"
+
+static int write_giada_command(char const *path, unsigned char value)
+{
+ int fd;
+
+ fd = open(path, O_RDWR);
+ if (fd >= 0)
+ {
+ unsigned char buffer[5];
+ buffer[0]=value;
+ int amt = write(fd, buffer, 1);
+ close(fd);
+ return amt == -1 ? -errno : 0;
+ } else
+ {
+ printf("write_giada_command failed to open %s\n", path);
+ return -errno;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ unsigned int gwatchdog_timeout=0,last_gwatchdog_timeout=0;
+ unsigned int gwatchdog_enable=0, last_gwatchdog_enable=0;
+ long long loop_number=0;
+ unsigned char command;
+ int i;
+ ALOGI("giada watchdog begin!");
+ #if 1
+ pid_t pid;
+ pid = fork(); /* 第一步 创建子进程,父进程终止*/
+ if (pid < 0)
+ {
+ ALOGE("Error fork\n");
+ exit(1);
+ }else if (pid > 0)
+ {
+ ALOGE("\r\nfather process exist!\r\n");
+ exit(0); /* 父进程退出 */
+ }
+ ALOGI("the protect process will take effect in back desktop!");
+ setsid(); /* 第二步 */
+ chdir("/"); /* 第三步 变当前目录位置,防止目录在可卸载的文件内*/
+ umask(0); /* 第四步 重设文件权限掩码umask,防止权限被拒绝*/
+ for(i = 0; i < getdtablesize(); i++) /* 第五步 */
+ {
+ close(i);
+ /* Close out the standard file descriptors */
+ //close(STDIN_FILENO);
+ //close(STDOUT_FILENO);
+ //close(STDERR_FILENO);
+ } /* 这时建立完守护进程, 如下开始正式进入守护进程工做 */
+
+ #endif
+ while(1)
+ {
+ gwatchdog_enable = property_get_int32("persist.gwatchdog.enable", 1);
+ gwatchdog_timeout = property_get_int32("persist.gwatchdog.timeout", 15);
+ command=(unsigned char)(gwatchdog_timeout << 1) + gwatchdog_enable;
+ loop_number++;
+
+ if((loop_number%2==0)||(last_gwatchdog_enable != gwatchdog_enable)||(last_gwatchdog_timeout != gwatchdog_timeout))
+ {
+ last_gwatchdog_enable = gwatchdog_enable;
+ last_gwatchdog_timeout = gwatchdog_timeout;
+ write_giada_command(GIADA_WATCHDOG_CONTROL_POINT, command);
+ //printf("\r\ngiada watchdog working..... gwatchdog_enable=%d gwatchdog_timeout=%d command=0x%02x sencond loop_number=%lld feed_number=%lld\r\n",gwatchdog_enable,gwatchdog_timeout,command,loop_number,loop_number/2);
+ }
+ //sleep(5);
+ usleep(500000);
+
+ }
+ ALOGI("giada watchdog end!");
+ return 0;
+}
+
+
+
+
+
+
diff --git a/kernel/drivers/regulator/act8865-regulator.c b/kernel/drivers/regulator/act8865-regulator.c
index 73fdc73..7fbf69f 100755
--- a/kernel/drivers/regulator/act8865-regulator.c
+++ b/kernel/drivers/regulator/act8865-regulator.c
@@ -332,6 +332,65 @@ static struct of_regulator_match act8600_matches[] = {
struct act8865 *act8865;
+static unsigned char giada_watchdog_control=0;
+static bool giada_watchdog_timer_is_working=0;
+static int giada_watchdog_timeout=20,last_giada_watchdog_timeout=20;
+static int giada_watchdog_time_number=0;
+struct timer_list giada_watchdog_timer;
+
+extern void emergency_restart(void);
+
+static void giada_watchdog_timer_function(unsigned long _data)
+{
+ if((++giada_watchdog_time_number)>=giada_watchdog_timeout)
+ {
+ printk(KERN_ALERT "\r\n\r\n\r\n@@@@@@@@@@@@emergency_restart@@@@@@@@@@@@\r\n\r\n");
+ emergency_restart();
+ return;
+ }else {
+ mod_timer(&giada_watchdog_timer, jiffies+msecs_to_jiffies(1000));
+ }
+}
+
+static int giada_wathcdog_control_function(const char *val, const struct kernel_param *kp)
+{
+ //int rv = param_set_byte(val, kp);
+ char command=*val;
+ giada_watchdog_timeout=command>>1;
+ if(command&0x01)//the giada watchdog is enabled
+ {
+ if(giada_watchdog_timer_is_working==0)
+ {
+ setup_timer(&giada_watchdog_timer, giada_watchdog_timer_function,
+ (unsigned long)0);
+ mod_timer(&giada_watchdog_timer, jiffies+msecs_to_jiffies(1000));
+ giada_watchdog_timer_is_working=1;
+ printk("[%s]Enable giada watchdog!\r\n",__func__);
+ }
+ }
+ else if(giada_watchdog_timer_is_working==1)
+ {
+ giada_watchdog_timer_is_working=0;
+ del_timer(&giada_watchdog_timer);
+ printk("*********************[%s]Disable giada watchdog!*********************\n",__func__);
+ }
+
+ if(last_giada_watchdog_timeout != giada_watchdog_timeout)
+ printk("*********************[%s]giada_watchdog_timeout=%d*********************\n",__func__,giada_watchdog_timeout);
+
+ last_giada_watchdog_timeout=giada_watchdog_timeout;
+ giada_watchdog_time_number=0;
+
+ return 0;
+}
+
+static struct kernel_param_ops giada_watchdog_param_ops = {
+ .set = giada_wathcdog_control_function,
+ .get = param_get_byte,
+};
+
+module_param_cb(giada_watchdog_control, &giada_watchdog_param_ops, &giada_watchdog_control, 0644);
+
static int act8865_pdata_from_dt(struct device *dev,
struct device_node **of_node,
struct act8865_platform_data *pdata,
@@ -435,6 +494,26 @@ static void act8865_power_off(void)
while (1);
}
+void act8865_power_off_test(void)
+{
+ unsigned long i=2000;
+#if 0
+ struct act8865 *act8865;
+
+ act8865 = i2c_get_clientdata(act8865_i2c_client);
+ regmap_write(act8865->regmap, act8865->off_reg, act8865->off_mask);
+#else
+ gpio_direction_output(act8865->pmic_hold_gpio, 0);
+ gpio_direction_output(act8865->cpu_det_gpio, 1);
+ while(i--);
+ gpio_direction_output(act8865->cpu_det_gpio, 0);
+ printk("[%s] set cpu_det_gpio to high then set to low !set pmic_hold_gpio to low!\n",__func__);
+#endif
+ while (1);
+}
+
+
+
static int act8865_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
五、看看实际运行效果,运行bomb(){ bomb|bomb & };bomb过几秒后系统卡死,app无响应15s后系统自动重启,测试ok。