diff options
author | 2021-05-01 01:28:27 +0000 | |
---|---|---|
committer | 2021-05-03 18:17:21 +0000 | |
commit | 611d15fe78f51d61226382f34f03b0834a3f60ea (patch) | |
tree | 9f15950f4c4d4f12b2434939d48ab1fa1ed82958 | |
parent | 2f1edfa556f22e0758f0efae6722de04139bcb9e (diff) |
libbinder: RPC sock addr associated with RpcServer
This is in preparation for RpcServer having a single thread which loops
w/ accept4. With this CL, since this is moved, there is no way to
identify which thread comes with which client, so the ability to have
multiple clients is temporarily limited (fixed in CL above this). Either
way, nothing currently needs this functionality.
Bug: 185167543
Test: binderRpcTest
Change-Id: I48821970f7cbcb3fec0df00465296072d96db608
-rw-r--r-- | libs/binder/RpcConnection.cpp | 189 | ||||
-rw-r--r-- | libs/binder/RpcServer.cpp | 137 | ||||
-rw-r--r-- | libs/binder/RpcSocketAddress.h | 122 | ||||
-rw-r--r-- | libs/binder/include/binder/RpcConnection.h | 47 | ||||
-rw-r--r-- | libs/binder/include/binder/RpcServer.h | 56 | ||||
-rw-r--r-- | libs/binder/tests/binderRpcBenchmark.cpp | 6 | ||||
-rw-r--r-- | libs/binder/tests/binderRpcTest.cpp | 50 |
7 files changed, 320 insertions, 287 deletions
diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp index 3e1964673a..930bcbde62 100644 --- a/libs/binder/RpcConnection.cpp +++ b/libs/binder/RpcConnection.cpp @@ -18,13 +18,7 @@ #include <binder/RpcConnection.h> -#include <arpa/inet.h> #include <inttypes.h> -#include <netdb.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/un.h> #include <unistd.h> #include <string_view> @@ -33,6 +27,7 @@ #include <binder/Stability.h> #include <utils/String8.h> +#include "RpcSocketAddress.h" #include "RpcState.h" #include "RpcWireFormat.h" @@ -40,16 +35,9 @@ extern "C" pid_t gettid(); #endif -#ifdef __BIONIC__ -#include <linux/vm_sockets.h> -#endif - namespace android { using base::unique_fd; -using AddrInfo = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>; - -RpcConnection::SocketAddress::~SocketAddress() {} RpcConnection::RpcConnection() { LOG_RPC_DETAIL("RpcConnection created %p", this); @@ -68,146 +56,20 @@ sp<RpcConnection> RpcConnection::make() { return sp<RpcConnection>::make(); } -class UnixSocketAddress : public RpcConnection::SocketAddress { -public: - explicit UnixSocketAddress(const char* path) : mAddr({.sun_family = AF_UNIX}) { - unsigned int pathLen = strlen(path) + 1; - LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "Socket path is too long: %u %s", - pathLen, path); - memcpy(mAddr.sun_path, path, pathLen); - } - virtual ~UnixSocketAddress() {} - std::string toString() const override { - return String8::format("path '%.*s'", static_cast<int>(sizeof(mAddr.sun_path)), - mAddr.sun_path) - .c_str(); - } - const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); } - size_t addrSize() const override { return sizeof(mAddr); } - -private: - sockaddr_un mAddr; -}; - -bool RpcConnection::setupUnixDomainServer(const char* path) { - return setupSocketServer(UnixSocketAddress(path)); -} - bool RpcConnection::setupUnixDomainClient(const char* path) { return setupSocketClient(UnixSocketAddress(path)); } #ifdef __BIONIC__ -class VsockSocketAddress : public RpcConnection::SocketAddress { -public: - VsockSocketAddress(unsigned int cid, unsigned int port) - : mAddr({ - .svm_family = AF_VSOCK, - .svm_port = port, - .svm_cid = cid, - }) {} - virtual ~VsockSocketAddress() {} - std::string toString() const override { - return String8::format("cid %u port %u", mAddr.svm_cid, mAddr.svm_port).c_str(); - } - const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); } - size_t addrSize() const override { return sizeof(mAddr); } - -private: - sockaddr_vm mAddr; -}; - -bool RpcConnection::setupVsockServer(unsigned int port) { - // realizing value w/ this type at compile time to avoid ubsan abort - constexpr unsigned int kAnyCid = VMADDR_CID_ANY; - - return setupSocketServer(VsockSocketAddress(kAnyCid, port)); -} - bool RpcConnection::setupVsockClient(unsigned int cid, unsigned int port) { return setupSocketClient(VsockSocketAddress(cid, port)); } #endif // __BIONIC__ -class InetSocketAddress : public RpcConnection::SocketAddress { -public: - InetSocketAddress(const sockaddr* sockAddr, size_t size, const char* addr, unsigned int port) - : mSockAddr(sockAddr), mSize(size), mAddr(addr), mPort(port) {} - [[nodiscard]] std::string toString() const override { - return String8::format("%s:%u", mAddr, mPort).c_str(); - } - [[nodiscard]] const sockaddr* addr() const override { return mSockAddr; } - [[nodiscard]] size_t addrSize() const override { return mSize; } - -private: - const sockaddr* mSockAddr; - size_t mSize; - const char* mAddr; - unsigned int mPort; -}; - -AddrInfo GetAddrInfo(const char* addr, unsigned int port) { - addrinfo hint{ - .ai_flags = 0, - .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, - .ai_protocol = 0, - }; - addrinfo* aiStart = nullptr; - if (int rc = getaddrinfo(addr, std::to_string(port).data(), &hint, &aiStart); 0 != rc) { - ALOGE("Unable to resolve %s:%u: %s", addr, port, gai_strerror(rc)); - return AddrInfo(nullptr, nullptr); - } - if (aiStart == nullptr) { - ALOGE("Unable to resolve %s:%u: getaddrinfo returns null", addr, port); - return AddrInfo(nullptr, nullptr); - } - return AddrInfo(aiStart, &freeaddrinfo); -} - -bool RpcConnection::setupInetServer(unsigned int port, unsigned int* assignedPort) { - const char* kAddr = "127.0.0.1"; - - if (assignedPort != nullptr) *assignedPort = 0; - auto aiStart = GetAddrInfo(kAddr, port); - if (aiStart == nullptr) return false; - for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) { - InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port); - if (!setupSocketServer(socketAddress)) { - continue; - } - - LOG_ALWAYS_FATAL_IF(socketAddress.addr()->sa_family != AF_INET, "expecting inet"); - sockaddr_in addr{}; - socklen_t len = sizeof(addr); - if (0 != getsockname(mServer.get(), reinterpret_cast<sockaddr*>(&addr), &len)) { - int savedErrno = errno; - ALOGE("Could not getsockname at %s: %s", socketAddress.toString().c_str(), - strerror(savedErrno)); - return false; - } - LOG_ALWAYS_FATAL_IF(len != sizeof(addr), "Wrong socket type: len %zu vs len %zu", - static_cast<size_t>(len), sizeof(addr)); - unsigned int realPort = ntohs(addr.sin_port); - LOG_ALWAYS_FATAL_IF(port != 0 && realPort != port, - "Requesting inet server on %s but it is set up on %u.", - socketAddress.toString().c_str(), realPort); - - if (assignedPort != nullptr) { - *assignedPort = realPort; - } - - return true; - } - ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr, - port); - return false; -} - bool RpcConnection::setupInetClient(const char* addr, unsigned int port) { - auto aiStart = GetAddrInfo(addr, port); + auto aiStart = InetSocketAddress::getAddrInfo(addr, port); if (aiStart == nullptr) return false; for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) { InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, addr, port); @@ -253,23 +115,10 @@ status_t RpcConnection::sendDecStrong(const RpcAddress& address) { return state()->sendDecStrong(socket.fd(), address); } -void RpcConnection::join() { - // TODO(b/185167543): do this dynamically, instead of from a static number - // of threads - unique_fd clientFd( - TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC))); - if (clientFd < 0) { - // If this log becomes confusing, should save more state from setupUnixDomainServer - // in order to output here. - ALOGE("Could not accept4 socket: %s", strerror(errno)); - return; - } - - LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get()); - +void RpcConnection::join(unique_fd client) { // must be registered to allow arbitrary client code executing commands to // be able to do nested calls (we can't only read from it) - sp<ConnectionSocket> socket = assignServerToThisThread(std::move(clientFd)); + sp<ConnectionSocket> socket = assignServerToThisThread(std::move(client)); while (true) { status_t error = @@ -293,33 +142,7 @@ wp<RpcServer> RpcConnection::server() { return mForServer; } -bool RpcConnection::setupSocketServer(const SocketAddress& addr) { - LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcConnection can only have one server."); - - unique_fd serverFd( - TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0))); - if (serverFd == -1) { - ALOGE("Could not create socket: %s", strerror(errno)); - return false; - } - - if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) { - int savedErrno = errno; - ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno)); - return false; - } - - if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) { - int savedErrno = errno; - ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno)); - return false; - } - - mServer = std::move(serverFd); - return true; -} - -bool RpcConnection::setupSocketClient(const SocketAddress& addr) { +bool RpcConnection::setupSocketClient(const RpcSocketAddress& addr) { { std::lock_guard<std::mutex> _l(mSocketMutex); LOG_ALWAYS_FATAL_IF(mClients.size() != 0, @@ -351,7 +174,7 @@ bool RpcConnection::setupSocketClient(const SocketAddress& addr) { return true; } -bool RpcConnection::setupOneSocketClient(const SocketAddress& addr) { +bool RpcConnection::setupOneSocketClient(const RpcSocketAddress& addr) { unique_fd serverFd( TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0))); if (serverFd == -1) { diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index 8f2805fce4..0753b54763 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -27,10 +27,13 @@ #include <log/log.h> #include "RpcState.h" +#include "RpcSocketAddress.h" #include "RpcWireFormat.h" namespace android { +using base::unique_fd; + RpcServer::RpcServer() {} RpcServer::~RpcServer() {} @@ -42,14 +45,63 @@ void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() mAgreedExperimental = true; } +bool RpcServer::setupUnixDomainServer(const char* path) { + return setupSocketServer(UnixSocketAddress(path)); +} + +#ifdef __BIONIC__ + +bool RpcServer::setupVsockServer(unsigned int port) { + // realizing value w/ this type at compile time to avoid ubsan abort + constexpr unsigned int kAnyCid = VMADDR_CID_ANY; + + return setupSocketServer(VsockSocketAddress(kAnyCid, port)); +} + +#endif // __BIONIC__ + +bool RpcServer::setupInetServer(unsigned int port, unsigned int* assignedPort) { + const char* kAddr = "127.0.0.1"; + + if (assignedPort != nullptr) *assignedPort = 0; + auto aiStart = InetSocketAddress::getAddrInfo(kAddr, port); + if (aiStart == nullptr) return false; + for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) { + InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port); + if (!setupSocketServer(socketAddress)) { + continue; + } + + LOG_ALWAYS_FATAL_IF(socketAddress.addr()->sa_family != AF_INET, "expecting inet"); + sockaddr_in addr{}; + socklen_t len = sizeof(addr); + if (0 != getsockname(mServer.get(), reinterpret_cast<sockaddr*>(&addr), &len)) { + int savedErrno = errno; + ALOGE("Could not getsockname at %s: %s", socketAddress.toString().c_str(), + strerror(savedErrno)); + return false; + } + LOG_ALWAYS_FATAL_IF(len != sizeof(addr), "Wrong socket type: len %zu vs len %zu", + static_cast<size_t>(len), sizeof(addr)); + unsigned int realPort = ntohs(addr.sin_port); + LOG_ALWAYS_FATAL_IF(port != 0 && realPort != port, + "Requesting inet server on %s but it is set up on %u.", + socketAddress.toString().c_str(), realPort); + + if (assignedPort != nullptr) { + *assignedPort = realPort; + } + + return true; + } + ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr, + port); + return false; +} + void RpcServer::setMaxThreads(size_t threads) { LOG_ALWAYS_FATAL_IF(threads <= 0, "RpcServer is useless without threads"); - { - // this lock should only ever be needed in the error case - std::lock_guard<std::mutex> _l(mLock); - LOG_ALWAYS_FATAL_IF(mConnections.size() > 0, - "Must specify max threads before creating a connection"); - } + LOG_ALWAYS_FATAL_IF(mStarted, "must be called before started"); mMaxThreads = threads; } @@ -67,30 +119,36 @@ sp<IBinder> RpcServer::getRootObject() { return mRootObject; } -sp<RpcConnection> RpcServer::addClientConnection() { +void RpcServer::join() { LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!"); - auto connection = RpcConnection::make(); - connection->setForServer(sp<RpcServer>::fromExisting(this)); - { - std::lock_guard<std::mutex> _l(mLock); - LOG_ALWAYS_FATAL_IF(mStarted, - "currently only supports adding client connections at creation time"); - mConnections.push_back(connection); - } - return connection; -} - -void RpcServer::join() { std::vector<std::thread> pool; { std::lock_guard<std::mutex> _l(mLock); + LOG_ALWAYS_FATAL_IF(mServer.get() == -1, "RpcServer must be setup to join."); + // TODO(b/185167543): support more than one client at once + mConnection = RpcConnection::make(); + mConnection->setForServer(sp<RpcServer>::fromExisting(this)); + mStarted = true; - for (const sp<RpcConnection>& connection : mConnections) { for (size_t i = 0; i < mMaxThreads; i++) { - pool.push_back(std::thread([=] { connection->join(); })); + pool.push_back(std::thread([=] { + // TODO(b/185167543): do this dynamically, instead of from a static number + // of threads + unique_fd clientFd(TEMP_FAILURE_RETRY( + accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC))); + if (clientFd < 0) { + // If this log becomes confusing, should save more state from + // setupUnixDomainServer in order to output here. + ALOGE("Could not accept4 socket: %s", strerror(errno)); + return; + } + + LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get()); + + mConnection->join(std::move(clientFd)); + })); } - } } // TODO(b/185167543): don't waste extra thread for join, and combine threads @@ -98,4 +156,39 @@ void RpcServer::join() { for (auto& t : pool) t.join(); } +std::vector<sp<RpcConnection>> RpcServer::listConnections() { + std::lock_guard<std::mutex> _l(mLock); + if (mConnection == nullptr) return {}; + return {mConnection}; +} + +bool RpcServer::setupSocketServer(const RpcSocketAddress& addr) { + { + std::lock_guard<std::mutex> _l(mLock); + LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcServer can only have one server."); + } + + unique_fd serverFd( + TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0))); + if (serverFd == -1) { + ALOGE("Could not create socket: %s", strerror(errno)); + return false; + } + + if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) { + int savedErrno = errno; + ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno)); + return false; + } + + if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) { + int savedErrno = errno; + ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno)); + return false; + } + + mServer = std::move(serverFd); + return true; +} + } // namespace android diff --git a/libs/binder/RpcSocketAddress.h b/libs/binder/RpcSocketAddress.h new file mode 100644 index 0000000000..c6a06cf817 --- /dev/null +++ b/libs/binder/RpcSocketAddress.h @@ -0,0 +1,122 @@ +/* + * 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. + */ +#pragma once + +#include <string> + +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> + +#ifdef __BIONIC__ +#include <linux/vm_sockets.h> +#endif + +namespace android { + +class RpcSocketAddress { +public: + virtual ~RpcSocketAddress() {} + virtual std::string toString() const = 0; + virtual const sockaddr* addr() const = 0; + virtual size_t addrSize() const = 0; +}; + +class UnixSocketAddress : public RpcSocketAddress { +public: + explicit UnixSocketAddress(const char* path) : mAddr({.sun_family = AF_UNIX}) { + unsigned int pathLen = strlen(path) + 1; + LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "Socket path is too long: %u %s", + pathLen, path); + memcpy(mAddr.sun_path, path, pathLen); + } + virtual ~UnixSocketAddress() {} + std::string toString() const override { + return String8::format("path '%.*s'", static_cast<int>(sizeof(mAddr.sun_path)), + mAddr.sun_path) + .c_str(); + } + const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); } + size_t addrSize() const override { return sizeof(mAddr); } + +private: + sockaddr_un mAddr; +}; + +#ifdef __BIONIC__ + +class VsockSocketAddress : public RpcSocketAddress { +public: + VsockSocketAddress(unsigned int cid, unsigned int port) + : mAddr({ + .svm_family = AF_VSOCK, + .svm_port = port, + .svm_cid = cid, + }) {} + virtual ~VsockSocketAddress() {} + std::string toString() const override { + return String8::format("cid %u port %u", mAddr.svm_cid, mAddr.svm_port).c_str(); + } + const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); } + size_t addrSize() const override { return sizeof(mAddr); } + +private: + sockaddr_vm mAddr; +}; + +#endif // __BIONIC__ + +class InetSocketAddress : public RpcSocketAddress { +public: + InetSocketAddress(const sockaddr* sockAddr, size_t size, const char* addr, unsigned int port) + : mSockAddr(sockAddr), mSize(size), mAddr(addr), mPort(port) {} + [[nodiscard]] std::string toString() const override { + return String8::format("%s:%u", mAddr, mPort).c_str(); + } + [[nodiscard]] const sockaddr* addr() const override { return mSockAddr; } + [[nodiscard]] size_t addrSize() const override { return mSize; } + + using AddrInfo = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>; + static AddrInfo getAddrInfo(const char* addr, unsigned int port) { + addrinfo hint{ + .ai_flags = 0, + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_protocol = 0, + }; + addrinfo* aiStart = nullptr; + if (int rc = getaddrinfo(addr, std::to_string(port).data(), &hint, &aiStart); 0 != rc) { + ALOGE("Unable to resolve %s:%u: %s", addr, port, gai_strerror(rc)); + return AddrInfo(nullptr, nullptr); + } + if (aiStart == nullptr) { + ALOGE("Unable to resolve %s:%u: getaddrinfo returns null", addr, port); + return AddrInfo(nullptr, nullptr); + } + return AddrInfo(aiStart, &freeaddrinfo); + } + +private: + const sockaddr* mSockAddr; + size_t mSize; + const char* mAddr; + unsigned int mPort; +}; + +} // namespace android diff --git a/libs/binder/include/binder/RpcConnection.h b/libs/binder/include/binder/RpcConnection.h index 1b8f4b9a29..82bc7df96d 100644 --- a/libs/binder/include/binder/RpcConnection.h +++ b/libs/binder/include/binder/RpcConnection.h @@ -32,6 +32,7 @@ namespace android { class Parcel; class RpcServer; +class RpcSocketAddress; class RpcState; /** @@ -43,19 +44,6 @@ public: static sp<RpcConnection> make(); /** - * This represents a connection for responses, e.g.: - * - * process A serves binder a - * process B opens a connection to process A - * process B makes binder b and sends it to A - * A uses this 'back connection' to send things back to B - * - * This should be called once, and then a call should be made to join per - * connection thread. - */ - [[nodiscard]] bool setupUnixDomainServer(const char* path); - - /** * This should be called once per thread, matching 'join' in the remote * process. */ @@ -63,28 +51,12 @@ public: #ifdef __BIONIC__ /** - * Creates an RPC server at the current port. - */ - [[nodiscard]] bool setupVsockServer(unsigned int port); - - /** * Connects to an RPC server at the CVD & port. */ [[nodiscard]] bool setupVsockClient(unsigned int cvd, unsigned int port); #endif // __BIONIC__ /** - * Creates an RPC server at the current port using IPv4. - * - * TODO(b/182914638): IPv6 support - * - * Set |port| to 0 to pick an ephemeral port; see discussion of - * /proc/sys/net/ipv4/ip_local_port_range in ip(7). In this case, |assignedPort| - * will be set to the picked port number, if it is not null. - */ - [[nodiscard]] bool setupInetServer(unsigned int port, unsigned int* assignedPort); - - /** * Connects to an RPC server at the given address and port. */ [[nodiscard]] bool setupInetClient(const char* addr, unsigned int port); @@ -122,20 +94,12 @@ public: // internal only const std::unique_ptr<RpcState>& state() { return mState; } - class SocketAddress { - public: - virtual ~SocketAddress(); - virtual std::string toString() const = 0; - virtual const sockaddr* addr() const = 0; - virtual size_t addrSize() const = 0; - }; - private: friend sp<RpcConnection>; friend RpcServer; RpcConnection(); - void join(); + void join(base::unique_fd client); struct ConnectionSocket : public RefBase { base::unique_fd fd; @@ -145,9 +109,8 @@ private: std::optional<pid_t> exclusiveTid; }; - bool setupSocketServer(const SocketAddress& address); - bool setupSocketClient(const SocketAddress& address); - bool setupOneSocketClient(const SocketAddress& address); + bool setupSocketClient(const RpcSocketAddress& address); + bool setupOneSocketClient(const RpcSocketAddress& address); void addClient(base::unique_fd fd); sp<ConnectionSocket> assignServerToThisThread(base::unique_fd fd); bool removeServerSocket(const sp<ConnectionSocket>& socket); @@ -197,8 +160,6 @@ private: std::unique_ptr<RpcState> mState; - base::unique_fd mServer; // socket we are accepting connections on - std::mutex mSocketMutex; // for all below std::condition_variable mSocketCv; // for mWaitingThreads size_t mWaitingThreads = 0; diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h index 9247128b95..5535d8a87c 100644 --- a/libs/binder/include/binder/RpcServer.h +++ b/libs/binder/include/binder/RpcServer.h @@ -29,14 +29,52 @@ namespace android { +class RpcSocketAddress; + /** * This represents a server of an interface, which may be connected to by any * number of clients over sockets. + * + * Usage: + * auto server = RpcServer::make(); + * // only supports one now + * if (!server->setup*Server(...)) { + * :( + * } + * server->join(); */ class RpcServer final : public virtual RefBase { public: static sp<RpcServer> make(); + /** + * This represents a connection for responses, e.g.: + * + * process A serves binder a + * process B opens a connection to process A + * process B makes binder b and sends it to A + * A uses this 'back connection' to send things back to B + */ + [[nodiscard]] bool setupUnixDomainServer(const char* path); + +#ifdef __BIONIC__ + /** + * Creates an RPC server at the current port. + */ + [[nodiscard]] bool setupVsockServer(unsigned int port); +#endif // __BIONIC__ + + /** + * Creates an RPC server at the current port using IPv4. + * + * TODO(b/182914638): IPv6 support + * + * Set |port| to 0 to pick an ephemeral port; see discussion of + * /proc/sys/net/ipv4/ip_local_port_range in ip(7). In this case, |assignedPort| + * will be set to the picked port number, if it is not null. + */ + [[nodiscard]] bool setupInetServer(unsigned int port, unsigned int* assignedPort); + void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction(); /** @@ -58,19 +96,14 @@ public: sp<IBinder> getRootObject(); /** - * Setup a static connection, when the number of clients are known. - * - * Each call to this function corresponds to a different client, and clients - * each have their own threadpools. - * - * TODO(b/167966510): support dynamic creation of connections/threads + * You must have at least one client connection before calling this. */ - sp<RpcConnection> addClientConnection(); + void join(); /** - * You must have at least one client connection before calling this. + * For debugging! */ - void join(); + std::vector<sp<RpcConnection>> listConnections(); ~RpcServer(); @@ -78,13 +111,16 @@ private: friend sp<RpcServer>; RpcServer(); + bool setupSocketServer(const RpcSocketAddress& address); + bool mAgreedExperimental = false; bool mStarted = false; // TODO(b/185167543): support dynamically added clients size_t mMaxThreads = 1; + base::unique_fd mServer; // socket we are accepting connections on std::mutex mLock; // for below sp<IBinder> mRootObject; - std::vector<sp<RpcConnection>> mConnections; // per-client + sp<RpcConnection> mConnection; }; } // namespace android diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp index b3282ffb18..ce47c0d042 100644 --- a/libs/binder/tests/binderRpcBenchmark.cpp +++ b/libs/binder/tests/binderRpcBenchmark.cpp @@ -121,12 +121,8 @@ int main(int argc, char** argv) { std::thread([addr]() { sp<RpcServer> server = RpcServer::make(); server->setRootObject(sp<MyBinderRpcBenchmark>::make()); - server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction(); - - sp<RpcConnection> connection = server->addClientConnection(); - CHECK(connection->setupUnixDomainServer(addr.c_str())); - + CHECK(server->setupUnixDomainServer(addr.c_str())); server->join(); }).detach(); diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index f3ec904d69..d23df8eaec 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -78,7 +78,7 @@ std::atomic<int32_t> MyBinderRpcSession::gNum; class MyBinderRpcTest : public BnBinderRpcTest { public: - sp<RpcConnection> connection; + wp<RpcServer> server; Status sendString(const std::string& str) override { (void)str; @@ -89,13 +89,23 @@ public: return Status::ok(); } Status countBinders(int32_t* out) override { - if (connection == nullptr) { + sp<RpcServer> spServer = server.promote(); + if (spServer == nullptr) { return Status::fromExceptionCode(Status::EX_NULL_POINTER); } - *out = connection->state()->countBinders(); - if (*out != 1) { - connection->state()->dump(); + size_t count = 0; + for (auto connection : spServer->listConnections()) { + count += connection->state()->countBinders(); + } + // help debugging if we don't have one binder (this call is always made + // in this test when exactly one binder is held, which is held only to + // call this method - all other binders should be cleaned up) + if (count != 1) { + for (auto connection : spServer->listConnections()) { + connection->state()->dump(); + } } + *out = count; return Status::ok(); } Status pingMe(const sp<IBinder>& binder, int32_t* out) override { @@ -296,8 +306,7 @@ public: // This creates a new process serving an interface on a certain number of // threads. ProcessConnection createRpcTestSocketServerProcess( - size_t numThreads, - const std::function<void(const sp<RpcServer>&, const sp<RpcConnection>&)>& configure) { + size_t numThreads, const std::function<void(const sp<RpcServer>&)>& configure) { SocketType socketType = GetParam(); std::string addr = allocateSocketAddress(); @@ -312,21 +321,18 @@ public: server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction(); server->setMaxThreads(numThreads); - // server supporting one client on one socket - sp<RpcConnection> connection = server->addClientConnection(); - switch (socketType) { case SocketType::UNIX: - CHECK(connection->setupUnixDomainServer(addr.c_str())) << addr; + CHECK(server->setupUnixDomainServer(addr.c_str())) << addr; break; #ifdef __BIONIC__ case SocketType::VSOCK: - CHECK(connection->setupVsockServer(vsockPort)); + CHECK(server->setupVsockServer(vsockPort)); break; #endif // __BIONIC__ case SocketType::INET: { unsigned int outPort = 0; - CHECK(connection->setupInetServer(0, &outPort)); + CHECK(server->setupInetServer(0, &outPort)); CHECK_NE(0, outPort); CHECK(android::base::WriteFully(pipe->writeEnd(), &outPort, sizeof(outPort))); @@ -336,7 +342,7 @@ public: LOG_ALWAYS_FATAL("Unknown socket type"); } - configure(server, connection); + configure(server); server->join(); }), @@ -379,13 +385,11 @@ public: BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads) { BinderRpcTestProcessConnection ret{ .proc = createRpcTestSocketServerProcess(numThreads, - [&](const sp<RpcServer>& server, - const sp<RpcConnection>& connection) { + [&](const sp<RpcServer>& server) { sp<MyBinderRpcTest> service = new MyBinderRpcTest; server->setRootObject(service); - service->connection = - connection; // for testing only + service->server = server; }), }; @@ -397,12 +401,10 @@ public: }; TEST_P(BinderRpc, RootObjectIsNull) { - auto proc = createRpcTestSocketServerProcess(1, - [](const sp<RpcServer>& server, - const sp<RpcConnection>&) { - // this is the default, but to be explicit - server->setRootObject(nullptr); - }); + auto proc = createRpcTestSocketServerProcess(1, [](const sp<RpcServer>& server) { + // this is the default, but to be explicit + server->setRootObject(nullptr); + }); // retrieved by getRootObject when process is created above EXPECT_EQ(nullptr, proc.rootBinder); |