rpc_binder: Properly shut down on socketpair() EOF
FdTrigger::triggerablePoll returns OK on POLLIN (higher priority)
and DEAD_OBJECT on POLLHUP (lower priority). Unlike INET or vsock,
socketpair() sockets trigger POLLIN|POLLHUP on EOF and EOF is detected
by recvmsg() returning zero bytes.
Adjust the server accept loop to take this into account and correctly
break out of the loop.
Bug: 250685929
Test: cleanly shut down UDS bootstrap RpcServer
Change-Id: I56d6a67373f16b5b1bdc167de94a7252bedca8e2
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index d47e4f0..0d06e9e 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -204,11 +204,15 @@
iovec iov{&zero, sizeof(zero)};
std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds;
- if (receiveMessageFromSocket(server.mServer, &iov, 1, &fds) < 0) {
+ ssize_t num_bytes = receiveMessageFromSocket(server.mServer, &iov, 1, &fds);
+ if (num_bytes < 0) {
int savedErrno = errno;
ALOGE("Failed recvmsg: %s", strerror(savedErrno));
return -savedErrno;
}
+ if (num_bytes == 0) {
+ return DEAD_OBJECT;
+ }
if (fds.size() != 1) {
ALOGE("Expected exactly one fd from recvmsg, got %zu", fds.size());
return -EINVAL;
@@ -243,8 +247,11 @@
socklen_t addrLen = addr.size();
RpcTransportFd clientSocket;
- if (mAcceptFn(*this, &clientSocket) != OK) {
- continue;
+ if ((status = mAcceptFn(*this, &clientSocket)) != OK) {
+ if (status == DEAD_OBJECT)
+ break;
+ else
+ continue;
}
LOG_RPC_DETAIL("accept on fd %d yields fd %d", mServer.fd.get(), clientSocket.fd.get());