From 0dd653e624f332ea1e90dc4a93ce4c048dc0510f Mon Sep 17 00:00:00 2001 From: Woody Lin Date: Mon, 17 Jun 2024 14:13:12 +0800 Subject: [PATCH] gs_watchdogd: Use timeout defined by platform Uses timeout value of watchdog device directly, without modifying it with ioctl. On some platforms, especially these with multiple watchdog devices, the timeout values can be strictly defined for the watchdogs to timeout in a certain order. Leaves timeout value as it is and divides minimal of them by 2 as watchdog kicking period. Flag: EXEMPT normal/day-to-day bugfix Bug: 348318712 Change-Id: Icdcce368f1803cd3b38a48f05e2788d881e3ad6f --- gs_watchdogd/gs_watchdogd.cpp | 64 ++++++++++++++++--------------- gs_watchdogd/init.gs_watchdogd.rc | 4 +- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/gs_watchdogd/gs_watchdogd.cpp b/gs_watchdogd/gs_watchdogd.cpp index 82e01d0..333e023 100644 --- a/gs_watchdogd/gs_watchdogd.cpp +++ b/gs_watchdogd/gs_watchdogd.cpp @@ -19,38 +19,31 @@ #include #include #include +#include -#include #include #include #include #include #include +#include #include -#include +#include #include +#define NSEC_PER_SEC (1000LL * 1000LL * 1000LL) + #define DEV_GLOB "/sys/devices/platform/*.watchdog_cl*/watchdog/watchdog*" -#define DEFAULT_INTERVAL 10s -#define DEFAULT_MARGIN 10s - using android::base::Basename; using android::base::StringPrintf; -using std::literals::chrono_literals::operator""s; -int main(int argc, char** argv) { +int main(int __unused argc, char** argv) { + auto min_timeout_nsecs = std::numeric_limits::max(); + android::base::InitLogging(argv, &android::base::KernelLogger); - std::chrono::seconds interval = argc >= 2 - ? std::chrono::seconds(atoi(argv[1])) : DEFAULT_INTERVAL; - std::chrono::seconds margin = argc >= 3 - ? std::chrono::seconds(atoi(argv[2])) : DEFAULT_MARGIN; - - LOG(INFO) << "gs_watchdogd started (interval " << interval.count() - << ", margin " << margin.count() << ")!"; - glob_t globbuf; int ret = glob(DEV_GLOB, GLOB_MARK, nullptr, &globbuf); if (ret) { @@ -61,8 +54,7 @@ int main(int argc, char** argv) { std::vector wdt_dev_fds; for (size_t i = 0; i < globbuf.gl_pathc; i++) { - std::chrono::seconds timeout = interval + margin; - int timeout_secs = timeout.count(); + int timeout_secs; std::string dev_path = StringPrintf("/dev/%s", Basename(globbuf.gl_pathv[i]).c_str()); int fd = TEMP_FAILURE_RETRY(open(dev_path.c_str(), O_RDWR | O_CLOEXEC)); @@ -71,29 +63,39 @@ int main(int argc, char** argv) { return 1; } - wdt_dev_fds.emplace_back(fd); - ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout_secs); + ret = ioctl(fd, WDIOC_GETTIMEOUT, &timeout_secs); if (ret) { - PLOG(ERROR) << "Failed to set timeout to " << timeout_secs; - ret = ioctl(fd, WDIOC_GETTIMEOUT, &timeout_secs); - if (ret) { - PLOG(ERROR) << "Failed to get timeout"; - } else { - interval = timeout > margin ? timeout - margin : 1s; - LOG(WARNING) << "Adjusted interval to timeout returned by driver: " - << "timeout " << timeout_secs - << ", interval " << interval.count() - << ", margin " << margin.count(); - } + PLOG(ERROR) << "Failed to get timeout on " << dev_path; + continue; + } else { + min_timeout_nsecs = std::min(min_timeout_nsecs, NSEC_PER_SEC * timeout_secs); } + + wdt_dev_fds.emplace_back(fd); } globfree(&globbuf); + if (wdt_dev_fds.empty()) { + LOG(ERROR) << "no valid wdt dev found"; + return 1; + } + + timespec ts; + auto result = div(min_timeout_nsecs / 2, NSEC_PER_SEC); + ts.tv_sec = result.quot; + ts.tv_nsec = result.rem; + while (true) { + timespec rem = ts; + for (const auto& fd : wdt_dev_fds) { TEMP_FAILURE_RETRY(write(fd, "", 1)); } - sleep(interval.count()); + + if (TEMP_FAILURE_RETRY(nanosleep(&rem, &rem))) { + PLOG(ERROR) << "nanosleep failed"; + return 1; + } } } diff --git a/gs_watchdogd/init.gs_watchdogd.rc b/gs_watchdogd/init.gs_watchdogd.rc index f58ce50..23d5fb2 100644 --- a/gs_watchdogd/init.gs_watchdogd.rc +++ b/gs_watchdogd/init.gs_watchdogd.rc @@ -1,5 +1,5 @@ -# Set watchdog timer to 30 seconds and pet it every 10 seconds to get a 20 second margin -service gs_watchdogd /system_ext/bin/gs_watchdogd 10 20 +# Pet watchdog timer every half of its timeout period. +service gs_watchdogd /system_ext/bin/gs_watchdogd class core oneshot seclabel u:r:gs_watchdogd:s0