libhealthloop: Handle netlink receive buffer overflows
The Linux kernel netlink implementation sets EPOLLERR if delivery of a
netlink message fails because of a buffer overrun (see also the Linux
kernel netlink_overrun() and sock_def_error_report() functions). Handle
buffer overruns by calling ScheduleBatteryUpdate() unconditionally.
Bug: 203462310
Change-Id: I54f7d239e6b4caad0db4d1b15de7c0385f796ebd
Signed-off-by: Bart Van Assche <bvanassche@google.com>
diff --git a/health/utils/libhealthloop/HealthLoop.cpp b/health/utils/libhealthloop/HealthLoop.cpp
index ba7e75a..f8c3490 100644
--- a/health/utils/libhealthloop/HealthLoop.cpp
+++ b/health/utils/libhealthloop/HealthLoop.cpp
@@ -57,14 +57,13 @@
EventHandler{this, fd, std::move(func)}))
.get();
- struct epoll_event ev;
-
- ev.events = EPOLLIN;
+ struct epoll_event ev = {
+ .events = EPOLLIN | EPOLLERR,
+ .data.ptr = reinterpret_cast<void*>(event_handler),
+ };
if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
- ev.data.ptr = reinterpret_cast<void*>(event_handler);
-
if (epoll_ctl(epollfd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
KLOG_ERROR(LOG_TAG, "epoll_ctl failed; errno=%d\n", errno);
return -1;
@@ -119,9 +118,15 @@
// TODO(b/140330870): Use BPF instead.
#define UEVENT_MSG_LEN 2048
-void HealthLoop::UeventEvent(uint32_t /*epevents*/) {
+void HealthLoop::UeventEvent(uint32_t epevents) {
// No need to lock because uevent_fd_ is guaranteed to be initialized.
+ if (epevents & EPOLLERR) {
+ // The netlink receive buffer overflowed.
+ ScheduleBatteryUpdate();
+ return;
+ }
+
char msg[UEVENT_MSG_LEN + 2];
char* cp;
int n;