From 32a9bfec7b9ca161c0adab4633cbac905fced75e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 29 Aug 2024 08:05:10 -0700 Subject: [PATCH 1/2] libhealthloop: Modify receive buffer overflow handling Let epoll_wait() wake up healthd if a receive buffer overflow has happened. If a receive buffer overflow happened, this indicates that one or more power supply uevent messages have been discarded. Handle this by updating the battery statistics. This is the approach recommended in the netlink(7) man page. From that manual page: "However, reliable transmissions from kernel to user are impossible in any case. The kernel can't send a netlink message if the socket buffer is full: the message will be dropped and the kernel and the user-space process will no longer have the same view of kernel state. It is up to the application to detect when this happens (via the ENOBUFS error returned by recvmsg(2)) and resynchronize." Bug: 362986353 Change-Id: I0c89907eaa014f9e2859a73b29239e82f066f03f Signed-off-by: Bart Van Assche --- health/utils/libhealthloop/HealthLoop.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/health/utils/libhealthloop/HealthLoop.cpp b/health/utils/libhealthloop/HealthLoop.cpp index 691d8966e6..a43a69932c 100644 --- a/health/utils/libhealthloop/HealthLoop.cpp +++ b/health/utils/libhealthloop/HealthLoop.cpp @@ -64,7 +64,7 @@ int HealthLoop::RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) { .get(); struct epoll_event ev = { - .events = EPOLLIN, + .events = EPOLLIN | EPOLLERR, .data.ptr = reinterpret_cast(event_handler), }; @@ -128,6 +128,9 @@ bool HealthLoop::RecvUevents() { for (;;) { char msg[kUeventMsgLen + 2]; int n = uevent_kernel_multicast_recv(uevent_fd_, msg, kUeventMsgLen); + if (n < 0 && errno == ENOBUFS) { + update_stats = true; + } if (n <= 0) return update_stats; if (n >= kUeventMsgLen) { // too long -- discard From 4187755208c13f10ac0f7fcdd1f0326d7409a471 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 29 Aug 2024 08:13:18 -0700 Subject: [PATCH 2/2] libhealthloop: Reduce the size of the uevent receive buffer The HealthLoop code only checks the name of the subsystem in the uevents that it receives. Since the recently added BPF filter only passes power supply uevents, all we need to know is whether or not any such uevents have been received. We do not need to know how many of these events have been received. Hence, reduce the size of the uevent receive buffer. This CL reduces the number of ScheduleBatteryUpdate() calls if uevents are received faster than these can be processed. Bug: 362986353 Change-Id: If286ae5d05a95d59bc637a869c94d5c5472b5be2 Signed-off-by: Bart Van Assche --- health/utils/libhealthloop/HealthLoop.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health/utils/libhealthloop/HealthLoop.cpp b/health/utils/libhealthloop/HealthLoop.cpp index a43a69932c..c5ad5a8079 100644 --- a/health/utils/libhealthloop/HealthLoop.cpp +++ b/health/utils/libhealthloop/HealthLoop.cpp @@ -180,7 +180,7 @@ Result HealthLoop::AttachFilter(int uevent_fd) { } void HealthLoop::UeventInit(void) { - uevent_fd_.reset(uevent_create_socket(64 * 1024, true)); + uevent_fd_.reset(uevent_create_socket(kUeventMsgLen, true)); if (uevent_fd_ < 0) { KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");