xref: /aosp_15_r20/frameworks/native/libs/binder/RpcTransportTipcAndroid.cpp (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 
17*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "RpcTransportTipcAndroid"
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include <binder/RpcSession.h>
20*38e8c45fSAndroid Build Coastguard Worker #include <binder/RpcTransportTipcAndroid.h>
21*38e8c45fSAndroid Build Coastguard Worker #include <log/log.h>
22*38e8c45fSAndroid Build Coastguard Worker #include <poll.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <trusty/tipc.h>
24*38e8c45fSAndroid Build Coastguard Worker 
25*38e8c45fSAndroid Build Coastguard Worker #include "FdTrigger.h"
26*38e8c45fSAndroid Build Coastguard Worker #include "RpcState.h"
27*38e8c45fSAndroid Build Coastguard Worker #include "RpcTransportUtils.h"
28*38e8c45fSAndroid Build Coastguard Worker 
29*38e8c45fSAndroid Build Coastguard Worker using namespace android::binder::impl;
30*38e8c45fSAndroid Build Coastguard Worker using android::binder::borrowed_fd;
31*38e8c45fSAndroid Build Coastguard Worker using android::binder::unique_fd;
32*38e8c45fSAndroid Build Coastguard Worker 
33*38e8c45fSAndroid Build Coastguard Worker namespace android {
34*38e8c45fSAndroid Build Coastguard Worker 
35*38e8c45fSAndroid Build Coastguard Worker // RpcTransport for writing Trusty IPC clients in Android.
36*38e8c45fSAndroid Build Coastguard Worker class RpcTransportTipcAndroid : public RpcTransport {
37*38e8c45fSAndroid Build Coastguard Worker public:
RpcTransportTipcAndroid(android::RpcTransportFd socket)38*38e8c45fSAndroid Build Coastguard Worker     explicit RpcTransportTipcAndroid(android::RpcTransportFd socket) : mSocket(std::move(socket)) {}
39*38e8c45fSAndroid Build Coastguard Worker 
pollRead()40*38e8c45fSAndroid Build Coastguard Worker     status_t pollRead() override {
41*38e8c45fSAndroid Build Coastguard Worker         if (mReadBufferPos < mReadBufferSize) {
42*38e8c45fSAndroid Build Coastguard Worker             // We have more data in the read buffer
43*38e8c45fSAndroid Build Coastguard Worker             return OK;
44*38e8c45fSAndroid Build Coastguard Worker         }
45*38e8c45fSAndroid Build Coastguard Worker 
46*38e8c45fSAndroid Build Coastguard Worker         // Trusty IPC device is not a socket, so MSG_PEEK is not available
47*38e8c45fSAndroid Build Coastguard Worker         pollfd pfd{.fd = mSocket.fd.get(), .events = static_cast<int16_t>(POLLIN), .revents = 0};
48*38e8c45fSAndroid Build Coastguard Worker         ssize_t ret = TEMP_FAILURE_RETRY(::poll(&pfd, 1, 0));
49*38e8c45fSAndroid Build Coastguard Worker         if (ret < 0) {
50*38e8c45fSAndroid Build Coastguard Worker             int savedErrno = errno;
51*38e8c45fSAndroid Build Coastguard Worker             if (savedErrno == EAGAIN || savedErrno == EWOULDBLOCK) {
52*38e8c45fSAndroid Build Coastguard Worker                 return WOULD_BLOCK;
53*38e8c45fSAndroid Build Coastguard Worker             }
54*38e8c45fSAndroid Build Coastguard Worker 
55*38e8c45fSAndroid Build Coastguard Worker             LOG_RPC_DETAIL("RpcTransport poll(): %s", strerror(savedErrno));
56*38e8c45fSAndroid Build Coastguard Worker             return adjustStatus(-savedErrno);
57*38e8c45fSAndroid Build Coastguard Worker         }
58*38e8c45fSAndroid Build Coastguard Worker 
59*38e8c45fSAndroid Build Coastguard Worker         if (pfd.revents & POLLNVAL) {
60*38e8c45fSAndroid Build Coastguard Worker             return BAD_VALUE;
61*38e8c45fSAndroid Build Coastguard Worker         }
62*38e8c45fSAndroid Build Coastguard Worker         if (pfd.revents & POLLERR) {
63*38e8c45fSAndroid Build Coastguard Worker             return DEAD_OBJECT;
64*38e8c45fSAndroid Build Coastguard Worker         }
65*38e8c45fSAndroid Build Coastguard Worker         if (pfd.revents & POLLIN) {
66*38e8c45fSAndroid Build Coastguard Worker             // Copied from FdTrigger.cpp: Even though POLLHUP may also be set,
67*38e8c45fSAndroid Build Coastguard Worker             // treat it as a success condition to ensure data is drained.
68*38e8c45fSAndroid Build Coastguard Worker             return OK;
69*38e8c45fSAndroid Build Coastguard Worker         }
70*38e8c45fSAndroid Build Coastguard Worker         if (pfd.revents & POLLHUP) {
71*38e8c45fSAndroid Build Coastguard Worker             return DEAD_OBJECT;
72*38e8c45fSAndroid Build Coastguard Worker         }
73*38e8c45fSAndroid Build Coastguard Worker 
74*38e8c45fSAndroid Build Coastguard Worker         return WOULD_BLOCK;
75*38e8c45fSAndroid Build Coastguard Worker     }
76*38e8c45fSAndroid Build Coastguard Worker 
interruptableWriteFully(FdTrigger * fdTrigger,iovec * iovs,int niovs,const std::optional<SmallFunction<status_t ()>> & altPoll,const std::vector<std::variant<unique_fd,borrowed_fd>> * ancillaryFds)77*38e8c45fSAndroid Build Coastguard Worker     status_t interruptableWriteFully(
78*38e8c45fSAndroid Build Coastguard Worker             FdTrigger* fdTrigger, iovec* iovs, int niovs,
79*38e8c45fSAndroid Build Coastguard Worker             const std::optional<SmallFunction<status_t()>>& altPoll,
80*38e8c45fSAndroid Build Coastguard Worker             const std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override {
81*38e8c45fSAndroid Build Coastguard Worker         auto writeFn = [&](iovec* iovs, size_t niovs) -> ssize_t {
82*38e8c45fSAndroid Build Coastguard Worker             // TODO: send ancillaryFds. For now, we just abort if anyone tries
83*38e8c45fSAndroid Build Coastguard Worker             // to send any.
84*38e8c45fSAndroid Build Coastguard Worker             LOG_ALWAYS_FATAL_IF(ancillaryFds != nullptr && !ancillaryFds->empty(),
85*38e8c45fSAndroid Build Coastguard Worker                                 "File descriptors are not supported on Trusty yet");
86*38e8c45fSAndroid Build Coastguard Worker             return TEMP_FAILURE_RETRY(tipc_send(mSocket.fd.get(), iovs, niovs, nullptr, 0));
87*38e8c45fSAndroid Build Coastguard Worker         };
88*38e8c45fSAndroid Build Coastguard Worker 
89*38e8c45fSAndroid Build Coastguard Worker         status_t status = interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, writeFn,
90*38e8c45fSAndroid Build Coastguard Worker                                                    "tipc_send", POLLOUT, altPoll);
91*38e8c45fSAndroid Build Coastguard Worker         return adjustStatus(status);
92*38e8c45fSAndroid Build Coastguard Worker     }
93*38e8c45fSAndroid Build Coastguard Worker 
interruptableReadFully(FdTrigger * fdTrigger,iovec * iovs,int niovs,const std::optional<SmallFunction<status_t ()>> & altPoll,std::vector<std::variant<unique_fd,borrowed_fd>> *)94*38e8c45fSAndroid Build Coastguard Worker     status_t interruptableReadFully(
95*38e8c45fSAndroid Build Coastguard Worker             FdTrigger* fdTrigger, iovec* iovs, int niovs,
96*38e8c45fSAndroid Build Coastguard Worker             const std::optional<SmallFunction<status_t()>>& altPoll,
97*38e8c45fSAndroid Build Coastguard Worker             std::vector<std::variant<unique_fd, borrowed_fd>>* /*ancillaryFds*/) override {
98*38e8c45fSAndroid Build Coastguard Worker         auto readFn = [&](iovec* iovs, size_t niovs) -> ssize_t {
99*38e8c45fSAndroid Build Coastguard Worker             // Fill the read buffer at most once per readFn call, then try to
100*38e8c45fSAndroid Build Coastguard Worker             // return as much of it as possible. If the input iovecs are spread
101*38e8c45fSAndroid Build Coastguard Worker             // across multiple messages that require multiple fillReadBuffer
102*38e8c45fSAndroid Build Coastguard Worker             // calls, we expect the caller to advance the iovecs past the first
103*38e8c45fSAndroid Build Coastguard Worker             // read and call readFn as many times as needed to get all the data
104*38e8c45fSAndroid Build Coastguard Worker             status_t ret = fillReadBuffer();
105*38e8c45fSAndroid Build Coastguard Worker             if (ret != OK) {
106*38e8c45fSAndroid Build Coastguard Worker                 // We need to emulate a Linux read call, which sets errno on
107*38e8c45fSAndroid Build Coastguard Worker                 // error and returns -1
108*38e8c45fSAndroid Build Coastguard Worker                 errno = -ret;
109*38e8c45fSAndroid Build Coastguard Worker                 return -1;
110*38e8c45fSAndroid Build Coastguard Worker             }
111*38e8c45fSAndroid Build Coastguard Worker 
112*38e8c45fSAndroid Build Coastguard Worker             ssize_t processSize = 0;
113*38e8c45fSAndroid Build Coastguard Worker             for (size_t i = 0; i < niovs && mReadBufferPos < mReadBufferSize; i++) {
114*38e8c45fSAndroid Build Coastguard Worker                 auto& iov = iovs[i];
115*38e8c45fSAndroid Build Coastguard Worker                 size_t numBytes = std::min(iov.iov_len, mReadBufferSize - mReadBufferPos);
116*38e8c45fSAndroid Build Coastguard Worker                 memcpy(iov.iov_base, mReadBuffer.get() + mReadBufferPos, numBytes);
117*38e8c45fSAndroid Build Coastguard Worker                 mReadBufferPos += numBytes;
118*38e8c45fSAndroid Build Coastguard Worker                 processSize += numBytes;
119*38e8c45fSAndroid Build Coastguard Worker             }
120*38e8c45fSAndroid Build Coastguard Worker 
121*38e8c45fSAndroid Build Coastguard Worker             return processSize;
122*38e8c45fSAndroid Build Coastguard Worker         };
123*38e8c45fSAndroid Build Coastguard Worker 
124*38e8c45fSAndroid Build Coastguard Worker         status_t status = interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, readFn, "read",
125*38e8c45fSAndroid Build Coastguard Worker                                                    POLLIN, altPoll);
126*38e8c45fSAndroid Build Coastguard Worker         return adjustStatus(status);
127*38e8c45fSAndroid Build Coastguard Worker     }
128*38e8c45fSAndroid Build Coastguard Worker 
isWaiting()129*38e8c45fSAndroid Build Coastguard Worker     bool isWaiting() override { return mSocket.isInPollingState(); }
130*38e8c45fSAndroid Build Coastguard Worker 
131*38e8c45fSAndroid Build Coastguard Worker private:
adjustStatus(status_t status)132*38e8c45fSAndroid Build Coastguard Worker     status_t adjustStatus(status_t status) {
133*38e8c45fSAndroid Build Coastguard Worker         if (status == -ENOTCONN) {
134*38e8c45fSAndroid Build Coastguard Worker             // TIPC returns ENOTCONN on disconnect, but that's basically
135*38e8c45fSAndroid Build Coastguard Worker             // the same as DEAD_OBJECT and the latter is the common libbinder
136*38e8c45fSAndroid Build Coastguard Worker             // error code for dead connections
137*38e8c45fSAndroid Build Coastguard Worker             return DEAD_OBJECT;
138*38e8c45fSAndroid Build Coastguard Worker         }
139*38e8c45fSAndroid Build Coastguard Worker 
140*38e8c45fSAndroid Build Coastguard Worker         return status;
141*38e8c45fSAndroid Build Coastguard Worker     }
142*38e8c45fSAndroid Build Coastguard Worker 
fillReadBuffer()143*38e8c45fSAndroid Build Coastguard Worker     status_t fillReadBuffer() {
144*38e8c45fSAndroid Build Coastguard Worker         if (mReadBufferPos < mReadBufferSize) {
145*38e8c45fSAndroid Build Coastguard Worker             return OK;
146*38e8c45fSAndroid Build Coastguard Worker         }
147*38e8c45fSAndroid Build Coastguard Worker 
148*38e8c45fSAndroid Build Coastguard Worker         if (!mReadBuffer) {
149*38e8c45fSAndroid Build Coastguard Worker             // Guarantee at least kDefaultBufferSize bytes
150*38e8c45fSAndroid Build Coastguard Worker             mReadBufferCapacity = std::max(mReadBufferCapacity, kDefaultBufferSize);
151*38e8c45fSAndroid Build Coastguard Worker             mReadBuffer.reset(new (std::nothrow) uint8_t[mReadBufferCapacity]);
152*38e8c45fSAndroid Build Coastguard Worker             if (!mReadBuffer) {
153*38e8c45fSAndroid Build Coastguard Worker                 return NO_MEMORY;
154*38e8c45fSAndroid Build Coastguard Worker             }
155*38e8c45fSAndroid Build Coastguard Worker         }
156*38e8c45fSAndroid Build Coastguard Worker 
157*38e8c45fSAndroid Build Coastguard Worker         // Reset the size and position in case we have to exit with an error.
158*38e8c45fSAndroid Build Coastguard Worker         // After we read a message into the buffer, we update the size
159*38e8c45fSAndroid Build Coastguard Worker         // with the actual value.
160*38e8c45fSAndroid Build Coastguard Worker         mReadBufferPos = 0;
161*38e8c45fSAndroid Build Coastguard Worker         mReadBufferSize = 0;
162*38e8c45fSAndroid Build Coastguard Worker 
163*38e8c45fSAndroid Build Coastguard Worker         while (true) {
164*38e8c45fSAndroid Build Coastguard Worker             ssize_t processSize = TEMP_FAILURE_RETRY(
165*38e8c45fSAndroid Build Coastguard Worker                     read(mSocket.fd.get(), mReadBuffer.get(), mReadBufferCapacity));
166*38e8c45fSAndroid Build Coastguard Worker             if (processSize == 0) {
167*38e8c45fSAndroid Build Coastguard Worker                 return DEAD_OBJECT;
168*38e8c45fSAndroid Build Coastguard Worker             } else if (processSize < 0) {
169*38e8c45fSAndroid Build Coastguard Worker                 int savedErrno = errno;
170*38e8c45fSAndroid Build Coastguard Worker                 if (savedErrno == EMSGSIZE) {
171*38e8c45fSAndroid Build Coastguard Worker                     // Buffer was too small, double it and retry
172*38e8c45fSAndroid Build Coastguard Worker                     if (__builtin_mul_overflow(mReadBufferCapacity, 2, &mReadBufferCapacity)) {
173*38e8c45fSAndroid Build Coastguard Worker                         return NO_MEMORY;
174*38e8c45fSAndroid Build Coastguard Worker                     }
175*38e8c45fSAndroid Build Coastguard Worker                     mReadBuffer.reset(new (std::nothrow) uint8_t[mReadBufferCapacity]);
176*38e8c45fSAndroid Build Coastguard Worker                     if (!mReadBuffer) {
177*38e8c45fSAndroid Build Coastguard Worker                         return NO_MEMORY;
178*38e8c45fSAndroid Build Coastguard Worker                     }
179*38e8c45fSAndroid Build Coastguard Worker                     continue;
180*38e8c45fSAndroid Build Coastguard Worker                 } else {
181*38e8c45fSAndroid Build Coastguard Worker                     LOG_RPC_DETAIL("RpcTransport fillBuffer(): %s", strerror(savedErrno));
182*38e8c45fSAndroid Build Coastguard Worker                     return adjustStatus(-savedErrno);
183*38e8c45fSAndroid Build Coastguard Worker                 }
184*38e8c45fSAndroid Build Coastguard Worker             } else {
185*38e8c45fSAndroid Build Coastguard Worker                 mReadBufferSize = static_cast<size_t>(processSize);
186*38e8c45fSAndroid Build Coastguard Worker                 return OK;
187*38e8c45fSAndroid Build Coastguard Worker             }
188*38e8c45fSAndroid Build Coastguard Worker         }
189*38e8c45fSAndroid Build Coastguard Worker     }
190*38e8c45fSAndroid Build Coastguard Worker 
191*38e8c45fSAndroid Build Coastguard Worker     RpcTransportFd mSocket;
192*38e8c45fSAndroid Build Coastguard Worker 
193*38e8c45fSAndroid Build Coastguard Worker     // For now, we copy all the input data into a temporary buffer because
194*38e8c45fSAndroid Build Coastguard Worker     // we might get multiple interruptableReadFully calls per message, but
195*38e8c45fSAndroid Build Coastguard Worker     // the tipc device only allows one read call. We read every message into
196*38e8c45fSAndroid Build Coastguard Worker     // this temporary buffer, then return pieces of it from our method.
197*38e8c45fSAndroid Build Coastguard Worker     //
198*38e8c45fSAndroid Build Coastguard Worker     // The special transaction GET_MAX_THREADS takes 40 bytes, so the default
199*38e8c45fSAndroid Build Coastguard Worker     // size should start pretty high.
200*38e8c45fSAndroid Build Coastguard Worker     static constexpr size_t kDefaultBufferSize = 64;
201*38e8c45fSAndroid Build Coastguard Worker     std::unique_ptr<uint8_t[]> mReadBuffer;
202*38e8c45fSAndroid Build Coastguard Worker     size_t mReadBufferPos = 0;
203*38e8c45fSAndroid Build Coastguard Worker     size_t mReadBufferSize = 0;
204*38e8c45fSAndroid Build Coastguard Worker     size_t mReadBufferCapacity = 0;
205*38e8c45fSAndroid Build Coastguard Worker };
206*38e8c45fSAndroid Build Coastguard Worker 
207*38e8c45fSAndroid Build Coastguard Worker // RpcTransportCtx for Trusty.
208*38e8c45fSAndroid Build Coastguard Worker class RpcTransportCtxTipcAndroid : public RpcTransportCtx {
209*38e8c45fSAndroid Build Coastguard Worker public:
newTransport(android::RpcTransportFd fd,FdTrigger *) const210*38e8c45fSAndroid Build Coastguard Worker     std::unique_ptr<RpcTransport> newTransport(android::RpcTransportFd fd,
211*38e8c45fSAndroid Build Coastguard Worker                                                FdTrigger*) const override {
212*38e8c45fSAndroid Build Coastguard Worker         return std::make_unique<RpcTransportTipcAndroid>(std::move(fd));
213*38e8c45fSAndroid Build Coastguard Worker     }
getCertificate(RpcCertificateFormat) const214*38e8c45fSAndroid Build Coastguard Worker     std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
215*38e8c45fSAndroid Build Coastguard Worker };
216*38e8c45fSAndroid Build Coastguard Worker 
newServerCtx() const217*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcAndroid::newServerCtx() const {
218*38e8c45fSAndroid Build Coastguard Worker     return std::make_unique<RpcTransportCtxTipcAndroid>();
219*38e8c45fSAndroid Build Coastguard Worker }
220*38e8c45fSAndroid Build Coastguard Worker 
newClientCtx() const221*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcAndroid::newClientCtx() const {
222*38e8c45fSAndroid Build Coastguard Worker     return std::make_unique<RpcTransportCtxTipcAndroid>();
223*38e8c45fSAndroid Build Coastguard Worker }
224*38e8c45fSAndroid Build Coastguard Worker 
toCString() const225*38e8c45fSAndroid Build Coastguard Worker const char* RpcTransportCtxFactoryTipcAndroid::toCString() const {
226*38e8c45fSAndroid Build Coastguard Worker     return "trusty";
227*38e8c45fSAndroid Build Coastguard Worker }
228*38e8c45fSAndroid Build Coastguard Worker 
make()229*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTipcAndroid::make() {
230*38e8c45fSAndroid Build Coastguard Worker     return std::unique_ptr<RpcTransportCtxFactoryTipcAndroid>(
231*38e8c45fSAndroid Build Coastguard Worker             new RpcTransportCtxFactoryTipcAndroid());
232*38e8c45fSAndroid Build Coastguard Worker }
233*38e8c45fSAndroid Build Coastguard Worker 
234*38e8c45fSAndroid Build Coastguard Worker } // namespace android
235