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