xref: /aosp_15_r20/frameworks/native/libs/binder/RpcTransportUtils.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright (C) 2022 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker #pragma once
17*38e8c45fSAndroid Build Coastguard Worker 
18*38e8c45fSAndroid Build Coastguard Worker #include <binder/unique_fd.h>
19*38e8c45fSAndroid Build Coastguard Worker #include <poll.h>
20*38e8c45fSAndroid Build Coastguard Worker 
21*38e8c45fSAndroid Build Coastguard Worker #include "FdTrigger.h"
22*38e8c45fSAndroid Build Coastguard Worker #include "RpcState.h"
23*38e8c45fSAndroid Build Coastguard Worker 
24*38e8c45fSAndroid Build Coastguard Worker namespace android {
25*38e8c45fSAndroid Build Coastguard Worker 
26*38e8c45fSAndroid Build Coastguard Worker template <typename SendOrReceive>
interruptableReadOrWrite(const android::RpcTransportFd & socket,FdTrigger * fdTrigger,iovec * iovs,int niovs,SendOrReceive sendOrReceiveFun,const char * funName,int16_t event,const std::optional<binder::impl::SmallFunction<status_t ()>> & altPoll)27*38e8c45fSAndroid Build Coastguard Worker status_t interruptableReadOrWrite(
28*38e8c45fSAndroid Build Coastguard Worker         const android::RpcTransportFd& socket, FdTrigger* fdTrigger, iovec* iovs, int niovs,
29*38e8c45fSAndroid Build Coastguard Worker         SendOrReceive sendOrReceiveFun, const char* funName, int16_t event,
30*38e8c45fSAndroid Build Coastguard Worker         const std::optional<binder::impl::SmallFunction<status_t()>>& altPoll) {
31*38e8c45fSAndroid Build Coastguard Worker     MAYBE_WAIT_IN_FLAKE_MODE;
32*38e8c45fSAndroid Build Coastguard Worker 
33*38e8c45fSAndroid Build Coastguard Worker     if (niovs < 0) {
34*38e8c45fSAndroid Build Coastguard Worker         return BAD_VALUE;
35*38e8c45fSAndroid Build Coastguard Worker     }
36*38e8c45fSAndroid Build Coastguard Worker 
37*38e8c45fSAndroid Build Coastguard Worker     // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
38*38e8c45fSAndroid Build Coastguard Worker     // may never know we should be shutting down.
39*38e8c45fSAndroid Build Coastguard Worker     if (fdTrigger->isTriggered()) {
40*38e8c45fSAndroid Build Coastguard Worker         return DEAD_OBJECT;
41*38e8c45fSAndroid Build Coastguard Worker     }
42*38e8c45fSAndroid Build Coastguard Worker 
43*38e8c45fSAndroid Build Coastguard Worker     // If iovs has one or more empty vectors at the end and
44*38e8c45fSAndroid Build Coastguard Worker     // we somehow advance past all the preceding vectors and
45*38e8c45fSAndroid Build Coastguard Worker     // pass some or all of the empty ones to sendmsg/recvmsg,
46*38e8c45fSAndroid Build Coastguard Worker     // the call will return processSize == 0. In that case
47*38e8c45fSAndroid Build Coastguard Worker     // we should be returning OK but instead return DEAD_OBJECT.
48*38e8c45fSAndroid Build Coastguard Worker     // To avoid this problem, we make sure here that the last
49*38e8c45fSAndroid Build Coastguard Worker     // vector at iovs[niovs - 1] has a non-zero length.
50*38e8c45fSAndroid Build Coastguard Worker     while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
51*38e8c45fSAndroid Build Coastguard Worker         niovs--;
52*38e8c45fSAndroid Build Coastguard Worker     }
53*38e8c45fSAndroid Build Coastguard Worker     if (niovs == 0) {
54*38e8c45fSAndroid Build Coastguard Worker         // The vectors are all empty, so we have nothing to send.
55*38e8c45fSAndroid Build Coastguard Worker         return OK;
56*38e8c45fSAndroid Build Coastguard Worker     }
57*38e8c45fSAndroid Build Coastguard Worker 
58*38e8c45fSAndroid Build Coastguard Worker     bool havePolled = false;
59*38e8c45fSAndroid Build Coastguard Worker     while (true) {
60*38e8c45fSAndroid Build Coastguard Worker         ssize_t processSize = sendOrReceiveFun(iovs, niovs);
61*38e8c45fSAndroid Build Coastguard Worker         if (processSize < 0) {
62*38e8c45fSAndroid Build Coastguard Worker             int savedErrno = errno;
63*38e8c45fSAndroid Build Coastguard Worker 
64*38e8c45fSAndroid Build Coastguard Worker             // Still return the error on later passes, since it would expose
65*38e8c45fSAndroid Build Coastguard Worker             // a problem with polling
66*38e8c45fSAndroid Build Coastguard Worker             if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
67*38e8c45fSAndroid Build Coastguard Worker                 LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
68*38e8c45fSAndroid Build Coastguard Worker                 return -savedErrno;
69*38e8c45fSAndroid Build Coastguard Worker             }
70*38e8c45fSAndroid Build Coastguard Worker         } else if (processSize == 0) {
71*38e8c45fSAndroid Build Coastguard Worker             return DEAD_OBJECT;
72*38e8c45fSAndroid Build Coastguard Worker         } else {
73*38e8c45fSAndroid Build Coastguard Worker             while (processSize > 0 && niovs > 0) {
74*38e8c45fSAndroid Build Coastguard Worker                 auto& iov = iovs[0];
75*38e8c45fSAndroid Build Coastguard Worker                 if (static_cast<size_t>(processSize) < iov.iov_len) {
76*38e8c45fSAndroid Build Coastguard Worker                     // Advance the base of the current iovec
77*38e8c45fSAndroid Build Coastguard Worker                     iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
78*38e8c45fSAndroid Build Coastguard Worker                     iov.iov_len -= processSize;
79*38e8c45fSAndroid Build Coastguard Worker                     break;
80*38e8c45fSAndroid Build Coastguard Worker                 }
81*38e8c45fSAndroid Build Coastguard Worker 
82*38e8c45fSAndroid Build Coastguard Worker                 // The current iovec was fully written
83*38e8c45fSAndroid Build Coastguard Worker                 processSize -= iov.iov_len;
84*38e8c45fSAndroid Build Coastguard Worker                 iovs++;
85*38e8c45fSAndroid Build Coastguard Worker                 niovs--;
86*38e8c45fSAndroid Build Coastguard Worker             }
87*38e8c45fSAndroid Build Coastguard Worker             if (niovs == 0) {
88*38e8c45fSAndroid Build Coastguard Worker                 LOG_ALWAYS_FATAL_IF(processSize > 0,
89*38e8c45fSAndroid Build Coastguard Worker                                     "Reached the end of iovecs "
90*38e8c45fSAndroid Build Coastguard Worker                                     "with %zd bytes remaining",
91*38e8c45fSAndroid Build Coastguard Worker                                     processSize);
92*38e8c45fSAndroid Build Coastguard Worker                 return OK;
93*38e8c45fSAndroid Build Coastguard Worker             }
94*38e8c45fSAndroid Build Coastguard Worker         }
95*38e8c45fSAndroid Build Coastguard Worker 
96*38e8c45fSAndroid Build Coastguard Worker         if (altPoll) {
97*38e8c45fSAndroid Build Coastguard Worker             if (status_t status = (*altPoll)(); status != OK) return status;
98*38e8c45fSAndroid Build Coastguard Worker             if (fdTrigger->isTriggered()) {
99*38e8c45fSAndroid Build Coastguard Worker                 return DEAD_OBJECT;
100*38e8c45fSAndroid Build Coastguard Worker             }
101*38e8c45fSAndroid Build Coastguard Worker         } else {
102*38e8c45fSAndroid Build Coastguard Worker             if (status_t status = fdTrigger->triggerablePoll(socket, event); status != OK)
103*38e8c45fSAndroid Build Coastguard Worker                 return status;
104*38e8c45fSAndroid Build Coastguard Worker             if (!havePolled) havePolled = true;
105*38e8c45fSAndroid Build Coastguard Worker         }
106*38e8c45fSAndroid Build Coastguard Worker     }
107*38e8c45fSAndroid Build Coastguard Worker }
108*38e8c45fSAndroid Build Coastguard Worker 
109*38e8c45fSAndroid Build Coastguard Worker } // namespace android
110