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
diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp
index 3e19646..930bcbd 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 @@
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 @@
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 @@
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 @@
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 8f2805f..0753b54 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 @@
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 @@
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 @@
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 0000000..c6a06cf
--- /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 1b8f4b9..82bc7df 100644
--- a/libs/binder/include/binder/RpcConnection.h
+++ b/libs/binder/include/binder/RpcConnection.h
@@ -32,6 +32,7 @@
class Parcel;
class RpcServer;
+class RpcSocketAddress;
class RpcState;
/**
@@ -43,19 +44,6 @@
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 @@
#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 @@
// 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 @@
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 @@
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 9247128..5535d8a 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,33 +96,31 @@
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
- */
- sp<RpcConnection> addClientConnection();
-
- /**
* You must have at least one client connection before calling this.
*/
void join();
+ /**
+ * For debugging!
+ */
+ std::vector<sp<RpcConnection>> listConnections();
+
~RpcServer();
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 b3282ff..ce47c0d 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -121,12 +121,8 @@
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 f3ec904..d23df8e 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -78,7 +78,7 @@
class MyBinderRpcTest : public BnBinderRpcTest {
public:
- sp<RpcConnection> connection;
+ wp<RpcServer> server;
Status sendString(const std::string& str) override {
(void)str;
@@ -89,13 +89,23 @@
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 @@
// 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 @@
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 @@
LOG_ALWAYS_FATAL("Unknown socket type");
}
- configure(server, connection);
+ configure(server);
server->join();
}),
@@ -379,13 +385,11 @@
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 @@
};
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);