diff options
-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); |