libbinder: move interruptableReadOrWrite to new file
Moves interruptableReadOrWrite to a new RpcTransportUtils.h
file so it can be used by multiple transports.
Bug: 224644083
Test: m
Change-Id: Ife48519ab5c6a99d5fbbcd4ad9e6c3fe517dd0ba
diff --git a/libs/binder/FdTrigger.h b/libs/binder/FdTrigger.h
index 5c7102e..a25dc11 100644
--- a/libs/binder/FdTrigger.h
+++ b/libs/binder/FdTrigger.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#include <memory>
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 7cc58cd..51326f6 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -24,6 +24,7 @@
#include "FdTrigger.h"
#include "RpcState.h"
+#include "RpcTransportUtils.h"
namespace android {
@@ -55,90 +56,6 @@
return OK;
}
- template <typename SendOrReceive>
- status_t interruptableReadOrWrite(
- FdTrigger* fdTrigger, iovec* iovs, int niovs, SendOrReceive sendOrReceiveFun,
- const char* funName, int16_t event,
- const std::optional<android::base::function_ref<status_t()>>& altPoll) {
- MAYBE_WAIT_IN_FLAKE_MODE;
-
- if (niovs < 0) {
- return BAD_VALUE;
- }
-
- // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
- // may never know we should be shutting down.
- if (fdTrigger->isTriggered()) {
- return DEAD_OBJECT;
- }
-
- // If iovs has one or more empty vectors at the end and
- // we somehow advance past all the preceding vectors and
- // pass some or all of the empty ones to sendmsg/recvmsg,
- // the call will return processSize == 0. In that case
- // we should be returning OK but instead return DEAD_OBJECT.
- // To avoid this problem, we make sure here that the last
- // vector at iovs[niovs - 1] has a non-zero length.
- while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
- niovs--;
- }
- if (niovs == 0) {
- // The vectors are all empty, so we have nothing to send.
- return OK;
- }
-
- bool havePolled = false;
- while (true) {
- ssize_t processSize = sendOrReceiveFun(iovs, niovs);
- if (processSize < 0) {
- int savedErrno = errno;
-
- // Still return the error on later passes, since it would expose
- // a problem with polling
- if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
- LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
- return -savedErrno;
- }
- } else if (processSize == 0) {
- return DEAD_OBJECT;
- } else {
- while (processSize > 0 && niovs > 0) {
- auto& iov = iovs[0];
- if (static_cast<size_t>(processSize) < iov.iov_len) {
- // Advance the base of the current iovec
- iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
- iov.iov_len -= processSize;
- break;
- }
-
- // The current iovec was fully written
- processSize -= iov.iov_len;
- iovs++;
- niovs--;
- }
- if (niovs == 0) {
- LOG_ALWAYS_FATAL_IF(processSize > 0,
- "Reached the end of iovecs "
- "with %zd bytes remaining",
- processSize);
- return OK;
- }
- }
-
- if (altPoll) {
- if (status_t status = (*altPoll)(); status != OK) return status;
- if (fdTrigger->isTriggered()) {
- return DEAD_OBJECT;
- }
- } else {
- if (status_t status = fdTrigger->triggerablePoll(mSocket.get(), event);
- status != OK)
- return status;
- if (!havePolled) havePolled = true;
- }
- }
- }
-
status_t interruptableWriteFully(
FdTrigger* fdTrigger, iovec* iovs, int niovs,
const std::optional<android::base::function_ref<status_t()>>& altPoll,
@@ -198,7 +115,8 @@
};
return TEMP_FAILURE_RETRY(sendmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
};
- return interruptableReadOrWrite(fdTrigger, iovs, niovs, send, "sendmsg", POLLOUT, altPoll);
+ return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, send, "sendmsg",
+ POLLOUT, altPoll);
}
status_t interruptableReadFully(
@@ -255,7 +173,8 @@
};
return TEMP_FAILURE_RETRY(recvmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
};
- return interruptableReadOrWrite(fdTrigger, iovs, niovs, recv, "recvmsg", POLLIN, altPoll);
+ return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, recv, "recvmsg",
+ POLLIN, altPoll);
}
private:
diff --git a/libs/binder/RpcTransportUtils.h b/libs/binder/RpcTransportUtils.h
new file mode 100644
index 0000000..00cb2af
--- /dev/null
+++ b/libs/binder/RpcTransportUtils.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <poll.h>
+
+#include "FdTrigger.h"
+#include "RpcState.h"
+
+namespace android {
+
+template <typename SendOrReceive>
+status_t interruptableReadOrWrite(
+ int socketFd, FdTrigger* fdTrigger, iovec* iovs, int niovs, SendOrReceive sendOrReceiveFun,
+ const char* funName, int16_t event,
+ const std::optional<android::base::function_ref<status_t()>>& altPoll) {
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
+ if (niovs < 0) {
+ return BAD_VALUE;
+ }
+
+ // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
+ // may never know we should be shutting down.
+ if (fdTrigger->isTriggered()) {
+ return DEAD_OBJECT;
+ }
+
+ // If iovs has one or more empty vectors at the end and
+ // we somehow advance past all the preceding vectors and
+ // pass some or all of the empty ones to sendmsg/recvmsg,
+ // the call will return processSize == 0. In that case
+ // we should be returning OK but instead return DEAD_OBJECT.
+ // To avoid this problem, we make sure here that the last
+ // vector at iovs[niovs - 1] has a non-zero length.
+ while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
+ niovs--;
+ }
+ if (niovs == 0) {
+ // The vectors are all empty, so we have nothing to send.
+ return OK;
+ }
+
+ bool havePolled = false;
+ while (true) {
+ ssize_t processSize = sendOrReceiveFun(iovs, niovs);
+ if (processSize < 0) {
+ int savedErrno = errno;
+
+ // Still return the error on later passes, since it would expose
+ // a problem with polling
+ if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
+ LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
+ return -savedErrno;
+ }
+ } else if (processSize == 0) {
+ return DEAD_OBJECT;
+ } else {
+ while (processSize > 0 && niovs > 0) {
+ auto& iov = iovs[0];
+ if (static_cast<size_t>(processSize) < iov.iov_len) {
+ // Advance the base of the current iovec
+ iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
+ iov.iov_len -= processSize;
+ break;
+ }
+
+ // The current iovec was fully written
+ processSize -= iov.iov_len;
+ iovs++;
+ niovs--;
+ }
+ if (niovs == 0) {
+ LOG_ALWAYS_FATAL_IF(processSize > 0,
+ "Reached the end of iovecs "
+ "with %zd bytes remaining",
+ processSize);
+ return OK;
+ }
+ }
+
+ if (altPoll) {
+ if (status_t status = (*altPoll)(); status != OK) return status;
+ if (fdTrigger->isTriggered()) {
+ return DEAD_OBJECT;
+ }
+ } else {
+ if (status_t status = fdTrigger->triggerablePoll(socketFd, event); status != OK)
+ return status;
+ if (!havePolled) havePolled = true;
+ }
+ }
+}
+
+} // namespace android