diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-10-10 17:15:20 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2022-10-10 17:15:20 +0000 |
commit | 4f13cee30999f192d8ac3571282bfb93fffda596 (patch) | |
tree | 71d752446e669606f8d4d2b4cf8e4b3a47160e25 | |
parent | 2cbb261298c2e3f661b1ec4eba99da51d4209a34 (diff) | |
parent | 36a4a98ec1650c38ad2de6ef2b9dc110c28a8b6b (diff) | |
download | native-4f13cee30999f192d8ac3571282bfb93fffda596.tar.gz |
Merge "Snap for 9157731 from 08178a7279c08cdbe09bc186735063a43621f9bc to gki13-boot-release" into gki13-boot-release
22 files changed, 507 insertions, 141 deletions
diff --git a/libs/binder/OS.cpp b/libs/binder/OS.cpp index 24ce2bb465..77e401f83e 100644 --- a/libs/binder/OS.cpp +++ b/libs/binder/OS.cpp @@ -18,6 +18,7 @@ #include <android-base/file.h> #include <binder/RpcTransportRaw.h> +#include <log/log.h> #include <string.h> using android::base::ErrnoError; @@ -25,6 +26,9 @@ using android::base::Result; namespace android { +// Linux kernel supports up to 253 (from SCM_MAX_FD) for unix sockets. +constexpr size_t kMaxFdsPerMsg = 253; + Result<void> setNonBlocking(android::base::borrowed_fd fd) { int flags = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_GETFL)); if (flags == -1) { @@ -63,4 +67,99 @@ std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory() { return RpcTransportCtxFactoryRaw::make(); } +int sendMessageOnSocket( + const RpcTransportFd& socket, iovec* iovs, int niovs, + const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) { + if (ancillaryFds != nullptr && !ancillaryFds->empty()) { + if (ancillaryFds->size() > kMaxFdsPerMsg) { + errno = EINVAL; + return -1; + } + + // CMSG_DATA is not necessarily aligned, so we copy the FDs into a buffer and then + // use memcpy. + int fds[kMaxFdsPerMsg]; + for (size_t i = 0; i < ancillaryFds->size(); i++) { + fds[i] = std::visit([](const auto& fd) { return fd.get(); }, ancillaryFds->at(i)); + } + const size_t fdsByteSize = sizeof(int) * ancillaryFds->size(); + + alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(int) * kMaxFdsPerMsg)]; + + msghdr msg{ + .msg_iov = iovs, + .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), + .msg_control = msgControlBuf, + .msg_controllen = sizeof(msgControlBuf), + }; + + cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(fdsByteSize); + memcpy(CMSG_DATA(cmsg), fds, fdsByteSize); + + msg.msg_controllen = CMSG_SPACE(fdsByteSize); + return TEMP_FAILURE_RETRY(sendmsg(socket.fd.get(), &msg, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC)); + } + + msghdr msg{ + .msg_iov = iovs, + // posix uses int, glibc uses size_t. niovs is a + // non-negative int and can be cast to either. + .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), + }; + return TEMP_FAILURE_RETRY(sendmsg(socket.fd.get(), &msg, MSG_NOSIGNAL)); +} + +int receiveMessageFromSocket( + const RpcTransportFd& socket, iovec* iovs, int niovs, + std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) { + if (ancillaryFds != nullptr) { + int fdBuffer[kMaxFdsPerMsg]; + alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(fdBuffer))]; + + msghdr msg{ + .msg_iov = iovs, + .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), + .msg_control = msgControlBuf, + .msg_controllen = sizeof(msgControlBuf), + }; + ssize_t processSize = TEMP_FAILURE_RETRY(recvmsg(socket.fd.get(), &msg, MSG_NOSIGNAL)); + if (processSize < 0) { + return -1; + } + + for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + // NOTE: It is tempting to reinterpret_cast, but cmsg(3) explicitly asks + // application devs to memcpy the data to ensure memory alignment. + size_t dataLen = cmsg->cmsg_len - CMSG_LEN(0); + LOG_ALWAYS_FATAL_IF(dataLen > sizeof(fdBuffer)); // validity check + memcpy(fdBuffer, CMSG_DATA(cmsg), dataLen); + size_t fdCount = dataLen / sizeof(int); + ancillaryFds->reserve(ancillaryFds->size() + fdCount); + for (size_t i = 0; i < fdCount; i++) { + ancillaryFds->emplace_back(base::unique_fd(fdBuffer[i])); + } + break; + } + } + + if (msg.msg_flags & MSG_CTRUNC) { + errno = EPIPE; + return -1; + } + return processSize; + } + msghdr msg{ + .msg_iov = iovs, + // posix uses int, glibc uses size_t. niovs is a + // non-negative int and can be cast to either. + .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), + }; + + return TEMP_FAILURE_RETRY(recvmsg(socket.fd.get(), &msg, MSG_NOSIGNAL)); +} + } // namespace android diff --git a/libs/binder/OS.h b/libs/binder/OS.h index 5ab8bab0e7..0d38968ade 100644 --- a/libs/binder/OS.h +++ b/libs/binder/OS.h @@ -33,4 +33,12 @@ status_t dupFileDescriptor(int oldFd, int* newFd); std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory(); +int sendMessageOnSocket( + const RpcTransportFd& socket, iovec* iovs, int niovs, + const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds); + +int receiveMessageFromSocket( + const RpcTransportFd& socket, iovec* iovs, int niovs, + std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds); + } // namespace android diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 83332980b2..07d0a65ae0 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -1439,7 +1439,8 @@ status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership) { case RpcSession::FileDescriptorTransportMode::NONE: { return FDS_NOT_ALLOWED; } - case RpcSession::FileDescriptorTransportMode::UNIX: { + case RpcSession::FileDescriptorTransportMode::UNIX: + case RpcSession::FileDescriptorTransportMode::TRUSTY: { if (rpcFields->mFds == nullptr) { rpcFields->mFds = std::make_unique<decltype(rpcFields->mFds)::element_type>(); } diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index e581d0b16c..83d0de7835 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -37,6 +37,7 @@ #include "OS.h" #include "RpcSocketAddress.h" #include "RpcState.h" +#include "RpcTransportUtils.h" #include "RpcWireFormat.h" #include "Utils.h" @@ -61,6 +62,10 @@ sp<RpcServer> RpcServer::make(std::unique_ptr<RpcTransportCtxFactory> rpcTranspo return sp<RpcServer>::make(std::move(ctx)); } +status_t RpcServer::setupUnixDomainSocketBootstrapServer(unique_fd bootstrapFd) { + return setupExternalServer(std::move(bootstrapFd), &RpcServer::recvmsgSocketConnection); +} + status_t RpcServer::setupUnixDomainServer(const char* path) { return setupSocketServer(UnixSocketAddress(path)); } @@ -177,11 +182,50 @@ void RpcServer::start() { rpcJoinIfSingleThreaded(*mJoinThread); } +status_t RpcServer::acceptSocketConnection(const RpcServer& server, RpcTransportFd* out) { + RpcTransportFd clientSocket(unique_fd(TEMP_FAILURE_RETRY( + accept4(server.mServer.fd.get(), nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK)))); + if (clientSocket.fd < 0) { + int savedErrno = errno; + ALOGE("Could not accept4 socket: %s", strerror(savedErrno)); + return -savedErrno; + } + + *out = std::move(clientSocket); + return OK; +} + +status_t RpcServer::recvmsgSocketConnection(const RpcServer& server, RpcTransportFd* out) { + int zero = 0; + iovec iov{&zero, sizeof(zero)}; + std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds; + + if (receiveMessageFromSocket(server.mServer, &iov, 1, &fds) < 0) { + int savedErrno = errno; + ALOGE("Failed recvmsg: %s", strerror(savedErrno)); + return -savedErrno; + } + if (fds.size() != 1) { + ALOGE("Expected exactly one fd from recvmsg, got %zu", fds.size()); + return -EINVAL; + } + + unique_fd fd(std::move(std::get<unique_fd>(fds.back()))); + if (auto res = setNonBlocking(fd); !res.ok()) { + ALOGE("Failed setNonBlocking: %s", res.error().message().c_str()); + return res.error().code() == 0 ? UNKNOWN_ERROR : -res.error().code(); + } + + *out = RpcTransportFd(std::move(fd)); + return OK; +} + void RpcServer::join() { { RpcMutexLockGuard _l(mLock); LOG_ALWAYS_FATAL_IF(!mServer.fd.ok(), "RpcServer must be setup to join."); + LOG_ALWAYS_FATAL_IF(mAcceptFn == nullptr, "RpcServer must have an accept() function"); LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Already joined"); mJoinThreadRunning = true; mShutdownTrigger = FdTrigger::make(); @@ -192,20 +236,19 @@ void RpcServer::join() { while ((status = mShutdownTrigger->triggerablePoll(mServer, POLLIN)) == OK) { std::array<uint8_t, kRpcAddressSize> addr; static_assert(addr.size() >= sizeof(sockaddr_storage), "kRpcAddressSize is too small"); - socklen_t addrLen = addr.size(); - RpcTransportFd clientSocket(unique_fd(TEMP_FAILURE_RETRY( - accept4(mServer.fd.get(), reinterpret_cast<sockaddr*>(addr.data()), &addrLen, - SOCK_CLOEXEC | SOCK_NONBLOCK)))); - - LOG_ALWAYS_FATAL_IF(addrLen > static_cast<socklen_t>(sizeof(sockaddr_storage)), - "Truncated address"); - if (clientSocket.fd < 0) { - ALOGE("Could not accept4 socket: %s", strerror(errno)); + RpcTransportFd clientSocket; + if (mAcceptFn(*this, &clientSocket) != OK) { + continue; + } + if (getpeername(clientSocket.fd.get(), reinterpret_cast<sockaddr*>(addr.data()), + &addrLen)) { + ALOGE("Could not getpeername socket: %s", strerror(errno)); continue; } - LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.fd.get(), clientSocket.fd.get()); + + LOG_RPC_DETAIL("accept on fd %d yields fd %d", mServer.fd.get(), clientSocket.fd.get()); { RpcMutexLockGuard _l(mLock); @@ -550,16 +593,23 @@ unique_fd RpcServer::releaseServer() { return std::move(mServer.fd); } -status_t RpcServer::setupExternalServer(base::unique_fd serverFd) { +status_t RpcServer::setupExternalServer( + base::unique_fd serverFd, + std::function<status_t(const RpcServer&, RpcTransportFd*)>&& acceptFn) { RpcMutexLockGuard _l(mLock); if (mServer.fd.ok()) { ALOGE("Each RpcServer can only have one server."); return INVALID_OPERATION; } mServer = std::move(serverFd); + mAcceptFn = std::move(acceptFn); return OK; } +status_t RpcServer::setupExternalServer(base::unique_fd serverFd) { + return setupExternalServer(std::move(serverFd), &RpcServer::acceptSocketConnection); +} + bool RpcServer::hasActiveRequests() { RpcMutexLockGuard _l(mLock); for (const auto& [_, session] : mSessions) { diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp index 49843e5953..ff50c16102 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -41,6 +41,7 @@ #include "OS.h" #include "RpcSocketAddress.h" #include "RpcState.h" +#include "RpcTransportUtils.h" #include "RpcWireFormat.h" #include "Utils.h" @@ -147,6 +148,34 @@ status_t RpcSession::setupUnixDomainClient(const char* path) { return setupSocketClient(UnixSocketAddress(path)); } +status_t RpcSession::setupUnixDomainSocketBootstrapClient(unique_fd bootstrapFd) { + mBootstrapTransport = + mCtx->newTransport(RpcTransportFd(std::move(bootstrapFd)), mShutdownTrigger.get()); + return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) { + int socks[2]; + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, socks) < 0) { + int savedErrno = errno; + ALOGE("Failed socketpair: %s", strerror(savedErrno)); + return -savedErrno; + } + unique_fd clientFd(socks[0]), serverFd(socks[1]); + + int zero = 0; + iovec iov{&zero, sizeof(zero)}; + std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds; + fds.push_back(std::move(serverFd)); + + status_t status = mBootstrapTransport->interruptableWriteFully(mShutdownTrigger.get(), &iov, + 1, std::nullopt, &fds); + if (status != OK) { + ALOGE("Failed to send fd over bootstrap transport: %s", strerror(-status)); + return status; + } + + return initAndAddConnection(RpcTransportFd(std::move(clientFd)), sessionId, incoming); + }); +} + status_t RpcSession::setupVsockClient(unsigned int cid, unsigned int port) { return setupSocketClient(VsockSocketAddress(cid, port)); } diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 7067328358..b27f1028d4 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -56,6 +56,7 @@ static bool enableAncillaryFds(RpcSession::FileDescriptorTransportMode mode) { case RpcSession::FileDescriptorTransportMode::NONE: return false; case RpcSession::FileDescriptorTransportMode::UNIX: + case RpcSession::FileDescriptorTransportMode::TRUSTY: return true; } } @@ -1207,6 +1208,20 @@ status_t RpcState::validateParcel(const sp<RpcSession>& session, const Parcel& p rpcFields->mFds->size(), kMaxFdsPerMsg); return BAD_VALUE; } + break; + } + case RpcSession::FileDescriptorTransportMode::TRUSTY: { + // Keep this in sync with trusty_ipc.h!!! + // We could import that file here on Trusty, but it's not + // available on Android + constexpr size_t kMaxFdsPerMsg = 8; + if (rpcFields->mFds->size() > kMaxFdsPerMsg) { + *errorMsg = StringPrintf("Too many file descriptors in Parcel for Trusty " + "IPC connection: %zu (max is %zu)", + rpcFields->mFds->size(), kMaxFdsPerMsg); + return BAD_VALUE; + } + break; } } } diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp index 65e8fac341..1912d140f4 100644 --- a/libs/binder/RpcTransportRaw.cpp +++ b/libs/binder/RpcTransportRaw.cpp @@ -23,6 +23,7 @@ #include <binder/RpcTransportRaw.h> #include "FdTrigger.h" +#include "OS.h" #include "RpcState.h" #include "RpcTransportUtils.h" @@ -30,9 +31,6 @@ namespace android { namespace { -// Linux kernel supports up to 253 (from SCM_MAX_FD) for unix sockets. -constexpr size_t kMaxFdsPerMsg = 253; - // RpcTransport with TLS disabled. class RpcTransportRaw : public RpcTransport { public: @@ -63,57 +61,9 @@ public: override { bool sentFds = false; auto send = [&](iovec* iovs, int niovs) -> ssize_t { - if (ancillaryFds != nullptr && !ancillaryFds->empty() && !sentFds) { - if (ancillaryFds->size() > kMaxFdsPerMsg) { - // This shouldn't happen because we check the FD count in RpcState. - ALOGE("Saw too many file descriptors in RpcTransportCtxRaw: %zu (max is %zu). " - "Aborting session.", - ancillaryFds->size(), kMaxFdsPerMsg); - errno = EINVAL; - return -1; - } - - // CMSG_DATA is not necessarily aligned, so we copy the FDs into a buffer and then - // use memcpy. - int fds[kMaxFdsPerMsg]; - for (size_t i = 0; i < ancillaryFds->size(); i++) { - fds[i] = std::visit([](const auto& fd) { return fd.get(); }, - ancillaryFds->at(i)); - } - const size_t fdsByteSize = sizeof(int) * ancillaryFds->size(); - - alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(int) * kMaxFdsPerMsg)]; - - msghdr msg{ - .msg_iov = iovs, - .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), - .msg_control = msgControlBuf, - .msg_controllen = sizeof(msgControlBuf), - }; - - cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(fdsByteSize); - memcpy(CMSG_DATA(cmsg), fds, fdsByteSize); - - msg.msg_controllen = CMSG_SPACE(fdsByteSize); - - ssize_t processedSize = TEMP_FAILURE_RETRY( - sendmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC)); - if (processedSize > 0) { - sentFds = true; - } - return processedSize; - } - - msghdr msg{ - .msg_iov = iovs, - // posix uses int, glibc uses size_t. niovs is a - // non-negative int and can be cast to either. - .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), - }; - return TEMP_FAILURE_RETRY(sendmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL)); + int ret = sendMessageOnSocket(mSocket, iovs, niovs, sentFds ? nullptr : ancillaryFds); + sentFds |= ret > 0; + return ret; }; return interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, send, "sendmsg", POLLOUT, altPoll); @@ -124,54 +74,7 @@ public: const std::optional<android::base::function_ref<status_t()>>& altPoll, std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override { auto recv = [&](iovec* iovs, int niovs) -> ssize_t { - if (ancillaryFds != nullptr) { - int fdBuffer[kMaxFdsPerMsg]; - alignas(struct cmsghdr) char msgControlBuf[CMSG_SPACE(sizeof(fdBuffer))]; - - msghdr msg{ - .msg_iov = iovs, - .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), - .msg_control = msgControlBuf, - .msg_controllen = sizeof(msgControlBuf), - }; - ssize_t processSize = - TEMP_FAILURE_RETRY(recvmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL)); - if (processSize < 0) { - return -1; - } - - for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - // NOTE: It is tempting to reinterpret_cast, but cmsg(3) explicitly asks - // application devs to memcpy the data to ensure memory alignment. - size_t dataLen = cmsg->cmsg_len - CMSG_LEN(0); - LOG_ALWAYS_FATAL_IF(dataLen > sizeof(fdBuffer)); // sanity check - memcpy(fdBuffer, CMSG_DATA(cmsg), dataLen); - size_t fdCount = dataLen / sizeof(int); - ancillaryFds->reserve(ancillaryFds->size() + fdCount); - for (size_t i = 0; i < fdCount; i++) { - ancillaryFds->emplace_back(base::unique_fd(fdBuffer[i])); - } - break; - } - } - - if (msg.msg_flags & MSG_CTRUNC) { - ALOGE("msg was truncated. Aborting session."); - errno = EPIPE; - return -1; - } - - return processSize; - } - msghdr msg{ - .msg_iov = iovs, - // posix uses int, glibc uses size_t. niovs is a - // non-negative int and can be cast to either. - .msg_iovlen = static_cast<decltype(msg.msg_iovlen)>(niovs), - }; - return TEMP_FAILURE_RETRY(recvmsg(mSocket.fd.get(), &msg, MSG_NOSIGNAL)); + return receiveMessageFromSocket(mSocket, iovs, niovs, ancillaryFds); }; return interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, recv, "recvmsg", POLLIN, altPoll); diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index c91d56c95e..342e4a389a 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -58,13 +58,10 @@ "name": "CtsOsTestCases", "options": [ { - "exclude-annotation": "android.platform.test.annotations.LargeTest" + "include-filter": "android.os.cts.BinderTest" }, { - "exclude-filter": "android.os.cts.BuildTest#testSdkInt" - }, - { - "exclude-filter": "android.os.cts.StrictModeTest#testNonSdkApiUsage" + "include-filter": "android.os.cts.ParcelTest" } ] }, diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h index 2c99334fa4..81ae26a344 100644 --- a/libs/binder/include/binder/RpcServer.h +++ b/libs/binder/include/binder/RpcServer.h @@ -50,6 +50,17 @@ public: std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr); /** + * Creates an RPC server that bootstraps sessions using an existing + * Unix domain socket pair. + * + * Callers should create a pair of SOCK_STREAM Unix domain sockets, pass + * one to RpcServer::setupUnixDomainSocketBootstrapServer and the other + * to RpcSession::setupUnixDomainSocketBootstrapClient. Multiple client + * session can be created from the client end of the pair. + */ + [[nodiscard]] status_t setupUnixDomainSocketBootstrapServer(base::unique_fd serverFd); + + /** * This represents a session for responses, e.g.: * * process A serves binder a @@ -202,11 +213,18 @@ private: void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override; void onSessionIncomingThreadEnded() override; + status_t setupExternalServer( + base::unique_fd serverFd, + std::function<status_t(const RpcServer&, RpcTransportFd*)>&& acceptFn); + static constexpr size_t kRpcAddressSize = 128; static void establishConnection( sp<RpcServer>&& server, RpcTransportFd clientFd, std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen, std::function<void(sp<RpcSession>&&, RpcSession::PreJoinSetupResult&&)>&& joinFn); + static status_t acceptSocketConnection(const RpcServer& server, RpcTransportFd* out); + static status_t recvmsgSocketConnection(const RpcServer& server, RpcTransportFd* out); + [[nodiscard]] status_t setupSocketServer(const RpcSocketAddress& address); const std::unique_ptr<RpcTransportCtx> mCtx; @@ -228,6 +246,7 @@ private: std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions; std::unique_ptr<FdTrigger> mShutdownTrigger; RpcConditionVariable mShutdownCv; + std::function<status_t(const RpcServer& server, RpcTransportFd* out)> mAcceptFn; }; } // namespace android diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h index a25ba987c8..5e5d4eafa6 100644 --- a/libs/binder/include/binder/RpcSession.h +++ b/libs/binder/include/binder/RpcSession.h @@ -100,6 +100,8 @@ public: NONE = 0, // Send file descriptors via unix domain socket ancillary data. UNIX = 1, + // Send file descriptors as Trusty IPC handles. + TRUSTY = 2, }; /** @@ -115,6 +117,11 @@ public: [[nodiscard]] status_t setupUnixDomainClient(const char* path); /** + * Connects to an RPC server over a nameless Unix domain socket pair. + */ + [[nodiscard]] status_t setupUnixDomainSocketBootstrapClient(base::unique_fd bootstrap); + + /** * Connects to an RPC server at the CVD & port. */ [[nodiscard]] status_t setupVsockClient(unsigned int cvd, unsigned int port); @@ -366,6 +373,8 @@ private: RpcConditionVariable mAvailableConnectionCv; // for mWaitingThreads + std::unique_ptr<RpcTransport> mBootstrapTransport; + struct ThreadState { size_t mWaitingThreads = 0; // hint index into clients, ++ when sending an async transaction diff --git a/libs/binder/ndk/include_platform/android/binder_libbinder.h b/libs/binder/ndk/include_platform/android/binder_libbinder.h index dfe12a1cf7..74a7157314 100644 --- a/libs/binder/ndk/include_platform/android/binder_libbinder.h +++ b/libs/binder/ndk/include_platform/android/binder_libbinder.h @@ -16,7 +16,7 @@ #pragma once -#if !defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__) +#if (!defined(__ANDROID_APEX__) && !defined(__ANDROID_VNDK__)) || defined(__TRUSTY__) #include <android/binder_ibinder.h> #include <android/binder_parcel.h> diff --git a/libs/binder/tests/BinderRpcTestServerConfig.aidl b/libs/binder/tests/BinderRpcTestServerConfig.aidl index 34d74bee0d..4cdeac4a97 100644 --- a/libs/binder/tests/BinderRpcTestServerConfig.aidl +++ b/libs/binder/tests/BinderRpcTestServerConfig.aidl @@ -21,5 +21,6 @@ parcelable BinderRpcTestServerConfig { int rpcSecurity; int serverVersion; int vsockPort; + int unixBootstrapFd; // Inherited from parent @utf8InCpp String addr; } diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 2b7049202a..72943051c7 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -181,10 +181,20 @@ struct ProcessSession { wp<RpcSession> weakSession = session; session = nullptr; - sp<RpcSession> strongSession = weakSession.promote(); - EXPECT_EQ(nullptr, strongSession) - << (debugBacktrace(host.getPid()), debugBacktrace(getpid()), "Leaked sess: ") - << strongSession->getStrongCount(); + // b/244325464 - 'getStrongCount' is printing '1' on failure here, which indicates the + // the object should not actually be promotable. By looping, we distinguish a race here + // from a bug causing the object to not be promotable. + for (size_t i = 0; i < 3; i++) { + sp<RpcSession> strongSession = weakSession.promote(); + EXPECT_EQ(nullptr, strongSession) + << (debugBacktrace(host.getPid()), debugBacktrace(getpid()), + "Leaked sess: ") + << strongSession->getStrongCount() << " checked time " << i; + + if (strongSession != nullptr) { + sleep(1); + } + } } } }; @@ -244,6 +254,25 @@ static base::unique_fd connectTo(const RpcSocketAddress& addr) { return serverFd; } +static base::unique_fd connectToUnixBootstrap(const RpcTransportFd& transportFd) { + base::unique_fd sockClient, sockServer; + if (!base::Socketpair(SOCK_STREAM, &sockClient, &sockServer)) { + int savedErrno = errno; + LOG(FATAL) << "Failed socketpair(): " << strerror(savedErrno); + } + + int zero = 0; + iovec iov{&zero, sizeof(zero)}; + std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds; + fds.emplace_back(std::move(sockServer)); + + if (sendMessageOnSocket(transportFd, &iov, 1, &fds) < 0) { + int savedErrno = errno; + LOG(FATAL) << "Failed sendMessageOnSocket: " << strerror(savedErrno); + } + return std::move(sockClient); +} + using RunServiceFn = void (*)(android::base::borrowed_fd writeEnd, android::base::borrowed_fd readEnd); @@ -264,7 +293,14 @@ public: // Whether the test params support sending FDs in parcels. bool supportsFdTransport() const { return clientVersion() >= 1 && serverVersion() >= 1 && rpcSecurity() != RpcSecurity::TLS && - (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX); + (socketType() == SocketType::PRECONNECTED || socketType() == SocketType::UNIX || + socketType() == SocketType::UNIX_BOOTSTRAP); + } + + void SetUp() override { + if (socketType() == SocketType::UNIX_BOOTSTRAP && rpcSecurity() == RpcSecurity::TLS) { + GTEST_SKIP() << "Unix bootstrap not supported over a TLS transport"; + } } static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) { @@ -298,6 +334,14 @@ public: singleThreaded ? "_single_threaded" : "", noKernel ? "_no_kernel" : ""); + base::unique_fd bootstrapClientFd, bootstrapServerFd; + // Do not set O_CLOEXEC, bootstrapServerFd needs to survive fork/exec. + // This is because we cannot pass ParcelFileDescriptor over a pipe. + if (!base::Socketpair(SOCK_STREAM, &bootstrapClientFd, &bootstrapServerFd)) { + int savedErrno = errno; + LOG(FATAL) << "Failed socketpair(): " << strerror(savedErrno); + } + auto ret = ProcessSession{ .host = Process([=](android::base::borrowed_fd writeEnd, android::base::borrowed_fd readEnd) { @@ -315,6 +359,7 @@ public: serverConfig.serverVersion = serverVersion; serverConfig.vsockPort = allocateVsockPort(); serverConfig.addr = allocateSocketAddress(); + serverConfig.unixBootstrapFd = bootstrapServerFd.get(); for (auto mode : options.serverSupportedFileDescriptorTransportModes) { serverConfig.serverSupportedFileDescriptorTransportModes.push_back( static_cast<int32_t>(mode)); @@ -364,6 +409,10 @@ public: case SocketType::UNIX: status = session->setupUnixDomainClient(serverConfig.addr.c_str()); break; + case SocketType::UNIX_BOOTSTRAP: + status = session->setupUnixDomainSocketBootstrapClient( + base::unique_fd(dup(bootstrapClientFd.get()))); + break; case SocketType::VSOCK: status = session->setupVsockClient(VMADDR_CID_LOCAL, serverConfig.vsockPort); break; @@ -430,7 +479,8 @@ TEST_P(BinderRpc, SeparateRootObject) { } SocketType type = std::get<0>(GetParam()); - if (type == SocketType::PRECONNECTED || type == SocketType::UNIX) { + if (type == SocketType::PRECONNECTED || type == SocketType::UNIX || + type == SocketType::UNIX_BOOTSTRAP) { // we can't get port numbers for unix sockets return; } @@ -1566,7 +1616,7 @@ static bool testSupportVsockLoopback() { } static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) { - std::vector<SocketType> ret = {SocketType::UNIX, SocketType::INET}; + std::vector<SocketType> ret = {SocketType::UNIX, SocketType::UNIX_BOOTSTRAP, SocketType::INET}; if (hasPreconnected) ret.push_back(SocketType::PRECONNECTED); @@ -1767,6 +1817,8 @@ public: // A server that handles client socket connections. class Server { public: + using AcceptConnection = std::function<base::unique_fd(Server*)>; + explicit Server() {} Server(Server&&) = default; ~Server() { shutdownAndWait(); } @@ -1791,6 +1843,21 @@ public: return connectTo(UnixSocketAddress(addr.c_str())); }; } break; + case SocketType::UNIX_BOOTSTRAP: { + base::unique_fd bootstrapFdClient, bootstrapFdServer; + if (!base::Socketpair(SOCK_STREAM, &bootstrapFdClient, &bootstrapFdServer)) { + return AssertionFailure() << "Socketpair() failed"; + } + auto status = rpcServer->setupUnixDomainSocketBootstrapServer( + std::move(bootstrapFdServer)); + if (status != OK) { + return AssertionFailure() << "setupUnixDomainSocketBootstrapServer: " + << statusToString(status); + } + mBootstrapSocket = RpcTransportFd(std::move(bootstrapFdClient)); + mAcceptConnection = &Server::recvmsgServerConnection; + mConnectToServer = [this] { return connectToUnixBootstrap(mBootstrapSocket); }; + } break; case SocketType::VSOCK: { auto port = allocateVsockPort(); auto status = rpcServer->setupVsockServer(port); @@ -1838,14 +1905,33 @@ public: LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!"); mThread = std::make_unique<std::thread>(&Server::run, this); } + + base::unique_fd acceptServerConnection() { + return base::unique_fd(TEMP_FAILURE_RETRY( + accept4(mFd.fd.get(), nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK))); + } + + base::unique_fd recvmsgServerConnection() { + std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds; + int buf; + iovec iov{&buf, sizeof(buf)}; + + if (receiveMessageFromSocket(mFd, &iov, 1, &fds) < 0) { + int savedErrno = errno; + LOG(FATAL) << "Failed receiveMessage: " << strerror(savedErrno); + } + if (fds.size() != 1) { + LOG(FATAL) << "Expected one FD from receiveMessage(), got " << fds.size(); + } + return std::move(std::get<base::unique_fd>(fds[0])); + } + void run() { LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!"); std::vector<std::thread> threads; while (OK == mFdTrigger->triggerablePoll(mFd, POLLIN)) { - base::unique_fd acceptedFd( - TEMP_FAILURE_RETRY(accept4(mFd.fd.get(), nullptr, nullptr /*length*/, - SOCK_CLOEXEC | SOCK_NONBLOCK))); + base::unique_fd acceptedFd = mAcceptConnection(this); threads.emplace_back(&Server::handleOne, this, std::move(acceptedFd)); } @@ -1872,8 +1958,9 @@ public: private: std::unique_ptr<std::thread> mThread; ConnectToServer mConnectToServer; + AcceptConnection mAcceptConnection = &Server::acceptServerConnection; std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make(); - RpcTransportFd mFd; + RpcTransportFd mFd, mBootstrapSocket; std::unique_ptr<RpcTransportCtx> mCtx; std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier = std::make_shared<RpcCertificateVerifierSimple>(); diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h index fddf5f35a2..823bbf6b7f 100644 --- a/libs/binder/tests/binderRpcTestCommon.h +++ b/libs/binder/tests/binderRpcTestCommon.h @@ -49,6 +49,7 @@ #include "../BuildFlags.h" #include "../FdTrigger.h" +#include "../OS.h" // for testing UnixBootstrap clients #include "../RpcSocketAddress.h" // for testing preconnected clients #include "../RpcState.h" // for debugging #include "../vm_sockets.h" // for VMADDR_* @@ -67,15 +68,19 @@ static inline std::vector<RpcSecurity> RpcSecurityValues() { enum class SocketType { PRECONNECTED, UNIX, + UNIX_BOOTSTRAP, VSOCK, INET, }; + static inline std::string PrintToString(SocketType socketType) { switch (socketType) { case SocketType::PRECONNECTED: return "preconnected_uds"; case SocketType::UNIX: return "unix_domain_socket"; + case SocketType::UNIX_BOOTSTRAP: + return "unix_domain_socket_bootstrap"; case SocketType::VSOCK: return "vm_socket"; case SocketType::INET: diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp index 31eb5dadf1..a922b21dd7 100644 --- a/libs/binder/tests/binderRpcTestService.cpp +++ b/libs/binder/tests/binderRpcTestService.cpp @@ -42,6 +42,7 @@ int main(int argc, const char* argv[]) { server->setSupportedFileDescriptorTransportModes(serverSupportedFileDescriptorTransportModes); unsigned int outPort = 0; + base::unique_fd unixBootstrapFd(serverConfig.unixBootstrapFd); switch (socketType) { case SocketType::PRECONNECTED: @@ -50,6 +51,9 @@ int main(int argc, const char* argv[]) { CHECK_EQ(OK, server->setupUnixDomainServer(serverConfig.addr.c_str())) << serverConfig.addr; break; + case SocketType::UNIX_BOOTSTRAP: + CHECK_EQ(OK, server->setupUnixDomainSocketBootstrapServer(std::move(unixBootstrapFd))); + break; case SocketType::VSOCK: CHECK_EQ(OK, server->setupVsockServer(serverConfig.vsockPort)); break; diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h index e57bae6035..8fc9263b98 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_binder.h @@ -23,7 +23,7 @@ namespace android { // Get a random binder object for use in fuzzing. // -// may return multiple FDs (e.g. pipe), but will always return at least one +// May return nullptr. sp<IBinder> getRandomBinder(FuzzedDataProvider* provider); } // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp index 4bb486bef0..edc695f81a 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp @@ -36,6 +36,11 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOpti if (provider.ConsumeBool()) { auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make()); CHECK_EQ(OK, session->addNullDebuggingClient()); + // Set the protocol version so that we don't crash if the session + // actually gets used. This isn't cheating because the version should + // always be set if the session init succeeded and we aren't testing the + // session init here (it is bypassed by addNullDebuggingClient). + session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION); p->markForRpc(session); if (options->writeHeader) { diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp index 46346bb3e9..397ff41d58 100644 --- a/libs/binder/trusty/OS.cpp +++ b/libs/binder/trusty/OS.cpp @@ -16,6 +16,7 @@ #if defined(TRUSTY_USERSPACE) #include <openssl/rand.h> +#include <trusty_ipc.h> #else #include <lib/rand/rand.h> #endif @@ -23,6 +24,7 @@ #include <binder/RpcTransportTipcTrusty.h> #include "../OS.h" +#include "TrustyStatus.h" using android::base::Result; @@ -43,13 +45,32 @@ status_t getRandomBytes(uint8_t* data, size_t size) { #endif // TRUSTY_USERSPACE } -status_t dupFileDescriptor(int /*oldFd*/, int* /*newFd*/) { - // TODO: implement separately - return INVALID_OPERATION; +status_t dupFileDescriptor(int oldFd, int* newFd) { + int res = dup(oldFd); + if (res < 0) { + return statusFromTrusty(res); + } + + *newFd = res; + return OK; } std::unique_ptr<RpcTransportCtxFactory> makeDefaultRpcTransportCtxFactory() { return RpcTransportCtxFactoryTipcTrusty::make(); } +int sendMessageOnSocket( + const RpcTransportFd& /* socket */, iovec* /* iovs */, int /* niovs */, + const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /* ancillaryFds */) { + errno = ENOTSUP; + return -1; +} + +int receiveMessageFromSocket( + const RpcTransportFd& /* socket */, iovec* /* iovs */, int /* niovs */, + std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /* ancillaryFds */) { + errno = ENOTSUP; + return -1; +} + } // namespace android diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp index 0b67b9fb12..58bfe71211 100644 --- a/libs/binder/trusty/RpcTransportTipcTrusty.cpp +++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "RpcTransportTipcTrusty" +#include <inttypes.h> #include <trusty_ipc.h> #include <binder/RpcSession.h> @@ -47,7 +48,7 @@ public: status_t interruptableWriteFully( FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs, const std::optional<android::base::function_ref<status_t()>>& /*altPoll*/, - const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /*ancillaryFds*/) + const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override { if (niovs < 0) { return BAD_VALUE; @@ -58,12 +59,32 @@ public: size += iovs[i].iov_len; } + handle_t msgHandles[IPC_MAX_MSG_HANDLES]; ipc_msg_t msg{ .num_iov = static_cast<uint32_t>(niovs), .iov = iovs, - .num_handles = 0, // TODO: add ancillaryFds + .num_handles = 0, .handles = nullptr, }; + + if (ancillaryFds != nullptr && !ancillaryFds->empty()) { + if (ancillaryFds->size() > IPC_MAX_MSG_HANDLES) { + // This shouldn't happen because we check the FD count in RpcState. + ALOGE("Saw too many file descriptors in RpcTransportCtxTipcTrusty: " + "%zu (max is %u). Aborting session.", + ancillaryFds->size(), IPC_MAX_MSG_HANDLES); + return BAD_VALUE; + } + + for (size_t i = 0; i < ancillaryFds->size(); i++) { + msgHandles[i] = + std::visit([](const auto& fd) { return fd.get(); }, ancillaryFds->at(i)); + } + + msg.num_handles = ancillaryFds->size(); + msg.handles = msgHandles; + } + ssize_t rc = send_msg(mSocket.fd.get(), &msg); if (rc == ERR_NOT_ENOUGH_BUFFER) { // Peer is blocked, wait until it unblocks. @@ -97,8 +118,7 @@ public: status_t interruptableReadFully( FdTrigger* /*fdTrigger*/, iovec* iovs, int niovs, const std::optional<android::base::function_ref<status_t()>>& /*altPoll*/, - std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /*ancillaryFds*/) - override { + std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override { if (niovs < 0) { return BAD_VALUE; } @@ -124,11 +144,16 @@ public: return status; } + LOG_ALWAYS_FATAL_IF(mMessageInfo.num_handles > IPC_MAX_MSG_HANDLES, + "Received too many handles %" PRIu32, mMessageInfo.num_handles); + bool haveHandles = mMessageInfo.num_handles != 0; + handle_t msgHandles[IPC_MAX_MSG_HANDLES]; + ipc_msg_t msg{ .num_iov = static_cast<uint32_t>(niovs), .iov = iovs, - .num_handles = 0, // TODO: support ancillaryFds - .handles = nullptr, + .num_handles = mMessageInfo.num_handles, + .handles = haveHandles ? msgHandles : 0, }; ssize_t rc = read_msg(mSocket.fd.get(), mMessageInfo.id, mMessageOffset, &msg); if (rc < 0) { @@ -141,6 +166,28 @@ public: "Message offset exceeds length %zu/%zu", mMessageOffset, mMessageInfo.len); + if (haveHandles) { + if (ancillaryFds != nullptr) { + ancillaryFds->reserve(ancillaryFds->size() + mMessageInfo.num_handles); + for (size_t i = 0; i < mMessageInfo.num_handles; i++) { + ancillaryFds->emplace_back(base::unique_fd(msgHandles[i])); + } + + // Clear the saved number of handles so we don't accidentally + // read them multiple times + mMessageInfo.num_handles = 0; + haveHandles = false; + } else { + ALOGE("Received unexpected handles %" PRIu32, mMessageInfo.num_handles); + // It should be safe to continue here. We could abort, but then + // peers could DoS us by sending messages with handles in them. + // Close the handles since we are ignoring them. + for (size_t i = 0; i < mMessageInfo.num_handles; i++) { + ::close(msgHandles[i]); + } + } + } + // Release the message if all of it has been read if (mMessageOffset == mMessageInfo.len) { releaseMessage(); diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h index cc31c95da1..7d9dd8c648 100644 --- a/libs/binder/trusty/include/binder/RpcServerTrusty.h +++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h @@ -60,6 +60,10 @@ public: std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr); void setProtocolVersion(uint32_t version) { mRpcServer->setProtocolVersion(version); } + void setSupportedFileDescriptorTransportModes( + const std::vector<RpcSession::FileDescriptorTransportMode>& modes) { + mRpcServer->setSupportedFileDescriptorTransportModes(modes); + } void setRootObject(const sp<IBinder>& binder) { mRpcServer->setRootObject(binder); } void setRootObjectWeak(const wp<IBinder>& binder) { mRpcServer->setRootObjectWeak(binder); } void setPerSessionRootObject(std::function<sp<IBinder>(const void*, size_t)>&& object) { diff --git a/libs/binder/trusty/ndk/include/sys/cdefs.h b/libs/binder/trusty/ndk/include/sys/cdefs.h new file mode 100644 index 0000000000..6a48d2b776 --- /dev/null +++ b/libs/binder/trusty/ndk/include/sys/cdefs.h @@ -0,0 +1,24 @@ +/* + * 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 <lk/compiler.h> + +/* Alias the bionic macros to the ones from lk/compiler.h */ +#define __BEGIN_DECLS __BEGIN_CDECLS +#define __END_DECLS __END_CDECLS + +#define __INTRODUCED_IN(x) /* nothing on Trusty */ diff --git a/libs/binder/trusty/ndk/rules.mk b/libs/binder/trusty/ndk/rules.mk new file mode 100644 index 0000000000..03fd006fd2 --- /dev/null +++ b/libs/binder/trusty/ndk/rules.mk @@ -0,0 +1,38 @@ +# Copyright (C) 2021 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. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +LIBBINDER_NDK_DIR := frameworks/native/libs/binder/ndk + +MODULE_SRCS := \ + $(LIBBINDER_NDK_DIR)/ibinder.cpp \ + $(LIBBINDER_NDK_DIR)/libbinder.cpp \ + $(LIBBINDER_NDK_DIR)/parcel.cpp \ + $(LIBBINDER_NDK_DIR)/status.cpp \ + +MODULE_EXPORT_INCLUDES += \ + $(LOCAL_DIR)/include \ + $(LIBBINDER_NDK_DIR)/include_cpp \ + $(LIBBINDER_NDK_DIR)/include_ndk \ + $(LIBBINDER_NDK_DIR)/include_platform \ + +MODULE_LIBRARY_DEPS += \ + trusty/user/base/lib/libstdc++-trusty \ + frameworks/native/libs/binder/trusty \ + +include make/library.mk |